带有动态接口的C#COM对象

时间:2013-09-27 16:43:20

标签: c# .net com idispatch

我想构建一个 COM可见 C#类,比如DynamicComponent,它将通过COM提供动态界面

在这个类中,这个类将维护一个代表字典:

"GetTheAnswer" -> () => { return 42; }
"Add" -> (int a, int b) => { return a + b; }
...

客户端代码将是一些VBA。

这是我天真想象的工作流程:

  • 从Excel / VBA编辑器中,用户引用 TLB
  • 用户实例化一个新的DynamicComponent(至少得到Excel / VBA提供的存根)
  • Excel / VBA COM基础架构通过其 IDispatch 接口
  • 查询组件
  • 组件使用像["GetTheAnswer" -> 1, "Add" -> 2]
  • 这样的disp-id地图进行回答
  • 用户可以从自动完成中受益,并看到两种方法:GetTheAnswerAdd
  • 用户调用任何这些方法,就好像它是静态定义的

我的第一个问题:是否可能

如果不是:为什么

如果是:如何

根据我对COM的了解,如果可能, IDispatch COM界面是我最好的朋友。

此外,根据我的理解,.Net 4的 ICustomQueryInterface 界面也可以提供很大帮助。

但是现在COM并不是真正的尖端;)很难找到像代码样本这样的资源。

我找到了这个有趣的示例:https://clrinterop.codeplex.com/releases/view/32350使用 ICustomQueryInterface 接口实现COM聚合

但它不是动态的,而是基于静态定义的类型和接口。

非常感谢任何帮助。

感谢。

2 个答案:

答案 0 :(得分:5)

公开IDispatchEx适用于JavaScript,但我认为VBA不会使用它。 AFAIK,VBA依赖IDispatch进行后期绑定。此外,C#dynamic非常适合在.NET端使用基于COM IDispatch的对象,但反之亦然。出于某种原因(.NET设计师决定?),ExpandoObjectDynamicObject的动态属性和方法默认情况下不会暴露给COM。

幸运的是,有一种方法可以覆盖它:通过实现IReflect接口。有关实施细节,请参阅此优秀blog post。我自己看了at exposing properties of C# anonymous class to COM,最后使用了IReflect。这是您向COM公开动态方法和属性的方法。形象地说,IReflect作为IDispatch向COM公开。

另外,IExpandoIDispatchEx执行相同的工作,因此JavaScript客户端可以添加以后可以通过托管代码访问的新属性。

[更新] 下面是一个原型实现,它将DynamicComponent的实例公开给在WebBrowser内运行的VBScript。它适用于VBScript,也应该适用于VBA。虽然,我怀疑VBA自动完成是否有效,或者有一种简单的方法来实现这样的功能。 AFAIU,VBA自动完成依赖于COM类型库(可通过IDispatch::GetTypeInfo获得),但我不认为.NET互操作引擎在通过{{1}实现IDispatch时会生成动态类型库} (我可能错了)。此外,此实现对于逐个名称的查找区分大小写,应该调整,因为VB不区分大小写。

IReflect

答案 1 :(得分:0)

您无法动态创建接口,但您可以创建方法。在C#中查看Expando Objects

特别是,您可以使用expandos创建自定义IDispatchEx实现;您可以使用expando将名称映射到ID,使用反射来调用对象。