C Sharp

Late Binding to COM Components

The two demos that you've seen so far-AirlineClient1App and AirlineClient2App-both use the RCW metadata to early bindthe .NET client to the COM object. Although early bindingprovides a whole smorgasbord of benefits-such as strong type checking at compile time, autocompletion capabilities from type information for development tools (such as Visual Studio.NET), and, of course, better performance-there might be instances when you don't have the compile-time metadata for the COM object that you're binding to and, therefore, you need to late bind to the component. For example, if the component you're attempting to use contains only a dispinterface, you are very much limited to late binding to use the component.

You can achieve late bindingto a COM object through the reflection mechanism that you learned about in Chapter 16. To bind in this fashion to a COM component, you'll need to know the component's ProgID. This is because the static CreateInstance method of the System.Activator class requires a Type object. However, using the component's ProgID, you can call the System.Type class's GetTypeFromProgID method. This will return a valid .NET Type object that you can then use in the call to the System.Activator.CreateInstance method. Once you've done that, you can invoke any of the methods or properties supported by the component's default interface by using the System.Type.InvokeMember instance method of the Type object that you got back from GetTypeFromProgID.

All you need to know is the name of the method or property and the parameter information that the method call accepts. When you call a method of a late bound component, the way you pass parameters is by bundling them into a generic System.Object array and passing it to the method. You also need to set the appropriate binding flags depending on whether you're invoking a method or getting/setting the value of a property.

As you can see in the following code, there's a bit more work to do than with early binding. However, in cases where late bindingis the only option, you're very glad to have it.

using System;
using System.Runtime.InteropServices;
using System.Reflection;
using AIRLINEINFORMATIONLib;
public class AirlineClient3App
{
    public static void Main()
    {
        ///////////////////////////////////////////////
        /// LATE BINDING
        ///////////////////////////////////////////////
        try
        {
           object objAirlineLateBound;
           Type objTypeAirline;
           object[] arrayInputParams= { "Air Scooby IC 5678" };
           objTypeAirline = Type.GetTypeFromProgID
                   ("AirlineInformation.AirlineInfo");
           objAirlineLateBound = Activator.CreateInstance
                                    (objTypeAirline);
           String str = (String)objTypeAirline.InvokeMember
                                   ("GetAirlineTiming",
                                   BindingFlags.Default |
                                   BindingFlags.InvokeMethod,
                                   null, objAirlineLateBound,
                                   arrayInputParams);
            Console.WriteLine("{0}",str);
            String strTime = (String)objTypeAirline.InvokeMember
                                       ("LocalTimeAtOrlando",
                                       BindingFlags.Default |
                                       BindingFlags.GetProperty,
                                       null, objAirlineLateBound,
                                       new object [] {});
            Console.WriteLine ("Hi there !. The Local Time in " +
                               "Orlando,Florida is: {0}", strTime);
        }
        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);
        }
    }
}