You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

提取图标信息异常:ICONINFOEX字段值为0的问题排查

图标资源信息获取失败的原因及解决方案

问题重现

执行以下代码后,控制台无输出,ICONINFOEX的szResName和wResID字段均为0,但目标文件确实包含图标,HICON和ICONINFOEX对象也不为空:

#include <Windows.h>
#include <vector>
#include <iostream>

using namespace::std;

BOOL CALLBACK EnumerateIcons(HMODULE hModule, LPCTSTR type, LPTSTR szName, LONG_PTR ptr) {
    if (ptr == 0)
        return FALSE;

    vector<HICON>* pVec    = (vector<HICON>*)ptr;
    HRSRC          hRes    = FindResource(hModule, szName, type);

    if (hRes == NULL)
        return TRUE;

    DWORD          dwSize  = SizeofResource(hModule, hRes);
    HGLOBAL        hGlobal = LoadResource(hModule, hRes);

    if (hGlobal == NULL)
        return TRUE;

    LPBYTE         bytes = (BYTE*)LockResource(hGlobal);

    HICON          hIcon = CreateIconFromResourceEx(bytes, dwSize, TRUE, 0x00030000,
        0, 0, LR_SHARED);

    if (hIcon)
        pVec->push_back(hIcon);

    return TRUE;
}

VOID IndexIcons(LPCWSTR szFileName) {
    HMODULE Binary = LoadLibraryEx(szFileName, NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE);
    if (!Binary)        
        return;    

    vector<HICON> Icons;
    EnumResourceNames(Binary,
        RT_ICON, (ENUMRESNAMEPROC)EnumerateIcons, (LONG_PTR)&Icons);

    for (HICON hIcon : Icons) {
        ICONINFOEX iconInfo = { sizeof(iconInfo) };
        if (!GetIconInfoExW(
            hIcon,
            &iconInfo))
            continue;
        
        wprintf(L"%s %d\n", iconInfo.szResName, iconInfo.wResID);
    }
}

原因分析

  • GetIconInfoEx的设计限制:通过CreateIconFromResourceEx生成的HICON是基于内存资源数据创建的独立图标对象,并未与原模块中的资源条目建立关联。GetIconInfoEx的szResName和wResID字段仅对通过LoadIcon/LoadImage直接从模块加载的图标有效,对内存生成的图标不会填充这些字段,所以返回0。
  • 枚举范围不完整:Windows中图标通常以RT_GROUP_ICON(图标组,对应资源管理器中看到的图标集合)形式存在,而你只枚举了RT_ICON(单个图标资源),可能漏掉了大部分实际需要的图标资源;此外,szName可能是整数ID(而非字符串),当前代码未区分这种情况,导致部分资源处理异常。

解决方案

方案一:枚举时直接记录资源标识

不需要依赖GetIconInfoEx,在EnumerateIcons回调中直接保存资源的原始名称/ID,因为此时的szName就是资源的原始标识:

#include <Windows.h>
#include <vector>
#include <iostream>

using namespace::std;

struct IconResourceInfo {
    HICON hIcon;
    // 存储资源名称或ID,通过isId区分
    LONG_PTR resIdent;
    BOOL isId;
};

BOOL CALLBACK EnumerateIcons(HMODULE hModule, LPCTSTR type, LPTSTR szName, LONG_PTR ptr) {
    if (ptr == 0)
        return FALSE;

    vector<IconResourceInfo>* pVec = (vector<IconResourceInfo>*)ptr;
    HRSRC hRes = FindResource(hModule, szName, type);
    if (hRes == NULL)
        return TRUE;

    DWORD dwSize = SizeofResource(hModule, hRes);
    HGLOBAL hGlobal = LoadResource(hModule, hRes);
    if (hGlobal == NULL)
        return TRUE;

    LPBYTE bytes = (BYTE*)LockResource(hGlobal);
    HICON hIcon = CreateIconFromResourceEx(bytes, dwSize, TRUE, 0x00030000, 0, 0, LR_SHARED);
    if (hIcon) {
        IconResourceInfo info;
        info.hIcon = hIcon;
        info.isId = IS_INTRESOURCE(szName);
        info.resIdent = (LONG_PTR)szName;
        pVec->push_back(info);
    }
    return TRUE;
}

VOID IndexIcons(LPCWSTR szFileName) {
    HMODULE Binary = LoadLibraryEx(szFileName, NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE);
    if (!Binary)        
        return;    

    vector<IconResourceInfo> Icons;
    // 同时枚举RT_ICON和RT_GROUP_ICON
    EnumResourceNames(Binary, RT_ICON, (ENUMRESNAMEPROC)EnumerateIcons, (LONG_PTR)&Icons);
    EnumResourceNames(Binary, RT_GROUP_ICON, (ENUMRESNAMEPROC)EnumerateIcons, (LONG_PTR)&Icons);

    for (const auto& info : Icons) {
        if (info.isId) {
            wprintf(L"资源ID: %d\n", LOWORD(info.resIdent));
        } else {
            wprintf(L"资源名称: %s\n", (LPTSTR)info.resIdent);
        }
        DestroyIcon(info.hIcon);
    }
    FreeLibrary(Binary);
}

方案二:直接遍历资源目录获取信息

如果不需要创建HICON,可以直接通过资源枚举函数获取所有图标资源的名称/ID,无需加载资源数据:

#include <Windows.h>
#include <iostream>

using namespace::std;

BOOL CALLBACK EnumIconResProc(HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam) {
    // 区分资源是ID还是字符串名称
    if (IS_INTRESOURCE(lpszName)) {
        wprintf(L"图标资源ID: %d\n", LOWORD((LONG_PTR)lpszName));
    } else {
        wprintf(L"图标资源名称: %s\n", lpszName);
    }
    return TRUE;
}

VOID IndexIcons(LPCWSTR szFileName) {
    HMODULE Binary = LoadLibraryEx(szFileName, NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE);
    if (!Binary)        
        return;    

    // 枚举图标组和单个图标资源
    EnumResourceNames(Binary, RT_GROUP_ICON, EnumIconResProc, 0);
    EnumResourceNames(Binary, RT_ICON, EnumIconResProc, 0);

    FreeLibrary(Binary);
}

内容的提问来源于stack exchange,提问作者Blaze

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 07:53:22