如何获取 COM 对象的类型

Posted

技术标签:

【中文标题】如何获取 COM 对象的类型【英文标题】:How to get type of COM object 【发布时间】:2010-11-28 14:38:23 【问题描述】:

我在 Visual Studio 中引用了一个 COM 库,因此它已自动为我创建了相应的 Interop 程序集。我想对这些 com 对象执行GetType(),但它们总是返回System.__ComObject。不过,查询它们的接口是可行的:

bool isOfType = someComeObject is ISomeComObject; //this works

但我真正想要的是返回 com 对象的实际类型:

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

有人知道我想做的事怎么做吗?

【问题讨论】:

【参考方案1】:

添加对Microsoft.VisualBasic.dll的引用,然后:

Microsoft.VisualBasic.Information.TypeName(someCOMObject)

MSDN 参考here。

【讨论】:

我刚试过这个,它有效!虽然它不返回全名,只返回类名,但这对于我的目的来说是可以的。我在内部调用“LegacyTypeNameOfCOMObject”的反射器中查看了这个方法,但我不知道它实际上做了什么。 我希望有什么东西可以给我该 com 对象的全名以避免冲突。 Microsoft.VisualBasic.dll 是一个 .NET 程序集,可以在每个应用程序中引用和使用。 注意您是否有用 C++/ATL 编写的 COM 组件。您可能会得到与预期不同的结果。 正是我想要的。谢谢!【参考方案2】:

Darin 接受的答案需要依赖于 Microsoft.VisualBasic.dll。如果你不想这样,你可以使用这个简单的帮助类:

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);
    

【讨论】:

这似乎也有效 - 只需要确保 System.Runtime.InteropServices.ComTypes 引用 ITypeInfo(Visual Studio IDE 自动建议 Microsoft.VisualStudio.OLE.Interop.ITypeInfo,但这是 不是你想要的!) 有什么办法可以用这个来获取COM对象的库吗?我有一个来自 Word 对象模型的对象,TypeName 为其返回 Shape,但我无法将其转换为 Word.Shape source in VBA。【参考方案3】:

你基本上已经明白了。 COM 对象上的 GetType() 将为您提供 System.__ComObject,您必须尝试将其强制转换为其他对象才能查看该对象的真正含义。

【讨论】:

嗯..真的没有别的办法了吗?因为我无法测试现有的每个可能的 COM 对象,所以我只想要类型。原因是我使用对象的类型作为字典中的键... Darin Dimitrov 的解决方案很棒。【参考方案4】:

几天前我在寻找System.__ComObject 对象的完整类型名称时偶然发现了这个问题。我最终使用 Darin 的解决方案获得了类型名称,然后遍历所有程序集中的所有类以测试匹配:

    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;
        
    

不是最快和最优雅的解决方案,但它确实有效。

【讨论】:

someCOMObject as type?不确定这是否可行。 因为没有。 @nawfal:为什么不呢?它试图将“someCOMObject”转换为“type”类型。如果它失败(并且只有那时),则结果为空。如果没有,那么它找到了正确的类型。 (我知道,我花了几天时间才得出这个答案:-P) @pwhty type 不是代码中的类型/类,它是类型的实例。 as 关键字适用于 type

以上是关于如何获取 COM 对象的类型的主要内容,如果未能解决你的问题,请参考以下文章

如何获取对象的完整类型名称

如何获取模型的名称或 Django 对象的内容类型?

如何从猫鼬中获取类型化的对象

java 获取对象的数据类型的方法

如何从特征对象中获取对具体类型的引用?

如何从 .net 中的数组类型获取数组项类型