views:

232

answers:

2

I would like to define the application icon of a Win32 window, e.g. through a call to SetClassLong with GCL_HICON and passing in a handle to an icon (see SetClassLong Function on MSDN).

This works great, but I have not figured out how I should load an icon (from an ICO file) in order to keep all available sizes (e.g. 16x16, 32x32, 48x48 and full size PNG icon). When I load the icon file through LoadImage into memory to get the HICON, I have to specify which size I want (see my reply to a related question).

My ICO file contains a small sized image which should be used as the window icon (top left corner of the title bar) and has been designed to be very crisp, but also larger variants which should show up in the Alt-Tab dialog, but...

  1. Loading the 16x16 icon shows the proper icon in the title bar, but - of course - an ugly stretched version of it when I Alt-Tab. And the one showing up in the task bar is not very pretty either.

  2. Loading the 48x48 icon shows a nice icon when I Alt-Tab, but the icon which shows up in the title bar is blurry, since it is a scaled down version of the 48x48 icon.

Is there any means of telling Windows that my Windows has a multi-sized icon? Is there some obvious API which I have missed?

+1  A: 

an .ICO file has multiple images in it. but a HICON is only one of those images. if you use LR_DEFAULTSIZE, then there may be some magical behavior that preserves a link to the .ico file and uses the appropriate image from it, but I doubt it.

If this doesn't do it, then nothing will.

HICON hicon = LoadImage(NULL, "filename.ico", IMAGE_ICON, 
                        0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE);

A little background.

When a .ico file is included in a application's resources, the file is cracked open and each image from the file becomes a separate resource. The file header is modified and it becomes the ICON resource. So when LoadIcon/LoadImage is passed the resource id of an ICON resource, it's really being passed a directory of other resources. It chooses the image that fits the request at that point in time and turns it into an HICON. The function that actually does this is called LookupIconIdFromDirectory

This is why when you GetIconInfo for an HICON, you get back only a single ICONINFO structure.

typedef struct _ICONINFO {
    BOOL fIcon;
    DWORD xHotspot;
    DWORD yHotspot;
    HBITMAP hbmMask;
    HBITMAP hbmColor;
} ICONINFO;
John Knoeller
For LR_DEFAULTSIZE MSDN says: "If the resource contains multiple images, the function uses the size of the first image"
Anders
@Anders: yes. but the .NET ICON appears to keep track of the .ico source and when you ask it to make a new icon from the old one, it will reach back into the source rather than just stretching. I think this _might_ also be true for unmanaged icons, but I have no definitive knowledge either way.
John Knoeller
Thank you for your ideas and explanations. LR_DEFAULTSIZE does not, however, do the magical behaviour we were dreaming of. I guess that I will have to use GCL_HICON and GCL_HICONSM; I'll report back in by commenting Anders' reply.
Pierre
+2  A: 

GCL_HICON sets the "big" icon, GCL_HICONSM sets the small icon (Sizes are normally 32x32 and 16x16, but you should use GetSystemMetrics with SM_CXICON and SM_CXSMICON to find the actual size (For the large icon, you can also just pass LR_DEFAULTSIZE to LoadImage with 0 size))

Anders
Currently, I cannot get `SetClassLong` to work as expected on my WinForms application. The default WinForms icon wins; and when I Alt-Tab, I get a short glimpse of my icon, but then the default WinForms icon is painted on top of mine. Strange. If I cannot figure this out by myself, I'll post another question on stack overflow.
Pierre
The other question is here, in case you wonder: http://stackoverflow.com/questions/2266479
Pierre