The original icon handling functions are ancient. They were introduced in 16-bit Windows and designed for a system that defined only one icon size. Therefore, most of those functions are unaware of the possibility of more than one icon size. To get to the differently sized icons in a resource additional work is required.
Following the ICO file format, consisting of an icon directory and the actual icon images, an icon resource consists of two parts as well: The icon directory of type RT_GROUP_ICON
and the individual icons (RT_ICON
). The directory is represented by the following structures:
#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 )
and
#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 )
The icon directory for an icon group ID can be retrieved using the following code:
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;
}
With the information from the icon directory the individual icons can be constructed with this code:
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;
}
Putting all the pieces together, the following loads explorer.exe
as a resource file, retrieves the first icon group with ID 101
and prints the information from the icon directory for each entry. It then creates the individual icons and outputs the xHotspot
and yHotspot
data. For icons, the hotspot is located in the center:
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;
}
To sum this up: Retrieving all icon sizes and color variations for an icon resources involves two steps:
- Retrieve the icon directory with information for all icons in an icon group.
- Iterate over the icon directory and construct the individual icons using
CreateIconFromResourceEx
.
References: