C Sharp

Early Binding to COM Components

Now that we've generated the metadata that's required by a .NET client, let's try invoking the GetAirlineTiming method in our COM object from the .NET client. Here's a C# client application that creates the COM object by using the metadata we generated earlier and invokes the GetAirlineTiming method. Note that in this example we're using early binding. Shortly, I'll show you two more examples that will illustrate dynamic type discovery and late binding.

using System;
using System.Runtime.InteropServices;
using System.Reflection;
using AIRLINEINFORMATIONLib;
public class AirlineClient1App
{
    public static void Main()
    {
        ///////////////////////////////////////////////
        /// EARLY BINDING EXAMPLE
        ///////////////////////////////////////////////
        String strAirline = "Air Scooby IC 5678";
        String strFoodJunkieAirline = "Air Jughead TX 1234";
        try
        {
            AirlineInfo objAirlineInfo;
            // Create a new AirlineInfo Object.
            objAirlineInfo = new AirlineInfo();
            // Display the output after calling
            // the GetAirileTiming method.
            Console.WriteLine("Details for Airline {0} --> {1}",
            strAirline,objAirlineInfo.GetAirlineTiming(strAirline));
            // ERROR: The following will result in a thrown
            // exception!
            // Console.WriteLine("Details for Airline {0} --> {1}",
            // strFoodJunkieAirline,objAirlineInfo.GetAirlineTiming
            // (strFoodJunkieAirline));
        }
        catch(COMException e)
        {
            Console.WriteLine("Oops- We encountered an error " +
                              "for Airline {0}. The Error message " +
                              "is : {1}. The  Error code is {2}",
                              strFoodJunkieAirline ,
                              e.Message,e.ErrorCode);
        }
    }
}

What's happening here is that the runtime is fabricating an RCW that maps the metadata class methods and fields to methods and properties exposed by the interface that the COM object implements. One RCW instance is created for each instance of the COM object. The .NET runtime is concerned only with managing the lifetime of the RCW and garbage collects the RCW. It's the RCW that takes care of maintaining reference counts on the COM object that it's mapped to, thereby shielding the .NET runtime from managing the reference counts on the actual COM object. As shown in Figure 17-2, the AirlineInfometadata is defined under a namespace called AIRLINEINFORMATIONLib. The .NET client sees all the interface methods as if they were class members of the AirlineInfo class. All we need to do is create an instance of the AirlineInfo class by using the new operator and call the public class methods of the created object. When the method is invoked, the RCW thunksdown the call to the corresponding COM method call. The RCW also handles all the marshalling and object lifetime issues. To the .NET client, it looks like nothing more than creating a typical managed object and calling one of its public class members! -

Notice that any time the COM method raises an error, the COM error is trapped by the RCW. This error is then converted into an equivalent COMException class (found in the System.Runtime.InteropServices namespace). Of course, the COM object still needs to implement the ISupportErrorInfo interface for this errorpropagation to work and so that the RCW knows that your object provides extended error information. The error can be caught by the .NET client with the usual try-catch exception handling mechanism, and the client has access to the error number, description, the source of the exception, and other details that would have been available to any COM-aware client. Now let's take this example a bit further and look at some other means of binding to COM components.