Exposing .NET Components to COM/COM+



Exposing .NET Components to COM/COM+

When COM+ was developed, COM was the prevalent component development technology. Therefore COM+ was developed with COM in mind. COM+ recognizes only COM components; any .NET component that is exposed to COM+ must be exposed as a COM component. In this section, you learn how to expose a .NET component as a COM component. After you do that, the .NET components can be used from the COM clients as well as they can make use of the COM+ services.

Calling a .NET Component from COM/COM+

For COM+ (or any COM client) to find a .NET component, you need to register the .NET component as a COM server in the Windows Registry. This process is known as the assembly registration process and it can be performed by any of the following methods:

  • When using Visual Studio .NET, open the project's property pages and change the Register for COM Interop option to true. The Register for COM Interop option is in the Configuration Properties, Build page of the project's Property Pages dialog box.

  • Use the Assembly Registration tool (regasm.exe) that ships as a part of the .NET Framework.

  • In a program, use the RegistrationServices class of the System.Runtime.InteropServices namespace.

However, before you use any of these options, you must sign a .NET assembly using the Strong Name tool (sn.exe). A strong name provides a unique identification to the assembly and avoids any possible conflicts with other programs. A strong name consists of the assembly's identity (its simple text name, version number, and culture information), a public key, and an optional digital signature.

Additionally you can also assign an assembly and each of its classes with distinct GUID values by using the Guid attribute. If you don't assign a GUID, the registration methods mentioned previously will assign one automatically for each element of the assembly (such as the assembly itself and its interfaces and classes). The GUID value is used to create a unique Registry key for the component, as shown in Figure.

1. The assembly registration process creates registry entries that COM uses to instantiate a component.

graphics/07fig01.jpg

Within each component's registry entry is a key named InprocServer32. The value of InprocServer32 key specifies the path of the DLL that COM uses to create the component by invoking the CoCreateInstance() COM method. However, if the DLL is managed code, COM does not know how to load the DLL and create objects. To resolve this problem, the assembly registration process takes a different approach. Rather than store a path to managed code DLL in the InprocServer32 key, the assembly registration process stores a path to the mscoree.dll file. The mscoree.dll is a special file in the .NET Framework that knows how to launch the CLR process and execute a managed DLL.

How does mscoree.dll know which managed code DLL to execute? The assembly registration process stores this information for mscoree.dll in another registry key named Assembly (refer to Figure). The Assembly key store the identity of the managed code DLL but does not store its path. The mscoree.dll has the assembly name, but does mscoree.dll know where to find the code for this assembly for execution? The mscoree.dll instructs the CLR to locate the assembly. One of the first places where the CLR searches for a strongly named assembly is the Global Assembly Cache (GAC). If the CLR cannot find the assembly in the GAC, it tries to locate the assembly in several other places. I have covered the complete process of how the CLR locates an assembly in Chapter 10, "Deployment."

When mscoree.dll locates the assembly containing the requested type, it invokes a global method named DllGetClassObject() to create an instance of the type. This method also creates a COM Callable Wrapper (CCW) on the fly, based on the type. You can think of the CCW as a proxy to the COM object. CCW enables communication between the calling COM code and the managed code. It also handles any conversion between the data types, as well as other messages between the COM types and the .NET types. Figure shows how a .NET component is invoked from COM.

2. The CCW works as a proxy and enables a COM component to call a .NET component.

graphics/07fig02.gif

The CCW exposes an IDispatch interface that can be used by a COM client to access methods or properties of a managed object in the following two steps:

  1. The COM client calls the IDispatch.GetIdsOfName() COM method on the CCW, passing it the name of the member you want to access. The method returns a unique dispatch id (DispId) for the member.

  2. The COM client calls the IDispatch.Invoke() COM method and passes it the DispId as an argument. This method provides access to the members exposed by an object.

Exporting .NET Components As COM Type Libraries

In the previous section, you saw that the CCW is created on the fly at runtime. The COM clients use a technique called late binding to access the object. In late binding, resolution of the type references is delayed until runtime. Although late binding is suitable for interpreted environments such as scripting languages, late binding is slow and does not support compile-time type checking.

The .NET Framework also enables .NET programmers to export their components as COM type libraries. A type library is a persistent CCW that makes the .NET types available to the COM programs at compile time. COM programmers can use the type information stored inside CCW to compile their programs and take advantage of early binding to the .NET types. Early binding significantly reduces the time required to access an object and additionally enables compilers to enforce type checking at compile time.

A .NET type can be exported as a COM type library in any of the following ways:

  • In Visual Studio .NET, open the project's property pages and change the Register for COM Interop option to true. The Register for COM Interop option is in the Configuration Properties, Build page of the project's Property Pages dialog box.

  • Use the Assembly Registration tool (regasm.exe) with its /tlb option.

  • Use the Type Library Exporter tool (tlbexp.exe) that ships as a part of .NET Framework SDK.

  • In a program, use the ConvertAssemblyToTypeLib() method of the TypeLibConverter class in the System.Runtime.InteropServices namespace.

The default extension of a type library is .tlb. You can use this library to compile the COM clients.

REVIEW BREAK

  • Instead of providing a new version of component services, Microsoft .NET Framework relies on the COM+ component services that ship as a part of Windows 2000, Windows XP, and the Windows Server 2003.

  • COM+ component services provide several features for increasing the security, reliability, availability, efficiency, and scalability of an enterprise application as part of the operating system infrastructure.

  • COM+ does not understand .NET and therefore cannot directly provide services to the .NET component. Instead, a .NET component must be exposed as a COM component through an assembly registration process.

  • To enable the communication between COM and .NET components, the .NET Framework generates a COM Callable Wrapper (CCW). The CCW enables communication between the calling COM code and the managed code. It also handles conversion between the data types, as well as other messages between the COM types and the .NET types.