windows - 使用 Win32 API 找出图标资源中的图标数量

标签 windows winapi gdi

我有一个 *.ico 文件,其中包含多个不同大小的图标作为资源链接到我的可执行文件。我使用此资源通过 RegisterClassEx() 设置我的应用程序图标,即:

wcx.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));

除此之外,我还想将此资源中的所有单个图标转换为 ARGB 像素数组。这应该可以通过对 GetIconInfo() 返回的位图使用 GetDIBits() 来实现。

但是,有一个问题:我需要找出 LoadIcon() 返回的 HICON 句柄中的图标数量及其大小。我似乎没有找到采用 HICON 句柄并告诉我其中实际有多少个图标以及它们的大小的 API。

这有可能吗?还是我需要自己动手解析 *.ico 资源?

最佳答案

原始的图标处理函数是古老的。它们是在 16 位 Windows 中引入的,专为仅定义一种图标大小的系统而设计。因此,这些功能中的大多数都没有意识到不止一种图标大小的可能性。要获得资源中不同大小的图标,需要额外的工作。

按照 ICO 文件格式,由图标目录和实际图标图像组成,图标资源也由两部分组成:RT_GROUP_ICON 类型的图标目录和单个图标(RT_ICON).该目录由以下结构表示:

#pragma pack( push )
#pragma pack( 2 )
typedef struct 
{
    WORD            idReserved;   // Reserved (must be 0)
    WORD            idType;       // Resource type (1 for icons)
    WORD            idCount;      // How many images?
    GRPICONDIRENTRY idEntries[1]; // The entries for each image
} GRPICONDIR, *LPGRPICONDIR;
#pragma pack( pop )

#pragma pack( push )
#pragma pack( 2 )
typedef struct
{
    BYTE   bWidth;               // Width, in pixels, of the image
    BYTE   bHeight;              // Height, in pixels, of the image
    BYTE   bColorCount;          // Number of colors in image (0 if >=8bpp)
    BYTE   bReserved;            // Reserved
    WORD   wPlanes;              // Color Planes
    WORD   wBitCount;            // Bits per pixel
    DWORD  dwBytesInRes;         // how many bytes in this resource?
    WORD   nID;                  // the ID
} GRPICONDIRENTRY, *LPGRPICONDIRENTRY;
#pragma pack( pop )

可以使用以下代码检索图标组 ID 的图标目录:

typedef std::list<GRPICONDIRENTRY> IconDirectory;

IconDirectory GetIconDirectory( HMODULE hMod, WORD Id ) {
    HRSRC hRsrc = FindResourceW( hMod, MAKEINTRESOURCE( Id ), RT_GROUP_ICON );
    HGLOBAL hGlobal = LoadResource( hMod, hRsrc );
    GRPICONDIR* lpGrpIconDir = (GRPICONDIR*)LockResource( hGlobal );

    IconDirectory dir;
    for ( size_t i = 0; i < lpGrpIconDir->idCount; ++i ) {
        dir.push_back( lpGrpIconDir->idEntries[ i ] );
    }
    return dir;
}

根据图标目录中的信息,可以使用以下代码构建各个图标:

HICON LoadSpecificIcon( HMODULE hMod, WORD Id ) {
    HRSRC hRsrc = FindResourceW( hMod, MAKEINTRESOURCE( Id ), RT_ICON );
    HGLOBAL hGlobal = LoadResource( hMod, hRsrc );
    BYTE* lpData = (BYTE*)LockResource( hGlobal );
    DWORD dwSize = SizeofResource( hMod, hRsrc );

    HICON hIcon = CreateIconFromResourceEx( lpData, dwSize, TRUE, 0x00030000,
                                            0, 0, LR_DEFAULTCOLOR );
    return hIcon;
}

将所有部分放在一起,以下将 explorer.exe 作为资源文件加载,检索 ID 为 101 的第一个图标组并打印图标目录中的信息对于每个条目。然后它创建单独的图标并输出 xHotspotyHotspot 数据。对于图标,热点位于中心:

void PrintIconDirEntry( const GRPICONDIRENTRY& DirEntry ) {
    _wprintf_p( L"ID: %04d; width=%02d; height=%02d; bpp=%02d\n",
                DirEntry.nID,
                DirEntry.bWidth, DirEntry.bHeight, DirEntry.wBitCount );
}

void PrintIconInfo( HICON hIcon ) {
    ICONINFO ii = { 0 };
    GetIconInfo( hIcon, &ii );
    _wprintf_p( L"xHotspot=%02d; yHotspot=%02d\n", ii.xHotspot, ii.yHotspot );
}

typedef std::list<GRPICONDIRENTRY>::const_iterator IconDirectoryCIt;

int _tmain(int argc, _TCHAR* argv[])
{
    HMODULE hMod = LoadLibraryExW( L"C:\\Windows\\system32\\explorer.exe",
                                   NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE );
    IconDirectory dir = GetIconDirectory( hMod, 101 );
    for ( IconDirectoryCIt it = dir.begin(); it != dir.end(); ++it ) {
        PrintIconDirEntry( *it );
        HICON hIcon = LoadSpecificIcon( hMod, it->nID );
        PrintIconInfo( hIcon );
        DestroyIcon( hIcon );
    }
    return 0;
}

总结一下:检索图标资源的所有图标大小和颜色变化涉及两个步骤:

  1. 检索包含图标组中所有图标信息的图标目录。
  2. 遍历图标目录并使用 CreateIconFromResourceEx 构造单个图标.

引用资料:

关于windows - 使用 Win32 API 找出图标资源中的图标数量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20729156/

相关文章:

linux - 如何删除正在连续写入的文件的旧内容?

windows - 使用 Powershell 创建的本地用户帐户未显示在设置 "Family & Other people"中

Windows Bat - 系统找不到指定的文件

c++ - 哪种方法更好地获取静态链接 DLL 的模块句柄 (HMODULE) - 使用 GetModuleHandleEx() 或 LoadLibrary()?

c++ - 生成 WM_NCHITTEST 消息

c++ - CreateDIBSection 图形工件或如何正确访问位图位

c# - C#.NET 中的 JPEG 2000 支持

php - 我无法在 symfony2 中创建包

windows - Windows下如何查询用户的session id?

java - 从 GDI32.HDC 转换为 awt.Graphics