System Menu Icon Bug

Published on April 12, 2008
This article was written back when Visual Studio 6 was new. As such, I cannot guarantee that the content of this article still applies in modern Windows environments.

Within the code generated by Microsoft’s MFC AppWizard, is a means of displaying the system menu icon (the little icon that appears in the upper left corner of all Windows programs). This code contains an annoying bug, however. The 16×16 icon you create for your project does not get used at all! Instead, Windows squishes the 32×32 icon down to fit into a 16×16 region, often times producing nasty results. So how can we fix this problem? First, we need to make a change in our main dialog’s class definition (.h) file. Here is the line in question:

HICON m_hIcon;

Replace that line of code with the following two lines:

HICON m_hIcon32x32;
HICON m_hIcon16x16;

Note that we are essentially creating two icon handles instead of the one which we had before. As you can see from their names, one will be for our 32×32 icon, while the other one will be used for our 16×16 icon. Now that we have those two handles available, we need to change the code responsible for actually loading the icon. This code can be found in the constructor for your application’s main dialog (in the class .cpp file):

m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

The LoadIcon() method only deals with icons which are SM_CXICON pixels wide by SM_CYICON pixels high, which almost always results in icons of size 32×32. Since this method uses these system constants (thereby displaying the wrong icon), we should make use of the LoadImage() method instead. Change the line of code above into the following two lines:

m_hIcon32x32 = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_hIcon16x16 = (HICON)LoadImage(AfxGetInstanceHandle(),
                MAKEINTRESOURCE(IDR_MAINFRAME), IMAGE_ICON,
                16, 16, LR_DEFAULTCOLOR);

First, we load up the 32×32 icon using the same LoadIcon() method. Then we load the 16×16 icon using the more robust LoadImage() method. Once both icons have been loaded, we must fix two other problems. The first is located in the default OnPaint() method. In the automatically generated code, you will find the following two lines:

// Draw the icon
dc.DrawIcon(x, y, m_hIcon);

Change the m_hIcon variable in that method call to m_hIcon16x16 instead. The result will look like this:

// Draw the icon
dc.DrawIcon(x, y, m_hIcon16x16);

Likewise, we need to change the icon name in the OnQueryDragIcon() method. The m_hIcon variable will again become m_hIcon16x16, resulting in the following code:

return (HCURSOR) m_hIcon16x16;

Once these changes have been made, your small icon will appear properly, and the larger icon will also be used as it should. A simple solution to an annoying problem!

Comments are closed.

Copyright © 2004-2018 Jonah Bishop. Hosted by DreamHost.