Today, I'll continue my discussion on how COM objects interact with the CLR type system by talking about consuming COM objects from managed code in a late bound fashion. Sorry there is no example code included in this one, but I'm in a hurry :)
As defined in my last post, late binding refers to access and use of a type that is not known at compile time. Note that there is a difference in compile-time late binding and late-bound method invocation. The former refers to knowledge of the type at compile time while the latter refers to how methods are invoked on an object at runtime. I'll cover both of these below.
How do I get an instance at runtime that represents a COM object?
First, I'll mention that if the metadata for a COM object is not available, the CLR will substitute the type with System.__ComObject, a generic type that provides no methods and acts as a representative for a non-strongly typed COM object.
1) You could use PInvoke to call into the IClassFactory for the object.
2) You could use Type.GetTypeFromCLSID to get a managed type object which represents the COM object's type. You could then activate an instance of this type with Activator.CreateInstance.
3) You could use Marshal.GetTypeForITypeInfo to get a managed type object which represents the COM object's type. This API is interesting in that it will automatically import the matching type library (if available) and create an IA on the fly. You will not get the generic System.__ComObject out of this API if the type library is available. Just as above, you can activate an instance of this type with Activator.CreateInstance.
4) You could receive an instance of a COM object as a return or out/ref parameter of another call to or from native code.
Now you have a runtime generated type. Depending on which API and method you used you will either have a strongly typed object or the generic System.__ComObject.
To call methods on this object, you'll end up having to cast the object to a real type, or use Type.InvokeMember since the compiler didn't know what type you were using when it emitted IL. For COM objects, Type.InvokeMember will marshal the arguments to their native versions, get the object's IDispatch interface, and call IDispatch::Invoke. This is the same path taken for strongly typed COM objects that only allow late-bound method invocation (in other words, for COM objects that don't supply a vtable and only allow calls via IDispatch).
VB actually calles Type.InvokeMember under the covers for you for late-bound types.
Any call that goes through IDispatch::Invoke indicates late-bound invocation on a COM object.Any call that goes through Type.InvokeMember indicates late-bound invocation on a managed object (which could be a RCW placeholder object in which case we'll end up going through IDispatch::Invoke).
Next time, I'll be covering calls from COM into the CLR...