[简介]
常用网名: 猪头三
出生日期: 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> 根据获取到的图标大小,依次显示出来.
[结尾]
以上内容都是经验总结, 希望对大家有帮助. 如果更好想法或者建议, 可以在文章的下方留言和评论.
719

被折叠的 条评论
为什么被折叠?



