0
votes

I realize win32 toolbar icon questions are common here, but none are relevant to my particular problem (most concern image lists, or associating with a bitmap handle).

I am trying to associate a toolbar button with an icon resource within my application. Since I am adding it to a toolbar that already has default images using TB_ADDBITMAP (new, open, save, etc), I cannot use an image list, as the article on MSDN says here:

The TB_SETIMAGELIST message cannot be combined with TB_ADDBITMAP. It also cannot be used with toolbars created with CreateToolbarEx, which calls TB_ADDBITMAP internally. When you create a toolbar with CreateToolbarEx or use TB_ADDBITMAP to add images, the toolbar manages the image list internally. Attempting to modify it with TB_SETIMAGELIST has unpredictable consequences.

MSDN says I should be able to use a resource directly with TB_ADDBITMAP, under the TBADDBITMAP::nID field:

If hInst is NULL, set this member to the bitmap handle of the bitmap with the button images. Otherwise, set it to the resource identifier of the bitmap with the button images.

The VS2008 resource editor shows a single 16x16 icon resource with the id IDI_ARROWLEFT. (I had a screenshot, but since I do not have enough "reputation" to post images you'll have to take my word for it)

This is clearly a valid icon as the following code makes the icon appear on the titlebar of the main window:

wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_ARROWLEFT));

The problem is the resource icon is not appearing on the toolbar button within the window. Below is the sample code that is loading the resource and applying it to the toolbar button:

void populateToolbarTest()
{   
    int index = -1;

    TBADDBITMAP tbab;
    TBBUTTON tbb;

    ZeroMemory(&tbab, sizeof(TBADDBITMAP));
    ZeroMemory(&tbb, sizeof(TBBUTTON));

    SendMessage(hWndToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);

    tbab.hInst = hInst;
    tbab.nID = IDI_ARROWLEFT;

    // SendMessage returns 0 when testing
    index = SendMessage(hWndToolbar, TB_ADDBITMAP, 1, (LPARAM)&tbab);
    if (index == -1) return;

    tbb.iBitmap = index;
    tbb.fsState = TBSTATE_ENABLED;
    tbb.fsStyle = TBSTYLE_BUTTON;

    // result is set to 1 when testing
    LRESULT result = SendMessage(hWndToolbar, TB_ADDBUTTONS, 1, (LPARAM)&tbb);
}

This code successfully produces a button. However, there is no icon displayed, unlike with the defaults that I used in IDB_STD_SMALL_COLOR

1
Do wcex.hInstance and hInst refer to the same module? Have you tried assigning wcex.hInstance to tbab.hInst? Also, does IDI_ARROWLEFT refer to a BITMAP resource or an ICON resource? LoadIcon() implies the latter, but TB_ADDBITMAP needs the former.Remy Lebeau
Yes, wcex.hInstance is the same as hInst. They are both the application instance. IDI_ARROWLEFT is an ICON resource, not a BITMAP. However, I have also tried using a PNG BITMAP resource IDB_ARROWLEFT with the same results.Scott L
PNG and BITMAP are not the same thing.Remy Lebeau
I was just thinking about that. I will try converting the image into MS BMP format and seeing if that goes better.Scott L
I tried importing it as a 24-bit BMP file. Still doesn't show up.Scott L

1 Answers

0
votes

I finally got it working. Turns out, it had nothing to do with the code.

Microsoft is EXTREMELY picky about the EXACT format of the image being referenced. It you use TB_ADDBITMAP with a custom image, it MUST be 256 colors, it MUST have the MS-Specific index format, and the only color I've gotten to register as transparent is black. I spent an hour in Photoshop messing with different formats and colors before figuring this out.

The clue was the CreateMappedBitmap function in the example on MSDN. The page on CreateMappedBitmap had this statement:

This function is fully supported only for images with color maps; that is, images with 256 or fewer colors.

What it doesn't mention is that this is true regardless of whether you use this function or not. I have tried each scenario with and without this helper function, as well as tried every other 256-color BMP index format. Some other formats managed to show up, but they were mangled.

Theoretically, you can use the CreateMappedBitmap COLORMAP to specify a transparency color other than black, but I'm not familiar enough with the "6 level RGB" format to know how to specify an exact color.

(ref: http://en.wikipedia.org/wiki/List_of_software_palettes#6_level_RGB)

Unless you're mixing custom icons with default ones, I would recommend sticking with TB_SETIMAGELIST. From what I've read, it's much more flexible (for example, it accepts more than 256 colors.)

(ref: Win32 Toolbars and 24bit Images)