在网上找过许多文章,都没有成功获取过大图标,只能获取最大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.]
1 UINT WINAPI PrivateExtractIcons( 2 _In_ LPCTSTR lpszFile, 3 _In_ int nIconIndex, 4 _In_ int cxIcon, 5 _In_ int cyIcon, 6 _Out_opt_ HICON *phicon, 7 _Out_opt_ UINT *piconid, 8 _In_ UINT nIcons, 9 _In_ UINT flags 10 );
C#使用DLL import进行引用。
1 [DllImport("User32.dll")] 2 public static extern int PrivateExtractIcons( 3 string lpszFile, //文件名可以是exe,dll,ico,cur,ani,bmp 4 int nIconIndex, //从第几个图标开始获取 5 int cxIcon, //获取图标的尺寸x 6 int cyIcon, //获取图标的尺寸y 7 IntPtr[] phicon, //获取到的图标指针数组 8 int[] piconid, //图标对应的资源编号 9 int nIcons, //指定获取的图标数量,仅当文件类型为.exe 和 .dll时候可用 10 int flags //标志,默认0就可以,具体可以看LoadImage函数 11 );
说明:如果想要获取的图标尺寸为256x256,而实际资源文件中的图标尺寸小于256x256的话,则会获取存在的最高分标率,色彩数最丰富的的图标,并拉伸。
具体代码如下
1 using System; 2 using System.Collections.Generic; 3 using System.Drawing; 4 using System.Drawing.Imaging; 5 using System.IO; 6 using System.Linq; 7 using System.Runtime.InteropServices; 8 using System.Text; 9 using System.Threading.Tasks; 10 11 namespace TryGetExeLargeIcon 12 { 13 class Program 14 { 15 [STAThread] 16 static void Main(string[] args) 17 { 18 //选择文件对话框 19 var opfd = new System.Windows.Forms.OpenFileDialog { Filter = "资源文件|*.exe;*.dll" }; 20 if (opfd.ShowDialog() != System.Windows.Forms.DialogResult.OK) return; 21 var file = opfd.FileName; 22 23 //指定存放图标的文件夹 24 const string folderToSave = "D:\\temp\\"; 25 if (!Directory.Exists(folderToSave)) Directory.CreateDirectory(folderToSave); 26 27 //选中文件中的图标总数 28 var iconTotalCount = PrivateExtractIcons(file, 0, 0, 0, null, null, 0, 0); 29 30 //用于接收获取到的图标指针 31 IntPtr[] hIcons = new IntPtr[iconTotalCount]; 32 //对应的图标id 33 int[] ids = new int[iconTotalCount]; 34 //成功获取到的图标个数 35 var successCount = PrivateExtractIcons(file, 0, 256, 256, hIcons, ids, iconTotalCount, 0); 36 37 //遍历并保存图标 38 for (var i = 0; i < successCount; i++) 39 { 40 //指针为空,跳过 41 if (hIcons[i] == IntPtr.Zero) continue; 42 43 using (var ico = Icon.FromHandle(hIcons[i])) 44 { 45 using (var myIcon = ico.ToBitmap()) 46 { 47 myIcon.Save(folderToSave + ids[i].ToString("000") + ".png", ImageFormat.Png); 48 } 49 } 50 //内存回收 51 DestroyIcon(hIcons[i]); 52 } 53 } 54 55 56 //details: https://msdn.microsoft.com/en-us/library/windows/desktop/ms648075(v=vs.85).aspx 57 //Creates an array of handles to icons that are extracted from a specified file. 58 //This function extracts from executable (.exe), DLL (.dll), icon (.ico), cursor (.cur), animated cursor (.ani), and bitmap (.bmp) files. 59 //Extractions from Windows 3.x 16-bit executables (.exe or .dll) are also supported. 60 [DllImport("User32.dll")] 61 public static extern int PrivateExtractIcons( 62 string lpszFile, //file name 63 int nIconIndex, //The zero-based index of the first icon to extract. 64 int cxIcon, //The horizontal icon size wanted. 65 int cyIcon, //The vertical icon size wanted. 66 IntPtr[] phicon, //(out) A pointer to the returned array of icon handles. 67 int[] piconid, //(out) A pointer to a returned resource identifier. 68 int nIcons, //The number of icons to extract from the file. Only valid when *.exe and *.dll 69 int flags //Specifies flags that control this function. 70 ); 71 72 //details:https://msdn.microsoft.com/en-us/library/windows/desktop/ms648063(v=vs.85).aspx 73 //Destroys an icon and frees any memory the icon occupied. 74 [DllImport("User32.dll")] 75 public static extern bool DestroyIcon( 76 IntPtr hIcon //A handle to the icon to be destroyed. The icon must not be in use. 77 ); 78 } 79 }