【问题标题】:Implementing IDispatch in c#在 C# 中实现 IDispatch
【发布时间】:2011-12-25 13:07:55
【问题描述】:

我正在编写一些测试代码来模拟调用我的后期绑定 COM 对象的 c# 实现的非托管代码。我有一个声明为 IDispatch 类型的接口,如下所示。

 [Guid("2D570F11-4BD8-40e7-BF14-38772063AAF0")]
 [InterfaceType(ComInterfaceType.InterfaceIsDual)]
 public interface TestInterface
 {
     int Test();
 }

 [ClassInterface(ClassInterfaceType.AutoDual)]
 public class TestImpl : TestInterface 
 {
 ...
 }

当我使用下面的代码调用 IDispatch 的 GetIDsOfNames 函数时

  ..
  //code provided by Hans Passant
  Object so = Activator.CreateInstance(Type.GetTypeFromProgID("ProgID.Test"));
  string[] rgsNames = new string[1];
  int[] rgDispId = new int[1];
  rgsNames[0] = "Test";

  //the next line throws an exception
  IDispatch disp = (IDispatch)so;

IDispatch 定义为:

 //code provided by Hans Passant
 [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);
  }

抛出 InvalidCastException。是否可以将 c# 接口转换为 IDispatch?

【问题讨论】:

  • 只有在 C# 接口实际上是从 IDispatch 派生的情况下才能成功,而从您提供的代码 n-ps 不是这种情况...
  • @Yahia - 谢谢。如果使用实现 IDispatch 的非托管 COM 对象的 ProgID,我不确定为什么相同的 cast sn-p 会成功?
  • 因为 COM 对象实际上是从 IDispatch 派生的 - 如果 .NET 运行时看到您访问托管 COM 对象(尤其是如果它使用相同的运行时版本)
  • 好的,但这不是 [InterfaceType(ComInterfaceType.InterfaceIsDual)] 的重点,它“指示接口作为双接口向 COM 公开,它启用了早期和后期绑定。”
  • 是的,但同样:IIRC .NET 运行时在使用托管代码中的托管 COM 对象时表现不同...为什么不用非托管代码模拟 COM 对象?

标签: c# com idispatch


【解决方案1】:

您需要使用 regasm 注册您的程序集,并且您需要使用 [ComVisible] 属性标记要从 COM 访问的类。您可能还需要使用 tlbexp(生成)和 tregsvr 来生成和注册类型库来注册它。

另外(从 Win32 的角度来看)“disp = (IDispatch) obj”与“disp = obj as IDispatch”不同 - 使用 'as' 运算符实际上调用对象上的 QueryInterface 方法来获取指向的指针请求的接口,而不是尝试将对象强制转换为接口。

最后,使用 c# 的“动态”类型可能更接近其他人访问您的课程的做法。

【讨论】:

    【解决方案2】:

    您应该能够在 COM 类型上使用反射来获取方法列表。

    Type comType = Type.GetTypeFromProgID("ProgID.Test");
    MethodInfo[] methods = comType.GetMethods();
    

    【讨论】:

    • 感谢您的提示,不幸的是,代码是从 3rd 方库调用的,他们调用 GetIDsOfNames。如果可能的话,我试图在托管代码中实现它。
    猜你喜欢
    • 2013-11-29
    • 2012-06-13
    • 2013-10-15
    • 2022-01-14
    • 2021-04-12
    • 2010-12-31
    • 2011-11-28
    • 2011-05-05
    • 1970-01-01
    相关资源
    最近更新 更多