昨日書いたブログの課題で少し進展がありました。
--- Quotation Begin ---
Metafile→現在どうやって保存するかもNo idea状態です。これはMicrosoftも推していないようで、(あまり使われないので)頑張って*.wmfに復元する意味はないかも?
MemoryStream→コンパイルはできるのですが、復元されていないようです。
PinnedBufferMemoryStream→こいつがどういうクラスなのかをこれから調べる予定→これで追記します。
--- Quotation End ---
Metafileですが、さすがにMicrosoftもクラスを作っているのでImageクラスで読めるだろう、と考え成功。いったんImageクラスで読み込めれば形式を指定してSaveメソッドで保存できます。
MemoryStreamは前回バイト配列に落とし込んで保存しようとして失敗しましたが、WEBでもっと簡単で安全な方法があることが分かり成功。
なお、Stringリソースについては「一行の文字列のファイルを書いても仕方ないんじゃね?」ということもあり、すべてのStringリソースを"*.restext"ファイルに落とす処理も書き加えました。
【「保存」メニューで「保存」ダイアログを出してOKボタンを押した際の処理の一部】
protected void OnOK_Click(object sender, EventArgs e)
{
if(String.IsNullOrEmpty(txbPath.Text))
{
MessageBox.Show("保存ファイル名が指定されていません。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if(FileType) //*.resourcesファイル
{
//ResourceSetを作成する
ResourceSet rs = new ResourceSet(ResFileName);
if(m_Type == "Bitmap")
{
//Bitmapリソースの保存(保存確認◎)
Image img = (Bitmap)rs.GetObject(m_Name);
img.Save(txbPath.Text, ImageFormat.Bmp);
}
else if(m_Type == "Icon")
{
//Iconリソースの保存(保存確認◎)
Image img = ((Icon)rs.GetObject(m_Name)).ToBitmap();
img.Save(txbPath.Text, ImageFormat.Icon);
}
else if(m_Type == "String")
{
//すべての文字列リソースを取得ファイル出力する選択
DialogResult dr = MessageBox.Show("指定出力ファイルを\".restext\"に変更し、すべての文字列リソースをまとめて出力しますか?", "restextファイル出力確認", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if(dr == DialogResult.Yes)
{
m_Name = m_Type = "StrResCollection"; //これをフラグとしてメインフォームで処理を行う
m_Data = txbPath.Text; //その為に保存ファイルパス、名を返す
}
else
{
//Textリソースの保存(保存確認◎)
using (StreamWriter sw = new StreamWriter(txbPath.Text))
{
sw.WriteLine(m_Data);
sw.Close();
}
}
}
else if(m_Type == "Byte[]")
{
//Byte[]リソースの保存(保存確認◎)
Byte[] bytes = (Byte[])rs.GetObject(m_Name);
File.WriteAllBytes (txbPath.Text, bytes);
}
else if(m_Type == "Metafile")
{
Metafile metaFile = (Metafile)rs.GetObject(m_Name);
Image img = (Metafile)metaFile;
img.Save(txbPath.Text, ImageFormat.Wmf); //結局こんなに簡単でした(汗;)。
/*
Metafile metaFile = (Metafile)rsx.GetObject(m_Name);
//GDI+ では、EMF および EMF+ 形式でメタファイルを記録できますが、WMF 形式では記録できません。
//https://learn.microsoft.com/ja-jp/dotnet/desktop/winforms/advanced/metafiles-in-gdi?view=netframeworkdesktop-4.8
Save メソッドを使用してグラフィック イメージを Windows メタファイル形式 (WMF) または拡張メタファイル形式 (EMF)
ファイルとして保存すると、結果のファイルは代わりにポータブル ネットワーク グラフィックス (PNG) ファイルとして保存
されます。 この動作は、.NET Frameworkの GDI+ コンポーネントに、ファイルを .wmf または .emf ファイルとして保存する
ために使用できるエンコーダーがないために発生します。
*/
}
else if(m_Type == "MemoryStream")
{
/* Case 1 MemoryStreamリソースの保存(保存確認×-jpgファイル使用)
MemoryStream mStream = new MemoryStream();
mStream = (MemoryStream)rsx.GetObject(m_Name);
using (FileStream file = new FileStream(txbPath.Text, FileMode.Create, FileAccess.Write)) //FileMode.Createは既存のファイルがあれば上書きする
{
Byte[] bytes = new Byte[mStream.Length];
mStream.Read(bytes, 0, (int)mStream.Length);
file.Write(bytes, 0, bytes.Length);
mStream.Close();
file.Close();
} */
// Case 2 MemoryStreamリソースの保存(保存確認◎-jpgファイル使用)
using (FileStream file = new FileStream(txbPath.Text, FileMode.Create, FileAccess.Write)) //FileMode.Createは既存のファイルがあれば上書きする
{
MemoryStream mStream = (MemoryStream)rs.GetObject(m_Name);
mStream.WriteTo(file);
} //これもこんなに簡単でした。Using構文は簡単で助かります。
/*
// Case 3 MemoryStreamリソースの保存
MemoryStream mStream = (MemoryStream)rsx.GetObject(m_Name);
FileStream file = new FileStream(txbPath.Text, FileMode.Create, FileAccess.Write);
mStream.WriteTo(file);
file.Close();
mStream.Close();
// Case 4 MemoryStreamリソースの保存
MemoryStream mStream = (MemoryStream)rsx.GetObject(m_Name);
File.WriteAllBytes(txbPath.Text, mStream.ToArray());
*/ //↑でダメならこれらを試すつもりでした。
}
//>>>> 同日追記 <<<<
else if(m_Type == "PinnedBufferMemoryStream")
{
/* http://www.dotnetframework.org/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/clr/src/BCL/System/IO/PinnedBufferMemoryStream@cs/1305376/PinnedBufferMemoryStream@cs
↑によればunmanagedMemoryStreamから派生させたクラスなので、↓で行けるかと思ったのですが「'System.IO.PinnedBufferMemoryStream' はアクセスできない保護レベルになっています」エラーが出ます。
using (FileStream file = new FileStream(txbPath.Text, FileMode.Create, FileAccess.Write)) //FileMode.Createは既存のファイルがあれば上書きする
{
PinnedBufferMemoryStream pbms = (PinnedBufferMemoryStream)rs.GetObject(m_Name);
pbms.WriteTo(file);
}
仕方がないので、無理やりMemoryStreamで読む実験をします。
using (FileStream file = new FileStream(txbPath.Text, FileMode.Create, FileAccess.Write)) //FileMode.Createは既存のファイルがあれば上書きする
{
MemoryStream mStream = (MemoryStream)rs.GetObject(m_Name);
mStream.WriteTo(file);
}
矢張り「System.InvalidCastException: 型 'System.IO.PinnedBufferMemoryStream' のオブジェクトを型 'System.IO.MemoryStream' にキャストできません」エラーが出ます。
PinnedBufferMemoryStream pbms = (PinnedBufferMemoryStream)rs.GetObject(m_Name);
File.WriteAllBytes(txbPath.Text, pbms.ToArray());
これもダメ。「PinnedBufferMemoryStream」は保護されており、使えません。
*/
/*だったのですが、矢張りねがしつこいので恨みがましくWEBを見ていて、ResourceReaderクラスのGetResourceDataメソッドに気が付きました。(これはバイトデータに落としてセーブしてくれる。)「とはいってもやはり保護クラスだからエラーが出てだめだよねぇ」と始める前から諦め気分でコンパイルしたら、
なーんと、通っちゃいましたぁ!!!
ということでコードを。
*/
//ResourceSetでは対応できないので、ResourceReaderのGetResourceDataメソッドを使ってみたらすんなり決まった!(以下が追記部分のソリューション)
ResourceReader rr = new ResourceReader(ResFileName);
string resType;
byte[] resData;
rr.GetResourceData(m_Name, out resType, out resData);
resType = String.Format("Resource Type: {0} and the Size : {1}", resType, resData.Length);
MessageBox.Show(resType, "PinnedBufferMemoryStream 情報", MessageBoxButtons.OK, MessageBoxIcon.Information); //動作確認用のMessageBoxです。
}
else
MessageBox.Show("違法なイメージリソースです", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
rs.Dispose();
}
else //*.resxファイル
{
//ResXResourceSetを作成する
ResXResourceSet rsx = new ResXResourceSet(ResFileName);
・・・・・以下resourcesと同等なので省略・・・・・
}
Close();
}
}
この「PinnedBufferMemoryStream」が何かというと、UnmanagedMemoryStreamから派生させたbyte[](Byte構造体の配列)で、"unsafe"でかかれたメモリーを固定したストリームであり「勝手にいじらせたくない」という感がありありとします。この型はjpeg等クラスのないイメージファイルを *.resources ファイルに書き込むと規定されるのですが、同じjpeg画像を"MemoryStream"で処理した記憶もあるので調べてみると、*.resx ファイルの際には「MemoryStream」型になっていることが分かりました。
いずれにしても「『保護された』型なのでアクセスが不能」「『保護された』型を変えるためにキャストすることも不能」なので全く手が出せない状態です。(注)
注:和文のサイトではこの「PinnedBufferMemoryStream」について触れている記事が全く見当たりません。また、英文記事でもこのMicrosoftの2007年のコード以外に何も見つけることができませんでした。
結論:「PinnedBufferMemoryStream」型のイメージファイルは断念し、ここまででResReaderを完結させることにしました。「勇気ある撤退」としてお許しを。→一旦は撤退しましたが、矢張り諦めきれずに、最後のソリューションを見つめました!今日は酒も美味いし、夜もよく眠れるでしょう!
バンザーイ!!!(すでに飲んでいますが...何か?)