34

I am referencing a COM library in Visual Studio, so it has automatically created the corresponding Interop assembly for me. I would like to do a GetType() on these com objects, but they always return System.__ComObject. Querying them for an interface works though:

bool isOfType = someComeObject is ISomeComObject; //this works

But what I really want is this to return the actual type of the com object:

Type type = someComeObject.GetType(); //returns System.__ComObject :-(

Does anyone know how to do what I want to do?

4 Answers 4

64

Add reference to Microsoft.VisualBasic.dll and then:

Microsoft.VisualBasic.Information.TypeName(someCOMObject)

MSDN reference here.

Sign up to request clarification or add additional context in comments.

7 Comments

I just tried this and it works! It does not return the full name though, just the class name, but that's ok for my purposes. I looked at this method in reflector which internally calls 'LegacyTypeNameOfCOMObject' but I can't figure out what it actually does.
I wish there was something that could give me the full name of that com object to avoid clashes.
Microsoft.VisualBasic.dll is a .NET assembly which can be referenced and used in every application.
Watch out if you have COM component written in C++/ATL. You might get a different result than you expect.
As @rpattabi mentions, this doesn't always work. In my case, it just returns "_ComObject".
|
16

The accepted answer by Darin requires a dependency to Microsoft.VisualBasic.dll. If you don't want to have that you can use this simple helper class:

public static class TypeInformation
{
    public static string GetTypeName(object comObject)
    {
        var dispatch = comObject as IDispatch;

        if (dispatch == null)
        {
            return null;
        }

        var pTypeInfo = dispatch.GetTypeInfo(0, 1033);

        string pBstrName;
        string pBstrDocString;
        int pdwHelpContext;
        string pBstrHelpFile;
        pTypeInfo.GetDocumentation(
            -1, 
            out pBstrName, 
            out pBstrDocString, 
            out pdwHelpContext, 
            out pBstrHelpFile);

        string str = pBstrName;
        if (str[0] == 95)
        {
            // remove leading '_'
            str = str.Substring(1);
        }

        return str;
    }

    [ComImport]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [Guid("00020400-0000-0000-C000-000000000046")]
    private interface IDispatch
    {
        int GetTypeInfoCount();

        [return: MarshalAs(UnmanagedType.Interface)]
        ITypeInfo GetTypeInfo(
            [In, MarshalAs(UnmanagedType.U4)] int iTInfo,
            [In, MarshalAs(UnmanagedType.U4)] int lcid);

        void GetIDsOfNames(
            [In] ref Guid riid,
            [In, MarshalAs(UnmanagedType.LPArray)] string[] rgszNames,
            [In, MarshalAs(UnmanagedType.U4)] int cNames,
            [In, MarshalAs(UnmanagedType.U4)] int lcid,
            [Out, MarshalAs(UnmanagedType.LPArray)] int[] rgDispId);
    }
}

2 Comments

This seems to work too - just need to ensure there is a reference to System.Runtime.InteropServices.ComTypes for ITypeInfo (Visual Studio IDE auto-suggested Microsoft.VisualStudio.OLE.Interop.ITypeInfo, but this is not the one you want!)
Is there any way to use this to get the library of the COM object? I have an object from the Word object model for which TypeName returns Shape, but I cannot cast it to Word.Shape source in VBA.
0

You've basically figured it out. GetType() on a COM object is going to give you System.__ComObject, and you have to try to cast it to something else to see what the object really is.

2 Comments

Hm..is there really no other way? Because I can't test for every possible COM object in existing, I just want the type. The reason is that I am using the type of an object as a key in a dictionary...
Darin Dimitrov's solution is great.
-3

I stumbled upon this question a few days ago while I was looking for the full type name of a System.__ComObject object. I ended up getting the type name using Darin's solution and then looping through all classes in all assemblies to test the match:

    typeName = Microsoft.VisualBasic.Information.TypeName(someCOMObject);
    foreach (System.Reflection.Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
    { 
        foreach (Type type in assembly.GetTypes())
        {
            if ((someCOMObject as type)!=null)
                fullTypeName = type.FullName;
        }
    }

Not the fastest and most elegant solution, but it worked.

4 Comments

someCOMObject as type? Not sure if that would work.
Because it doesn't.
@nawfal: why not? It's trying to cast "someCOMObject" to the type "type". If it fails (and only then), the result is null. If it doesn't, then it found the correct type. (I know, it took me a few days to come up with that answer :-P)
@pwhty type is not a type/class in your code, it is an instance of a type. as keyword works on a type

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.