C Sharp

Generating Metadata from a COM typelib

A .NET application that needs to talk to our COM component cannot directly consume the functionality that's exposed by that component. Why not? As we saw in Chapter 16, "Querying Metadata with Reflection," the .NET runtime is designed to work with components that have metadata, whereas COM is designed to work through the Registry and a series of interrogatory methods that are implemented by the component. Therefore, the first thing we need to do to enable this COM component to be used in the .NET world is generate some metadata for it. In the case of a COM component, this metadata layer is used by the runtime to determine type information. This type information is then used at run time to manufacture what's called a runtime callable wrapper (RCW). (See Figure 17-1.) The RCW handles the actual activation of the COM object and handles the marshalling requirements when the .NET application interacts with it. The RCW also does tons of other chores, such as managing object identity, object lifetimes, and interface caching.


Figure 17-1 The basic components of .NET COM interoperability.-

Object lifetime management is a critical issue because the .NET GC moves objects around and automatically disposes of them when they're no longer in use. The RCW serves the purpose of giving the .NET application the notion that it's interacting with a managed .NET component, and it gives the COM component in the unmanaged space the impression that it's being called by a traditional COM client. The RCW's creation and behavior varies depending on whether you're early binding or late binding to the COM object. Under the hood, the RCW is doing all the hard work and thunking down all the method invocations into corresponding vtable calls into the COM component that lives in the unmanaged world. It basically acts as an ambassador of goodwill between the managed world and the unmanaged IUnknown world.

Enough talk! Let's generate the metadata wrapper for our AirlineInfo COM component. To do that, we need to use a tool called the Type Library Importer ( tlbimp.exe). This utility ships with the .NET SDK and is used to read a COM typelib and to generate the corresponding metadata wrapper containing type information that the .NET runtime can comprehend. To do this, you'll need to install the demo applications from the companion CD and locate the AirlineInfo component.

Once you've done that, type the following at a command prompt: -

TLBIMP AirlineInformation.tlb /out:AirlineMetadata.dll

This command tells the TLBIMP to read the AirlineInfo COM typelib and to generate a corresponding metadata wrapper called AirlineMetadata.dll. If everything works as it should, you'll see the following message: -

TypeLib imported successfully to AirlineMetadata.dll

So, what kind of type information does this generated metadata contain, and what does it look like? As COM folks, we have always treasured our beloved OleView.exe utility because of-among other things-its ability to allow us to take a peek at the contents of a typelib. Fortunately, the .NET SDK ships with something similar: the IL disassembler named ILDASM-introduced in Chapter 2, "Introducing Microsoft .NET"-which allows us to view the metadata and the MSIL code that has been generated for managed assemblies. As you learned in Chapter 16, every managed assembly contains self-describing metadata, and ILDASM is a very useful tool when you need to spelunk that metadata. Go ahead and open AirlineMetadata.dll using ILDASM. You should see results similar to those shown in Figure 17-2.


Figure 17-2 ILDASM is a great tool for viewing metadata and MSIL for managed assemblies.-

From the metadata generated, you can see that the GetAirlineTiming method is listed as a public member for the AirlineInfo class. There is also a constructor that is generated for the AirlineInfo class. Notice that the method parameters have automatically been substituted to take their equivalent .NET counterparts. In this example, the BSTR has been replaced by the System.String parameter. Also notice that the parameter that was marked [out,retval] in the GetAirlineTiming method was converted to the actual return value of the method (returned as System.String). In addition, any failure HRESULT values that are returned back from the COM object-in case of an error or failed business logic-are raised as exceptions.