Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / VB

Developing COM Add-ins for Microsoft Office in VB.NET

3.33/5 (7 votes)
29 Oct 2007CPOL20 min read 1  
This article describes the ways a VB.NET developer can create a COM Add-in for Microsoft Office 2000, 2002 (XP), 2003, and 2007 in order to customize Office applications including adding UI elements and event handling.

What is a COM add-in?

A COM add-in is a COM DLL that implements the IDTExtensibility2 COM interface. COM add-ins run within the process of their container application (a.k.a. host application a.k.a. host).

How to create a COM add-in in VB.NET?

You can use the Shared Add-in wizard in Visual Studio, VSTO 2005 / VSTO 2005 SE, and Add-in Express 2007 for .NET. You can also start from scratch: just create a Class Library project in Visual Studio 2003 or 2005 and implement IDTExtensibility2.

To start the Shared Add-in wizard, you run Visual Studio 2003 or 2005 and choose File | New | Project in the menu. Then, in the New Project dialog, you choose Other Project Types / Extensibility in the Project Types pane and find Shared Add-in in the Templates pane.

Add-in Express supports both VS 2003 and 2005. It shows its wizards in Other Project Types / Extensibility, too.

VSTO 2005 is a VS 2005 based product. It installs its wizards to the following branch: Visual Basic / Office. VSTO 2005 SE - a free plug-in available for VS 2005 only - uses Visual Basic / Office / 2003 Add-ins and Visual Basic / Office / 2007 Add-ins branches.

Both Shared Add-in and Add-in Express support the development of multiple-host add-ins. Add-in Express allows developing several add-ins in the same assembly. VSTO allows creating a single add-in supporting a single version (2003 or 2007 only) of a single Office application. In addition, VSTO allows developing add-ins for a limited number of Office applications only.

With shared add-ins, you will need to cope with certain problems caused by the inconsistence of the IDTExtensibility2 interface at the add-in start up and shut down.

What areas of an Office application can be customized?

You can customize the user interface of the Office application in the following ways:

In command bar aware applications:

  • Add a custom command bar.
  • A custom command bar in Excel

  • Add a custom or built-in command bar control onto a built-in command bar (e.g., add an item to a menu or context menu).
  • Intercept the action of a built-in command bar control.
  • Add a custom .NET control onto a command bar (with Add-in Express only).

    A .NET control on a custom command bar in Outlook

In Ribbon-aware applications (Office 2007 only):

  • Add a custom Ribbon tab.
  • Add a custom Ribbon group onto a built-in Ribbon tab.
  • Intercept the action of a built-in Ribbon control.
  • Add a Custom Task Pane.

In all Office applications:

  • Create a custom keyboard shortcut or intercept an existing one (with Add-in Express only).
  • Handle all events provided in the host's object model.

In Outlook only:

  • Add a custom page to the Tools / Options dialog.
  • Add a custom page to the Folder Options dialog.
  • Add a custom item to the Shortcut area in Outlook Bar.
  • Replace the folder view of a given folder with a custom .NET form (with Add-in Express only).
  • Embed a custom .NET form into the following regions (with Add-in Express only):
  • Advanced Form Regions by Add-in Express

  • Get notified when the Navigation Pane (Outlook Bar), Reading Pane, and To-Do Bar is shown / hidden / moved (with Add-in Express only).
  • Get notified when the Office 2007 color schema is changed (with Add-in Express only).

Special case:

  • Add a custom Action Pane in Word 2003 and Excel 2003 in document-level add-ins developed on VSTO 2005 - not SE!

Note that for every entry above, Add-in Express provides a special component(s) or event(s).

What are command bars and command bar controls?

In Office, toolbars, menus, and context menus are command bars. Command bars are identified by their name. Nevertheless, while testing your add-in, you'll find that you can create several command bars of the same name. Usually, the host provides the CommandBars property in its Application class. The CommandBar class provides the Controls collection of command bar controls.

Command bar controls are divided into two big classes: built-in and custom. Built-in command bar controls are ID-based: every command bar control has the ID property and for built-in controls, their IDs are pre-defined. To find the ID of this or that command bar control as well as command bar names, you can use our free Built-in Controls Scanner.

The Office.MsoControlType enumeration suggests that you can create a lot of control types. Nevertheless, for the developer, command bar controls are just a button, combo box, and popup.

A command bar button allows showing a caption and/or an icon. The look-n-feel of the button depends on the Office version and the value of the Style property. The only event provided by buttons is Click.

A command bar combo box is a cut-down version of a true combo box supplied with a label. Bereaved of its dropdown part, it becomes a labeled text box, cut-down, too. The only event available is Change. This event fires after you change the text and move the focus off the control.

A command bar popup is a control that can show a pop-up menu. The simplest example is File on the Word menu. There are no events for this control.

The need to show true controls in command bars made us create Toolbar Controls for Microsoft Office which is now included into the Add-in Express packages. With this product, you can show any .NET control on the toolbar. See the following sample add-in that adds a UserControl onto the toolbar.

How to create a command bar in my add-in?

The command bar related part of the Office object model looks pretty simple and does not promise any troubles. But when you debug your first command bar so that it becomes stable and functional, you will learn the truth: command bars and command bar controls in Office require too many efforts for such a simple result. First, you will learn that Office applications treat toolbars differently. And even the same application can treat command bars differently (Word and Outlook). Then you will learn that a host can be launched via UI and via Automation. Sure, any decent command bar must support these cases. As for Outlook, it can be run in one more way: a program can start Outlook via Automation and then the user can run it in the usual way. Alas, in this scenario, there are no suitable events for adding command bars. Then you will find that command bar controls behave differently depending on the docking state of the command bar. And you have to delete your command bars when your add-in is turned off via the COM Add-ins dialog (see Add the COM Add-ins Command to a Toolbar or Menu on the Add-in Express forum) or uninstalled. Another problem - the user is able to delete your command bar.

In shared add-in and VSTO, you can start with the following sample code on OutlookCode.com. If you prefer to go this way, I'd recommend that you pay attention to the number of replies to this post. And don't you think that the answers cover the theme (command bars and controls) completely. Four Offices, two launch types (via UI, via Automation, plus a mixture of Automation and UI for Outlook), three editor types in Outlook, many Office applications: just multiply the figures to get the number of variants you need to test your toolbars on.

In Add-in Express, you add the CommandBar component to the add-in module and use its visual designer to populate the command bar with command bar control components. The components were tested on all of the scenarios above.

Add-in Express Command Bar Designer in action.

For Outlook, Add-in Express includes two special command bar components (for Explorer and inspector windows) that support multi-explorer and multi-inspector modes and add context-sensitivity features to Outlook command bars. For instance, you can specify message class(es) and/or folders for which your toolbar will show up. These Outlook-targeted command bar components solve almost all problems with command bars in WordMail (when Word is set as the default mail editor).

What is Ribbon?

In several Office 2007 applications, they added a new Ribbon user interface that provides a very different approach to Office customization when compared to command bars. The applications are Access, Excel, Outlook, PowerPoint, and Word. In Outlook 2007, the Ribbon UI is supplied for inspector windows only.

To make use of the Ribbon customization features, the add-in must implement the IRibbonExtesibility COM interface. When such an add-in starts, Office queries the interface in order for the add-in to return an XML markup describing the Ribbon controls created by the add-in as well as the names of the control-related callback procedures.

There is no way to create Ribbon controls dynamically (except for Ribbon items: menu, combobox, dropdown, and gallery items). You cannot add your control to a built-in Ribbon group. Instead, you can create a custom Ribbon group and add it to a built-in tab.

Whatever tool you use to customize the Ribbon, you will need Lists of Office 2007 Control IDs available for download on the Microsoft web-site.

How to customize the Ribbon interface in my add-in?

If you need a good starting point for developing your VSTO and Shared add-in, have a look at Customizing the 2007 Office Fluent Ribbon for Developers (Part 1 of 3) on MSDN.

The flexibility of the Ribbon UI is incomparable to that of command bars. In Add-in Express, we provide a true design-time for the Ribbon interface. With visual designers, you can create a Ribbon tab in minutes. Moreover, you don't need to care about the Office version your add-in is running in, because the Ribbon UI will show up in a Ribbon-aware application, and command bar components don't show up in this case by default. Add-in Express also provides a simple way to share Ribbon controls across multiple add-ins. And if you need the full flexibility, you are able to modify the Ribbon XML in the appropriate event handler.

Add-in Express Ribbon Tab Designer in action.

How to create a task pane?

In VSTO and Shared add-in, you need to implement the ICustomTaskPaneConsumer interface. It's simple, of course. Especially, if you do know the whereabouts. VSTO developers may want to read Andrew Whitechapel's post on his blog.

Add-in Express implements this interface and allows you to create a true task pane in three simple steps: you add a UserControl to the project, then add an item to the TaskPanes collection, and finally bind the item to the UserControl by selecting it in a property editor. Add-in Express also handles task pane inconsistencies for you.

For pre-2007 Outlook developers, Add-in Express provides Add-in Express Extensions for Microsoft Outlook. The tool embeds a custom form window into window chains of Outlook 2000, Outlook XP, Outlook 2003, and Outlook 2007!

How do managed add-ins load to an Office application?

.NET based add-ins are called managed because of the automatic memory management - a feature of the .NET Framework which is an extensive run-time library (20-100 MB depending on the version).

For an add-in to be recognized and loaded by the host application, the registry must contain one of the registry keys discussed below. With VB6 or other COM-aware development tools, you can just specify your ActiveX DLL in the key of your choice. In the case of a managed assembly, this doesn't work because Office is completely unmanaged and it doesn't know anything about .NET. The solution is an unmanaged DLL called "shim". When it is referenced in any of the above-mentioned keys, the host loads the shim that loads the Common Language Runtime (CLR) and creates an application domain (see the AppDomain class in MSDN). Then, the shim redirects calls from Office to your add-in and vice versa. Naturally, every shim implements IDTExtensibility2.

Shared add-ins are based on MSCOREE.DLL, a universal shim included into the .NET Framework. VSTO add-ins use the VSTO Loader, a part of the VSTO Runtime which is a prerequisite for VSTO add-ins. Add-in Express generates add-in projects supporting both MSCOREE.DLL and the VSTO Loader. It also provides a proprietary shim called the Add-in Express Loader. Please see the Shim Comparison Table below.

If you are familiar with C++, you can write a shim yourself: see Isolating Microsoft Office Extensions with the COM Shim Wizard Version 2.3 on Microsoft web-site.

How managed add-ins refer to the object model of the host application

You need to reference a COM type library through an Interop assembly (see COM Interop on MSDN) by adding a corresponding .NET reference to your project.

Microsoft provides free Primary Interop Assemblies (PIAs) for Office 2002 through 2007. For Office 2003-2007, the PIAs are included into the Office setup package. For Office 2002, you can download them from the Microsoft web site (see Working with the Office XP Primary Interop Assemblies). To support Office 2000 (and higher), you have two ways: create an interop for Office applications yourself (see Creating Interops Manually below) or use version-neutral interop assemblies provided by Add-in Express.

If you develop your add-in using PIAs, the add-in will support the Office version installed on your development PC and all higher Office versions. When using version-neutral interops, your add-in will support Office 2000 (provided the host application is available in Office 2000) and higher, whatever Office version is installed on your PC. To access properties and methods introduced in a higher version, you can use late binding (see the System.Type.Invoke() method in MSDN). To access events of a higher version, you will either have to connect to them (see How to establish a COM event sink in the .NET Framework with return values by using Visual C# .NET or Visual C# 2005) or use the version-aware event classes and the application-level event component provided by Add-in Express.

Creating interops manually: In Visual Studio, just add a COM reference to an application of the Office 2000 suite to the project. This automatically creates the interop you need. But it is the point where your problem begins: a great number of classes and events are inaccessible, because a number of identical bugs in Office type libraries make Studio create the interop that will not work for you. You can disassemble the interop, make unavailable classes and events public, and recompile it (ildasm.exe and ilasm.exe). This is exactly the way Add-in Express version-neutral interops were created.

How managed add-ins use COM objects from the host's object model

The area where .NET and COM differ is memory management. COM uses deterministic object destroying: when there are no references to a given COM object (you set a variable to Nothing or it leaves the scope), the object is destroyed and the corresponding memory is freed. In .NET, objects are destroyed in an indeterminate way: when a variable is set to Nothing or leaves the scope, the corresponding object is destroyed and its memory is freed when the Garbage Collector (GC) makes the next run and finds that the object is unused.

When you refer to a COM class, a Run-time Callable Wrapper (RCW) is created by the .NET Framework. The RCW is an intermediary between a variable referring to a COM object and the COM object itself. That is, you have the following chain: your variable refers to the RCW which in its turn refers to the COM object. When you set the variable to Nothing (or it leaves the scope), the RCW will be destroyed on the next run of GC. When being destroyed, the RCW frees the COM object it refers to.

Note that if you write in VB6 style, say OutlookApp.ActiveExplorer.Selection.Item(1).Subject, this will create three more RCWs that will not be associated with any .NET variables. Accordingly, the corresponding COM object will be released at an unpredictable time.

Usually, the time gap between disposing your variable and freeing the corresponding COM object makes no difference. Sometimes, however, you must free the corresponding COM object yourself. In such cases, you use the Marshal.ReleaseComObject() method located in the System.Runtime.InteropServices namespace. You pass your variable to this method, and it makes the associated RCW free the COM object.

A sample scenario where ReleaseComObject is obligatory includes the following steps:

  1. The user opens an inspector for an e-mail, appointment item, etc.
  2. The add-in handles either the InspectorsNewInspector or Inspector.Activate event to get a reference to the item displayed in the inspector.
  3. The user changes the item's subject (for example) and clicks Save.
  4. The add-in processes the Item.Write event and cancels the operation.
  5. The user closes the inspector without saving the changes and the inspector window becomes closed.
  6. The add-in doesn't release the item in the Inspector Close event; the corresponding Inspector object remains in the Inspectors collection awaiting for the next run of the GC.

As a result, the user can see the item's subject unchanged in the Explorer window but when the user opens it anew, the hidden inspector pops up with the e-mail subject still reflecting the changes that have just been canceled.

There is another significant difference between VB 6 and VB.NET. In VB 6, when you assign a variable referencing a COM type to another variable of the same type, the COM infrastructure knows that the COM object is referenced twice. To free the COM object in VB6, you must set both variables to Nothing. When you reproduce the same scenario in .NET, the COM object will be referenced only once because the variables will share the same RCW. When you use ReleaseComObject against one of the variables, this releases the COM object. Accordingly, when you try to use the second variable, you will get the following exception: "COM object that has been separated from its underlying RCW cannot be used".

Naturally, if even a single COM object isn't released by your add-in, the host application will not close. In Office 2003 and 2007, they have a feature: when the user closes an Office application, the application kills non-released COM resources after a time-out. The practice of Add-in Express indicates that this feature doesn't work sometimes. As to Office 2000 and 2002: if you don't release COM objects, these Offices will hang.

Considering the fact that Microsoft changes the behavior of Office applications by releasing updates and SPs (e.g., http://support.microsoft.com/kb/899919), the Add-in Express team insists on using ReleaseComObject for every COM object you acquire from the host object model. This approach guarantees that you will never run into the situations above. Once again, for Outlook 2000 and XP, this approach is absolutely the must.

How to debug my add-in?

Whatever tool you use, you specify the host application's path and file name in the Start External Program textbox in your project's properties. Then, with Shared Add-in and VSTO, you just run the project. With Add-in Express, you click Build / Register Add-in Express Project and run the project.

To study host events, we recommend using DebugView - a free utility available from the Microsoft website. It shows messages you send via the System.Diagnostics.Debug.WriteLine() method. So, just add the appropriate statements in the appropriate event handlers. It's fun to find how many programs write debug info!

To learn the state of COM objects, you set a breakpoint and use the Locals window. However, this approach works for typed variables only.

Note that you can use the good old VBA environment available in any VBA-enabled Office application.

On the first step, you create an Excel workbook (Word document, PowerPoint presentation), and go to the VBA environment (in the host application, choose menu Tools / Macro / Visual Basic Editor or just press Alt+F11). In the environment, you choose Tools | References: and check the entry for the Office application of your add-in. Then you write a macro.

For instance, in an Excel workbook referring (in the above-described way) to the Microsoft Outlook 11.0 Object Library, you write the following code in the module named ThisWorkbook (you can create a module of your own or use any existing one):

VB
Sub OutlookApplication()
Dim olApp As Outlook.Application
  Set olApp = New Outlook.Application
  Stop
End Sub

When you run this code, it stops on the Stop statement. At this point, you choose View / Local Windows and begin exploring the Outlook.Application class' properties (and properties' properties, etc). Naturally, you can create far more elaborated macros.

How to deploy my add-in

VSTO, the Shared Add-in wizard, and Add-in Express generate a setup project for your add-in automatically.

Add-ins installed for all users on the current PC are to be registered in:

HKEY_LOCAL_MACHINE\Software\Microsoft\Office\%APPLICATION%\Addins\%YourAddin%

Naturally, such add-ins must be installed by an admin only. By the way, such add-ins don't show up in the COM Add-ins dialog.

To be installed by the current user, the add-in must be registered in:

HKEY_CURRENT_USER \Software\Microsoft\Office\%APPLICATION%\Addins\%YourAddin%

A Shared Add-in creates one of these keys based on your choice. VSTO creates the minimal set of keys in the setup project. Note that VSTO doesn't allow registering add-ins in HKLM! There are other keys, though. You will need them to show option pages in Outlook. Add-in Express creates all the keys required for an add-in during the installation.

Unlike VSTO and a Shared Add-in that generate the Registry entries required for your add-in in their setup projects, Add-in Express provides a design-time property that allows re-targeting the add-in from HKLM to HKCU and vice versa. The property value is saved to an XML that is parsed by a ready-to-use custom action DLL. The same DLL creates the keys required for the add-in. This approach allows you to register your add-in via regsvr32! In this way, you can include your add-in into a non-Studio based setup project.

How to update my add-in

Add-in Express provides a unique feature: ClickOnce deployment for add-ins. This feature allows creating user-oriented Internet-downloadable setups. The feature includes a publishing wizard and a pre-compiled ClickOnce application that informs the developer when the add-in is registered, unregistered, updated, or reverted to the previous version. It provides the user with the abilities above, and allows the developer to show a custom GUI instead of the built-in one. To control the deployment, add-ins are supplied with the CheckForUpdates method.

For Shared add-ins and VSTO add-ins, you will have to develop a similar infrastructure yourself.

Conclusions

Complexities of add-in development can be classified as follows:

  • Add-in functionality: Admittedly it may be complex. Nothing can be done about it.
  • UI: Add-in Express includes a number of components that work on all Office versions and speed up the development. The less code you have to write, the fewer errors you make!
  • Interacting with Office object models: Add-in Express team provides a really great support for their customers, including consulting on Office object models.
  • Add-in deployment: Add-in Express eases this part, too. It generates setup projects and includes a number of ready-to-use custom actions. And it provides a unique feature - a true ClickOnce solution for add-ins!

In the items above, I have had no chance to mention Shared Add-in and VSTO because they just don't give you anything in these areas. I can be biased, though. Am I? What do you think?

Shim Comparison Table

Add-in Express LoaderVSTO LoaderNon-Isolated (MSCOREE.DLL)
Supported byAdd-in Express 2007 for .NET

VSTO 2005 (SE)

Add-in Express 2007 for .NET

Shared Add-in

Add-in Express 2007 for .NET

Visual Studio versionsVS 2003, VS 2005VS 2005VS 2003, VS 2005
Office versionsOffice 2000, 2002, 2003, 2007Office 2003, 2007Office 2000, 2002, 2003, 2007
Is the add-in isolated in a separate application domain?YesYesNo, your add-in shares the same application domain with other non-isolated add-ins.
Does the shim require adding to the setup project?Add-in Express Project Wizard adds it automaticallyNo, it is pre-installed with VSTO run-timeNo, it is pre-installed with .NET Framework 1.1 and 2.0
Which Add-in Express assembly provides ready-to-use custom actions for setup projects?adxloader.dlladxregaddin.exeAddinExpress.Install.dll
Can the shim be signed ?YesNoNo
Does the shim allow updating the add-in DLLs when the add-in is running?Yes.NoNo
Is the shim configurable?Yes, you can edit the manifest file.Yes, you can edit the manifest file.No

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)