Click here to Skip to main content
13,449,913 members (53,196 online)
Click here to Skip to main content
Add your own
alternative version


41 bookmarked
Posted 18 Feb 2009

Getting Started with VB.NET's Microsoft Outlook Standard Plugin Creator

, 20 Feb 2009
Rate this:
Please Sign up or sign in to vote.
Getting started with VB.NET's Microsoft Outlook standard plugin creator
Click to enlarge image


This small article will send you on your way developing Microsoft Visual Basic .NET plugins for Microsoft Outlook 2003.


Microsoft Outlook is, as we all know, an (or the) industry standard email client. Extending it by using VB.NET can be both profitable and actually fun (the final result of course, not the actual coding).

Well, Let's Get Started

First, create a clean "Outlook 2003 add-in" with the appropriate wizard. Call it anything you like.

Then, add this code to declare the objects that will be used. 

Private myCommandBarControll As CommandBar
Private btnGetAppointments As CommandBarControl
Private mnuPopup As CommandBarControl  

As you'll notice, the objects are declared without withevents and new, but we don't need those. Later, we will use DirectCast and AddHandler for making things work.

Now, at the ThisAddin_Startup event, add this code:

Private Sub ThisAddIn_Startup(ByVal sender As Object, _
	ByVal e As System.EventArgs) Handles Me.Startup

Dim btnclickhandler As CommandBarButton
Dim mnuPopuphandler As CommandBarPopup

Again, without new.

To make things work, we have to declare a commandbar. So add this code right after the last piece:

Dim oApp As Outlook.Application = New Outlook.Application()
myCommandBarControll = oApp.ActiveExplorer.CommandBars.Add_
	("YourCommandbar", MsoBarPosition.msoBarTop, False, True)
myCommandBarControll.Visible = True

The only thing new here, is the Outlook.Application() object. We only inherit from now on. What happens here is that Outlook creates the commandbar YourCommandbar and makes it visible. Be sure though that you explicitly make the property Visible True.

It has no functionality nor buttons, so let's change that. Use this piece of code, still within ThisAddIn_Startup:

mnuPopup = myCommandBarControll.Controls.Add(MsoControlType.msoControlPopup)
mnuPopup.Caption = "Your pulldown menu"
mnuPopup.Visible = True

mnuPopuphandler = DirectCast(mnuPopup, CommandBarPopup) 

That will do the job creating a standard pulldown menu within your commandbar. Note the directcast and we aren't using any new statements.

This pulldown menu, however, needs a purpose. Just like everything else in life. So, let's add a button to the menu.

btnGetAppointments = mnuPopuphandler.Controls.Add(MsoControlType.msoControlButton)
btnGetAppointments.Caption = "Your caption of this button"
btnGetAppointments.Visible = True

btnclickhandler = DirectCast(btnGetAppointments, CommandBarButton)
btnclickhandler.Style = MsoButtonStyle.msoButtonIconAndCaption

btnclickhandler.TooltipText = "Your tooltip text"
AddHandler btnclickhandler.Click, AddressOf OnApptClick

Let's analyze the code. It has:

  • Visible explicitly made true.
  • A directcast to make the control object behave like a button.
  • Tooltip text.
  • A style declaration set to MsoButtonStyle.msoButtonIconAndCaption to make images work.
  • An Addhandler for making the button actually do anything.
  • Still no new's.

Let's add the function that makes the plugin actually do anything on the user's command. We will finally leave ThisAddIn_Startup and create a new sub called OnApptClick.

Private Sub OnApptClick()
        MsgBox("Hello Outlook world!")
End Sub  

Now, run your plugin. You are now fully qualified to make all kind of wierd plugins. Be creative!

If you want to use images in your buttons, keep on reading.


Outlook uses IPictureDisp for images. But that's no real problem if you add a module containing the following code:

Imports System
Imports System.Drawing
Imports System.Collections.Generic
Imports System.Runtime.InteropServices

Public Module PictureDispConverter

    'IPictureDisp guid
    Public iPictureDispGuid As Guid = GetType(stdole.IPictureDisp).GUID

    'Converts an Icon into a IPictureDisp
    Public Function ToIPictureDisp(ByVal ico As Icon) As stdole.IPictureDisp

        Dim pictIcon As New PICTDESC.Icon(ico)
        Return PictureDispConverter.OleCreatePictureIndirect_
				(pictIcon, iPictureDispGuid, True)
    End Function

    'Converts an image into a IPictureDisp
    Public Function ToIPictureDisp(ByVal picture As Image) As stdole.IPictureDisp

        Dim bm As Bitmap
        If TypeOf picture Is Bitmap Then
            bm = picture
            bm = New Bitmap(picture)
        End If
        Dim pictBit As New PICTDESC.Bitmap(bm)
        Return PictureDispConverter.OleCreatePictureIndirect_
				(pictBit, iPictureDispGuid, True)
    End Function

    <DllImport("OleAut32.dll", EntryPoint:="OleCreatePictureIndirect", _
				ExactSpelling:=True, PreserveSig:=False)> _
    Private Function OleCreatePictureIndirect(<MarshalAs(UnmanagedType.AsAny)> _
	ByVal picdesc As Object, ByRef iid As Guid, ByVal fOwn As Boolean) _
	As stdole.IPictureDisp
    End Function

    Private ReadOnly hCollector As New HandleCollector("Icon handles", 1000)

    'PICTDESC is a union in native, so we'll just
    'define different ones for the different types
    'the "unused" fields are there to make it the right
    'size, since the struct in native is as big as the biggest
    Private Class PICTDESC

        'Picture Types
        Public Const PICTYPE_UNINITIALIZED As Short = -1
        Public Const PICTYPE_NONE As Short = 0
        Public Const PICTYPE_BITMAP As Short = 1
        Public Const PICTYPE_METAFILE As Short = 2
        Public Const PICTYPE_ICON As Short = 3
        Public Const PICTYPE_ENHMETAFILE As Short = 4

        <StructLayout(LayoutKind.Sequential)> _
        Public Class Icon

            Friend cbSizeOfStruct As Integer = Marshal.SizeOf(GetType(PICTDESC.Icon))
            Friend picType As Integer = PICTDESC.PICTYPE_ICON
            Friend hicon As IntPtr = IntPtr.Zero
            Friend unused1 As Integer = 0
            Friend unused2 As Integer = 0

            Friend Sub New(ByVal icon As System.Drawing.Icon)
                Me.hicon = icon.ToBitmap().GetHicon()
            End Sub

        End Class

        <StructLayout(LayoutKind.Sequential)> _
        Public Class Bitmap

            Friend cbSizeOfStruct As Integer = Marshal.SizeOf(GetType(PICTDESC.Bitmap))
            Friend picType As Integer = PICTDESC.PICTYPE_BITMAP
            Friend hbitmap As IntPtr = IntPtr.Zero
            Friend hpal As IntPtr = IntPtr.Zero
            Friend unused As Integer = 0

            Friend Sub New(ByVal bitmap As System.Drawing.Bitmap)
                Me.hbitmap = bitmap.GetHbitmap()
            End Sub
        End Class

    End Class

End Module

Many thanks to

Now, make the conversion of the image type actually work. The bold line is added:

        btnclickhandler = DirectCast(btnGetAppointments, CommandBarButton)
        btnclickhandler.Style = MsoButtonStyle.msoButtonIconAndCaption

        btnclickhandler.Picture = ToIPictureDisp(My.Resources.comments_add)

        btnclickhandler.TooltipText = "Your tooltip text"
        AddHandler btnclickhandler.Click, AddressOf OnApptClick

You can of course replace My.Resources.comments_add with any icon or bitmap you have.

Points of Interest

The annoying thing about developing for Microsoft Outlook is that you will have to use COM (there is no way to escape it) and debugging can be a pain in the neck. You will have to know what you're doing when you're coding.


  • 18th February, 2009: Initial post
  • 20th February, 2009: Added screenshot and source files


This article, along with any associated source code and files, is licensed under The BSD License


About the Author

Erwin Wolff
Software Developer
Netherlands Netherlands
No Biography provided

You may also be interested in...


Comments and Discussions

GeneralScreenshots would be helpful! Pin
torial18-Feb-09 17:48
membertorial18-Feb-09 17:48 
GeneralRe: Screenshots would be helpful! Pin
Nagaraj Muthuchamy18-Feb-09 18:37
memberNagaraj Muthuchamy18-Feb-09 18:37 
GeneralRe: Screenshots would be helpful! Pin
Erwin Wolff19-Feb-09 2:36
memberErwin Wolff19-Feb-09 2:36 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web03-2016 | 2.8.180318.3 | Last Updated 20 Feb 2009
Article Copyright 2009 by Erwin Wolff
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid