使用 SHGetFileInfo 获取 exe 图标失败

Posted

技术标签:

【中文标题】使用 SHGetFileInfo 获取 exe 图标失败【英文标题】:Failed to get exe icon with SHGetFileInfo 【发布时间】:2016-05-21 12:16:44 【问题描述】:

我正在使用cmake + nmake构建exe,我想从可执行文件本身获取图标句柄。

CMakeLists.txt:

add_executable(test test.cpp test.rc)

test.rc:

IDI_ICON   ICON  DISCARDABLE  "test.ico"
IDI_ICON0   ICON  DISCARDABLE  "test.ico"
IDI_ICON1   ICON  DISCARDABLE  "test.ico"
IDI_ICON2   ICON  DISCARDABLE  "test.ico"

test.cpp:

#include <windows.h>
#include <iostream>
using namespace std;

int main() 
    SHFILEINFO  sfi;
    memset(&sfi, 0, sizeof(sfi));
    DWORD_PTR ret = ::SHGetFileInfo("g:/workspace/test2/debug/test.exe",
                    0, &sfi, sizeof(sfi), SHGFI_LARGEICON|SHGFI_SMALLICON|SHGFI_ICON);
    cout << hex;
    cout << ret << endl; // prints 0
    cout << sfi.hIcon << endl; // prints 0

可执行文件g:/workspace/test2/debug/test.exe有图标,但是SHGetFileInfo获取不到图标,代码有什么问题?

【问题讨论】:

您是否尝试过将uFlags 参数与特定图标类型SHGFI_ICON | SHGFI_LARGEICONSHGFI_ICON | SHGFI_SMALLICON 结合使用?您还应该检查来自SHGetFileInfo() 的返回值,以了解发生了什么。 使用这些参数和返回值更新原始帖子。 返回值是多少? Windows 通常使用反斜杠作为路径分隔符,而不是正斜杠 - 我不确定 SHGetFileInfo 函数是否接受这两者。 SHGFI_LARGEICON|SHGFI_SMALLICON 也有点矛盾。您一次只能获得一个。 在调用 SHGetFileInfo() 之前是否调用过 CoInitialize()? 【参考方案1】:

我最好的选择是您(根据documentation)在尝试提取图标信息之前需要调用CoInitialize()。如果我们有一个不能处理正斜杠的 windows 函数,我不会感到惊讶:

在调用 SHGetFileInfo 之前,您必须使用 CoInitialize 或 OleInitialize 初始化组件对象模型 (COM)。

所以,代码代码改为:

int main() 
  SHFILEINFO  sfi;

  // initialize COM library
  CoInitialize(NULL);
  memset(&sfi, 0, sizeof(sfi));
  DWORD_PTR ret = ::SHGetFileInfo("g:/workspace/test2/debug/test.exe",
                0, &sfi, sizeof(sfi), SHGFI_LARGEICON | SHGFI_ICON);
  cout << hex;
  cout << ret << endl;
  cout << sfi.hIcon << endl;

  CoUninitialize();

【讨论】:

Windows 上的路径分隔符是反斜杠 ("\")。虽然“Windows API 中的文件 I/O 函数将“/”转换为“\”作为将名称转换为 NT 样式名称的一部分” (Naming Files, Paths, and Namespaces),但此转换不会'当路径具有“\\?\”前缀时,不会这样做。顺便说一下,这个前缀将文件 I/O 函数的路径名限制推到 32k Unicode 字符。由于SHGetFileInfo 不是文件 I/O 函数的一部分,因此转换不是契约性的。【参考方案2】:

作为 Jonathan Potter 的评论帖子,它是由反斜杠引起的。该代码在文件路径中将“/”更改为“\”后有效。

【讨论】:

以上是关于使用 SHGetFileInfo 获取 exe 图标失败的主要内容,如果未能解决你的问题,请参考以下文章

如何使用Shell32.SHGetFileInfo在Windows 7上获取文件夹图标

SHGetFileInfo 返回空图标

获取文件夹中的图标资源

SHGetFileInfo函数详解

MFC文件之SHGetFileInfo函数与SHFILEINFO结构体

使用java传参调用exe并且获取程序进度和返回结果的一种方法