使用Win32 API查找图标资源中的图标数量

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

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

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

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

这是否有可能以某种方式,或者我需要去困难的方式和parsing* .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构造单个图标。

参考文献:

  • 图标格式的MSDN文档: 图标
  • 旧的新事物: ICO文件格式的演变,第1部分:单色的开始
  • 旧的新事物: ICO文件格式的演变,第2部分:现在是彩色的!
  • 旧的新事物: ICO文件格式的演变,第3部分:Alpha混合的图像
  • 旧的新事物: ICO文件格式的演变,第4部分:PNG图像
  • 旧的新事物: 图标资源的格式
  • 旧的新事物: 我如何覆盖默认的图标选择算法?