在应用程序中使用256 x 256 Windows Vista图标

我有一个应用程序,我已经制作了一个256 x 256 Windows Vista图标。

我想知道如何在用作应用程序图标的ico文件中使用256×256 PNG文件并将其显示在表单上的图片框中。

我使用的是VB.NET,但C#中的答案都很好。 我想我可能不得不使用reflection。

我不确定这在Windows XP中是否可行,并且可能需要Windows Vista API

今天,我做了一个非常好的function, 从Vista图标中提取256×256位图

和你一样,Nathan W,我用它在“关于”框中将大图标显示为位图。 例如,此代码将Vista图标作为PNG图像,并将其显示在256×256 PictureBox中:

picboxAppLogo.Image = ExtractVistaIcon(myIcon); 

此函数将Icon对象作为参数。 因此,您可以将它与任何图标一起使用 – 来自资源 ,文件,流等。 (请阅读以下有关提取EXE图标的信息)。

它运行在任何操作系统上 ,因为它不使用任何Win32 API,它是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 

重要! 如果你想直接从EXE文件加载这个图标,那么你不能使用Icon.ExtractAssociatedIcon(Application.ExecutablePath)作为参数,因为.NET函数ExtractAssociatedIcon()是如此愚蠢,它只提取32x32图标!

相反,您最好使用由Tsuda Kageyu( http://www.codeproject.com/KB/cs/IconExtractor.aspx )创建的整个IconExtractor类。 您可以稍微简化此类,以使其更小。 这种方式使用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); } 

注意:我现在仍在使用我的ExtractVistaIcon()函数,因为我不喜欢IconExtractor如何处理这项工作 - 首先,它通过使用IconExtractor.SplitIcon(icoAppIcon)提取所有图标格式,然后你必须知道确切的256x256图标索引,以获得所需的vista图标。 所以,使用我的ExtractVistaIcon()在这里更快更简单的方式:)

在这里找到信息。 要获得大型Vista图标,您需要使用Shell32的SHGetFileInfo方法。 我已经复制了下面的相关文本,当然你要用“Assembly.GetExecutingAssembly()。Location”替换filename变量。

 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; }; 

非托管代码的最终准备是定义SHGetFileInfo的签名,该签名位于流行的Shell32.dll中:

 // 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); 

现在我们已准备好所有内容,是时候调用函数并显示我们检索到的图标了。 将要检索的对象是Icon类型(System.Drawing.Icon),但我们想在PictureBox中显示它,因此我们将使用ToBitmap()方法将Icon转换为Bitmap。

但首先需要添加3个控件才能添加到窗体中,Button btnExtract的Text属性为“Extract Icon”,picIconSmall是PictureBox,picIconLarge也是PictureBox。 那是因为我们会得到两个图标大小。 现在双击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图标 – 只有小图标(32×32)和大图标(48×48)

这里有一个处理Vista图标的库

……由于双png alpha通道格式,它看起来相当复杂。

我将尝试在vb .net中做出简明的回答,但这可能需要一些时间。

具有从图片框中的ICO文件显示256 * 256 * 32图像的相同问题,我发现SAL80的解决方案是最有效的(并且几乎正常工作)。 但是,原始代码不支持存储为BMP的图像(大图标通常是PNG,但并不总是……)。

这是我的版本以供将来参考。 创建位图的代码也稍微简单一些:

  ///  /// Extracts the large Vista icon from a ICO file ///  /// Bytes of the ICO file /// The large icon or null if not found 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 图标function 。 还有一个概述提到查询不同的图标大小。 有一个Dream.In.Code论坛post,用于在C#中使用API​​以及Pinvoke.net参考 。