[原创]获取程序图标或文件关联图标的一些细节问题(ExtractIcon, ExtractIconEx, ExtractAssociatedIcon, SHGetFileInfo().

[简介]
常用网名: 猪头三
出生日期: 1981.XX.XX
QQ联系: 643439947
个人网站: 80x86汇编小站 https://www.x86asm.org
编程生涯: 2001年~至今[共22年]
职业生涯: 20年
开发语言: C/C++、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python
开发工具: Visual Studio、Delphi、XCode、Eclipse、C++ Builder
技能种类: 逆向 驱动 磁盘 文件
研发领域: Windows应用软件安全/Windows系统内核安全/Windows系统磁盘数据安全/macOS应用软件安全
项目经历: 磁盘性能优化/文件系统数据恢复/文件信息采集/敏感文件监测跟踪/网络安全检测

[序言]
在Windows开发中, 获取目标文件图标是非常有用的功能. 因为太多的Windows安全软件或者Windows系统优化软件需要枚举各种文件以及进程, 如果没有显示图标的话, 那么整个软件显得很单调.

[涉及到获取目标文件的API有哪些?]
1> ExtractIcon()
2> ExtractIconEx()
3> ExtractAssociatedIcon()
4> SHGetFileInfo()

[那么这4个API有什么区别呢?]
这里就不详细介绍每个API功能描述, 因为MSDN已经写得很清楚了. 这里仅仅只是抽取关键核心问题, 在开发中非常使用的技巧.

1> 如果针对程序文件, DLL或者图标文件处理, 那么可以优先考虑ExtractIcon()和ExtractIconEx()
2> 如果是其他普通文件, 比如典型的快捷方式文件, 可以考虑选择ExtractAssociatedIcon()和SHGetFileInfo()
3> SHGetFileInfo()最万能, 任何类型的文件都可以获取对应的图标, 可以根据实际情况选择使用.

[获取文件图标, 有几个配置参数要注意]
1> 如果要获取大图标和小图标的尺寸, 可以通过GetSystemMetrics()函数配合SM_CXICON, SM_CYICON, SM_CXSMICON和SM_CYSMICON获取
2> 如果一个文件包含多个图标, 可以通过ExtractIconEx(PChar(目标文件路径), -1, HICON(nil^), HICON(nil^), 0)这样方式来获取图标数目
3> 如果使用SHGetFileInfo()获取图标时:
    3.1> 获取默认关联的图标: SHGFI_ICON
    3.2> 获取默认关联的大图标: SHGFI_ICON or SHGFI_LARGEICON
    3.3> 获取默认关联的小图标: SHGFI_ICON or SHGFI_SMALLICON

[获取快捷方式文件图标的一些瑕疵问题]
当用SHGetFileInfo()或者ExtractAssociatedIcon()获取快捷方式文件图标时, 会带有一个小箭头. 如果想去掉整个箭头可以使用如下代码:

var str_LnkFilePath : string := 'C:\Users\Win11_PHT\Desktop\xxxxx.lnk'
var il_Icons : HIMAGELIST := nil ;
il_Icons := HIMAGELIST(SHGetFileInfo(PChar(str_LnkFilePath),
                       0,
                       Shell_Fileinfo,
                       SizeOf(TSHFileInfo),
                       SHGFI_SYSICONINDEX));
ImageList_GetIcon(il_Icons, Shell_Fileinfo.iIcon,  ILD_NORMAL) ;

[再次提及图标文件大小的问题.]
虽然自带有GetSystemMetrics()函数能获取图标的大小, 但是不够灵活, 如果是非标准大小的图标, 那么这个函数就失效了. 因此需要根据HICON句柄来获取图标大小,这样自由度更高, 兼容性更强.

BOOL GetIconDimensions(__in HICON hico, __out SIZE *psiz)
{
  ICONINFO ii;
  BOOL fResult = GetIconInfo(hico, &ii);
  if (fResult) {
    BITMAP bm;
    fResult = GetObject(ii.hbmMask, sizeof(bm), &bm) == sizeof(bm);
    if (fResult) {
      psiz->cx = bm.bmWidth;
      psiz->cy = ii.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
    }
    if (ii.hbmMask)  DeleteObject(ii.hbmMask);
    if (ii.hbmColor) DeleteObject(ii.hbmColor);
  }
  return fResult;
}

[如果一个程序或者其他文件内置多个图标, 如何处理?]
1> 通过ExtractIconEx()获取图标的数目
2> 通过for循环调用ExtractAssociatedIcon()或者ExtractIcon()或者ExtractIconEx()按照图标索引一次获取HICON
3> 通过HICON句柄获取图标的对应大小
4> 根据获取到的图标大小,依次显示出来.

[结尾]
以上内容都是经验总结, 希望对大家有帮助. 如果更好想法或者建议, 可以在文章的下方留言和评论.

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我不是代码教父

我的创作动力离不开你的真诚激励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值