COM Interop and Regasm.exe

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_ROOTCLSID. 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_ROOTCLSID. The required key for the add-in with the ProgID name under HKEY_CURRENT_USERSoftwareMicrosoftOffice\%appname%Addins and associated key values are not added by regasm.exe and must be added by custom install actions in the installer.

Listing 23-5. The Attributes in the Connect Class That Are Looked at by Regasm.exe

using System.Runtime.InteropServices; [GuidAttribute("581C28BD-E701-4AC1-BD75-0979BCEEC91E"), ProgId("WordAddin1.Connect")] public class Connect : Object, Extensibility.IDTExtensibility2 { }

 

Mscoree.dll and Managed Add-Ins

A managed component registered under HKEY_CLASSES_ROOTCLSID 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_ROOTCLSID{some guid}InProcServer32 key for a managed add-in class called Connect in an assembly called WordAddin1.

Figure 23-13. The values under the InProcServer32 key for a typical managed COM add-in.

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.

 

Problems with Using Mscoree.dll to Load Your COM Add-In

Problem 1: Mscoree.dll Can Be Disabled, Causing All Managed COM Add-Ins to Stop Loading

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.

Figure 23-14. Office offers to disable a 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.

Problem 2: Mscoree.dll Cannot Be Signed

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.

Figure 23-15. The Trust all installed add-ins and templates option in the Security dialog.

 

Problem 3: Mscoree.dll Loads All COM Add-Ins Into the Same AppDomain

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.

When the CLR is running inside of a host application, it can load managed code into a unit of isolation called an AppDomain. You can think of an AppDomain as a little mini-process running inside of the Office application process. Each VSTO code-behind-document solution loads into its own AppDomain. So when you have three Excel workbooks loaded in the Excel process with VSTO code behind them, an AppDomain is created for each workbook. These AppDomains are isolated from one anothercode in one AppDomain cannot adversely affect the other AppDomains. Also, when the workbook is closed, the AppDomain corresponding to it can be stopped and unloaded without affecting the running code in other AppDomains.

By default mscoree.dll loads managed COM add-ins into the same App Domainan AppDomain known as the default AppDomain. This is bad because the COM add-ins are all running in the same AppDomain and can easily adversely affect each other. Also, there is no mechanism to unload managed code that was loaded when a COM add-in was connected but is no longer needed when the COM add-in is disconnected because the default AppDomain cannot be unloaded until the Office process exits. What you really want is for each COM add-in to load into its own AppDomain instead of loading all together into the default AppDomain.

Категории