Now that we have looked at the way in which COM and COM+ fit in with the .NET world, we will move on to more specific topics in the next three chapters. To start with, this chapter looks at how COM components can be used in .NET code. Microsoft has taken care to provide backward compatibility in .NET for COM so that existing investment in COM components doesnt have to be abandoned when you move to .NET. The design of .NET makes it possible to use COM components as if they were native .NET components and will even let you use ActiveX controls in the Microsoft Visual Studio .NET Toolbox.
This chapter will show you how to use COM components and ActiveX controls in .NET projects. Youll see how COM coclasses and interfaces are represented in .NET, and how marshaling works between .NET clients and COM components. In the following chapters, youll see how to use .NET components in COM and COM+ code.
The common language runtime needs to have metadata for all the types used in .NET code, including imported COM types. Because metadata is included as part of .NET assemblies, the metadata for COM types must somehow be held in an assembly.
An assembly that represents a COM object to a .NET client or vice versa is called an interop assembly . As youve seen, there are two kinds of interop assemblies: Runtime Callable Wrappers (RCWs) that let COM objects be referenced by .NET clients, and COM Callable Wrappers (CCWs) that let .NET components act as COM objects.
There are three ways of producing interop assemblies using tools and classes provided by .NET. These three techniques, listed in order of increasing flexibility, are
Using the tools provided by Visual Studio .NET
Using the type library importer tool, TlbImp.exe, which is part of the .NET Framework
Using the System.Runtime.InteropServices.TypeLibConverter class
Youll see how to use each of these later in the chapter.
Each of these three techniques requires that a type library be available from which to generate an interop assembly. What if the type library isnt available, or the interop assembly is incomplete or needs tweaking? In those cases, you can create interop assemblies directly, using suitable attributes in .NET code. The techniques used to do this are covered in Chapter 14, Working with Predefined Interfaces.
Anyone can produce an interop assembly for a COM type library simply by running TlbImp.exe. If several vendors produced interop assemblies for a commonly used COM component, a client machine could end up with several interop assemblies that differ only in the details of who has produced them. This situation not only clutters machines with multiple copies of functionally identical code, it can also introduce problems. Consider the following scenario:
Two independently developed .NET applications (MyApp and YourApp) both make use of the same COM component and have generated their own interop assemblies. This shared COM component exposes the IComp interface.
MyApp exposes a method that needs to be passed an IComp reference. If YourApp calls the method, it will pass a reference to its own interop assembly. And this is where the problem rears its head: the two interop assemblies are signed with different keysone for MyApp and one for YourAppso .NET regards them as completely different entities. The fact that they are functionally equivalent makes no difference: MyApp will not be happy to be passed a reference to an interop assembly signed by YourApp.
A primary interop assembly (PIA) is a unique, master interop assembly that represents a COM component. Only the publisher of a type library can produce an official PIA, so vendors will use this mechanism to distribute interop assemblies that represent their COM types. It is important that only one primary interop assembly is produced for each COM type and that version numbering is strictly enforced. Otherwise, incompatibilities might be introduced. Note that the names and marshaling behavior of PIAs arent required to exactly match that of the underlying COM object, so they can be changed to make interoperation work more efficiently .
PIAs must fulfill certain requirements:
They must include all the COM types defined in the original COM library and maintain the same GUIDs.
They must be signed with a strong name .
They must use the PrimaryInteropAssembly attribute.
They must avoid redefining external COM types.
They can only reference external COM types that are themselves represented by a PIA.
Because they are designed to be used by all clients on a machine, PIAs will normally be installed in the Global Assembly Cache (GAC).
You should always use the primary interop assembly provided by the supplier of a COM component, if one is available, rather than producing your own interop assemblies.