我试图获取任何文件的图标(如HICON),以与Explorer一样的方式绘制它。这意味着如果我有一个exe文件的路径,我应该绘制它的默认图标。如果我有一个链接(.lnk)文件,我必须绘制一个图标,分配给链接,如果有的话,以及其目标文件图标。
不幸的是,SHGetFileInfo()应该返回图标,不适用于多个链接文件。这是代码:
SHFILEINFO fi = {0};
::SHGetFileInfo(L"C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\Windows Mobile Device Center.lnk",
//::SHGetFileInfo(L"C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\TortoiseGit\\TortoiseGitMerge.lnk",
0, &fi, sizeof(fi), SHGFI_ICON /*| SHGFI_SMALLICON*/);
CPaintDC dc(this);
dc.DrawIcon(0, 0, fi.hIcon);
第一个文件呈现为(CORRECT):
第二个呈现为(INCORRECT):
但是资源管理器将其渲染为:
我尝试过SHGFI_SMALLICON修饰符,但无济于事。如何获取这两种情况的图标?或者是否有其他功能可以实现这一目标?
更新
问题是应用程序是x86,操作系统是x64。有没有办法解决它没有分支到2个版本?
答案 0 :(得分:3)
如果您真的想要获得与Explorer相同的行为,那么您需要使用Explorer使用的相同Shell接口,例如IExtractIcon
和IExtractImage
:
有两种方法可以检索对象的图标。最简单的方法是调用SHGetFileInfo。但是,这种方法不灵活,可能很慢。检索项目图标的更灵活有效的方法是使用IExtractIcon。 Shell在显示文件夹内容时使用IExtractIcon检索图标。要使用IExtractIcon检索对象的图标,请执行以下操作:
- 获取指向包含该对象的文件夹的IShellFolder接口的指针。
- 使用指向对象的项标识符列表(PIDL)和IExtractIcon(IID_IExtractIcon)的接口ID的指针调用IShellFolder :: GetUIObjectOf。该文件夹创建一个对象来处理图标提取,并返回该对象的IExtractIcon接口指针。
- 调用IExtractIcon :: GetIconLocation以检索图标的位置。
- 调用IExtractIcon :: Extract以检索图标的句柄。
醇>
如果要实现命名空间对象的视图,并且想要显示缩略图图像,请使用IExtractImage。您可以使用Shell文件夹的IShellFolder :: GetUIObjectOf方法绑定到其IExtractImage接口。
请记住,Shell中的所有内容都由PIDL表示,因此可以通过IShellFolder
和相关接口访问。
您可以使用SHParseDisplayName()
将路径和文件名转换为绝对PIDL,然后使用SHBindToParent()
获取其父文件夹的IShellFolder
。
答案 1 :(得分:2)
您遇到的问题是32位应用程序在64位Windows上工作的问题。系统lnk解析器与指向Program Files目录中的文件的lnk文件无法正常工作。而不是Program Files解析器提取程序文件x86路径。这就是您尝试提取图标或提取目标名称失败的原因。唯一正确的解决方案是为64位操作系统创建64位版本的应用程序,为32位操作系统创建32位版本。您也可以使用hack - 使用您自己的代码读取和解析lnk文件。一些细节:JclShell.ShellLinkResolve gets wrong data另一个" hack" - 使用额外的64位进程来读取lnk文件的图标,但恕我直言,这是一个不好的方法。