Cottleston Pie

Fernando Felman’s thoughts on software development

Archive for the ‘vs2003’ Category

Microsoft Visual Studio 2003 uses the .Net 1.1

HOW TO: Check the Type of a COM Object (System.__ComObject) with Visual C# .NET

Posted by Fernando Felman on February 5, 2008

This one is a favourite of mine since I tried to resolve it in the past with no success.

The problem at hand is that we have a COM object o returned from Excel interop and we have to figure out what underlying interface it implements. If you try to use GetType() you’ll get a __ComObject which does not provide any helpful information as to what underlying types are implemented by the object.

The following KB article sheds some light: The suggested way in the article is to manually cast the object to any known type using the as directive and if a valid object is returned – that type is implemented by the object. This solution will work, but it’s utterly ugly and requires vast amounts of typing in order to support all the possible types. I needed to implement something similar without using manual casting, essentially I needed a method that receives a COM object (of the type __ComObject, assuming it was created by the Excel interop) and returns the underlying interface supported by that object.

First I thought to somehow ask the object to provide me with a list of implemented interfaces. Something like the System.Type.GetInterfaces method. The problem is that the type of the object does not expose any useful information and the object itself has no typed class, so that proved to be futile.

Then I thought that instead of getting the implemented types from the object, I can query all the existing types one by one. Sure, it’s not as pretty as the previous path but that’s actually how COM works by design. Every COM class implements the IUknown interface which supports the QueryInterface method used to get a pointer to where an interface is implemented in the class. The idea is that all the information about what methods are supported by the interfaces and what interfaces are implemented by a type should be acquired in advance and coded into the caller (IDL, TLB and h files comes in mind). There was no true run-time reflection in the old COM days.

.NET supports COM by means of interoperability proxies. I won’t get into too many details, but basically you get .NET objects typed as __ComObject mapping COM instances and .NET interfaces with some unique attributes mapping COM interfaces. More to the point, you get the System.Runtime.InteropServices.Marshal class to handle all bunch of COM and interop operations such as calling the QueryInterface method on a .NET object mapped to a COM instance.

So now we know that we can query interop interfaces against the object. Sweet. But in order to do that we need the Interface ID, or iid, which is the GUID identifying an interface in COM. Oh, and we need that for each end every COM interface implemented by the Excel interop. Not sweet. OK, but we’re in .NET world now (thanks to the System.Runtime.InteropServices namespace) which has great support for runtime reflection. How difficult would it be to enumerate all the COM interfaces implemented by the Excel interop? Not too difficult really, we can use the System.Reflection.Assembly class to get a handler to the Excel interop assembly and from there it’s relatively easy going.

So let’s conclude what we need:

  1. Get all the COM interface types exposed by the Excel interop assembly.
  2. Fetch the Interface ID of each type and use it on QueryInterface to test whether an interface is implemented by the object (if a valid pointer is returned, the interface is implemented by the object).

This doesn’t sound too complicated. Obviously there are some syntax and plumbing issues to address, but the concept is rather simple. Good, let’s implement it:

GetExcelTypeForComObject method

using Excel = Microsoft.Office.Interop.Excel;
using interop = System.Runtime.InteropServices;

Note that in many cases a wrapped COM object implements many interfaces, so breaking after the first implemented interface is found might not do it for you…

Posted in .Net v2, Samples, vs2003, VS2005 | 20 Comments »