Introduction
This small article will send you on your way developing Microsoft Visual Basic .NET plugins for Microsoft Outlook 2003.
Background
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.
IPictureDisp
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
Public iPictureDispGuid As Guid = GetType(stdole.IPictureDisp).GUID
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
Public Function ToIPictureDisp(ByVal picture As Image) As stdole.IPictureDisp
Dim bm As Bitmap
If TypeOf picture Is Bitmap Then
bm = picture
Else
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)
Private Class PICTDESC
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 http://blogs.msdn.com/rgregg/archive/2006/11/27/converting-bitmaps-to-ipicturedisp.aspx.
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.
History
- 18th February, 2009: Initial post
- 20th February, 2009: Added screenshot and source files