SHGetFileInfo()返回错误的HICON

时间:2014-11-10 12:06:29

标签: winapi icons

我试图获取任何文件的图标(如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):

enter image description here

第二个呈现为(INCORRECT):

enter image description here

但是资源管理器将其渲染为:

enter image description here

我尝试过SHGFI_SMALLICON修饰符,但无济于事。如何获取这两种情况的图标?或者是否有其他功能可以实现这一目标?

更新

问题是应用程序是x86,操作系统是x64。有没有办法解决它没有分支到2个版本?

2 个答案:

答案 0 :(得分:3)

如果您真的想要获得与Explorer相同的行为,那么您需要使用Explorer使用的相同Shell接口,例如IExtractIconIExtractImage

  

有两种方法可以检索对象的图标。最简单的方法是调用SHGetFileInfo。但是,这种方法不灵活,可能很慢。检索项目图标的更灵活有效的方法是使用IExtractIcon。 Shell在显示文件夹内容时使用IExtractIcon检索图标。要使用IExtractIcon检索对象的图标,请执行以下操作:

     
      
  1. 获取指向包含该对象的文件夹的IShellFolder接口的指针。
  2.   
  3. 使用指向对象的项标识符列表(PIDL)和IExtractIcon(IID_IExtractIcon)的接口ID的指针调用IShellFolder :: GetUIObjectOf。该文件夹创建一个对象来处理图标提取,并返回该对象的IExtractIcon接口指针。
  4.   
  5. 调用IExtractIcon :: GetIconLocation以检索图标的位置。
  6.   
  7. 调用IExtractIcon :: Extract以检索图标的句柄。
  8.   

  

如果要实现命名空间对象的视图,并且想要显示缩略图图像,请使用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文件的图标,但恕我直言,这是一个不好的方法。