【问题标题】:How to get type of COM object如何获取 COM 对象的类型
【发布时间】: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 :-(

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

【问题讨论】:

    标签: .net reflection com interop com-interop


    【解决方案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
    猜你喜欢
    • 2013-11-09
    • 2014-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-08
    • 1970-01-01
    • 1970-01-01
    • 2010-11-27
    相关资源
    最近更新 更多