How do I get the dimensions of a cursor or icon?

Given a HICON or a HCURSOR, how do you get the dimensions of the icon or cursor?

The GetIconInfo function gets you most of the way there, returning you an ICONINFO structure which gives you the mask and color bitmaps (and the hotspot, if a cursor). You can then use the GetObject function to get the attributes of the bitmap. And then here's the tricky part: You have to massage the data a bit.

// Also works for cursors
BOOL GetIconDimensions(__in HICON hico, __out SIZE *psiz)
  BOOL fResult = GetIconInfo(hico, &ii);
  if (fResult) {
    BITMAP bm;
    fResult = GetObject(ii.hbmMask, sizeof(bm), &bm) == sizeof(bm);
    if (fResult) {
      psiz->cx = bm.bmWidth;
      psiz->cy = ii.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
    if (ii.hbmMask)  DeleteObject(ii.hbmMask);
    if (ii.hbmColor) DeleteObject(ii.hbmColor);
  return fResult;

As we've learned over the past few days, an icon consists of two bitmaps, a mask and an image. A cursor is the same as an icon, but with a hotspot.

To get the dimensions of the icon or cursor, just take the dimensions of the color bitmap. If you have one.

If the icon/cursor is monochrome, then there is no color bitmap. As we've learned, in that case, the mask and image bitmaps are combined into a single double-height bitmap, and the color is reported as NULL. To get the size of the image, you therefore have to take the mask bitmap and divide its height by two.

Comments (14)
  1. WndSucks says:

    "The width of an icon always equals its height" (…/bb761850%28v=VS.85%29.aspx ) so why check both? Or does that only apply to the shell? (I understand that the icon format will allow you to create icons with w!=h but I assume such a thing would break shell display or something)

    [Good job reading text out of context. The width of an icon generated by the IExtractIcon::Extract method always equals its height. -Raymond]
  2. Jules says:


    I think that's just a restriction of that specific function.  Some other functions might also make the same assumption, but there are icons out there with non-square dimensions, and at least in some situations they work. I distinctly remember that CGA mode on Windows 3.0 used 32×16 icons (CGA full colour mode resolution is something like 320×120, so pixels are a long way from square).  But I installed a shell replacement that didn't understand the idea of non-square icons, and just displayed half of each, so the problem has been around at least that long.

  3. Gab says:

    Jules: CGA modes were 320×200 (4 colors) and 640×200 (2 colors).

  4. Gert says:

    I know that this week mostly concerns icons (and the PNG icons haven't been covered yet), but the layout of the .ani format might be intersting is as well. (My guess would be that it might just be an icon with multiple icons in the same file, a hostsport / hotspot per frame and possibly some animation parameters such as delay between frames)

    (If it is a multiple icon icon file, it would also be interesting to see what happens if someone messes it up – by adding icons of different size and color depths and formats…)

  5. Ivo says:

    Speaking of IExtractIcon and icon sizes – IExtractIcon::Extract lets you specify the size, however it most often returns S_FALSE, which means "don't bother me, call ExtractIcon". But ExtractIcon (and ExtractIconEx) doesn't have a size parameter! How do I get an icon of arbitrary size from IExtractIcon?

  6. Adrian says:

    It's great you made deleting the bitmap objects explicit, as that's often overlooked with this function.  Thanks for the info.

  7. JonPotter says:

    It's always seemed ridiculously inefficient to me to have to call a function that creates two bitmaps, just to get the dimensions that would already be known internally anyway. Couldn't a GetIconSize() function have been added at some point?

    [Yes, that strikes me as odd too. Where's my time machine? -Raymond]
  8. JonPotter says:

    Windows 8 is still in the future – how 'bout it?

  9. Koro says:

    It *is* possible to create icons where width != height. I remember an old version of the ImagEdit allowed to create 32×16 monochrome icons.

  10. 640k says:

    You'll have to wait for windows 9 until GetIconSize is implemented.

  11. Alex Cohn says:

    I found icons with width!=height extremely useful, because using icon was the only way to embed 32-bit (that is, with 8-bit alpha channel) image resource. Paint.NET has a wonderful plugin that allows to save an .ico file with arbitrary collection of images.

  12. Neil says:

    CGALOGO.RLE will give you an idea of the aspect ratio of the CGA monochrome mode. If you can still find software capable of reading it, of course…

  13. Ivo says:

    @alexcohn – I am using 32-bit bitmap resources just fine. Are you sure they don't work for you? I am using Visual Studio 2008 and my code runs on Vista+, so maybe on older compiler or OS there are problems.

  14. AC says:

    I know this is WAY off topic (and a bit late), but anyway:

    The "Header Annotations" documentation you link to above says the following:

    __nullnullterminated : The buffer may be accessed up to and including the first sequence of two null characters or pointers.

    But as you have blogged about a single is a valid (empty) double-null-terminated strings. Does this mean that:

    a) That annotation must not be used for double-null-terminated strings or

    b) it is valid for double-null-terminated strings but the documentation is not quite correct in this regard?

    [Take what you learned from that earlier blog entry and apply it to this situation. -Raymond]

Comments are closed.