Adding Picture To Button On OutLook CommandBar


This article describes the process to add a picture on a button on an Outlook Commandbar.

Using VSTO, we can add coomandbars to an office application. Following code can be used to add a commandbar to an outlook application.

using Outlook = Microsoft.Office.Interop.Outlook;
using
Office = Microsoft.Office.Core;
string
COMMANDBAR_NAME = "My ToolBar";
Office.CommandBar myBar;
Office.CommandBarButton myButton;
myBar =
this.ActiveExplorer().CommandBars.Add(COMMANDBAR_NAME, Office.MsoBarPosition.msoBarTop, false, true
);
myBar.Visible =
true;

Now to add a button to the commandbar use following code

string BUTTON_NAME = "My Button";
Office.CommandBarButton myButton;
myButton = (Office.CommandBarButton)myBar.Controls.Add(Office.MsoControlType.msoControlButton, Type.Missing, Type.Missing, Type.Missing,
true
);
myButton.Caption = BUTTON_NAME;
myButton.Style = Office.MsoButtonStyle.msoButtonIconAndCaption;
myButton.Enabled =
true;

Till now things were so easy, isn't it? Now comes the toughest part i.e. how to add a picture to the command button like u see in various office applications.

If however you can see in the below diagram that CommandBarButton supports a property Picture. The issue with this property as evident form the diagram below is this Picture property takes an instance of stdole.IPictureDisp. 

So how doe we get IPictureDisp from a bitmap. We can make use of a class System.Windows.Forms.AxHost which provides a protected method GetIPictureDispFromPicture which will return an IPictureDisp from an Image.

Include following class in your application.

using System;
using
System.Drawing;
using
System.Windows.Forms;
using
stdole;
public class
MyHost : AxHost
{
public
MyHost(): base("59EE46BA-677D-4d20-BF10-8D8067CB8B33")
{
}
public new static
IPictureDisp GettIPictureDispFromPicture(Image image)
{
return
(IPictureDisp)AxHost.GetIPictureDispFromPicture(image);
}
}

Above class inherits from System.Windows.Forms.AxHost. So now that we have this class, we can pass an image to the method GetIPictureDispFromPicture and can get the IPictureDisp in return. There are several ways to pass an image to this method.

You can embed a bitmap in your project (assign the Build Action property as Embedded Resource) and then load the same using reflection as shown below.

Assembly ThisAssembly = Assembly.GetExecutingAssembly();
Stream imgageStream = ThisAssembly.GetManifestResourceStream("AssembleName.BitmapFile");
myButton.Picture = MyHost.GetIPictureDispFromPicture(Image.FromStream(imgageStream));

Alternatively you can have an ImageList control on a form class in your application and assign the picture to the image list. Then the same can be passed to the GetIPictureDispFromPicture as shown below.

myButton.Picture = MyHost.GetIPictureDispFromPicture(MyForm.ImageList.Images(0));

This approach will work fine when you use Explorer. The same fails when you try to assign the picture property to a CommandBarButton on a CommandBar using Outlook Inspector. Just to inform, the Outlook object model also defines two interesting types i.e. Explorer and Inspector, which allows you to manipulate the user interface. An Explorer represents a window in which folder contents are displayed. An inspector represents a window that contains a specific Outlook item, such as an e-mail message or a contact, and any tabbed pages within the Outlook item (for example, the Details tab of a task item). The Application class maintains a collection of all Explorers and Inspectors, which can be obtained using the properties Explorers and Inspectors. You can get the currently active UI element by using methods GetActiveExplorer() and GetActiveInspector() of Application class.

Ok now let's come back to our original discussion point i.e. how to assign the Picture property to a CommandBarButton while using Outlook Inspector. Somehow the above approach doesn't work with Outlook Inspector.

However there is a workaround for the same. To set the Picture property to a CommandBarButton while using Outlook Inspector, you can use the ClipBoard object. ClipBoard exposes a method SetDataObject as shown below.

public static void SetDataObject(object data, bool copy);

This method places data on the system clipboard and specifies whether the data should remain on the clipboard after the application exits (as indicated by the Boolean variable copy).

Now you can use following code to assign the picture property to a CommandBarButton while using Outlook Inspector.

Clipboard.SetDataObject(MyForm.ImageList.Images(0), false);
myButton.PasteFace();

On a closing note, you can specify an image on a CommandBarButton by assigning a property called FaceId. Office provides thousands of icons by default. You just have to choose one and assign the FaceId property as shown below.

myButton.FaceId = 2521;

In above code I am assigning the FaceId as 2521, which represents the Print icon as shown below.