A COM object identifiesall of the interfaces, methods, and code that are exposed to outside code through the use of a type library. In order to use a COM object from within the .NET Framework, you need access to the type library so that the framework can create an appropriate wrapper around the COM object itself.
This wrapper is called a Runtime Callable Wrapper. These wrapper objects serve as proxies between the actual COM object and the C# client code. When you make a call on the wrapper, the call is to purely managed code and you send standard managed parameters like System.String, System.Int32, and so on. The wrapper then takes care of the marshaling of data between your managed code and the COM object and back again in order to process the results.
When you add a reference from within your project in Visual Studio 2005, a tab appears in the Add Reference dialog called COM, as shown in Figure 13.1.
Figure 13.1. The COM tab in the Add Reference dialog.
When you add a reference to a COM object, Visual Studio will extract the type library and then create a pure managed class that interfaces directly with the COM code. This enables you to be insulated from the painful and repetitive details of things like reference counting and querying the interface list. You don't even really need to know what a vtable is to consume COM code from C#.
If you don't use Visual Studio to create the Runtime Callable Wrapper (RCW) around the intended COM object, you can use a command-line tool to exert more fine-grained control over the creation of the type library. This tool is called TLBIMP.EXE, and it is part of the .NET Framework SDK.
TLBIMP allows you to specify the namespace of the COM objects contained within the type library, as well as to indicate things like the output filename, the strong-name key pair with which to sign the wrapper Assembly, and whether or not the Assembly will be a Primary InterOp Assembly (discussed in the next section).
The following is an example that takes the Microsoft Fax control from a COM type library and imports it into a DLL called Microsoft.Fax.dll:
tlbimp fxsocm.dll /namespace:Microsoft.Fax /out:Microsoft.Fax.dll
For a complete list of all the options available in the TLBIMP tool, consult the .NET Framework SDK, or you can simply type TLBIMP in your Visual Studio Command Prompt with no arguments and the list of all options will be displayed.
Using Primary InterOp Assemblies
When consuming a vendor's COM objects, they will often have created Primary InterOp Assemblies. What this means is that the vendor has already done the work of creating the wrapper around the type library, and could possibly have done some extra work to make the library easier to use such as defining custom marshaling rules, and so on. When using a Primary InterOp Assembly (PIA), you reference the PIA the same way you would reference any other managed assembly (for example, you either browse to the file or you find it in the .NET tab of your Add Reference dialog).
Typically, a component or application vendor will install the PIAs when the application is installed to allow developers immediate access to the exposed components whether they're using COM or .NET. For example, when you install Microsoft Office 2003, you can include the .NET Programmability option for each of the Office products like Microsoft Word or Microsoft Outlook.
To create an application that consumes a PIA (or any other COM object, for that matter), first create your project. In this case, we'll be creating a console application because we haven't covered working with Windows Forms yet.
After you've created your project, right-click the project, choose References, and then add a reference. The Primary InterOp Assemblies for Microsoft Office are located in the Global Assembly Cache. You cannot reference Assemblies directly from the GAC; instead you have to reference them from their home directories and the system will use the GAC Assembly at runtime. The same is true for the PIAs.
In the COM tab, browse all the way down to the Microsoft Word 11.0 Type Library (assuming you have Office 2003 installed on your PC). Select it and click OK to add the reference to your application.
If there is a PIA for that type library in the GAC, Visual Studio will automatically reference that PIA and will not generate its own private Runtime Callable Wrapper Assembly. Because there is a PIA for Word, the reference in your application is a PIA reference to the assembly in the GAC. You can prove this by hovering the mouse over the Path property in the Word reference. You will see that it's pointing to a path beneath the \windows\Assembly directory, which is where all of the GAC Assemblies are stored.
When you have a reference to Microsoft Word, you can feel free to use the Word object model to manipulate Word documents, as shown in Listing 13.1.
Listing 13.1. Creating a Word Document Using a COM PIA
When you run the preceding application, assuming Office 2003 is installed properly, you will get a Word document like the one shown in Figure 13.2.
Figure 13.2. Word document created via COM InterOp.
What you might notice from the preceding sample is that there are a lot of object references and very little strong typing. This kind of code is typical of COM programming where the original COM API wasn't strictly typed and used a lot of open object references.
The idea behind this sample is that the mechanics of creating the Runtime Callable Wrapper around a COM type library aren't the difficult part: the difficult part is using the code exposed by the COM object to begin with.