Anyone who wants to build a professional looking add-in for Microsoft Outlook knows that it’s important to make their add-in appear flush/stock/standard/factory, which means implementing the add-in functionality directly into the native Outlook interface via the toolbar/ribbon/menu/property pages/etc. An important part of this is understanding how to use IPictureDisp, because this is the only image type that Outlook will allow you to use for CommandBar controls.
I’ve been working on a few add-ins for Outlook recently and ran into a problem trying to use .png images for the Outlook.CommandBar objects. What makes this difficult is the fact that Outlook’s CommandBar and related controls require images to be IPictureDisp objects; it does not support System.Drawing.Image objects directly. You can observe the Outlook.CommandBarButton.Picture and Outlook.CommandBarButton.Mask properties; they only accept an object of type IPictureDisp. Therefore, I needed a decent way to convert a System.Drawing.Image (including any alpha transparency) into an IPictureDisp in order to integrate my custom icons into the native Outlook toolbar.
Lo and behold, a quick Google for ipicturedisp mask digs up a solution on MSDN in an astounding 0.28 seconds. Hold on there cowboy!!! That solution was posted by me several years ago which I have since forgotten about….weird!
Anyhow, here’s the class that wraps up all this functionality:
Public Class IPictureDisp Inherits System.Windows.Forms.AxHost Public Sub New() MyBase.New("59EE46BA-677D-4d20-BF10-8D8067CB8B32") End Sub Public Shared Function FromImage(ByVal pImg As System.Drawing.Image) As stdole.IPictureDisp Dim b As New Bitmap(16, 16) Dim g As Graphics = Graphics.FromImage(b) ' fill the bitmap with white g.FillRectangle(Brushes.White, 0, 0, 16, 16) ' draw the image over the white bitmap g.DrawImage(pImg, 0, 0, 16, 16) ' return the opaque image Return GetIPictureFromPicture(b) End Function Public Shared Function MaskFromImage(ByVal pImg As System.Drawing.Image) As stdole.IPictureDisp Dim b As New Bitmap(16, 16) Dim g As Graphics = Graphics.FromImage(b) ' draw the image over the transparent bitmap g.DrawImage(pImg, 0, 0, 16, 16) ' convert pixels to grayscale For x As Integer = 0 To 15 For y As Integer = 0 To 15 ' get the pixel alpha Dim pa As Integer pa = b.GetPixel(x, y).A ' get the grayscale alpha equivalent of the pixel alpha Dim pg As Integer pg = 255 - pa ' replace the current pixel with a grayscale equivalent b.SetPixel(x, y, Color.FromArgb(pg, pg, pg)) Next Next ' return the picture Return GetIPictureFromPicture(b) End Function End Class
And to use the class, just do something like this:
Dim myButton as Outlook.CommandBarButton myButton.Picture = IPictureDisp.FromImage(my.resources.icon1) myButton.Mask = IPictureDisp.MaskFromImage(my.resources.icon1)
The original solution can be found in the MSDN article How to: Add Custom Icons to Toolbar and Menu Items