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