Architecture of the Outlook Add-in Support in Visual Studio 2005 Tools for Office
This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.
Andrew Whitechapel, Microsoft Corporation
Published: June 2005
Revised: December 2005
Applies to: Microsoft Visual Studio 2005 Tools for the Microsoft Office System, Microsoft Visual Studio 2005, Microsoft Office Outlook 2003
Summary: Learn about new support for managed add-ins in Microsoft Office Outlook 2003, introduced with Microsoft Visual Studio 2005 Tools for the Microsoft Office System. (21 printed pages)
Contents
Introduction to the Add-In Loader
Getting Started with the Outlook Add-In Solution
Why We Designed AddinLoader Component
Problems with Traditional Outlook Add-In Models
Problems with IDTExtensibility2 and Outlook Add-Ins
Problems with Unloading Outlook Add-Ins
AddinLoader Component Benefits
Architecture of the Outlook Add-In Loader
Security Benefits to the AddinLoader Component
Loading Outlook Add-Ins
Application Manifests and the AddinLoader Component
AddinLoader Registry Entries
Unloading Outlook Add-Ins
Preventing Outlook Shutdowns
Disabling Outlook Add-Ins
Creating Visual Studio Add-in Projects
Setting Up and Deploying Outlook Add-Ins with Visual Studio Tools for Office
Updating Outlook Add-Ins Using Application Manifests
Conclusion
Additional Resources
Introduction to the Add-In Loader
Microsoft Visual Studio 2005 Tools for the Microsoft Office System (Visual Studio 2005 Tools for Office) includes support for building application-level add-ins for Microsoft Office Outlook 2003 using managed code. This includes both design-time and run-time support:
Visual Studio project templates help you build Outlook add-ins and add-in setup projects.
A dedicated add-in loader component (AddinLoader) creates a separate AppDomain for each add-in, enforces strict security policy, and unloads the add-in when it is disconnected.
The AddinLoader component uses the Visual Studio 2005 Tools for Office run-time engine to provide a single, consistent mechanism for loading both document-level customizations and application-level add-ins into Microsoft Office applications. For the first time, you can build strongly typed, managed add-ins that you can easily deploy and run under High Security settings.
Getting Started with the Outlook Add-In Solution
Microsoft Visual Studio 2005 includes a new project type: an Outlook add-in project. Let us create a Microsoft Office Outlook add-in solution and see what it looks like in Microsoft Visual Studio 2005. The new project type is available under the Office tab in the New Project dialog box, in both Microsoft Visual C# and Microsoft Visual Basic .NET, as shown in Figure 1.
Figure 1. New Project dialog box (click to see larger image)
When you select this option, Visual Studio creates two projects in the solution:
The add-in project contains starter code for the add-in, and it contains the application manifest.
You use the setup project after you complete development of the add-in and you want to deploy it. The setup project builds a Microsoft Installer (MSI) file, which inserts entries into the registry and deploys the solution files (the assembly and manifests).
The add-in project includes a primary class for the add-in, which implements the IStartup interface. Using partial classes, this generated code is represented by a class divided into two files, to maintain consistency with Visual Studio 2005 Tools for Office document customizations. An example of the code produced by the add-in project for a simple "Hello World" add-in is shown in Figure 2.
Figure 2. ThisApplication code (click to see larger image)
When you create Visual Studio 2005 Tools for Office projects for Microsoft Office Word or Microsoft Office Excel, the primary class generated represents a document or worksheet. In the case of the Outlook add-in, the primary class represents the Outlook application because the add-in operates at the application level rather than at the document level. This class acts as a very thin wrapper to the Outlook application object, as indicated in Figure 3.
Figure 3. ThisApplication IntelliSense
As you can see in Figure 2, the project wizard generates two methods in the class, ThisApplication_Startup and ThisApplication_Shutdown, intended to be the entry point and exit point of your add-in. These represent the earliest and latest points at which you can add your custom code. So, to complete our simple add-in, add this code to the ThisApplication_Startup method:
MessageBox.Show("Hello World");
When you build and run the solution, Visual Studio launches Outlook, and Outlook loads the add-in. As soon as it is loaded, the add-in displays the "Hello World" message box. Note that, for Outlook to load the add-in, two more kinds of data must also be in place: registry information and a Microsoft .NET code access security policy. To streamline the development experience, Visual Studio adds these when you build the solution. Of course, when you deploy the add-in to your target users, you use the setup project to add the registry and code access security information.
Note
For more information about code access security, see How To: Use Code Access Security Policy to Constrain an Assembly.
Why We Designed AddinLoader Component
Many applications — especially information worker productivity applications such as Office — are designed to be customizable or extensible in arbitrary ways. However, Office has a defined standard set of interfaces for customization. The most commonly used is IDTExtensibility2. End-user solution developers and independent software vendors (ISVs) implement add-ins in either managed or unmanaged code by using this interface. Increasingly, they use managed code because of the rich functional capabilities of the Microsoft .NET Framework runtime and class library, and because of the rich development experience of Visual Studio 2005.
Before the release of the Visual Studio 2005 Tools for Office AddinLoader component, you loaded managed extensions into an Office application at run time in one of three standard ways:
No Shim. You could use COM to register the managed add-in (leaving its InprocServer32 key set by default to MSCorEE.dll, the .NET-based common language runtime engine). The host then loads MSCorEE.dll and passes the CLSID (class identifier) of the add-in. MSCorEE.dll checks the registry to find the code base (the path of the assembly) for the given CLSID and loads the add-in into the default AppDomain.
Simple COM Shim. Instead of registering the managed add-in, administrators could register an unmanaged shim component for each add-in. The host loads the shim, and the shim then loads the managed add-in for which it was built. The registry holds information about only the shim. You must build and register a separate shim for each add-in.
OTKLoadr. Microsoft Office 2003 applications use the Microsoft Visual Studio Tools for the Microsoft Office System, Version 2003 loader (OTKLoadr.dll) to load Microsoft Visual Studio Tools for the Microsoft Office System, Version 2003 customizations, certain managed smart tags, and managed smart documents. The OTKLoadr is not designed to load managed add-ins.
Note
You should not use add-ins that do not include shims. You can find an explanation of why, and details about the COM shim and the COM shim wizards for Visual Studio, in Isolating Office Extensions with the COM Shim Wizard and Using the COM Add-in Shim Solution to Deploy Managed COM Add-ins in Office XP.
Each approach has advantages and disadvantages. The Visual Studio 2005 Tools for Office AddinLoader component incorporates the advantages (and more), and avoids or resolves the disadvantages of these approaches.
Problems with Traditional Outlook Add-In Models
As you look more closely, you can see that each of the three standard ways to load extensions has limitations.
Poor Experience without Shims
Most managed COM add-ins are created by using the Shared add-in project type in Visual Studio. This sets up the registration for the add-in using MSCorEE.dll without using a shim and creates acute problems:
The managed add-in loads into the same AppDomain as all other managed add-ins that do not contain shims (including smart tags and real-time data components), so it cannot be isolated or unloaded independently from other add-ins. Loading into the same AppDomain makes it more prone to failure if another add-in is not functioning correctly. (For example, another add-in might call the ReleaseComObject method in a loop.)
All add-ins in the same AppDomain share the same security context.
The registered add-in .DLL that the host loads for an managed add-in that does not include a shim is typically MSCorEE.dll — the .NET-based .DLL that functions as a bootstrap application. For Office hosts running in High Security mode, with "Trust All Installed Add-ins and Templates" cleared in the Macro Security dialog box, the host requires that you digitally sign the .DLL of the registered add-in. However, you cannot sign MSCorEE.dll. Because MSCorEE.dll is listed as the .DLL for all managed add-ins, signing it causes all managed add-ins to be inherently trusted with no further checks, completely defeating the security model. This creates a dilemma for administrators: because you cannot sign MSCorEE.dll, they must either lower the security level to Medium or Low, or trust all installed add-ins and templates. Neither option is satisfactory.
No Default Support for Shims
You can download a Visual Studio COM Shim Wizard and project set from Microsoft, which enables you to build an unmanaged shim for managed add-ins. This approach solves some of the problems of a managed add-in that does not include a shim, but some issues remain:
This approach is unsupported by Microsoft.
This approach requires you to deploy an unmanaged shim component, plus one or more managed components with different installation requirements. This can be confusing for administrators (and developers) to maintain.
The (wizard-generated) shim is written in C++, a development language with which managed add-in developers are not always familiar.
With this model, each add-in requires an associated shim DLL, even though more than 99 percent of the code is identical across all such shims.
The shim can support only add-ins that implement IDTExtensibility2, ISmartTagRecognizer, ISmartTagAction, or IRtdServer. You cannot use it for other kinds of add-in or for hosts that do not expect to use these interfaces.
OTKLoadr Is Strictly Focused
OTKLoadr does an excellent job of creating separate AppDomains, ensuring that strict security policy is applied, and allowing for the complete unloading of managed extensions, but it was designed with a very specific purpose — to load Microsoft Visual Studio Tools for the Microsoft Office System, Version 2003, document-level customizations, managed smart tags, and managed smart documents. It was not designed to load add-ins.
Problems with IDTExtensibility2 and Outlook Add-Ins
Office applications have long supported the IDTExtensibility2 interface. It was the primary interface that Office requires add-ins to implement. Office does support other extension interfaces, including ISmartTagRecognizer, ISmartTagAction, ISmartDocument, and IRtdServer. With the introduction of Visual Studio 2005 Tools for Office, Office also indirectly supports the IStartup interface.
Multiple Office hosts support IDTExtensibility2, and its design enables you to build an IDTExtensibility2 add-in that can be loaded into multiple hosts. For this reason, IDTExtensibility2 is not strongly typed. For example, in the OnConnection method, a reference to the host is passed to the add-in, but it is passed as a generic object. You are responsible for casting this object to the type you expect to get. Although some developers take advantage of this feature, it is more commonly considered a liability rather than an asset. One problem with this approach is that the add-in necessarily incorporates redundant functionality. If the add-in targets, for example, Word, Excel, and Outlook, when it is running in Word all the code that is specific to Excel and Outlook is typically unused.
In contrast, the Visual Studio 2005 Tools for Office model is strongly typed. When you build a Visual Studio 2005 Tools for Office solution by using Visual Studio, the project wizard generates starter code that is specific to either Word or Excel. When the Office host loads your Visual Studio 2005 Tools for Office customization, the Visual Studio 2005 Tools for Office runtime passes to you a strongly typed Excel or Word application object as well as an Excel workbook or Word document object. This strong typing has a number of benefits. At design time, it means that you can take advantage of Microsoft IntelliSense and autocomplete, and that you write less code because you early-bind to defined types. At run time, memory consumption is improved because your code is less redundant, and performance improves because your code paths are less complex.
Another consideration is that IDTExtensibility2 has five methods, and developers typically do not use all of these — instead, they conflate them into two methods. The Visual Studio 2005 Tools for Office IStartup interface is a simpler, more streamlined interface, and it has only the two methods that developers typically need. Tables 1 and 2 show the typical ways that developers implement IDTExtensibility2 in add-ins, and how these map to the IStartup interface.
Table 1. Add-in loading methods
IDTExtensibility2 Method |
Typical Implementation |
IStartup Method |
---|---|---|
OnConnection |
Developers typically test to determine whether OnConnection is called during host startup. If OnConnection is called at any other time, they call a custom initialization method. If OnConnection is called during host startup, the custom initialization method is called by OnStartupComplete instead. |
Startup |
OnAddInsUpdate |
OnAddInsUpdate is called (usually multiple times) during startup as add-ins are added or removed. OnAddInsUpdate is very rarely used by add-in developers. |
(none) |
OnStartupComplete |
Developers typically do no work in this method. Instead, they call the same custom initialization method that is conditionally called in OnConnection. |
(none) |
Table 2. Add-in unloading methods
IDTExtensibility2 Method |
Typical Implementation |
IStartup Method |
---|---|---|
OnBeginShutdown |
OnBeginShutdown is called if the host disconnects the add-in when the host itself is shutting down. |
(none) |
OnDisconnection |
OnDisconnection is called when the add-in is disconnected, just before it unloads from memory, including when the add-in is being disconnected during host shutdown. Developers typically perform all cleanup tasks here. |
Shutdown |
From these tables, you can see that even if you implement four of the five methods, you typically need only two. Developers frequently do the same tasks in OnConnection and OnStartupComplete to initialize the add-in. They frequently do the same tasks in OnBeginShutdown and OnDisconnection to clean up when the add-in is unloaded. So, the typical requirement is not for five distinct sets of behavior, but instead for only two — "startup" and "shutdown" behaviors.
Although some developers do use more than two of the IDTExtensibility2 methods, this situation is rare. Forcing developers to work with the five IDTExtensibility2 methods, when three of them typically remain unused, is difficult to justify. Moving to the simpler, more readily understood IStartup interface improves developer productivity, simplifies add-in design, and reduces support and maintenance costs. AddinLoader component proxies IDTExtensibility2 to Office and maps the two used methods to the two IStartup methods that an IStartup add-in implements.
Problems with Unloading Outlook Add-Ins
Outlook has a well-known anomaly unloading add-ins that makes add-in development particularly problematic. The Outlook team is aware of the issue, but after careful review, it is clear that the fix also requires significant changes across the whole application. This, of course, brings considerable risk and could compromise other aspects of the programmability environment in Outlook that developers also depend upon. The number of user scenarios that are affected by this problem is relatively small, but the Outlook team is very committed to improving the situation.
The current problem is that, in some circumstances, Outlook fails to shut down add-ins cleanly — Outlook does not call the OnDisconnection method if the add-in has outstanding variables that are still holding references to Outlook objects. This is effectively a deadlock: the add-in continues to hold references until it gets an OnDisconnection call, but Outlook never makes the OnDisconnection call because the add-in is still holding references.
In a very simple add-in, you can avoid this situation by diligently cleaning up all your references as soon as you are finished with them. However, in a realistic add-in with more elaborate functionality and many more object references, this is often not practical — you typically want to hold on to objects to keep event handlers active. You often cannot avoid the problem without severely limiting the functionality of your add-in.
AddinLoader Component Benefits
The Visual Studio 2005 Tools for Office AddinLoader component is simple, and it fixes the majority of problems facing developers and administrators today. The AddinLoader component has several significant advantages:
AppDomain Isolation. The AddinLoader component offers all the advantages of the COM shim (and the OTKLoadr): separate AppDomains, add-in isolation, and the ability to unload the add-in and its entire AppDomain completely when the add-in is disconnected.
Strict Security. Visual Studio 2005 Tools for Office mandates that you must grant document-level customization explicit FullTrust permissions before the customization is allowed to run. This increases the security of these solutions, and the same policy is enforced for add-ins loaded with the AddinLoader component. You must give add-ins FullTrust permissions or it fails to load.
Single Shim. Instead of building a separate shim component — with redundant code — for each managed add-in, you can use the AddinLoader component for all of them.
Supported Shim. Unlike the COM shim, the Visual Studio 2005 Tools for Office AddinLoader component is fully supported by Microsoft.
Consistent Loader. The AddinLoader is effectively a bootstrap application and an interface proxy. The complicated work of creating AppDomains, setting security policy, and loading and unloading add-ins is accomplished by the Visual Studio 2005 Tools for Office runtime. So the same run-time engine is used for both document-level customizations and application-level add-ins.
Consistent Interface. Visual Studio 2005 Tools for Office customizations use the IStartup interface, and managed add-ins loaded by the AddinLoader component must also implement IStartup. This allows them to take full advantage of the Visual Studio 2005 Tools for Office run-time engine, and provides developers with a more streamlined interface against which to develop. It also promotes consistency between document-level customizations and application-level add-ins.
Familiar Deployment Model. Even though you use the AddinLoader component for all the run-time benefits it brings, the mechanism uses the same basic deployment model with which Office developers and administrators are already familiar, that is, the registration of an add-in in the conventional way.
No Changes to Office. To support the AddinLoader component and IStartup add-ins, the Office executables did not require changes, so Office functions exactly as it always did. Once the Visual Studio 2005 Tools for Office runtime and your add-in are correctly deployed, Office loads your new add-in in the same way it loads traditional IDTExtensibility2-based add-ins. Office goes to the registry and requests to load the add-in, at which point the AddinLoader component uses the Visual Studio 2005 Tools for Office run-time engine in a way that is completely opaque to Office.
Outlook Shutdown. The AddinLoader component implements the standard workaround to enhance the ability of Outlook to shut down cleanly even when add-ins are loaded. It also includes extended functionality to support Outlook shutdown even in some automation scenarios.
Design-Time Support. Visual Studio 2005 includes design-time support for building managed add-ins that uses the AddinLoader component and the Visual Studio 2005 Tools for Office runtime. Visual Studio 2005 provides not only a project template for creating add-ins but also a Visual Studio setup project for building setup packages for your add-ins.
Architecture of the Outlook Add-In Loader
The majority of the run-time functionality offered by the proposed system is provided by the Visual Studio 2005 Tools for Office runtime. This engine has been in development for two years and will be the basis for customizations for a range of host applications.
To complete the picture, there is one new Visual Studio 2005 Tools for Office run-time component — an unmanaged COM-registered DLL, called AddinLoader.dll. This component consists of two logical features:
Add-in Loading. This is a very small piece of functionality, because the loader bootstraps the Visual Studio 2005 Tools for Office loader. The loader does all the work of creating AppDomains, parsing manifests, checking security, and loading the target assembly.
IDTExtensibility2 Proxy. The proxy is responsible for mapping IDTExtensibility2 into the Visual Studio 2005 Tools for Office runtime. Office expects add-ins to implement IDTExtensibility2, while the runtime expects add-ins to implement IStartup. The proxy maps between the two interfaces.
The various pieces involved in the system are summarized in Figure 4. Note that the only portion that an add-in developer builds is the managed add-in itself. All other aspects are part of Office or the Visual Studio 2005 Tools for Office runtime. The AddinLoader.dll file itself is distributed with the runtime.
Figure 4. AddinLoader architecture (click to see larger image)
Security Benefits to the AddinLoader Component
Traditional managed add-ins and Visual Studio 2005 Tools for Office customizations use two different security models. Traditionally, if you deploy a managed add-in into an Office setup where Office is running with High or Very High security, you must sign the add-in before it is allowed to run. (See the earlier discussion of this limitation in relation to managed add-ins without shims.) Conversely, Visual Studio 2005 Tools for Office customizations use .NET-based Code Access Security. Specifically, the default local computer policy, FullTrust permission, is revoked, and the customization is allowed to run only if code access security policy is in place that explicitly gives it FullTrust permission.
Managed add-ins loaded by using the AddinLoader component use the Visual Studio 2005 Tools for Office security model. They are not allowed to run unless explicitly granted FullTrust permission. This has two obvious benefits:
Requiring explicit FullTrust policy significantly strengthens the security of the solution.
Security and deployment (and all the administrative processes for security and deployment) are identical for all kinds of extension — managed add-ins and Visual Studio 2005 Tools for Office customizations.
The AddinLoader.dll file itself is Authenticode-signed with a Microsoft certificate. This signature allows the user to make a trust decision (whether to install the component) at install time. One problem with the old model is that you cannot sign MSCorEE.dll, because to do so effectively trusts all installed add-ins without further checks. With the new AddinLoader model, signing AddinLoader.dll and trusting it does not automatically trust any add-ins, because you must also explicitly trust each add-in using the code access security policy.
Note
The rationale for the Visual Studio 2005 Tools for Office security model is discussed in the blog entry Channel 9 Video: .NET Code Access Security and Visual Studio 2005 Tools for Office Solutions.
Loading Outlook Add-Ins
When an Office application such as Outlook starts, it scans the registry to find the list of add-ins that it must try to load. For each add-in in the list, it loads the registered DLL and asks that DLL to return to it an IDTExtensibility2 pointer for the add-in. In the new architecture, each add-in is registered against AddinLoader.dll. Therefore, Outlook loads AddinLoader.dll and asks for the IDTExtensibility2 pointer for each specific add-in.
When asked to load an add-in, the AddinLoader component creates an IDTExtensibility2 proxy for the add-in and sends a pointer to this proxy back to the Office application. It then gets the registered manifest for the add-in and passes the manifest to the Visual Studio 2005 Tools for Office runtime. The runtime exists, separately, in the default AppDomain known as "DefaultDomain". The runtime parses the manifest, validates that correct security policy is in place, creates a fresh AppDomain, and loads the specified add-in assembly into that AppDomain. Soon after this, the Office application calls the add-in by using the IDTExtensibility2 pointer. Because this is actually a call to the proxy, the AddinLoader component converts this into a call to the Startup method implemented by the add-in.
The run-time behavior for loading an add-in is summarized in Figure 5.
Figure 5. Loading an add-in (click to see larger image)
This design ensures a single consistent mechanism for loading Office add-ins and customizations that also uses the rich services of the Visual Studio 2005 Tools for Office run-time engine. Both managed add-ins and Visual Studio 2005 Tools for Office customizations use the same runtime and the same basic loading mechanism.
Application Manifests and the AddinLoader Component
The AddinLoader component functions as a bootstrapping application for the Visual Studio 2005 Tools for Office runtime, and the runtime expects each customization to be accompanied by an application manifest (a simple XML configuration file). This represents a shift from the registry toward the more agile manifest-based configuration model. This is the model used in ClickOnce (although Visual Studio 2005 Tools for Office solutions do not use ClickOnce itself). This model is used both for document-level customizations and for application-level add-ins. The manifest approach provides a level of indirection to give more flexibility in maintenance and updating without touching the registry again. Therefore, each add-in that is to be loaded by the AddinLoader component must be deployed with an application manifest.
When an Office application starts, it determines the list of add-ins that it is required to load from the registry. The AddinLoader component registers new IStartup add-ins in the same way. The difference is that the registry entry points to an application manifest (not an assembly), and this manifest specifies the location of the assembly.
An example of the application manifest is shown below. The significant value in this manifest is the URL to the target managed add-in assembly (shown in bold). In this example, the assembly is assumed to be in the same folder as the manifest. However, the code base value could be a relative or absolute path to any location on the local file system or on a network share.
<assembly xmlns="urn:schemas-microsoft-com:asm.v1"
xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" manifestVersion="1.0">
<assemblyIdentity name="HelloWorldAddin.manifest" version="1.0.0.0" />
<asmv2:entryPoint name="Startup" dependencyName="dependency0">
<asmv2:clrClassInvocation class="HelloWorldAddin.ThisApplication" />
</asmv2:entryPoint>
<asmv2:dependency asmv2:name="dependency0">
<asmv2:dependentAssembly>
<assemblyIdentity name="HelloWorldAddin" version="1.0.0.0" culture="neutral" />
</asmv2:dependentAssembly>
</asmv2:dependency>
</assembly>
Note
For more information about the manifest deployment and updating mechanism, see the Setting Up and Deploying Outlook Add-Ins with Visual Studio Tools for Office.
For more information about Visual Studio 2005 Tools for Office manifests, see Application Manifests for Office Solutions and Deployment Manifests for Office Solutions.
AddinLoader Registry Entries
The AddinLoader mechanism is opaque to the host Office application: The host Office application believes it is loading a traditional IDTExtensibility2 COM add-in. Each add-in has a traditional registry entry in the format that Office expects. The registry entry includes one additional piece of information: the URL of the manifest for the add-in. When the Office application loads an add-in with the AddinLoader component, the various registry entries are used to identify which add-in to load, as shown in Figure 6.
Figure 6. Registry mappings (click to see larger image)
The setup project that is generated by the project wizard makes registry entries. The concatenation of all the entries is represented in the registry file listing below (although registry files are not actually used). The registry information does not include the managed add-in assembly. Instead, it includes the path to the AddinLoader DLL and the path to the manifest (both shown in bold):
[HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\Outlook\Addins\HelloWorldAddin]
"FriendlyName"="HelloWorldAddin"
"Description"="This is sample com addin using AddinLoader.dll"
"LoadBehavior"=dword:00000003
"CommandLineSafe"=dword:00000001
[HKEY_CLASSES_ROOT\HelloWorldAddin]
@="Sample COM Addin"
[HKEY_CLASSES_ROOT\HelloWorldAddin\CLSID]
@="{F0E54810-A875-4c54-9697-0AE40DAA7317}"
[HKEY_CLASSES_ROOT\CLSID\{F0E54810-A875-4c54-9697-0AE40DAA7317}]
"ThreadingModel"="Both"
[HKEY_CLASSES_ROOT\CLSID\{F0E54810-A875-4c54-9697-0AE40DAA7317}\ProgID]
@="HelloWorldAddin"
[HKEY_CLASSES_ROOT\CLSID\{F0E54810-A875-4c54-9697-0AE40DAA7317}\Programmable]
[HKEY_CLASSES_ROOT\CLSID\{F0E54810-A875-4c54-9697-0AE40DAA7317}\
VersionIndependentProgID]
@="HelloWorldAddin"
Note that the preceding sample assumes that AddinLoader.dll itself is deployed to the following well-known location:
%CommonProgramFiles%\Microsoft Shared\VSTO\8.0\
This is the same location where the Visual Studio 2005 Tools for Office runtime DLL is deployed. Registry entries for add-ins registered against the AddinLoader.dll are made in the same registry location as traditional COM add-in registry entries.
Unloading Outlook Add-Ins
The new model also supports unloading add-ins (triggered by the user choosing to disconnect the add-in by using the COM Add-ins dialog box), which is a feature that traditional add-in models did not address. When the host Office application (Outlook, in this case) wants to disconnect an add-in, it calls the OnDisconnection method on the add-in. Because this call goes through the proxy, the AddinLoader component can take control. The AddinLoader component converts the OnDisconnection call into a call to the Shutdown method that is implemented by the add-in.
The AddinLoader component then calls the Visual Studio 2005 Tools for Office runtime to unload the AppDomain, in which the add-in is loaded, thereby unloading the add-in assembly itself. In this context, the Visual Studio 2005 Tools for Office runtime functions the same in regards to both document-level customizations and application-level add-ins. The run-time behavior for unloading an add-in is summarized in Figure 7.
Figure 7. Unloading an add-in (click to see larger image)
Preventing Outlook Shutdowns
As mentioned previously, there is a well-known anomaly in the way Outlook traditionally has interacted with add-ins — Outlook does not call the OnDisconnection method if the add-in has outstanding variables that are still holding references to Outlook objects. A well-known workaround also exists, to correct this unexpected behavior so that it happens infrequently or never. This workaround is built into AddinLoader.dll and the Visual Studio 2005 Tools for Office runtime. The AddinLoader component determines whether it is running within Outlook, and if so, it listens for the appropriate events so that add-ins are correctly cleaned up. Specifically, the proxy listens for the Outlook Explorer.Close, Inspector.Close, and Application.Quit events. The AddinLoader component keeps track of the count of Explorers and Inspectors. When Application.Quit is called, or when the Close event fires, and no more Explorers or Inspectors are open (the count is zero), we can be reasonably confident that Outlook is shutting down. In this case, the AddinLoader component calls Shutdown on the add-in's IStartup implementation and then unloads the AppDomain, thereby cleaning up the references that are keeping Outlook alive. This allows Outlook to shut down cleanly in almost all situations.
Disabling Outlook Add-Ins
Currently, Office hosts can disable add-ins in two main ways, called "hard" and "soft" disabling. An add-in is soft-disabled if the user simply disconnects it by using the Office COM Add-ins dialog box, or if the add-in throws an unhandled exception as it loads. An add-in is hard-disabled if it crashes the host application as it is loaded. (This situation includes on-demand loading of the add-in after host startup.) Hard disabling is also known as the Office " resiliency model" because it makes Office applications resilient to failures in add-ins.
If an add-in is soft-disabled, the user can attempt to re-enable it by using the Office COM Add-ins dialog box. If the add-in is hard-disabled, the user can attempt to re-enable it by using the Office Disabled Items dialog box.
Office identifies soft-disabled add-ins by the LoadBehavior registry subkey for each add-in. Office identifies hard-disabled add-ins by an entry in the StartupItems registry key, which Office converts into an entry in the DisabledItems key.
The AddinLoader component does not change the Office hard-disabling behavior (the resiliency model) at all. That is, although add-ins are registered against AddinLoader.dll instead of MSCorEE.dll, nothing prevents AddinLoader.dll from being blocked. This maintains the behavior that users and administrators currently expect.
Add-ins registered against AddinLoader.dll do not change the Office algorithm for LoadBehavior. They adhere to the same LoadBehavior semantics as legacy COM add-ins. Depending on the value of LoadBehavior, a registered add-in may not load at startup, on demand, or not at all.
Office applications present different user interfaces when a traditional add-in fails to load than they do when a Visual Studio 2005 Tools for Office customization fails to load. When a Visual Studio 2005 Tools for Office customization fails to load, a dialog box appears with a user-friendly error message. When an add-in fails to load, there is no UI indication, although the user may subsequently (and explicitly) navigate to the COM Add-ins dialog box and there identify which add-ins are loaded. For add-ins loaded with the AddinLoader component, we provide exactly the same dialog box that we use for Visual Studio 2005 Tools for Office document customizations. The dialog gives a short description of the problem and shows the stack where the problem occurred.
By default, this dialog box is not shown to end users. This is consistent with current add-in behavior. We provide the dialog box primarily to support developers during debugging. However, the dialog box is available to end users if they (or their administrators) choose to make it available. The dialog box is activated if either (or both) of the following is true:
The host application is being debugged with either a managed or an unmanaged debugger.
The VSTO_SUPPRESSDISPLAYALERTS environment variable is set to 0.
Creating Visual Studio Add-in Projects
The setup project includes the primary output from the add-in project. When the setup project is built, the MSI file contains the following:
The add-in assembly.
Any dependent assemblies set CopyLocal=true. Typically, these are any dependencies that are not in the global assembly cache.
The application manifest file.
The required registry entries.
The Visual Studio 2005 Publish option can also be used for Outlook add-in projects. If you choose this option, Visual Studio performs the following actions:
Generates a deployment manifest.
Copies the add-in assembly, any dependencies, and both the application manifest and the deployment manifest to the chosen location.
Creates an association between the application manifest and the deployment manifest by putting the location of the deployment manifest in the application manifest.
The sequence of operations for loading an add-in published with a deployment manifest is illustrated in Figure 8.
Figure 8. Loading a published add-in (click to see larger image)
When the AddinLoader component passes the application manifest name and location to the Visual Studio 2005 Tools for Office runtime, the runtime extracts from the application manifest the location of the deployment manifest. It then checks the deployment manifest to determine whether there is an updated version of the application manifest (and therefore probably an updated version of the assembly). If so, it loads the updated application manifest and the assembly to which the updated application manifest points. Later, the local copy of the application manifest is overwritten with the latest version.
A typical deployment manifest is listed below. The reference to the latest version of the application manifest is shown in bold.
<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly xsi:schemaLocation="urn:schemas-microsoft-com:asm.v1
assembly.adaptive.xsd" manifestVersion="1.0"
xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns="urn:schemas-
microsoft-com:asm.v2" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1"
xmlns:asmv2="urn:schemas-microsoft-com:asm.v2"
xmlns:xrml="urn:mpeg:mpeg21:2003:01-REL-R-NS"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<assemblyIdentity name="HelloWorldAddin.application" version="1.0.0.0"
publicKeyToken="0000000000000000" language="neutral"
processorArchitecture="msil" xmlns="urn:schemas-microsoft-com:asm.v1" />
<description asmv2:publisher="VPCs Inc" asmv2:product="HelloWorldAddin"
xmlns="urn:schemas-microsoft-com:asm.v1" />
<deployment install="true" />
<dependency>
<assemblyIdentity name="HelloWorldAddin.manifest" version="1.0.0.0" />
<hash>
<dsig:Transforms>
<dsig:Transform Algorithm="urn:schemas-microsoft-
com:HashTransforms.Identity" />
</dsig:Transforms>
<dsig:DigestMethod
Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<dsig:DigestValue>2W4LgekQ5+O4biOA1nRyajoUjxM=</dsig:DigestValue>
</hash>
</dependentAssembly>
</dependency>
</asmv1:assembly>
When you publish the HelloWorld add-in, the corresponding application manifest for this solution is updated to include a reference to the deployment manifest (shown in bold).
<assembly xmlns="urn:schemas-microsoft-com:asm.v1"
xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" manifestVersion="1.0">
<assemblyIdentity name="HelloWorldAddin.manifest" version="1.0.0.0" />
<asmv2:entryPoint name="Startup" dependencyName="dependency0">
<asmv2:clrClassInvocation class="HelloWorldAddin.ThisApplication" />
</asmv2:entryPoint>
<asmv2:dependency asmv2:name="dependency0">
<asmv2:dependentAssembly>
<assemblyIdentity name="HelloWorldAddin" version="1.0.0.0"
culture="neutral" />
</asmv2:dependentAssembly>
<asmv2:installFrom codebase="HelloWorldAddin.dll" />
</asmv2:dependency>
</assembly>
Note that, while you are working on a developer computer, when you build your add-in solution, Visual Studio sets up code access security policy for you on the local computer. However, when you publish an add-in (even on a developer computer), you must set up the appropriate code access security policy manually for the new location.
Setting Up and Deploying Outlook Add-Ins with Visual Studio Tools for Office
When you create a traditional managed add-in, the IDTExtensibility2 Shared Add-in Project Wizard inserts the host-specific registry entries at design time. Then, when the add-in is built, RegAsm is called to insert generic COM-visibility registry entries. Additionally, the setup project that is auto-generated when the add-in project is created builds an MSI that contains the host-specific registry entries and that calls RegAsm to insert the generic registry entries.
This behavior has two issues:
You may get confused when you move the project from one computer to another (for example, if you check the solution code out of source control for a different developer), because the host-specific entries are present only on the computer where the project was originally generated. Best-practice advice here is that you should always build and run the MSI as a development step — do not rely on the original wizard-generated registry entries.
The fact that the MSI project contains some explicit registry settings, yet relies on calling RegAsm for other registry settings, may also be confusing.
In the new model, when you create a project for a managed add-in, you get two projects: one for the add-in itself, and one for the setup for the add-in. The setup project incorporates all of the registry entries that need to be made. Registration is the same as a managed add-in that does not include a shim registered against MSCorEE.dll, except that it is registered against AddinLoader.dll, and entries are added that specify the manifest URL.
Unlike the IDTExtensibility2 Shared add-in project, the new project system does not insert registry entries when the project is created. Instead, it inserts these registry entries when the project is built. This means you can check the solution into and out of source control or move it from one developer computer to another, and still get all of the necessary registry entries when you build the solution. You always have the option of building and running the MSI during development, if you choose — and you will at some point, if only to test the setup project.
Visual Studio 2005 Tools for Office document-level customizations support a server-side deployment model. That is, the managed assembly (and any dependent assemblies) that represent the customization may be deployed on a server. For Visual Studio 2005 Tools for Office application-level add-ins, we also support this model. Regardless of whether the add-in is on the local computer or a server, there must still be a local installation. The local installation must install the registry entries that refer to the manifest, and you must deploy the code access security policy on the local computer. You can install the application manifest on the local computer, or on a server. The manifest specifies the path to the add-in assembly. This assembly may also be either on the local computer or on a server.
This model is consistent with Visual Studio 2005 Tools for Office document-level customizations. The key differences are that, with document-level customizations, the manifest is embedded in the document or workbook, whereas with application-level add-ins, the manifest is a separate file on the file system, and application-level add-ins require registry entries.
Add-ins, registered against the AddinLoader component, obviously require that you correctly deploy the AddinLoader.dll on the computer. The AddinLoader component has a dependency on the Visual Studio 2005 Tools for Office runtime. The runtime has a dependency on version 2.0 of the common language runtime (CLR). If you register an add-in against the AddinLoader component, but AddinLoader.dll or anything else in the dependency chain is not available, the add-in fails to load. If error messages are not turned on, this failure is represented by a cleared check box in the COM Add-ins dialog box.
The following components are required to be on the computer in order for an IStartup-based add-in to work:
The Microsoft .NET Framework version 2.0
Outlook 2003 Service Pack 1
Outlook 2003 Primary Interop Assemblies
Note
The Office 2003 Primary Interop Assemblies are now available in a redistributable package for solution developers. To download them, see Office 2003 Update: Redistributable Primary Interop Assemblies.
The Visual Studio 2005 Tools for Office runtime
Appropriate code access security policy
The add-in DLL itself, any dependent DLLs, the application and deployment manifest, and registry entries
To make deployment as simple as possible for administrators, the add-in setup project includes a step to deploy the Visual Studio 2005 Tools for Office runtime if it is not already on the target computer.
For more information about setting up and deploying Visual Studio 2005 Tools for Office solutions, see Deploying Office Solutions.
Updating Outlook Add-Ins Using Application Manifests
Visual Studio 2005 Tools for Office document-level customizations support updating. The mechanism has a local application manifest that points to a deployment manifest (typically server-side). The deployment manifest points to the latest version of the application manifest on the server. The application manifest includes the information about the latest version and location of the assembly. To support intermittently disconnected scenarios, this mechanism updates (overwrites) the local application manifest when a new version (of the server-side application manifest and the assembly) becomes available.
Application-level add-ins also support updating, using a mechanism that is almost identical to the existing document-level mechanism. The two main deployment options are listed in Table 3.
Table 3. Deployment options
Mechanism |
Local Computer |
Server |
Updating |
---|---|---|---|
MSI |
Registry settings, code access security policy, application manifest, deployment manifest, and add-in assembly |
(none) |
removing, reinstalling |
MSI, .reg, and/or script |
Registry settings, code access security policy, and application manifest |
Deployment manifest and add-in assembly Also, the latest version of the application manifest |
You can copy new versions of the assembly by using Xcopy. You can edit manifests directly. |
We can support the most common deployment scenarios through our setup projects, and there are two types:
For local computer installation (typically used by ISVs who distribute their solutions to desktops they do not control), we have a setup project that includes all the pieces: add-in assembly, both application manifest and deployment manifest, registry entries, and code access security policy.
For server installation (typically used by enterprises that control their organization's desktops), the administrator uses Xcopy to copy the add-in assembly and both manifests to a server location. Administrators must also deploy the local computer registry settings, the local copy of the application manifest, and code access security policy.
In almost all update scenarios, administrators are free to make manual changes to the assembly, application manifest, or deployment manifest without touching the registry. The only scenario in which administrators need to change the registry settings is when the path to the local application manifest is changed.
Conclusion
With the introduction of Outlook add-in support, Microsoft extends the functionality of the Visual Studio 2005 Tools for Office technology to cover not only document-level customizations but also application-level managed Office add-ins. For the first time, developers have a robust, supported way to build managed add-ins for Office that use AppDomain isolation, a type-safe code model, and a strict code access security model.
Additional Resources
For more information about Outlook add-in tools, see these resources:
Visual Studio 2005 Tools for Office Training: Outlook Hands-on Labs
Visual Studio 2005 Tools for Office Sample: Outlook Snippets
Introducing Outlook Add-in Support in Visual Studio 2005 Tools for Office
Creating an Outlook Task Add-in Solution with Visual Studio 2005 Tools for Office
For more information about programmability in Outlook, see these resources: