Page 1 of 1

Images on Buttons disappear when XP/Vista themes are active

Posted: Thu Jun 05 2008
by Devteam
Problem description:
Applications that have support for Vista or XP User Interface themes might see some of their buttons with no bitmaps displayed on them. This problem seems to happen because of the new common controls DLL (version 6) that is used to create the new visual effects.

Applications or controls that need to display images on buttons typically use the BM_SETIMAGE windows message to specify whic icon or image to display, e.g.:
// create a button with the BS_ICON style in order to show an icon only with not text
// the button size is set to 10x10 pixels

hChild = CreateWindowEx(0, _T("BUTTON"), _T(""), BS_ICON | WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, m_hWnd, (HMENU)IDC_CMD, hExeInst, 0);
// load the icon to be displayed on the button
// it is assumed here that the icon stored in the resources is also 10x10 pixels

m_hIcon = (HICON)LoadImage(hResInst, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 10, 10, 0);
// set the button' s icon to the one loaded from resources
::SendMessage(hChild , BM_SETIMAGE, IMAGE_ICON, (LPARAM) m_hIcon);

The main advantage of using an icon is that this format supports transparencies, and we need to have an image with a transparent background so that it displays nicely on a button with any color.

This method unfortunately fails to display the image as soon as the application starts using the new Vista button styles. No information is available to indicate that there is something wrong. At first, the problem seemed to be the unconventional 10x10 pixel size for the icons, but choosing a different size did not help.

Workaround:
The workaround we found after playing around with this problem for a while was to use a BITMAP instead of an ICON to draw the button. After converting all the icons to bitmaps and changing the code to load and draw bitmaps, the buttons started appearing on any system:
// create a button with the BS_BITMAP style in order to show a bitmap only with not text
// the button size is set to 10x10 pixels

hChild = CreateWindowEx(0, _T("BUTTON"), _T(""), BS_BITMAP | WS_CHILD | WS_VISIBLE, 0, 0, 10, 10, m_hWnd, (HMENU)IDC_CMD, hExeInst, 0);
// load the bitmap to be displayed on the button
// it is assumed here that the bitmap stored in the resources is also 10x10 pixels

m_hBmp = (HBITMAP)LoadImage(hResInst, MAKEINTRESOURCE(IDB_BITMAP), IMAGE_BITMAP, 10, 10, LR_LOADTRANSPARENT | LR_LOADMAP3DCOLORS);
// set the button' s bitmap to the one loaded from resources
::SendMessage(hChild , BM_SETIMAGE, IMAGE_BITMAP, (LPARAM) m_hBmp);

The options LR_LOADTRANSPARENT | LR_LOADMAP3DCOLORS were very handy in allowing the system to draw transparent bitmaps on top of the buttons.