gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 22:04:18 25 4
gpt4 key购买 nike

我通过 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 为空。谁能帮帮我?

最佳答案

我刚刚发表了一篇关于如何做 Reflection with IDispatch-based COM objects 的 CodeProject 文章.本文提供了一个小型 C# DispatchUtility 帮助程序类,可以轻松将其包含在其他项目中。在内部,它使用 IDispatch 的自定义声明和 .NET 的 TypeToTypeInfoMarshaler 将 IDispatch 的 ITypeInfo 转换为丰富的 .NET Type 实例。

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

FWIW,DispatchUtility 的 IDispatch.GetTypeInfo 声明与您的声明几乎相同。但是,调用 GetTypeInfo 时,它会为 lcid 参数传入 LOCALE_SYSTEM_DEFAULT (2048) 而不是 0。也许 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>(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.
}
}

关于c# - C#中如何枚举COM对象的成员?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4159843/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com