Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / MFC

Extracting A Particular Icon From an .ICO Resource

4.83/5 (9 votes)
26 Jan 2011CPOL 1  
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:

C++
//------------------------------------------------------------------------------
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;
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)