Why does the DrawIcon function draw at the default icon size?


Miral wondered why the Draw­Icon function draws at the default icon size instead of respecting the actual icon size. After all, if you loaded a nonstandard-sized icon via Load­Image, then presumably you want to use that nonstandard size.

The question is one of those types of questions that fails to understand history, like asking why NASA didn't send the space shuttle to rescue the Apollo 13 astronauts.

At the time the Draw­Icon function was written, the Load­Image function didn't exist, and wouldn't exist for over a decade. The Load­Image function showed up in Windows 95, but Windows was drawing icons long before then, and for a long time, the only way to load icons was with the Load­Icon function, which always loaded icons at their default size. When the ability to create nonstandard-sized icons was added, you then had the question of how to draw them. Code which relied on the fact that all icons were the same size would call Draw­Icon expecting the result to be a 32×32 image (or whatever your icon size was). If you drew it at its actual size, you would either have this L-shaped "hole" in the application (if the actual size was smaller), or you would have an icon that overflowed some other part of the application. Either way you lose.

Therefore, Draw­Icon always draws at the standard icon size. Think of it as Draw­Icon­Back­Compat. If you are a fancy new application that can handle icons at nonstandard sizes, then use Draw­Icon­Ex and don't pass the DI_DEFAULT­SIZE flag.

Bonus chatter: The documentation states that the DI_COMPAT has no effect. Presumably it had an effect in some previous version of Windows?

In Windows 95, if you used the LoadCursor to load a standard cursor (like, say, IDC_ARROW), but the standard arrow cursor was customized by the user, Windows would draw the customized cursor. Passing the DI_COMPAT flag forced the standard arrow cursor to be drawn. So far as I can tell, nobody ever passed that flag.

Update: My claim that nobody passed that flag is incorrect. The Draw­Icon function itself passed that flag (and still does today, even though it no longer does anything).

Comments (17)
  1. Goran says:

    "So far as I can tell, nobody ever passed that flag." So… Do you have some user activity logs, or…? How much of that? ;-)

  2. Rick C says:

    @Goran more likely, over the years, at least one person would've complained that the "wrong" arrow was drawn.

  3. Rick C says:

    Interestingly, MSDN says

    To duplicate DrawIcon (hDC, X, Y, hIcon), call DrawIconEx as follows:

    DrawIconEx (hDC, X, Y, hIcon, 0, 0, 0, NULL, DI_NORMAL | DI_COMPAT | DI_DEFAULTSIZE);

    Why do I need to specify DI_COMPAT, if DI_COMPAT is ignored?  (Perhaps DrawIconEx says that for those three flags, with the previous four parameters set to 0, it simply calls DrawIcon.)

    [See update. -Raymond]
  4. Jon says:

    "why NASA didn't send the space shuttle to rescue the Apollo 13 astronauts?"

    Easy!

    A.  The shuttle takes too long to get ready,  fueled etc for launch.   Apollo 13 couldn't wait that long for rescue.

    B.  The oxygen tank on apollo 13 exploded when they were approaching the moon,  the shuttle is only able to reach earth orbit and wouldn't have been able to reach them.

  5. Joshua says:

    If I needed the functionality of DI_COMPAT I'd be paranoid enough to ship a copy of the arrow anyway.

  6. Joshua Ganes says:

    @Jon – Your comment made me shake my head and smile at the same time :)

  7. JJJ says:

    @Jon:  The shuttle still could have docked with the Apollo 13 module when they got back to avoid the dangerous re-entry.  As a bonus, the shuttle could have simply dropped off the astronauts at the International Space Station.

  8. Random832 says:

    @Joshua – Well, obviously they would also have to design and build a Space Shuttle, but the problem of the extra time that would add is essentially academic, considering the plan is already not viable due to the other issues.

  9. ErikF says:

    The Apollo 13 crew could have saved themselves all that difficulty if they had only landed at the Moon colony. Better yet, they could have watched the movie and fixed the problem before leaving Earth!

  10. Jonathan_S says:

    @JJJ – The Apollo capsules weren't designed to reestablish orbit around the earth before reentering.  They came straight back from the moon on a reentry profile.  That means even if you had a shuttle there's no way it could rendezvous with a returning Apollo 13 because the Apollo capsule didn't have the capability to match orbits with it.

  11. Rick C says:

    Regarding the update, does that mean that when DrawIconEx was added, DrawIcon's body was replaced with a call to DrawIconEx (or the moral equivalent) (as opposed to being entirely replaced with a macro, like GetWindowLongPtr is under win32 (as opposed to win64,) since DrawIcon is defined in winuser.h as a function?  (DrawIcon isn't documented as taking a flag-type parameter, nor is DI_COMPAT (or any other flag) mentioned on DrawIcon's page.)

  12. Foo says:

    @Johnathan_S… They can just use the tractor beam on the moon base to alter the capsule's trajectory for orbit. Duh.

  13. new code says:

    @Raymond: "Code which relied on the fact that all icons were the same size would call Draw­Icon expecting the result to be a 32×32 image (or whatever your icon size was)."

    To be able to call LoadImage, you had to develop *new* code. That *new* code is of course developed with nonstandard sized icons in mind. I don't see the problem here.

    [New code calls Load­Image and then passes the icon to old code. -Raymond]
  14. new code says:

    New *bug free* code doesn't shove a non-standard sized icon into old code (which assumes 32×32 sized icons).

    New *bug free* code calls drawing logic which can handle non-standard icon sizes.

    Are you optimizing your APIs for buggy code on non-buggy code's expense?

    [Sometimes you don't control which code your icon gets shoved into. For example, by your logic, new bug-free code can never put a nonstandard-sized icon into a static control on a dialog, because some random old screen-scraping app might send an STM_GETICON message to retrieve it. -Raymond]
  15. Joshua says:

    [Sometimes you don't control which code your icon gets shoved into. For example, by your logic, new bug-free code can never put a nonstandard-sized icon into a static control on a dialog, because some random old screen-scraping app might send an STM_GETICON message to retrieve it. -Raymond]

    Good one!

  16. ender says:

    Speaking of DrawIconEx, how do I draw the Windows' own icons in the current icon size – specifically, I'm trying to use the message box icons (OIC_NOTE etc.), but they always load as 32×32 (I tried both LoadIcon and LoadImage to load them, and DrawIcon and DrawIconEx; DrawIcon will scale the image to the correct size, but this results in a jaggy icon rather than the nice pre-scaled version that message boxes use).

  17. Medinoc says:

    A problem with scaling images is that upscaling a small image is very easily ugly. I'd have centered them instead (but still downscaled bigger icons).

Comments are closed.