You are currently offline, waiting for your internet to reconnect

How To Create a Transparent Picture For Office CommandBar Buttons

Support for Office 2003 has ended

Microsoft ended support for Office 2003 on April 8, 2014. This change has affected your software updates and security options. Learn what this means for you and how to stay protected.

This article was previously published under Q288771
Very often an Automation client (or COM AddIn) needs to add a button to the toolbar or menu for an Office application, and would like to associate a picture for the button image. Office exposes the CommandBars collection and a CommandBarButton object to allow programmers to programmatically add a button, but if a custom image is required, it is difficult to provide one that will preserve a transparent background.

This article shows you how to add both a button face and a button mask to the clipboard so that the PasteFace method for a CommandBarButton stores the bitmap in a manner that allows it to be drawn with a transparent background. It also shows you how to create the transparency mask on the fly to save you from having to keep track of two separate bitmaps.
Office CommandBarButtons use simple bitmaps for their images. While this makes rendering Office CommandBars fast and efficient, it makes adding a custom image difficult because a simple bitmap does not maintain transparency information. To get the image to appear transparent, a monochrome bitmap "mask" is needed to let Office know which parts of the image need to be painted, and which need to be left transparent. When you edit bitmap images in Office itself, this is done for you. When you work with Office programmatically, you need to supply the mask yourself.

Automation clients who want to add an image to a CommandBarButton normally use the PasteFace method. Because this method takes only simple bitmaps, to pass the correct transparency information you need to add a special clipboard format that contains a mask for the current image. If this format is provided, Office will render the image with transparency.

Office XP offers a new Picture and Mask property for CommandBarButtons. This allows in-process clients (such as macro code or a COM Add-In) to directly assign a StdPicture object to the button without using the clipboard. For additional information, click the following article number to view the article in the Microsoft Knowledge Base:
286460 How To Set the Mask and Picture Properties for Office XP CommandBars
However, due to limitations outside of Office, this technique does not work for out-of-process Automation clients, nor does it work for clients that need to remain compatible with earlier versions of Office. In these cases, code like the following is still appropriate.

In order to remain compatible with current Office guidelines, the bitmap image you use for a custom CommandBarButton picture should be a 256-color device independent bitmap (DIB) no bigger than 16 x 16 pixels in size. You can use any graphics editor to create these bitmaps, provided that it can save images as a standard Windows bitmap (.bmp or .dib) file, but be sure not to use high-color images because these may appear distorted on some systems with lower resolution. Also, choose a color that is not likely to appear in your main images, such as magenta (RGB(255, 0, 255)), and use it to fill in those areas that you want to make transparent.

To generate the transparency mask and add it to the clipboard, you need to use the Win32 application programming interface (API). This sample assumes that you are working in Microsoft Visual Basic, but the code can be modified to work from Microsoft Visual C++ as well.

Copying a Transparent Office Toolbar Picture

  1. Use Microsoft Paint (or a third-party image editor) to create a 256-color bitmap with a design of your choice. The image should be no bigger than 16 pixels wide and 16 pixels high.
  2. Fill in all areas of the bitmap you want to be transparent with the color magenta (RGB(255, 0, 255)), and then save the bitmap as C:\MyTestPic.bmp.
  3. Start Visual Basic and create a new Standard project. Form1 is created by default.
  4. Add a button to Form1, and then add the following code to the button's Click event:
    Private Sub Command1_Click()   Dim oPic As StdPicture   Dim oWord As Object   Dim oCommandBar As Object   Dim oButton As Object    ' Load the picture (.bmp file) to use for the button image.   Set oPic = LoadPicture("C:\MyTestPic.bmp")    ' Start Microsoft Word for Automation and create a new ' toolbar and button to test the PasteFace method.   Set oWord = CreateObject("Word.Application")   oWord.Visible = True      Set oCommandBar = oWord.CommandBars.Add("Test Bar")   oCommandBar.Visible = True      Set oButton = oCommandBar.Controls.Add(1)   With oButton      .Caption = "Test Button"      .Style = 1          ' Here we create a mask based on the image and put both    ' the image and the mask on the clipboard. Any color areas with    ' magenta will be transparent.      CopyBitmapAsButtonFace oPic, &HFF00FF          ' PasteFace will now add the image with transparency.      .PasteFace            .Visible = True   End With      MsgBox "You have a new button with a transparent picture.", _         vbMsgBoxSetForeground      Set oButton = Nothing      If MsgBox("Do you want to delete the toolbar?", _        vbYesNo Or vbQuestion) = vbYes Then      oCommandBar.Delete   End If      Set oCommandBar = Nothing   Set oWord = NothingEnd Sub					
  5. On the Project menu, click Add Module, and paste the following code in the code window for the new module:
    Option ExplicitPublic Type BITMAPINFOHEADER '40 bytes   biSize As Long   biWidth As Long   biHeight As Long   biPlanes As Integer   biBitCount As Integer   biCompression As Long   biSizeImage As Long   biXPelsPerMeter As Long   biYPelsPerMeter As Long   biClrUsed As Long   biClrImportant As LongEnd TypePublic Type BITMAP   bmType As Long   bmWidth As Long   bmHeight As Long   bmWidthBytes As Long   bmPlanes As Integer   bmBitsPixel As Integer   bmBits As LongEnd Type' ==================================================================='   GDI/Drawing Functions (to build the mask)' ===================================================================Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As LongPrivate Declare Function ReleaseDC Lib "user32" _  (ByVal hwnd As Long, ByVal hdc As Long) As LongPrivate Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As LongPrivate Declare Function CreateCompatibleDC Lib "gdi32" _  (ByVal hdc As Long) As LongPrivate Declare Function CreateCompatibleBitmap Lib "gdi32" _  (ByVal hdc As Long, ByVal nWidth As Long, ByVal nHeight As Long) As LongPrivate Declare Function CreateBitmap Lib "gdi32" _  (ByVal nWidth As Long, ByVal nHeight As Long, ByVal nPlanes As Long, _   ByVal nBitCount As Long, lpBits As Any) As LongPrivate Declare Function SelectObject Lib "gdi32" _  (ByVal hdc As Long, ByVal hObject As Long) As LongPrivate Declare Function DeleteObject Lib "gdi32" _  (ByVal hObject As Long) As LongPrivate Declare Function GetBkColor Lib "gdi32" _  (ByVal hdc As Long) As LongPrivate Declare Function SetBkColor Lib "gdi32" _  (ByVal hdc As Long, ByVal crColor As Long) As LongPrivate Declare Function GetTextColor Lib "gdi32" _  (ByVal hdc As Long) As LongPrivate Declare Function SetTextColor Lib "gdi32" _  (ByVal hdc As Long, ByVal crColor As Long) As LongPrivate Declare Function BitBlt Lib "gdi32" _  (ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, _   ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, _   ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As LongPrivate Declare Function CreateHalftonePalette Lib "gdi32" _  (ByVal hdc As Long) As LongPrivate Declare Function SelectPalette Lib "gdi32" _  (ByVal hdc As Long, ByVal hPalette As Long, _   ByVal bForceBackground As Long) As LongPrivate Declare Function RealizePalette Lib "gdi32" _  (ByVal hdc As Long) As LongPrivate Declare Function OleTranslateColor Lib "oleaut32.dll" _  (ByVal lOleColor As Long, ByVal lHPalette As Long, _   lColorRef As Long) As LongPrivate Declare Function GetDIBits Lib "gdi32" _  (ByVal aHDC As Long, ByVal hBitmap As Long, ByVal nStartScan As Long, _   ByVal nNumScans As Long, lpBits As Any, lpBI As Any, _   ByVal wUsage As Long) As LongPrivate Declare Function GetObjectAPI Lib "gdi32" Alias "GetObjectA" _  (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long' ==================================================================='   Clipboard APIs' ===================================================================Private Declare Function OpenClipboard Lib "user32" _  (ByVal hwnd As Long) As LongPrivate Declare Function CloseClipboard Lib "user32" () As LongPrivate Declare Function RegisterClipboardFormat Lib "user32" _  Alias "RegisterClipboardFormatA" (ByVal lpString As String) As LongPrivate Declare Function GetClipboardData Lib "user32" _  (ByVal wFormat As Long) As LongPrivate Declare Function SetClipboardData Lib "user32" _  (ByVal wFormat As Long, ByVal hMem As Long) As LongPrivate Declare Function EmptyClipboard Lib "user32" () As LongPrivate Const CF_DIB = 8' ==================================================================='   Memory APIs (for clipboard transfers)' ===================================================================Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _  (pDest As Any, pSource As Any, ByVal cbLength As Long)Private Declare Function GlobalAlloc Lib "kernel32" _  (ByVal wFlags As Long, ByVal dwBytes As Long) As LongPrivate Declare Function GlobalFree Lib "kernel32" _  (ByVal hMem As Long) As LongPrivate Declare Function GlobalLock Lib "kernel32" _  (ByVal hMem As Long) As LongPrivate Declare Function GlobalSize Lib "kernel32" _  (ByVal hMem As Long) As LongPrivate Declare Function GlobalUnlock Lib "kernel32" _  (ByVal hMem As Long) As LongPrivate Const GMEM_DDESHARE = &H2000Private Const GMEM_MOVEABLE = &H2' ==================================================================='  CopyBitmapAsButtonFace''  This is the public function to call to create a mask based on the'  bitmap provided and copy both to the clipboard. The first parameter'  is a standard VB Picture object. The second should be the color in'  the image you want to be made transparent.''  Note: This code sample does limited error handling and is designed'  for VB only (not VBA). You will need to make changes as appropriate'  to modify the code to suit your needs.'' ===================================================================Public Sub CopyBitmapAsButtonFace(ByVal picSource As StdPicture, _  ByVal clrMaskColor As OLE_COLOR)   Dim hPal As Long   Dim hdcScreen As Long   Dim hbmButtonFace As Long   Dim hbmButtonMask As Long   Dim bDeletePal As Boolean   Dim lMaskClr As Long    ' Check to make sure we have a valid picture.   If picSource Is Nothing Then GoTo err_invalidarg   If picSource.Type <> vbPicTypeBitmap Then GoTo err_invalidarg   If picSource.Handle = 0 Then GoTo err_invalidarg    ' Get the DC for the display device we are on.   hdcScreen = GetDC(0)   hPal = picSource.hPal   If hPal = 0 Then      hPal = CreateHalftonePalette(hdcScreen)      bDeletePal = True   End If    ' Translate the OLE_COLOR value to a GDI COLORREF value based on the palette.   OleTranslateColor clrMaskColor, hPal, lMaskClr       ' Create a mask based on the image handed in (hbmButtonMask is the result).   CreateButtonMask picSource.Handle, lMaskClr, hdcScreen, _          hPal, hbmButtonMask          ' Let VB copy the bitmap to the clipboard (for the CF_DIB).   Clipboard.SetData picSource, vbCFDIB ' Now copy the Button Mask.   CopyButtonMaskToClipboard hbmButtonMask, hdcScreen    ' Delete the mask and clean up (a copy is on the clipboard).   DeleteObject hbmButtonMask   If bDeletePal Then DeleteObject hPal   ReleaseDC 0, hdcScreen   Exit Suberr_invalidarg:   Err.Raise 481 'VB Invalid Picture ErrorEnd Sub' ==================================================================='  CreateButtonMask -- Internal helper function' ===================================================================Private Sub CreateButtonMask(ByVal hbmSource As Long, _  ByVal nMaskColor As Long, ByVal hdcTarget As Long, ByVal hPal As Long, _  ByRef hbmMask As Long)      Dim hdcSource As Long   Dim hdcMask As Long   Dim hbmSourceOld As Long   Dim hbmMaskOld As Long   Dim hpalSourceOld As Long   Dim uBM As BITMAP    ' Get some information about the bitmap handed to us.   GetObjectAPI hbmSource, 24, uBM    ' Check the size of the bitmap given.   If uBM.bmWidth < 1 Or uBM.bmWidth > 30000 Then Exit Sub   If uBM.bmHeight < 1 Or uBM.bmHeight > 30000 Then Exit Sub  ' Create a compatible DC, load the palette and the bitmap.   hdcSource = CreateCompatibleDC(hdcTarget)   hpalSourceOld = SelectPalette(hdcSource, hPal, True)   RealizePalette hdcSource   hbmSourceOld = SelectObject(hdcSource, hbmSource) ' Create a black and white mask the same size as the image.   hbmMask = CreateBitmap(uBM.bmWidth, uBM.bmHeight, 1, 1, ByVal 0)    ' Create a compatble DC for it and load it.   hdcMask = CreateCompatibleDC(hdcTarget)   hbmMaskOld = SelectObject(hdcMask, hbmMask)    ' All you need to do is set the mask color as the background color ' on the source picture, and set the forground color to white, and ' then a simple BitBlt will make the mask for you.   SetBkColor hdcSource, nMaskColor   SetTextColor hdcSource, vbWhite   BitBlt hdcMask, 0, 0, uBM.bmWidth, uBM.bmHeight, hdcSource, _       0, 0, vbSrcCopy    ' Clean up the memory DCs.   SelectObject hdcMask, hbmMaskOld   DeleteDC hdcMask   SelectObject hdcSource, hbmSourceOld   SelectObject hdcSource, hpalSourceOld   DeleteDC hdcSourceEnd Sub' ==================================================================='  CopyButtonMaskToClipboard -- Internal helper function' ===================================================================Private Sub CopyButtonMaskToClipboard(ByVal hbmMask As Long, _  ByVal hdcTarget As Long)   Dim cfBtnFace As Long   Dim cfBtnMask As Long   Dim hGMemFace As Long   Dim hGMemMask As Long   Dim lpData As Long   Dim lpData2 As Long   Dim hMemTmp As Long   Dim cbSize As Long   Dim arrBIHBuffer(50) As Byte   Dim arrBMDataBuffer() As Byte   Dim uBIH As BITMAPINFOHEADER   uBIH.biSize = 40    ' Get the BITMAPHEADERINFO for the mask.   GetDIBits hdcTarget, hbmMask, 0, 0, ByVal 0&, uBIH, 0   CopyMemory arrBIHBuffer(0), uBIH, 40 ' Make sure it is a mask image.   If uBIH.biBitCount <> 1 Then Exit Sub   If uBIH.biSizeImage < 1 Then Exit Sub    ' Create a temp buffer to hold the bitmap bits.   ReDim Preserve arrBMDataBuffer(uBIH.biSizeImage + 4) As Byte    ' Open the clipboard.   If Not CBool(OpenClipboard(0)) Then Exit Sub    ' Get the cf for button face and mask.   cfBtnFace = RegisterClipboardFormat("Toolbar Button Face")   cfBtnMask = RegisterClipboardFormat("Toolbar Button Mask")      ' Open DIB on the clipboard and make a copy of it for the button face.   hMemTmp = GetClipboardData(CF_DIB)   If hMemTmp <> 0 Then      cbSize = GlobalSize(hMemTmp)      hGMemFace = GlobalAlloc(&H2002, cbSize)      If hGMemFace <> 0 Then         lpData = GlobalLock(hMemTmp)         lpData2 = GlobalLock(hGMemFace)         CopyMemory ByVal lpData2, ByVal lpData, cbSize         GlobalUnlock hGMemFace         GlobalUnlock hMemTmp               If SetClipboardData(cfBtnFace, hGMemFace) = 0 Then            GlobalFree hGMemFace         End If               End If   End If    ' Now get the mask bits and the rest of the header.   GetDIBits hdcTarget, hbmMask, 0, uBIH.biSizeImage, _        arrBMDataBuffer(0), arrBIHBuffer(0), 0       ' Copy them to global memory and set it on the clipboard.   hGMemMask = GlobalAlloc(&H2002, uBIH.biSizeImage + 50)   If hGMemMask <> 0 Then         lpData = GlobalLock(hGMemMask)         CopyMemory ByVal lpData, arrBIHBuffer(0), 48         CopyMemory ByVal (lpData + 48), _                       arrBMDataBuffer(0), uBIH.biSizeImage         GlobalUnlock hGMemMask                  If SetClipboardData(cfBtnMask, hGMemMask) = 0 Then            GlobalFree hGMemMask         End If            End If    ' We're done.   CloseClipboard   End Sub					
  6. Press F5 to run the Visual Basic application. Click the command button to automate Word, add a new toolbar and button, and paste the image of the bitmap with the transparency.

Article ID: 288771 - Last Review: 02/12/2007 19:46:21 - Revision: 4.7

  • Microsoft Office Professional Edition 2003
  • Microsoft Office Basic Edition 2003
  • Microsoft Office Small Business Edition 2003
  • Microsoft Office Students and Teachers Edition 2003
  • Microsoft Office Standard Edition 2003
  • Microsoft Office XP Developer Edition
  • Microsoft Office 2000 Developer Edition
  • Microsoft Office 97 Developer Edition
  • Microsoft Visual Basic 6.0 Professional Edition
  • Microsoft Visual Basic 5.0 Professional Edition
  • kbautomation kbbitmap kbclipboard kbhowto KB288771
data-bi-slot="2"> Privacy & cookies
  • Trademarks
  • © 2015 Microsoft