The mechanism for loading COM add-ins into Office was developed long before .NET existed and relies entirely on a technology called COM to instantiate the COM add-in. For a COM add-in written in C# to be used in Office, it must be registered as a COM component. The ability to register a C# class as a COM component is a core feature of the CLR called COM interop and can be achieved easily by running the regasm.exe tool on the assembly containing your Connect class or by selecting the Register setting for the primary output assembly in the setup project.
The regasm.exe tool works by reading the declaration of your class, and in particular the class-level attributes GuidAttribute and ProgID shown in Listing 23-5. These class-level attributes are defined in the System.Runtime.InteropServices namespace. The GuidAttribute tells the regasm.exe tool what CLSID to use in the registry for the class when registering it under HKEY_CLASSES_ROOT\CLSID. The ProgID tells the regasm.exe tool what ProgID to use when registering the class. The regasm.exe tool only writes the necessary keys under HKEY_CLASSES_ROOT\CLSID. The required key for the add-in with the ProgID name under HKEY_CURRENT_USER\Software\Microsoft\Office\%appname%\Addins and associated key values are
not added by regasm.exe and must be added by custom install actions in the installer.
using System.Runtime.InteropServices; [GuidAttribute("581C28BD-E701-4AC1-BD75-0979BCEEC91E"), ProgId("WordAddin1.Connect")] public class Connect : Object, Extensibility.IDTExtensibility2 { }
Managed Add-Ins
A managed component registered under HKEY_CLASSES_ROOT\CLSID differs from a typical unmanaged COM component primarily with regard to the InProcServer32 key in the registry for the component. An unmanaged component would set the InProcServer32 to be the DLL that implements the COM component. A managed component cannot set this value to the name of the managed DLL because to create an instance of the managed assembly the CLR needs to be loaded and there is no guarantee that the calling application will have already loaded the CLR into memory. In fact, it is almost certain that the calling application will not load have loaded the CLR because it is trying to load what it thinks is a COM component. To circumvent this chicken-and-egg situation, the CLR provides a DLL called mscoree.dll that loads the CLR, instantiates the class out of the managed assembly, and returns a COM Callable Wrapper for the managed class to the calling application.
When a managed class is registered by regasm.exe, the InProcServer32 key for the assembly always has a default value of mscoree.dll and an additional set of registry values are set that mscoree.dll uses to load the managed class. These additional keys provide information about the managed class and assembly that mscoree.dll will create and load. Figure 23-13 shows these values under a typical HKEY_CLASSES_ROOT\CLSID\{some guid}\InProcServer32 key for a managed add-in class called Connect in an assembly called WordAddin1.
All managed COM add-ins created by the Shared Add-In Wizard use mscoree.dll to get loaded into the Office process. Unfortunately, this presents several problems for Office COM add-in development that have led to the need for replacing the mscoree.dll with a different custom loadersometimes called a shimwhen building COM add-ins for Office applications.
If you are targeting Outlook 2003, you do not need to use a shimyou can use the new VSTO Outlook add-in project type that solves the problems associated with mscoree.dll. |
Office is composed of some of the most widely used applications in the world, and ensuring that the Office applications remain as stable as possible is a key concern for the Office development team. Because Office is so widely used, a number of COM add-ins have been designed to run inside of Office applications. Unfortunately, not all of them are written well, and they crash. When a COM add-in crashes, the hosting Office application becomes unstable or often crashes itself, leaving the user with little or no way of knowing what on earth happened.
Office invested heavily in the crash detection and reporting system in Office XP to try to track down these crashes in Office. While doing this, they quickly realized that many crashes were a result of third-party COM add-ins that were crashing. Using this information, Office introduced the ability to detect when a COM add-in crashes during Office application startup. On the next run of the application, Office displays a dialog such as the one shown in Figure 23-14 offering to disable the COM add-in.
If the user clicks the Yes button, Office will "black list" the COM add-in so that it will not be loaded into Office until an update has been received from the vendor. Although this is a great step forward for the reliability of Office applications, the way it was implemented does not work well with the default registration mechanism for managed COM add-ins because Office believes the offending DLL is mscoree.dll, which it blocks. Blocking mscoree.dll will not only block the crashing COM add-in but also every other managed COM add-in registered for that Office application.
In the late 1990s, Office was plagued with viruses such as the Melissa virus that took advantage of the ability to run code contained in an Office document. To defend against such attacks, Office introduced several security measures in Office XP primarily aimed at stopping malicious VBA code from running, but also to mitigate potential risks from COM add-ins. The primary defense against an add-in was to introduce the capability to only load COM add-ins signed by a trusted publisher. On the surface, this seems like a great idea, and indeed it is for unmanaged COM components. Unfortunately, it does not work well with the default registration mechanism for managed COM add-ins because Office checks the signature of the InProcServer32 binary, which is always mscoree.dll, and not the managed DLL started by mscoree.dll that contains the managed COM add-in. Mscoree.dll is a system DLL that is not signed and is installed by the CLR, so signing it with your own certificate is not possible. Mscoree.dll cannot be signed because it cannot vouch that the components it loads are safe.
Luckily, the default setting for Office is to trust all installed add-ins even if they are not signed, so this problem is not one that you will encounter on all Office installations. But it does mean if a company or individual is particularly security conscious and unchecks the Trust all installed add-ins and templates setting in the Security dialog shown in Figure 23-15, your COM add-in will not run. This dialog can be invoked by choosing the Security menu item from the Macros menu in the Tools menu of most Office applications.
Whenever managed code is loaded into an unmanaged application, the CLR must be hosted inside of the application in order to run the managed code. Hosting the CLR is something that can be achieved implicitly or explicitly. Implicit hosting of the CLR is achieved by the unmanaged application talking to mscoree.dll (which advertises itself as a COM object), which in turn starts up the CLR in the application and loads the managed code. Alternatively, the application can host the CLR directly by using the CLR hosting APIs, which provide considerable control over how the CLR gets loaded and in particular how assemblies get loaded. None of the Office 2003 applications host the CLR directly with respect to COM add-ins (although Word and Excel do host the CLR for document-based customizations created by Visual Studio Tools for Office), so all COM add-ins are loaded via their InProcServer32 setting.