アプリケーションで256 x 256 Windows Vistaアイコンを使用する
質問
256 x 256のWindows  Vistaアイコンを作成したアプリケーションがあります。
アプリケーションアイコンとして使用されるicoファイルで256x256 PNGファイルを使用し、フォームの画像ボックスに表示する方法を考えました。
VB.NETを使用していますが、C#での回答は問題ありません。リフレクションを使用する必要があると考えています。
これがWindows  XPでも可能かどうか不明で、Windows  Vista APIが必要な場合があります
解決
今日、私は Vistaアイコンから256x256ビットマップを抽出するための非常に素晴らしい機能を作成しました。
Nathan Wさん、あなたと同じように、「About」のビットマップとして大きなアイコンを表示するために使用します。ボックス。たとえば、次のコードはVistaアイコンをPNG画像として取得し、256x256 PictureBoxに表示します。
picboxAppLogo.Image = ExtractVistaIcon(myIcon);
この関数は、アイコンオブジェクトをパラメーターとして受け取ります。したがって、任意のアイコンで使用できます-リソースから、ファイルから、ストリームからなど。 (EXEアイコンの抽出については以下をお読みください。)
任意のOS で実行されます。Win32APIを使用しないため、 100%マネージコードです:-)
// Based on: http://www.codeproject.com/KB/cs/IconExtractor.aspx
// And a hint from: http://www.codeproject.com/KB/cs/IconLib.aspx
Bitmap ExtractVistaIcon(Icon icoIcon)
{
Bitmap bmpPngExtracted = null;
try
{
byte[] srcBuf = null;
using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
{ icoIcon.Save(stream); srcBuf = stream.ToArray(); }
const int SizeICONDIR = 6;
const int SizeICONDIRENTRY = 16;
int iCount = BitConverter.ToInt16(srcBuf, 4);
for (int iIndex=0; iIndex<iCount; iIndex++)
{
int iWidth = srcBuf[SizeICONDIR + SizeICONDIRENTRY * iIndex];
int iHeight = srcBuf[SizeICONDIR + SizeICONDIRENTRY * iIndex + 1];
int iBitCount = BitConverter.ToInt16(srcBuf, SizeICONDIR + SizeICONDIRENTRY * iIndex + 6);
if (iWidth == 0 && iHeight == 0 && iBitCount == 32)
{
int iImageSize = BitConverter.ToInt32(srcBuf, SizeICONDIR + SizeICONDIRENTRY * iIndex + 8);
int iImageOffset = BitConverter.ToInt32(srcBuf, SizeICONDIR + SizeICONDIRENTRY * iIndex + 12);
System.IO.MemoryStream destStream = new System.IO.MemoryStream();
System.IO.BinaryWriter writer = new System.IO.BinaryWriter(destStream);
writer.Write(srcBuf, iImageOffset, iImageSize);
destStream.Seek(0, System.IO.SeekOrigin.Begin);
bmpPngExtracted = new Bitmap(destStream); // This is PNG! :)
break;
}
}
}
catch { return null; }
return bmpPngExtracted;
}
重要!このアイコンをEXEファイルから直接ロードする場合は、使用できない Icon.ExtractAssociatedIcon(Application.ExecutablePath)をパラメーターとして使用します。.NET関数ExtractAssociatedIcon()は非常に愚かなため、32x32のアイコンのみを抽出します!
代わりに、津田影生(IconExtractor クラス全体を使用することをお勧めします「noreferrer」> http://www.codeproject.com/KB/cs/IconExtractor.aspx )。このクラスを少し単純化して、小さくすることができます。この方法で IconExtractor を使用します:
// Getting FILL icon set from EXE, and extracting 256x256 version for logo...
using (TKageyu.Utils.IconExtractor IconEx = new TKageyu.Utils.IconExtractor(Application.ExecutablePath))
{
Icon icoAppIcon = IconEx.GetIcon(0); // Because standard System.Drawing.Icon.ExtractAssociatedIcon() returns ONLY 32x32.
picboxAppLogo.Image = ExtractVistaIcon(icoAppIcon);
}
注: IconExtractor がこのジョブを処理する方法が気に入らないため、ここではExtractVistaIcon()関数を使用しています。まず、IconExtractor.SplitIcon(icoAppIconを使用してすべてのアイコン形式を抽出します)、そして、あなたは、正確な256x256アイコンインデックスを知っていて、目的のvista-iconを得る必要があります。したがって、ここでExtractVistaIcon()を使用すると、はるかに高速で簡単な方法になります:)
他のヒント
こちらで情報を見つけました。大きなVistaアイコンを取得するには、Shell32のSHGetFileInfoメソッドを使用する必要があります。以下の関連テキストをコピーしました。もちろん、ファイル名変数を&quot; Assembly.GetExecutingAssembly()。Location&quot;に置き換えます。
using System.Runtime.InteropServices;
取得するアイコンのサイズを指定するためにSHGetFileInfo()の呼び出しで使用する一連の定数:
// Constants that we need in the function call
private const int SHGFI_ICON = 0x100;
private const int SHGFI_SMALLICON = 0x1;
private const int SHGFI_LARGEICON = 0x0;
SHFILEINFO構造は、グラフィックアイコンなどのさまざまなファイル情報へのハンドルとなるため、非常に重要です。
// This structure will contain information about the file
public struct SHFILEINFO
{
// Handle to the icon representing the file
public IntPtr hIcon;
// Index of the icon within the image list
public int iIcon;
// Various attributes of the file
public uint dwAttributes;
// Path to the file
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string szDisplayName;
// File type
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string szTypeName;
};
アンマネージコードの最終準備は、人気のShell32.dll内にあるSHGetFileInfoの署名を定義することです:
// The signature of SHGetFileInfo (located in Shell32.dll)
[DllImport("Shell32.dll")]
public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, int cbFileInfo, uint uFlags);
すべての準備が整ったので、関数を呼び出して、取得したアイコンを表示します。取得されるオブジェクトはアイコン型(System.Drawing.Icon)ですが、PictureBoxに表示したいので、ToBitmap()メソッドを使用してアイコンをビットマップに変換します。
しかし、まず最初に、フォームに追加する必要がある3つのコントロール、「抽出アイコン」を持つボタンbtnExtractがあります。そのTextプロパティのために、PictureBoxであるpicIconSmallとPictureBoxでもあるpicIconLargeがあります。これは、2つのアイコンサイズを取得するためです。 Visual StudioのデザインビューでbtnExtractをダブルクリックすると、Clickイベントが表示されます。内部には残りのコードがあります:
private void btnExtract_Click(object sender, EventArgs e)
{
// Will store a handle to the small icon
IntPtr hImgSmall;
// Will store a handle to the large icon
IntPtr hImgLarge;
SHFILEINFO shinfo = new SHFILEINFO();
// Open the file that we wish to extract the icon from
if(openFile.ShowDialog() == DialogResult.OK)
{
// Store the file name
string FileName = openFile.FileName;
// Sore the icon in this myIcon object
System.Drawing.Icon myIcon;
// Get a handle to the small icon
hImgSmall = SHGetFileInfo(FileName, 0, ref shinfo, Marshal.SizeOf(shinfo), SHGFI_ICON | SHGFI_SMALLICON);
// Get the small icon from the handle
myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon);
// Display the small icon
picIconSmall.Image = myIcon.ToBitmap();
// Get a handle to the large icon
hImgLarge = SHGetFileInfo(FileName, 0, ref shinfo, Marshal.SizeOf(shinfo), SHGFI_ICON | SHGFI_LARGEICON);
// Get the large icon from the handle
myIcon = System.Drawing.Icon.FromHandle(shinfo.hIcon);
// Display the large icon
picIconLarge.Image = myIcon.ToBitmap();
}
}
更新:さらに詳細な情報が見つかりましたこちら。
上記の回答のいずれもVistaアイコンを処理しません-小さい(32x32)および大きい(48x48)のみ
Vistaアイコンを処理するライブラリがありますこちら
... dual-pngアルファチャネル形式のため、非常に複雑に見えます。
vb .netで簡潔な回答をしようとしますが、時間がかかる場合があります。
画像ボックス内のICOファイルから256 * 256 * 32画像を表示するという同じ問題を抱えていたので、SAL80からのソリューションが最も効率的な(そしてほとんど機能する)ソリューションであることがわかりました。ただし、元のコードはBMPとして保存された画像をサポートしていません(大きなアイコンは通常PNGですが、常にではありません...)。
これは将来の参考のために私のバージョンです。ビットマップを作成するコードも少し簡単です:
/// <summary>
/// Extracts the large Vista icon from a ICO file
/// </summary>
/// <param name="srcBuf">Bytes of the ICO file</param>
/// <returns>The large icon or null if not found</returns>
private static Bitmap ExtractVistaIcon(byte[] srcBuf)
{
const int SizeIcondir = 6;
const int SizeIcondirentry = 16;
// Read image count from ICO header
int iCount = BitConverter.ToInt16(srcBuf, 4);
// Search for a large icon
for (int iIndex = 0; iIndex < iCount; iIndex++)
{
// Read image information from image directory entry
int iWidth = srcBuf[SizeIcondir + SizeIcondirentry * iIndex];
int iHeight = srcBuf[SizeIcondir + SizeIcondirentry * iIndex + 1];
int iBitCount = BitConverter.ToInt16(srcBuf, SizeIcondir + SizeIcondirentry * iIndex + 6);
// If Vista icon
if (iWidth == 0 && iHeight == 0 && iBitCount == 32)
{
// Get image data position and length from directory
int iImageSize = BitConverter.ToInt32(srcBuf, SizeIcondir + SizeIcondirentry * iIndex + 8);
int iImageOffset = BitConverter.ToInt32(srcBuf, SizeIcondir + SizeIcondirentry * iIndex + 12);
// Check if the image has a PNG signature
if (srcBuf[iImageOffset] == 0x89 && srcBuf[iImageOffset+1] == 0x50 && srcBuf[iImageOffset+2] == 0x4E && srcBuf[iImageOffset+3] == 0x47)
{
// the PNG data is stored directly in the file
var x = new MemoryStream(srcBuf, iImageOffset, iImageSize, false, false);
return new Bitmap(x);
}
// Else it's bitmap data with a partial bitmap header
// Read size from partial header
int w = BitConverter.ToInt32(srcBuf, iImageOffset + 4);
// Create a full header
var b = new Bitmap(w, w, PixelFormat.Format32bppArgb);
// Copy bits into bitmap
BitmapData bmpData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.WriteOnly, b.PixelFormat);
Marshal.Copy(srcBuf, iImageOffset + Marshal.SizeOf(typeof(Bitmapinfoheader)), bmpData.Scan0, b.Width*b.Height*4);
b.UnlockBits(bmpData);
return b;
}
}
return null;
}
Windowsをご覧くださいアイコン関数利用可能です。 概要もあります。アイコンのサイズ。 C#でAPIを使用するだけでなく、 Dream.In.Code フォーラムスレッドがあります。 Pinvoke.netリファレンス。