C# 获取exe、dll中的图标,支持获取256x256分辨率

在网上找过许多文章,都没有成功获取过大图标,只能获取最大32x32。最后自己尝试了相关的windows api,终于找到一个可用的。

主要用到的C++的PrivateExtractIcons函数,具体说明请看:PrivateExtractIcons function

该函数原文有个说明可能需要注意一下:[This function is not intended for general use. It may be altered or unavailable in subsequent versions of Windows.]

 UINT WINAPI PrivateExtractIcons(
_In_ LPCTSTR lpszFile,
_In_ int nIconIndex,
_In_ int cxIcon,
_In_ int cyIcon,
_Out_opt_ HICON *phicon,
_Out_opt_ UINT *piconid,
_In_ UINT nIcons,
_In_ UINT flags
);

C#使用DLL import进行引用。

 [DllImport("User32.dll")]
public static extern int PrivateExtractIcons(
string lpszFile, //文件名可以是exe,dll,ico,cur,ani,bmp
int nIconIndex, //从第几个图标开始获取
int cxIcon, //获取图标的尺寸x
int cyIcon, //获取图标的尺寸y
IntPtr[] phicon, //获取到的图标指针数组
int[] piconid, //图标对应的资源编号
int nIcons, //指定获取的图标数量,仅当文件类型为.exe 和 .dll时候可用
int flags //标志,默认0就可以,具体可以看LoadImage函数
);

说明:如果想要获取的图标尺寸为256x256,而实际资源文件中的图标尺寸小于256x256的话,则会获取存在的最高分标率,色彩数最丰富的的图标,并拉伸。

具体代码如下

 using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks; namespace TryGetExeLargeIcon
{
class Program
{
[STAThread]
static void Main(string[] args)
{
//选择文件对话框
var opfd = new System.Windows.Forms.OpenFileDialog { Filter = "资源文件|*.exe;*.dll" };
if (opfd.ShowDialog() != System.Windows.Forms.DialogResult.OK) return;
var file = opfd.FileName; //指定存放图标的文件夹
const string folderToSave = "D:\\temp\\";
if (!Directory.Exists(folderToSave)) Directory.CreateDirectory(folderToSave); //选中文件中的图标总数
var iconTotalCount = PrivateExtractIcons(file, , , , null, null, , ); //用于接收获取到的图标指针
IntPtr[] hIcons = new IntPtr[iconTotalCount];
//对应的图标id
int[] ids = new int[iconTotalCount];
//成功获取到的图标个数
var successCount = PrivateExtractIcons(file, , , , hIcons, ids, iconTotalCount, ); //遍历并保存图标
for (var i = ; i < successCount; i++)
{
//指针为空,跳过
if (hIcons[i] == IntPtr.Zero) continue; using (var ico = Icon.FromHandle(hIcons[i]))
{
using (var myIcon = ico.ToBitmap())
{
myIcon.Save(folderToSave + ids[i].ToString("") + ".png", ImageFormat.Png);
}
}
//内存回收
DestroyIcon(hIcons[i]);
}
} //details: https://msdn.microsoft.com/en-us/library/windows/desktop/ms648075(v=vs.85).aspx
//Creates an array of handles to icons that are extracted from a specified file.
//This function extracts from executable (.exe), DLL (.dll), icon (.ico), cursor (.cur), animated cursor (.ani), and bitmap (.bmp) files.
//Extractions from Windows 3.x 16-bit executables (.exe or .dll) are also supported.
[DllImport("User32.dll")]
public static extern int PrivateExtractIcons(
string lpszFile, //file name
int nIconIndex, //The zero-based index of the first icon to extract.
int cxIcon, //The horizontal icon size wanted.
int cyIcon, //The vertical icon size wanted.
IntPtr[] phicon, //(out) A pointer to the returned array of icon handles.
int[] piconid, //(out) A pointer to a returned resource identifier.
int nIcons, //The number of icons to extract from the file. Only valid when *.exe and *.dll
int flags //Specifies flags that control this function.
); //details:https://msdn.microsoft.com/en-us/library/windows/desktop/ms648063(v=vs.85).aspx
//Destroys an icon and frees any memory the icon occupied.
[DllImport("User32.dll")]
public static extern bool DestroyIcon(
IntPtr hIcon //A handle to the icon to be destroyed. The icon must not be in use.
);
}
}
上一篇:给Qt生成的exe执行程序添加版本信息


下一篇:【译】.NET Core 2.2 Preview 2 发布