如何在C#中枚举COM对象的成员?

我通过COM连接到某个程序并接收System .__ ComObject。 我知道它的几种方法,所以我可以这样做:

object result = obj.GetType().InvokeMember("SomeMethod", BindingFlags.InvokeMethod, null, obj, new object[] { "Some string" }); 

并且喜欢这个

 dynamic dyn = obj; dyn.SomeMethod("Some string"); 

两种方法都很好。 但是如何确定com对象的内部类型信息并通过其所有成员进行枚举?

我试过这个:

 [ComImport, Guid("00020400-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IDispatch { void Reserved(); [PreserveSig] int GetTypeInfo(uint nInfo, int lcid, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(TypeToTypeInfoMarshaler))] out System.Type typeInfo); } ... IDispatch disp = (IDispatch)obj; Type t; disp.GetTypeInfo(0, 0, out t); 

但是t最后是空的。 谁能帮我?

您无法获得COM对象的类型。 这将需要您为COM组件创建互操作库。 如果COM服务器具有类型库,只需添加对它的引用或运行Tlbimp.exe实用程序,这当然是一个低难点。 如果它存在,那么类型库通常嵌入在DLL中。 当你得到它时,编辑器和对象浏览器都可以更加智能地了解COM类上可用的方法和属性。

看到IDispatch强制转换工作,很可能也可以使用类型库。 COM服务器作者创建一个是非常简单的。 您可以用来查看类型库的另一个工具是OleView.exe,View + Typelib。

如果这不起作用,那么你确实可以从IDispatch中挖出东西。 您的声明看起来很可疑,IDispatch :: GetTypeInfo的第三个参数是ITypeInfo,一个COM接口。 无需自定义编组程序,System.Runtime.InteropServices.ComTypes命名空间中提供了ITypeInfo。 您可以使用Reflector从框架代码中挖掘出IDispatch声明。

当然,没有什么可以替代体面的文档。 当您获得使用此组件的许可时,您应该能够获得一些。

我刚刚发布了一篇关于如何使用基于IDispatch的COM对象进行reflection的CodeProject文章。 本文提供了一个小型的C# DispatchUtility助手类,它很容易包含在其他项目中。 在内部,它使用IDispatch和.NET的TypeToTypeInfoMarshaler的自定义声明将IDispatch的ITypeInfo转换为丰富的.NET Type实例。

在您的示例中,您可以调用DispatchUtility.GetType(obj, true)来获取.NET Type实例,然后可以在其上调用GetMembers。

FWIW, DispatchUtility的IDispatch.GetTypeInfo声明几乎与您的相同。 但是,在调用GetTypeInfo时,它会传入LOCALE_SYSTEM_DEFAULT(2048)而不是0来传递lcid参数。 也许GetTypeInfo为您的disp.GetTypeInfo(0, 0, out t)调用返回了一个失败的HRESULT。 由于您使用[PreserveSig]声明了它,因此您需要检查其结果(例如,通过调用Marshal.ThrowExceptionForHR )。

这是DispatchUtility类的一个版本,删除了大多数注释:

 using System; using System.Runtime.InteropServices; using System.Reflection; public static class DispatchUtility { private const int S_OK = 0; //From WinError.h private const int LOCALE_SYSTEM_DEFAULT = 2 << 10; //From WinNT.h == 2048 == 0x800 public static bool ImplementsIDispatch(object obj) { bool result = obj is IDispatchInfo; return result; } public static Type GetType(object obj, bool throwIfNotFound) { RequireReference(obj, "obj"); Type result = GetType((IDispatchInfo)obj, throwIfNotFound); return result; } public static bool TryGetDispId(object obj, string name, out int dispId) { RequireReference(obj, "obj"); bool result = TryGetDispId((IDispatchInfo)obj, name, out dispId); return result; } public static object Invoke(object obj, int dispId, object[] args) { string memberName = "[DispId=" + dispId + "]"; object result = Invoke(obj, memberName, args); return result; } public static object Invoke(object obj, string memberName, object[] args) { RequireReference(obj, "obj"); Type type = obj.GetType(); object result = type.InvokeMember(memberName, BindingFlags.InvokeMethod | BindingFlags.GetProperty, null, obj, args, null); return result; } private static void RequireReference(T value, string name) where T : class { if (value == null) { throw new ArgumentNullException(name); } } private static Type GetType(IDispatchInfo dispatch, bool throwIfNotFound) { RequireReference(dispatch, "dispatch"); Type result = null; int typeInfoCount; int hr = dispatch.GetTypeInfoCount(out typeInfoCount); if (hr == S_OK && typeInfoCount > 0) { dispatch.GetTypeInfo(0, LOCALE_SYSTEM_DEFAULT, out result); } if (result == null && throwIfNotFound) { // If the GetTypeInfoCount called failed, throw an exception for that. Marshal.ThrowExceptionForHR(hr); // Otherwise, throw the same exception that Type.GetType would throw. throw new TypeLoadException(); } return result; } private static bool TryGetDispId(IDispatchInfo dispatch, string name, out int dispId) { RequireReference(dispatch, "dispatch"); RequireReference(name, "name"); bool result = false; Guid iidNull = Guid.Empty; int hr = dispatch.GetDispId(ref iidNull, ref name, 1, LOCALE_SYSTEM_DEFAULT, out dispId); const int DISP_E_UNKNOWNNAME = unchecked((int)0x80020006); //From WinError.h const int DISPID_UNKNOWN = -1; //From OAIdl.idl if (hr == S_OK) { result = true; } else if (hr == DISP_E_UNKNOWNNAME && dispId == DISPID_UNKNOWN) { result = false; } else { Marshal.ThrowExceptionForHR(hr); } return result; } [ComImport] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [Guid("00020400-0000-0000-C000-000000000046")] private interface IDispatchInfo { [PreserveSig] int GetTypeInfoCount(out int typeInfoCount); void GetTypeInfo(int typeInfoIndex, int lcid, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(System.Runtime.InteropServices.CustomMarshalers.TypeToTypeInfoMarshaler))] out Type typeInfo); [PreserveSig] int GetDispId(ref Guid riid, ref string name, int nameCount, int lcid, out int dispId); // NOTE: The real IDispatch also has an Invoke method next, but we don't need it. } } 

您可以使用: http : //www.nektra.com/products/deviare-api-hook-windows/

它有一个完整的API作为COM对象提供,可用于获取所有已注册COM对象的信息和function并拦截它们。