C# 在应用程序中使用 256 x 256 Windows Vista 图标
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/220465/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using a 256 x 256 Windows Vista icon in an application
提问by Nathan W
I have an application which I have made a 256 x 256 Windows Vista icon for.
我有一个应用程序,我为它制作了一个 256 x 256 的 Windows Vista 图标。
I was wondering how I would be able to use a 256x256 PNG file in the ico file used as the application icon and show it in a picture box on a form.
我想知道如何在用作应用程序图标的 ico 文件中使用 256x256 PNG 文件并将其显示在表单上的图片框中。
I am using VB.NET, but answers in C# are fine. I'm thinking I may have to use reflection.
我正在使用 VB.NET,但 C# 中的答案很好。我想我可能不得不使用反射。
I am not sure if this is even possible in Windows XP and may need Windows Vista APIs
我不确定这在 Windows XP 中是否可行,并且可能需要 Windows Vista API
采纳答案by SLA80
Today, I made a very nice function for extracting the 256x256 Bitmaps from Vista icons.
今天,我做了一个非常好的功能,用于从 Vista 图标中提取 256x256 位图。
Like you, Nathan W, I use it to display the large icon as a Bitmap in "About" box. For example, this code gets Vista icon as PNG image, and displays it in a 256x256 PictureBox:
和你一样,Nathan W,我用它在“关于”框中将大图标显示为位图。例如,此代码获取 Vista 图标作为 PNG 图像,并将其显示在 256x256 PictureBox 中:
picboxAppLogo.Image = ExtractVistaIcon(myIcon);
This function takes Icon object as a parameter. So, you can use it with any icons - from resources, from files, from streams, and so on. (Read below about extracting EXE icon).
该函数将 Icon 对象作为参数。因此,您可以将它与任何图标一起使用 -来自资源、来自文件、来自流等。(阅读以下有关提取 EXE 图标的信息)。
It runs on any OS, because it does notuse any Win32 API, it is 100% managed code:-)
它可以运行在任何操作系统,因为它并没有使用任何的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<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;
}
IMPORTANT!If you want to load this icon directly from EXE file, then you CAN'Tuse Icon.ExtractAssociatedIcon(Application.ExecutablePath)as a parameter, because .NET function ExtractAssociatedIcon() is so stupid, it extracts ONLY 32x32 icon!
重要的!如果你想直接从 EXE 文件中加载这个图标,那么你不能使用Icon.ExtractAssociatedIcon(Application.ExecutablePath)作为参数,因为 .NET 函数 ExtractAssociatedIcon() 太愚蠢了,它只能提取 32x32 图标!
Instead, you better use the whole IconExtractorclass, created by Tsuda Kageyu (http://www.codeproject.com/KB/cs/IconExtractor.aspx). You can slightly simplify this class, to make it smaller. Use IconExtractorthis way:
相反,您最好使用由 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);
}
Note: I'm still using my ExtractVistaIcon() function here, because I don't like how IconExtractorhandles this job - first, it extracts all icon formats by using IconExtractor.SplitIcon(icoAppIcon), and then you have to know the exact 256x256 icon index to get the desired vista-icon. So, using my ExtractVistaIcon() here is much faster and simplier way :)
注意:我仍然在这里使用我的 ExtractVistaIcon() 函数,因为我不喜欢IconExtractor处理这项工作的方式 - 首先,它使用 IconExtractor.SplitIcon(icoAppIcon) 提取所有图标格式,然后您必须知道确切的256x256 图标索引以获得所需的 vista 图标。所以,在这里使用我的 ExtractVistaIcon() 是更快更简单的方法:)
回答by TheSoftwareJedi
Found info here. To get the large Vista icon, you need to use Shell32's SHGetFileInfo method. I've copied the relevant text below, of course you'll want to replace the filename variable with "Assembly.GetExecutingAssembly().Location".
在这里找到信息。要获得较大的 Vista 图标,您需要使用 Shell32 的 SHGetFileInfo 方法。我已经复制了下面的相关文本,当然您需要将文件名变量替换为“Assembly.GetExecutingAssembly().Location”。
using System.Runtime.InteropServices;
A bunch of constants we will use in the call to SHGetFileInfo() to specify the size of the icon we wish to retrieve:
我们将在调用 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;
The SHFILEINFO structure is very important as it will be our handle to various file information, among which is the graphic icon.
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;
};
The final preparation for the unmanaged code is to define the signature of SHGetFileInfo, which is located inside the popular Shell32.dll:
非托管代码的最后准备是定义 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);
Now that we have everything prepared, it's time to make the call to the function and display the icon that we retrieved. The object that will be retrieved is an Icon type (System.Drawing.Icon) but we want to display it in a PictureBox so we'll convert the Icon to a Bitmap using the ToBitmap() method.
现在我们已经准备好了一切,是时候调用该函数并显示我们检索到的图标了。将要检索的对象是图标类型 (System.Drawing.Icon),但我们希望将其显示在 PictureBox 中,因此我们将使用 ToBitmap() 方法将图标转换为位图。
But first of all there are 3 controls you need to add to the form, a Button btnExtract that has "Extract Icon" for its Text property, picIconSmall which is a PictureBox and a picIconLarge which is also a PictureBox. That's because we will get two icons sizes. Now double click btnExtract in Visual Studio's Design view and you'll get to its Click event. Inside it is the rest of the code:
但首先,您需要将 3 个控件添加到表单中,一个 Button btnExtract,其 Text 属性具有“提取图标”,picIconSmall 是一个图片框,一个 picIconLarge 也是一个图片框。那是因为我们将得到两个图标大小。现在在 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();
}
}
UPDATE: found even more info here.
更新:在这里找到更多信息。
回答by Mark Cidade
Have a look at the Windows icon functionsthat are available. There's also an overviewthat mentions querying for different icon sizes. There's a Dream.In.Codeforum thread for using the APIs in C# as well as a Pinvoke.net reference.
查看可用的 Windows图标功能。还有一个概述提到查询不同的图标大小。有一个Dream.In.Code论坛主题,用于在 C# 中使用 API 以及Pinvoke.net 参考。
回答by Damien
None of the above answers handle Vista Icons - only small (32x32) and large (48x48)
以上答案均不处理 Vista 图标 - 只有小 (32x32) 和大 (48x48)
There is a library that handles Vista Icons here
存在一个处理Vista的图标库在这里
...it looks quite complicated due to the dual-png alpha channel format.
...由于双 png alpha 通道格式,它看起来相当复杂。
I will try to make a concise answer in vb .net but it may take some time.
我将尝试在 vb .net 中做出简洁的回答,但这可能需要一些时间。
回答by Jean-Philippe
Having the same problem of displaying the 256*256*32 image from an ICO file in a picture box, I found the solution from SAL80 the most efficient one (and almost working). However, the original code doesn't support images stored as BMP (the large icon is usually PNG, but not always...).
在图片框中显示来自 ICO 文件的 256*256*32 图像的相同问题,我发现来自 SAL80 的解决方案是最有效的(并且几乎可以工作)。但是,原始代码不支持存储为 BMP 的图像(大图标通常是 PNG,但并不总是......)。
Here is my version for future references. The code to create the bitmap is also slightly simpler :
这是我的版本以供将来参考。创建位图的代码也稍微简单一些:
/// <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;
}