Knowledge Base

How To Place a Custom Bitmap on an Office Commandbar Button

Article ID: 198522

Article Last Modified on 3/21/2005


APPLIES TO


This article was previously published under Q198522

SUMMARY

Using Automation, you can modify the Microsoft Office CommandBar to add one or more CommandBarButtons and customize the appearance of those additions with respect to the caption, the tooltip text, and the graphic image on the face.

The graphic can be one of the standard icons supplied by Microsoft Windows, one of the existing icons used by other CommandBarButttons, or a custom graphic such as a user-designed icon or bitmap. This article contains sample code to illustrate the last concept.

MORE INFORMATION

This article discusses an approach to using the Microsoft Foundation Class (MFC) Library installed with Microsoft Visual C++ versions 5.0 and 6.0 to add a CommandBar Control button to Microsoft Word's CommandBars, then to place a custom bitmap on that button. Two other articles in the Microsoft Knowledge Base show other aspects of managing the Microsoft Office menu and its controls. They are:

180625 How To Use Automation to Modify the Office Menu

194906 How To Add and Run a VBA Macro Using Automation from MFC

The second article shows how to use the graphic from an existing CommandBarButton as the graphic for the new button.

With adaptation, the Visual C++ code in this article can be used in your application, but the purpose of the article is to help you learn, both by walking through the code and by running the program.

Notes for Automating Microsoft Word 2000:

Some methods and properties have changed for Microsoft Word 2000. For additional information about using the sample code described in this article with the Microsoft Word 2000 type library, please see the following article in the Microsoft Knowledge Base:

224925 INFO: Type Libraries for Office May Change with New Release

Steps to Create the Project

  1. Follow steps 1 through 12 in the following Microsoft Knowledge Base article to create a sample project, but change the type library used in step 9 to MSWord8.olb:

    178749 How To Create an Automation Project Using MFC and a Type Library

  2. Repeat steps 8, 9, and 10 of the above article to add the typelib for Microsoft Office to the project. The typelib for Microsoft Office 97 is in the file Mso97.dll (default location is as follows):

    C:\Program Files\Microsoft Office\mso97.dll

    For Office 2000 the typelib is MSO9.dll. For Office XP the default location of the typelib is C:\Program Files\Common Files\Microsoft Shared\Office10\MSO.dll. NOTE: Select all of the components of that typelib. You will generate and add to your project the files Mso97.h and Mso97.cpp (or names appropriate to the version).

    As a result, you will get duplicates in the COleDispatchDriver wrapper classes. These result from the duplication of IDispatch names in Microsoft Word and Microsoft Office.
  3. To resolve those duplications, for this exercise, use the "namespace" facility provided by Visual C++. These steps will resolve the duplications:
    1. At the very top of the Mswordx.h header file, insert the line:

      namespace word { // that's an opening brace
    2. At the very bottom of that same file, add a line that contains only the closing brace and a semi-colon--specifically "};" (without the quotation marks)
  4. At the beginning of the Mswordx.cpp file, on a new line just after the compiler directive "#endif", and before the line that reads LPDISPATCH _Application:GetApplication, add the following line:

    using namespace word;
  5. Add the following #include statements to the #include statements at the top of AutoProjectDlg.cpp. Make sure these are added to the end (after stdafx.h):
        #include "msword8.h"  // or the appropriate version's header
        #include "mso97.h"    // ot the appropriate version's header
    					
  6. Add the following code to the CAutoProjectDlg::OnRun() event handler in the AutoProjectDlg.cpp file:
      // Sample code
      word::_Application oWord;  // using namespace for the
                                 // Word typelib's members
    
      // Convenient values declared as ColeVariants.
      COleVariant covTrue((short)TRUE),
                covFalse((short)FALSE),
                covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
    
      // Get the Word IDispatch pointer and attach it to the Word object.
      if (!oWord.CreateDispatch("Word.Application"))
      {
       AfxMessageBox("Couldn't get Word object.");
       return;
      }
    
      oWord.SetVisible(TRUE);  //This shows the application.
    
      word::Documents oDocs(oWord.GetDocuments());
      word::_Document oDoc;
    
      // Create a new document...
    	 /* Word 97
      oDoc = oDocs.Add(covOptional, covOptional);
    	 End Word 97 */ 
    
     /*  Word 2002 */ 
     oDoc = oDocs.Add(covOptional,  // Template
              covOptional,  // New Template
    	  covOptional,  // Document Type
    	  covTrue);     // Visible
    
    	 /* Office 97 - no underscore in front of CommandBars 
      CommandBars oBars = oWord.GetCommandBars(); // New CommandBars
                                                  // collection object
    	end of Office 97 syntax */ 
    
     /* Office XP - note the underscore in front of CommandBars */ 
     _CommandBars oBars = oWord.GetCommandBars(); // New CommandBars
                                                  // collection object
    
      CommandBar oBar;
      CommandBarControls oControls;
     /* Office 97 usage - no underscore in front of CommandBarButton
      CommandBarButton oButton;
     end of Office 97 usage */ 
    
     /* Office XP usage - note the underscore in front of CommandBarButton */ 
     _CommandBarButton oButton;
    
      VARIANT vName;
      vName.vt = VT_BSTR;
      vName.bstrVal = SysAllocString(L"MyNewCommandBar");
    
      VARIANT vPosition;
      vPosition.vt = VT_I2;
      vPosition.iVal = 4; // 4 = Floating;  0 = top;
    
      //  Add new bar to the command bars collection
      CommandBar oNewBar = oBars.Add(vName,     // const Variant Name
                              vPosition, // const Variant Position
                              covFalse,  // const Variant (replace)MenuBar
                              covTrue    // const Variant Temporary
                              );
    
      oNewBar.SetVisible(TRUE);
    
      // Get the collection (now empty) of controls on the new commandbar
      CommandBarControls oNewControls = oNewBar.GetControls();
    
      VARIANT vType;
      vType.vt = VT_I4;
      vType.lVal = (long)1;
    
      // Add a commandbarbutton to the collection of controls
      //  on new commandbar
      // CommandBarButton oNewButton1 = // Office XP uses underscore
    
     _CommandBarButton oNewButton1 =  // Office XP - note leading underscore
                 oNewControls.Add(vType, // Type = msoControlButton
                 covOptional,  // Id
                 covOptional,  // Parameter
                 covOptional,  // Before
                 covTrue       // Temporary
                 );
    
      oNewButton1.SetStyle(3);  // msoButtonIconAndCaption
      oNewButton1.SetCaption("New");
      oNewButton1.SetTooltipText("This is a new button");
      oNewButton1.SetVisible(TRUE);
      oNewButton1.SetState(0);  // msoButtonUp
    
      OpenClipboard(); // Reserve clipboard for this program
    
      // ***************************************************************
      // There are two alternative sources of bitmaps that this sample
      //  can use. Choose either the 4 lines (next) that use "MyBitmap"
      //  from the  resource file, or the line below that which loads a
      //  bitmap from a bitmap file.
    
      // Alternative 1: This code places a bitmap drawn by you in the
      // resource editor onto a button
      /* Remove the comment if you use this alternative
      CBitmap MyBitmap;
      MyBitmap.LoadBitmap(IDB_BITMAP1);  // A Bitmap you drew in the
                                         //  Resource Editor
      HBITMAP MyBitmapHandle = (HBITMAP)MyBitmap;  // Cast it to a HBITMAP
      SetClipboardData(CF_BITMAP, MyBitmapHandle);
      */  //Remove the comment to use alternative 1.
      // End if alternative 1
    
      // Alternative 2: This code places a bitmap from a file onto
      //  the button. Comment it out if you use alternative 1 above.
      if(NULL==(SetClipboardData(CF_BITMAP, LoadImage(NULL,
                 "C:\\Test.bmp", IMAGE_BITMAP, 0,
                                  0, LR_DEFAULTSIZE|LR_LOADFROMFILE) )))
      {
        AfxMessageBox("SetClipboardData returned a NULL");
      };
      // End of alternative 2
    
      // End of alternatives
      // ***************************************************************
    
      CloseClipboard();  // Free clipboard so PasteFace() can use it
    
      oNewButton1.PasteFace();  // This places the image from the
                                //  clipboard onto the command button
    
      AfxMessageBox("Look at the button's face now");
    
      oWord.Quit(covFalse, covOptional, covFalse);
     // End of Sample code
    
    
    
    					
  7. Now, all you need is to copy a selected .bmp to c:\test.bmp, or change the above code's call to SetClipboardData() to use a path and filename of your choosing.
  8. Compile and run the example.

Keywords: kbautomation kbbutton kbhowto KB198522