【问题标题】:Find out number of icons in an icon resource using Win32 API使用 Win32 API 找出图标资源中的图标数量
【发布时间】:2014-01-10 19:45:03
【问题描述】:

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

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

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

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

这是否可能,还是我需要自己去解析 *.ico 资源?

【问题讨论】:

    标签: windows winapi gdi


    【解决方案1】:

    原始的图标处理功能是古老的。它们是在 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 构造各个图标。

    参考资料:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-08-21
      • 2012-09-12
      • 1970-01-01
      • 2018-12-24
      • 2013-03-19
      • 1970-01-01
      • 2010-09-09
      相关资源
      最近更新 更多