通过 ExtractIconEx 读取文件图标

参考(https://blog.csdn.net/bruce135lee/article/details/79790104),使用 ExtractIconEx 获取文件/扩展名图标,在实际使用过程中,会出现读取图标卡死情况;

经测试发现在文件少的目录不会出现卡死,但是在读取 c:\windows\system32 时,会出现卡死;

翻了MSDN,有提示需要通过 DestroyIcon 释放资源。

相对于参考资料,作以下修改:

1、添加参数:tcType 用于指定需要获取的是文件还是目录;(之前通过文件扩展名的方式获取有点问题,如果文件本身没扩展名的,会误认为是目录)

2、ExtractIconEx 声明中句柄列表使用 IntPtr 类型,方便后续判断;

3、获取图标资源之后,调用 DestroyIcon 释放资源;

4、读取注册表信息时,键值的数据中文件名部分可能会使用引号(如:"\"C:\Program Files\7-Zip\7z.rar\",1")而导致获取图片失败;因此:转为字符串数组后,去掉前后空格

5、直接读取文件中的图标,限定仅 .EXE和.ICO 才读取文件自带图标;原因:有些DLL中也带有图标资源,会导致DLL文件也提取到了自带图标

最终代码:

  1         /// <summary>
  2         /// 通过文件名称获取文件图标
  3         /// </summary>
  4         /// <param name="tcType">指定参数tcFullName的类型: FILE/DIR</param>
  5         /// <param name="tcFullName">需要获取图片的全路径文件名</param>
  6         /// <param name="tlIsLarge">是否获取大图标(32*32)</param>
  7         /// <returns></returns>
  8         private Icon GetIconByFileName(string tcType, string tcFullName, bool tlIsLarge = false)
  9         {
 10             Icon ico = null;
 11 
 12             string fileType = tcFullName.Contains(".") ? tcFullName.Substring(tcFullName.LastIndexOf('.')).ToLower() : string.Empty;
 13 
 14             RegistryKey regVersion = null;
 15             string regFileType = null;
 16             string regIconString = null;
 17             string systemDirectory = Environment.SystemDirectory + "\\";
 18             IntPtr[] phiconLarge = new IntPtr[1];
 19             IntPtr[] phiconSmall = new IntPtr[1];
 20             IntPtr hIcon = IntPtr.Zero;
 21             uint rst = 0;
 22 
 23             if (tcType == "FILE")
 24             {
 25                 //含图标的文件,优先使用文件中自带图标
 26                 if (".exe.ico".Contains(fileType))
 27                 {
 28                     //文件名 图标索引
 29                     phiconLarge[0] = phiconSmall[0] = IntPtr.Zero;
 30                     rst = ExtractIconEx(tcFullName, 0, phiconLarge, phiconSmall, 1);
 31                     hIcon = tlIsLarge ? phiconLarge[0] : phiconSmall[0];
 32                     ico = hIcon == IntPtr.Zero ? null : Icon.FromHandle(hIcon).Clone() as Icon;
 33                     if (phiconLarge[0] != IntPtr.Zero) DestroyIcon(phiconLarge[0]);
 34                     if (phiconSmall[0] != IntPtr.Zero) DestroyIcon(phiconSmall[0]);
 35                     if (ico != null)
 36                     {
 37                         return ico;
 38                     }
 39                 }
 40 
 41                 //通过文件扩展名读取图标
 42                 regVersion = Registry.ClassesRoot.OpenSubKey(fileType, false);
 43                 if (regVersion != null)
 44                 {
 45                     regFileType = regVersion.GetValue("") as string;
 46                     regVersion.Close();
 47                     regVersion = Registry.ClassesRoot.OpenSubKey(regFileType + @"\DefaultIcon", false);
 48                     if (regVersion != null)
 49                     {
 50                         regIconString = regVersion.GetValue("") as string;
 51                         regVersion.Close();
 52                     }
 53                 }
 54                 if (regIconString == null)
 55                 {
 56                     //没有读取到文件类型注册信息,指定为未知文件类型的图标  
 57                     regIconString = systemDirectory + "shell32.dll,0";
 58                 }
 59             }
 60             else
 61             {
 62                 //直接指定为文件夹图标  
 63                 regIconString = systemDirectory + "shell32.dll,3";
 64             }
 65 
 66             string[] fileIcon = regIconString.Split(new char[] { ',' });
 67             //系统注册表中注册的标图不能直接提取,则返回可执行文件的通用图标  
 68             fileIcon = fileIcon.Length == 2 ? fileIcon : new string[] { systemDirectory + "shell32.dll", "2" };
 69             
 70             phiconLarge[0] = phiconSmall[0] = IntPtr.Zero;
 71             rst = ExtractIconEx(fileIcon[0].Trim('\"'), Int32.Parse(fileIcon[1]), phiconLarge, phiconSmall, 1);
 72             hIcon = tlIsLarge ? phiconLarge[0] : phiconSmall[0];
 73             ico = hIcon == IntPtr.Zero ? null : Icon.FromHandle(hIcon).Clone() as Icon;
 74             if (phiconLarge[0] != IntPtr.Zero) DestroyIcon(phiconLarge[0]);
 75             if (phiconSmall[0] != IntPtr.Zero) DestroyIcon(phiconSmall[0]);
 76             if (ico != null)
 77             {
 78                 return ico;
 79             }
 80 
 81             // 对于文件,如果提取文件图标失败,则重新使用可执行文件通用图标
 82             if (tcType == "FILE")
 83             {
 84                 //系统注册表中注册的标图不能直接提取,则返回可执行文件的通用图标  
 85                 fileIcon = new string[] { systemDirectory + "shell32.dll", "2" }; 
 86                 phiconLarge = new IntPtr[1];
 87                 phiconSmall = new IntPtr[1];
 88                 rst = ExtractIconEx(fileIcon[0], Int32.Parse(fileIcon[1]), phiconLarge, phiconSmall, 1);
 89                 hIcon = tlIsLarge ? phiconLarge[0] : phiconSmall[0];
 90                 ico = hIcon == IntPtr.Zero ? null : Icon.FromHandle(hIcon).Clone() as Icon;
 91                 if (phiconLarge[0] != IntPtr.Zero) DestroyIcon(phiconLarge[0]);
 92                 if (phiconSmall[0] != IntPtr.Zero) DestroyIcon(phiconSmall[0]);
 93             }
 94 
 95             return ico;
 96         }
 97 
 98         [DllImport("shell32.dll", SetLastError = true)]
 99         private static extern uint ExtractIconEx(string lpszFile, int nIconIndex, IntPtr[] phiconLarge, IntPtr[] phiconSmall, uint nIcons);
100         [DllImport("User32.dll", SetLastError = true)]
101         private static extern uint DestroyIcon(IntPtr phicon);
View Code

 

posted @ 2019-09-26 14:26  兴龙在线  阅读(1608)  评论(0编辑  收藏  举报