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.
- 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).
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):
- 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.
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.
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:
- The user opens an inspector for an e-mail, appointment item, etc.
- The add-in handles either the
InspectorsNewInspector
or Inspector.Activate
event to get a reference to the item displayed in the inspector. - The user changes the item's subject (for example) and clicks Save.
- The add-in processes the
Item.Write
event and cancels the operation. - The user closes the inspector without saving the changes and the inspector window becomes closed.
- 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):
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 Loader | VSTO Loader | Non-Isolated (MSCOREE.DLL) |
Supported by | Add-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 versions | VS 2003, VS 2005 | VS 2005 | VS 2003, VS 2005 |
Office versions | Office 2000, 2002, 2003, 2007 | Office 2003, 2007 | Office 2000, 2002, 2003, 2007 |
Is the add-in isolated in a separate application domain? | Yes | Yes | No, 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 automatically | No, it is pre-installed with VSTO run-time | No, 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.dll | adxregaddin.exe | AddinExpress.Install.dll |
Can the shim be signed ? | Yes | No | No |
Does the shim allow updating the add-in DLLs when the add-in is running? | Yes. | No | No |
Is the shim configurable? | Yes, you can edit the manifest file. | Yes, you can edit the manifest file. | No |