Link to home
Start Free TrialLog in
Avatar of Koro_das_Master
Koro_das_Master

asked on

Loading icons of a specific color depth

Hi,

I'm currently programming an application which shows an icon in the tray. The problem, however, is that any versions of Windows older than ME don't support hi-color icons in the tray, so Windows reduces the color depth of my icon in an ugly fashion (instead of just taking the 4bpp image present in the icon). I'm using LoadImage to load the icon's 16x16 image, however, this function (and LoadIcon neither) does not let me specify the color depth of the icon I want to load.

I've found a temporary solution by defining two icon resources: the original one (which has images of 16x16,32x32,48x48 of 16, 256, and Windows XP alpha-blended colors each) and a copy of the original one containing only the 16-color images, but that's certainly not the best solution.

I'm using Microsoft Visual C++ 6.0 Enterprise on Windows 2000 with the latest Platform SDK
The app must run on Windows 98, Windows NT 4.0 with IE4 + Desktop Update
ASKER CERTIFIED SOLUTION
Avatar of DanRollins
DanRollins
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Koro_das_Master
Koro_das_Master

ASKER

Hi,

Thanks for the comment, however, I'm not trying to circumvent this limitation, I'm looking for a way to load an icon image of a specific color depth, because even if LoadImage lets me specify the size I want to load, there's no API I know of which lets me specify the color depth.

p.s. Thanks for the LoadImage tip, I shall be careful about that.
Hi,

I found a solution myself. I have not tested it yet, but I'm pretty sure it should work.

I post it here so it might help other people who might have the same problem.

I've coded a LoadIconEx() function that allows specifying the color depth of the icon to be loaded

-- iconex.h --

#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;

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 )

HICON LoadIconEx(HINSTANCE, LPCTSTR, int, int, int);

-- iconex.cpp --

#include <windows.h>

#include <math.h>   // For the pow() function

#include "iconex.h"

// LoadIconEx: Loads an icon with a specific size and color depth. This function
// will NOT try to strech or take an icon of another color depth if none is
// present.
HICON LoadIconEx(HINSTANCE hInstance, LPCTSTR lpszName, int cx, int cy, int uColors)
{
    HRSRC hRsrcIconGroup;

    // Load the icon group of the desired icon

    if (!(hRsrcIconGroup=FindResource(hInstance,lpszName,RT_GROUP_ICON)))
        return NULL;

    // Look for the specified color depth

    // Load the resource

    GRPICONDIR* pGrpIconDir;
    HRSRC hGlobalIconDir;

    if (!(hGlobalIconDir=LoadResource(hInstance,hRsrcIconGroup)))
        return NULL;

    // Lock the resource

    if (!(pGrpIconDir=(GRPICONDIR*) LockResource(hGlobalIconDir)))
        return NULL;

    // Cycle through all icon images trying to find the one we're looking for

    int i;
    BOOL bFound=FALSE;

    // In case of 8ppp or higher, the bColorCount of the structure is 0, and we
    // must find our icon with the wPlanes and wBitCount. So if the requested
    // number of colors is >=256, we calculate using those fields

    if (uColors>=256)
    {
        for (i=0;i<pGrpIconDir->idCount;i++)
        {
            // Color depth is always (bit count)*(plane count)
            // So color count is always (2^(color depth))
            if (uColors==pow(2,(pGrpIconDir->idEntries[i].wPlanes*
                     pGrpIconDir->idEntries[i].wBitCount)))
            {
                if ((pGrpIconDir->idEntries[i].bWidth==cx)&&
                    (pGrpIconDir->idEntries[i].bHeight==cy)) // Do the size match?
                {
                    bFound=TRUE;    // Yes, it matches
                    break;
                }
            }
        }
    }
    else
    {
        for (i=0;i<pGrpIconDir->idCount;i++)
        {
            if (pGrpIconDir->idEntries[i].bColorCount==uColors) // Do the color count match?
            {
                if ((pGrpIconDir->idEntries[i].bWidth==cx)&&
                    (pGrpIconDir->idEntries[i].bHeight==cy)) // Do the size match?
                {
                    bFound=TRUE;    // Yes, it matches
                    break;
                }
            }
        }
    }

    if (!bFound)
        return NULL;        // No icon was found matching the specs

    // Icon was found! i contains the index to the GRPICONDIR structure in the
    // icon group. Find the ID of the icon

    int nID;

    nID=pGrpIconDir->idEntries[i].nID;

    // Now, find the actual icon resource

    HRSRC hRsrcIcon;
    HRSRC hGlobalIcon;
    void* pIconBits;

    if (!(hRsrcIcon=FindResource(hInstance,MAKEINTRESOURCE(nID),RT_ICON)))
        return NULL;

    if (!(hGlobalIcon=LoadResource(hInstance,hRsrcIcon)))
        return NULL;

    if (!(pIconBits=LockResource(hGlobalIcon)))
        return NULL;

    // Now, use CreateIconFromResourceEx to create the actual HICON

    return CreateIconFromResourceEx(
        (unsigned char*) pIconBits, // Pointer to icon data
        pGrpIconDir->idEntries[i].dwBytesInRes, // Size of icon data
        TRUE, // TRUE to create an icon, not a cursor
        0x00030000, // Version number. MSDN says to put that number
        cx, cy, // Width and height
        0); // Flags (none)
}

-- end --

As for the points, DanRollins, even if your answer was not the one I was looking for, I liked a lot the links you've given me, so if you want them, just ask me, else I'll get them refunded.
Yes, I would like the points.  Thanks.
- Dan