文章 ID : 288771
最后更新日期 : 2004年4月13日
版本 : 1.0
本页内容
概要 概要
更多信息 更多信息

概要

自动化客户端(或 COM 加载项)通常需要向 Office 应用程序的工具栏或菜单添加一个按钮,并需要为该按钮图像关联一个图片。Office 公开了 CommandBars 集合和一个 CommandBarButton 对象,以允许编程人员以编程方式添加按钮;但是如果用户需要自定义图像,则很难提供一个保持透明背景的图像。

本文介绍如何向剪贴板中添加按钮图标和按钮屏蔽,以便 CommandBarButtonPasteFace 方法可以通过一种允许以透明背景绘制的方式存储位图。还介绍如何动态地创建透明屏蔽,以便您不必跟踪两个单独的位图。

更多信息

Office CommandBarButtons 对它们的图像使用简单的位图。尽管这样做可以快速有效地呈现 Office CommandBars,但是也使得添加自定义图像变得比较困难,因为简单位图不保留透明度信息。要使图像显示为透明,需要一个单色位图“屏蔽”,以便让 Office 知道图像的哪些部分需要着色,哪些部分需要保持透明。当您在 Office 自身中编辑位图图像时,将会为您自动完成这一操作。当您以编程方式使用 Office 时,您需要自己提供屏蔽。

需要向 CommandBarButton 添加图像的自动化客户端通常使用 PasteFace 方法。由于此方法只使用简单位图,因此为了传递正确的透明度信息,您需要添加一个包含当前图像的屏蔽的特殊剪贴板格式。如果提供了此格式,Office 将以透明方式呈现图像。

Office XP 为 CommandBarButtons 提供了一个新的图片和屏蔽属性。这就使得进程内客户端(如宏代码或 COM 加载项)可以直接向按钮指派 StdPicture 对象而不使用剪贴板。 有关其他信息,请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章:
286460 HOWTO:Set the Mask and Picture Properties for Office XP CommandBars
但是,由于 Office 以外的限制,这种方法对进程外的自动化客户端不起作用,对需要与较低版本的 Office 保持兼容的客户端也不起作用。在这些情况下,类似于以下内容的代码仍然是适用的。

为了与当前的 Office 指导原则保持兼容,用于自定义 CommandBarButton 图片的位图图像应该是 256 色与设备无关的位图 (DIB),其大小应不超过 16 x 16 像素。您可以使用任何图形编辑器来创建这些位图,前提条件是,它可以将图像保存为标准的 Windows 位图(.bmp 或 .dib)文件;但要确保不要使用增强色图像,因为这些图像在某些分辨率较低的系统上可能会失真。此外,还要选择一种您的主要图像上不大可能出现的颜色,如洋红色(RGB:255、0、255),并使用它来填充那么您希望保持透明的区域。

要生成透明度屏蔽并将它添加到剪贴板中,您需要使用 Win32 应用程序编程接口 (API)。此示例假设您在 Microsoft Visual Basic 中工作,但也可以修改代码以在 Microsoft Visual C++ 中工作。

复制透明的 Office 工具栏图片

1. 使用 Microsoft 画图(或第三方图像编辑器)通过您选择的设计创建一个 256 色位图。图像的宽和高都不应超过 16 像素。
2. 用洋红色(RGB:255、0、255)填充您希望保持透明的所有位图区域,然后将位图保存为 C:\MyTestPic.bmp。
3. 启动 Visual Basic 并创建一个新的标准项目。默认情况下会创建 Form1。
4. 向 Form1 中添加一个按钮,然后将以下代码添加到该按钮的 Click 事件中:
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 = Nothing
End Sub
					
5. 项目菜单上,单击添加模块,并将以下代码粘贴到新模块的代码窗口中:
Option Explicit

Public 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 Long
End Type

Public Type BITMAP
   bmType As Long
   bmWidth As Long
   bmHeight As Long
   bmWidthBytes As Long
   bmPlanes As Integer
   bmBitsPixel As Integer
   bmBits As Long
End Type

' ===================================================================
'   GDI/Drawing Functions (to build the mask)
' ===================================================================
Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function ReleaseDC Lib "user32" _
  (ByVal hwnd As Long, ByVal hdc As Long) As Long
Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function CreateCompatibleDC Lib "gdi32" _
  (ByVal hdc As Long) As Long
Private Declare Function CreateCompatibleBitmap Lib "gdi32" _
  (ByVal hdc As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long
Private 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 Long
Private Declare Function SelectObject Lib "gdi32" _
  (ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" _
  (ByVal hObject As Long) As Long
Private Declare Function GetBkColor Lib "gdi32" _
  (ByVal hdc As Long) As Long
Private Declare Function SetBkColor Lib "gdi32" _
  (ByVal hdc As Long, ByVal crColor As Long) As Long
Private Declare Function GetTextColor Lib "gdi32" _
  (ByVal hdc As Long) As Long
Private Declare Function SetTextColor Lib "gdi32" _
  (ByVal hdc As Long, ByVal crColor As Long) As Long
Private 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 Long
Private Declare Function CreateHalftonePalette Lib "gdi32" _
  (ByVal hdc As Long) As Long
Private Declare Function SelectPalette Lib "gdi32" _
  (ByVal hdc As Long, ByVal hPalette As Long, _
   ByVal bForceBackground As Long) As Long
Private Declare Function RealizePalette Lib "gdi32" _
  (ByVal hdc As Long) As Long
Private Declare Function OleTranslateColor Lib "oleaut32.dll" _
  (ByVal lOleColor As Long, ByVal lHPalette As Long, _
   lColorRef As Long) As Long
Private 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 Long
Private 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 Long
Private Declare Function CloseClipboard Lib "user32" () As Long
Private Declare Function RegisterClipboardFormat Lib "user32" _
  Alias "RegisterClipboardFormatA" (ByVal lpString As String) As Long
Private Declare Function GetClipboardData Lib "user32" _
  (ByVal wFormat As Long) As Long
Private Declare Function SetClipboardData Lib "user32" _
  (ByVal wFormat As Long, ByVal hMem As Long) As Long
Private Declare Function EmptyClipboard Lib "user32" () As Long
Private 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 Long
Private Declare Function GlobalFree Lib "kernel32" _
  (ByVal hMem As Long) As Long
Private Declare Function GlobalLock Lib "kernel32" _
  (ByVal hMem As Long) As Long
Private Declare Function GlobalSize Lib "kernel32" _
  (ByVal hMem As Long) As Long
Private Declare Function GlobalUnlock Lib "kernel32" _
  (ByVal hMem As Long) As Long
Private Const GMEM_DDESHARE = &H2000
Private 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 Sub
err_invalidarg:
   Err.Raise 481 'VB Invalid Picture Error
End 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 hdcSource

End 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. 按 F5 键运行 Visual Basic 应用程序。单击命令按钮以自动运行 Word,添加一个新工具栏和按钮,并粘贴透明的位图图像。
posted on 2005-01-21 08:20  James Wong   阅读(878)  评论(0)    收藏  举报