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: http://support.microsoft.com/kb/320523. 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:
- Get all the COM interface types exposed by the Excel interop assembly.
- 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:
Namespaces:
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…


Andrew Roberts said
Excellent.
I want to be able to access properties of the particular type found. e.g.
object oSelect = ExcelApp.Selection;
Type type = GetExcelTypeForComObject(oSelect);
//say that the type returned is Microsoft.Office.Interop.Excel.Arc
//Arc has a ShapeRange property
//how do I do this line??
Excel.ShapeRange shapeRange =(oSelect as type).ShapeRange
Regards
Andrew
Fernando Felman said
Hi Andrew,
if my method found that the underlying type is an Arc, then the following static casting should work:
Excel.ShapeRange shapeRange = (oSelect as Microsoft.Office.Interop.Excel.Arc).ShapeRangeOn the other hand, if you want to dynamically cast oSelect based on the returned type, you’ll have to use reflection.
Cheers,
Fernando
Elmue said
Hello
Thanks, your article helped me a lot.
I still have a problem.
I’m trying to set properties of a PowePoint Table Cell.
In C# this looks like:
Cell.Borders[PpBorderType.ppBorderTop].DashStyle = MsoLineDashStyle.msoLineDash;
But I want to be able to set ANY property of ANY ComObject 100% dynamically using information from a XML file.
Is there any why to find out WHICH enumeration type uses the Borders[] collection ?
It would be great if the was something like
Type GetEnumerationType(Type i_ComObject)
{
…
}
so that calling
GetEnumerationType(typeof(Borders))
would return
PpBorderType
There MUST be any way because Visual Studio complains if I put any invalid enumeration type like:
Cell.Borders[MsoTextOrientation.msoTextOrientationHorizontal]…
So this information exists in the typelib.
But how di I get it ?
Any idea ?
Thanks
Elmü
Elmue said
Hello
There is something missing in your code:
Marshal.Release(ipointer);
..
Marshal.Release(iunkwn);
Elmue said
Hello
I found out how to do it!
Your solution with a loop searching among all interfaces of a namespace
and cheking the result of QueryInterface() is extremely slow.
I found a much better solution which is as fast as normal reflection and also 100% dynamic.
If you came here because you are searching for a way to use Reflection on COM objects,
download my OpenSource project PowerPointCreator version 3.0.
http://www.codeproject.com/KB/office/PowerPointCreator.aspx?msg=2708475#xx2708475xx
There you see how to do it!
I also solved the problem I asked yesterday here.
Elmü
Fernando Felman said
Elmue,
I’m happy you found a solution to your question however I couldn’t find the “much better solution which is as fast as normal reflection” to get the underlying COM Interfaces implemented by any .NET interop object. By reviewing your source code I could only see XML manipulation but no COM or .NET interop manipulations. Could you please post here a short snippet of how to do so without the usage of the “extremly slow” loop I’m using in this article?
Cheers,
Fernando
Michael said
I gave up and wrote the code in VB.NET as a class library since you don’t need to worry about reflection in VB.NET and then used that in my C# project.
Michael said
My suggestion of using VB.NET works for about half the properties that were being reflected as __ComObject but unfortunately there are a number that don’t work so finished up using your get type method. Thanks for posting it.
Bjørn Egil Hansen said
Hi Fernando,
Thanks for useful information pointing me in the right direction.
In my case, I was looking at how to make a generic .NET utility for copying a specified set of properties between two objects in SAP Business One DI API (COM library wrapped with COM Interop). Using GetType directly, I got the same problems as described above – just System.__ComObject with no useful information (for this purpose). Looking up the desired type in the assembly, I get all the meta-information, including the PropertyInfo’s for getting and setting property values.
Rather than iterating all types in the assembly, I lookup the desired type directly and use this for manipulating the object. See code example below:
SAPbobsCOM.Items item =
(SAPbobsCOM.Items)sapCompany.GetBusinessObject(SAPbobsCOM.BoObjectTypes.oItems);
System.Reflection.Assembly sapAssembly =
System.Reflection.Assembly.GetAssembly(typeof (SAPbobsCOM.CompanyClass));
Type itemType = sapAssembly.GetType("SAPbobsCOM.IItems");
PropertyInfo propInfo = itemType.GetProperty("ItemCode");
object value = propInfo.GetValue(item, null);
Cheers,
Bjørn Egil
Alan Churchill said
This saved my bacon after I thought I was at a wall.
Thanks much.
Alan
Mark W. Schumann said
Neat slice of code. Thanks!