.
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))
mcbMenuCommandBarCtrl.PasteFace
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).