Virtual Developer Workshop: Containerized Development with Docker


Environment: VB5/VB6

When a VB Addin tries to add a button to a VB commandbar or menu, it has no simple way to properly specify a transparent background for the button or menu item bitmap. Since we have to use the clipboard to transfer the image to the button, it can't be an icon. This generally makes the button look very ugly, especially when the user has selected a fancy color scheme. Since built-in addins display their bitmapped buttons properly, I guessed that there should be a way... Here it is.

First add the following declarations to your General section in your addin:

private Type COLORMAP
    from as Long
    to as Long
End Type

private Type PICTDESC
    Size as Long
    Type as Long
    hBmp as Long
    hPal as Long
    Reserved as Long
End Type

private Type IID
    Data1 as Long
    Data2 as Integer
    Data3 as Integer
    Data4(7) as Byte
End Type

private Declare Function CreateMappedBitmap _
                    Lib "comctl32.dll" (byval hInstance as Long, _
                    byval idBitmap as Long, _
                    byval wFlags as Long, _
                    lpColorMap as COLORMAP, _
                    byval iNumMaps as Long) as Long

private Declare Function OleCreatePictureIndirect _
                    Lib "olepro32.dll" (desc as PICTDESC, _
                        RefIID as IID, _
                        byval fPictureOwnsHandle as Long, _
                        IPic as IPicture) as Long

private Declare Function GetSysColor Lib "user32" (byval nIndex as Long) as Long
Const COLOR_MENU = 4

Dim g_map as COLORMAP

This declares Win32 API and OLE functions that we'll need later. Then add the following function to your addin:

Function BitmapToPicture(byval hBmp as Long, _
                         optional byval hPal as Long = 0) as IPicture

    ' Code adapted from HardCore Visual Basic articles in MSDN

    ' Fill picture description

    Dim IPic as IPicture, picdes as PICTDESC, iidIPicture as IID
    picdes.Size = len(picdes)
    picdes.Type = vbPicTypeBitmap
    picdes.hBmp = hBmp
    picdes.hPal = hPal
    ' Fill in magic IPicture GUID {7BF80980-BF32-101A-8BBB-00AA00300CAB}

    iidIPicture.Data1 = &H7BF80980
    iidIPicture.Data2 = &HBF32
    iidIPicture.Data3 = &H101A
    iidIPicture.Data4(0) = &H8B
    iidIPicture.Data4(1) = &HBB
    iidIPicture.Data4(2) = &H0
    iidIPicture.Data4(3) = &HAA
    iidIPicture.Data4(4) = &H0
    iidIPicture.Data4(5) = &H30
    iidIPicture.Data4(6) = &HC
    iidIPicture.Data4(7) = &HAB
    ' Create picture from bitmap handle

    OleCreatePictureIndirect picdes, iidIPicture, true, IPic
    set BitmapToPicture = IPic
End Function

Finally, when your addin is about to add the bitmap representing your command in the VB menu or CommandBar, use the following code (assuming that mcbMenuCommandBarCtrl is the target CommandBarControl that you just created).

g_map.from = RGB(192, 192, 192)
g_map.to = GetSysColor(COLOR_MENU)

Clipboard.SetData BitmapToPicture(CreateMappedBitmap(App.hInstance, _
                                  BMP_ID, 0, g_map, 1))

BMP_ID being the resource identifier of the bitmap.

A few explanations : CreateMappedBitmap is a Win32 API function creating a new bitmap from an existing bitmap resource by translating specified a specified color to another color. The "from" and "to" colors are specified in a COLORMAP structure. You can translate as many colors as you wish. Here, we merely translate the bitmap background color (in that case RGB(192, 192, 192)) to the background color of menus and commandbars (which we get from GetSysColor)

However, CreateMappedBitmap returns a bitmap handle which we can't use as-is. BitmapToPicture is a handy function that is partially described and implemented in the MSDN. It creates an IPicture interface from the bitmap handle (a picture in VB actually points to an IPicture COM interface). So, you can assign the result of BitmapToPicture to a Picture object variable.

Once we have a "standard" VB picture, we can copy it to the clipboard and then paste it to the button face.

We use a global variable for the COLORMAP because we may have to re-use it if the CommandBarControl changes its state and therefore changes its bitmap.

That's it. Your VB Addin buttons and menu items will now be displayed properly. The Downloads section points to a VB Addin using this technique (and also allowing to automatically restore the last project when launching VB).

Download Restore Addin Demo Project (27kb)

Download Other freeware utilities from MainSoft's Web Site


  • Microsoft's method for doing that

    Posted by Legacy on 04/16/2002 07:00am

    Originally posted by: Tuvia Shterenberg

    Here's how Microsoft recommends doing it:

    Suprisingly, searching for "transparent bitmap office addin" results in nothing, but when you search the same thing in Google, it manages to find the MSDN article I pointed out, although it's the 3rd match (and this article is the first match)

    I haven't tried MS' method yet, but it seems that their method is better, since it uses real transparancy which gets preserved if the end user changes her menu background.

    If the programmer tries the method discussed here, then when the end user changes her color scheme, she'll see the icon inside a square of her old menu background (and she'll have to remove and restore the addin in order to see it in the current background).

  • That'll teach me...

    Posted by Legacy on 08/07/2000 07:00am

    Originally posted by: David Topham

    I've just spent the best part of a day scouring the MSDN to try and work out how to do this. I come to CodeGuru, and it's the second item returned by my first search. Thanks Patrick.

    It never ceases to amaze me that Microsoft can provide a simple high-level system for something like adding buttons to a toolbar (sorry, *CommandBar*), but overlook something like this. And I can't believe that myself and Patrick are the only persons to come up against this problem. So why is there no mention about it on the MSDN? Knowledge Base article Q198522 describes how to add a button to Word 8 from C++, using exactly the same COM interfaces, yet there's no mention of this simple issue. Or does everyone at Redmond have the 'Windows Default' colour scheme?

  • ;ljs;lf

    Posted by Legacy on 04/07/2000 07:00am

    Originally posted by: joe


  • You must have javascript enabled in order to post comments.

Leave a Comment
  • Your email address will not be published. All fields are required.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date