Extracting A Particular Icon From an .ICO Resource
Extracting A Particular Icon From an .ICO Resource
I have a number of third party controls in my application. Some of them support 32bpp icons and some don't. So, wanting it to look as good as it is able to, I thought I'd used 32bpp icons where I could, but include lower bit depths in the icon file for use where they weren't supported. All I'd need is a way to extract a particular icon from my icon resource. Simple, eh?
Well, depleting my Google-fu quite considerably, told me no, it isn't simple. It is in fact, absurdly complicated. Nevertheless, after a few hours of trial-and-error, I came up with a function that gave me what I needed:
//------------------------------------------------------------------------------
HICON LoadResourceIcon(UINT nResID, BYTE nWidth, BYTE nHeight, SHORT nBitDepth)
//------------------------------------------------------------------------------
{
HICON hIconRet = NULL;
#pragma pack(2)
struct IcoMemEntry // This is what an icon resource looks like in memory
{
byte Width; // Width, in pixels, of the image
byte Height; // Height, in pixels, of the image
byte ColorCount; // Number of colors in image(0 if >=8bpp)
byte Reserved; // Reserved (must be 0)
short Planes; // Color Planes
short BitCount; // Bits per pixel
int BytesInRes; // How many bytes in this resource?
short ID; // Where in the file is this image?
};
struct IcoHeader
{
short Reserved; // Reserved (must be 0)
short Type; // 1 = Icon, 0 = Bitmap
short Count; // number of icons
IcoMemEntry Entries; // address place holder
};
#pragma pack()
// Find the start of the icon resource in memory
HMODULE hModule = AfxGetInstanceHandle();
HRSRC hRes = ::FindResource(hModule, MAKEINTRESOURCE(nResID), RT_GROUP_ICON);
HGLOBAL hGlobal = ::LoadResource(hModule, hRes);
IcoHeader* pHead = (IcoHeader*)::LockResource(hGlobal);
if (pHead->Count != 0)
{
// Get the hicon headers so we can examine them
IcoMemEntry* pEntries = NULL;
pEntries = new IcoMemEntry[pHead->Count];
IcoMemEntry* pEntry = &(pHead->Entries);
CopyMemory(pEntries, pEntry, sizeof(IcoMemEntry) * pHead->Count);
for (int i = 0; i < pHead->Count; i++)
{
// If an icon matches our criteria, extract it
if (pEntries[i].Width == nWidth && pEntries[i].Height == nHeight &&
pEntries[i].BitCount == nBitDepth)
{
HRSRC hIconInfo = ::FindResource(hModule, MAKEINTRESOURCE(pEntry[i].ID),
MAKEINTRESOURCE(RT_ICON));
HGLOBAL hIconRes = ::LoadResource(hModule, hIconInfo);
BYTE* dibBits = (BYTE*)::LockResource(hIconRes);
long szLength = ::SizeofResource(hModule, hIconInfo);
hIconRet = CreateIconFromResourceEx((PBYTE) dibBits, szLength, TRUE, 0x00030000,
nWidth, nHeight, LR_DEFAULTCOLOR);
::DestroyIcon((HICON)dibBits);
break;
}
}
// Clean up
if (pEntries != NULL)
{
delete[] pEntries;
}
}
::DestroyIcon((HICON)pHead);
return hIconRet;
}