向 COM 公开 .NET 类(具有事件)
我想向 COM 公开一个 .NET 类。 这相当简单:
- 我创建一个接口,在其中定义该类应该是 ComVisible 的成员
- 我自己定义这些成员的 DispId
- 我定义该接口应该是 ComVisible
- 我分配一个
引导到该接口,
- 我创建了一个实现该接口的类,
没什么大不了的。这一切都有效。 但是,现在我的问题是:我在该类中有一些事件,我也想将它们公开给 COM。
这应该也不是什么大问题,但是,当我查看一些示例(由 MS 的 ComInterop 工具生成的 fi 代码)时,我发现事件是在单独的接口中声明的。 也就是说:应该是 ComVisible 的类实现 2 个接口:
- 一个接口定义应该是 ComVisible 的常规方法和属性,
- 另一个接口定义应该是 ComVisible 的事件ComVisible。
现在,我的问题是:为什么会这样?这是什么原因呢?
为什么 ComVisible
事件在另一个接口中定义,以及为什么它们没有在包含应为 ComVisible
的方法和属性的接口中定义?
这背后的原因是什么?
I want to expose a .NET class to COM.
That's fairly easy:
- I create an interface in where I define the members of that class that should be ComVisible
- I define the DispId's of those members myself
- I define that the interface should be
ComVisible
- I assign a
Guid
to that interface - I create a class which implements that interface
No big deal. This all works.
But, now my question is: I have a few events in that class, that I want to expose to COM as well.
This should be no big deal either, but, when I look at some examples (f.i. code generated by MS' ComInterop tool), I see that the events are declared in a separate interface.
That is: the class that should be ComVisible
, implements 2 interfaces:
- one interface which defines the regular methods and properties that should be
ComVisible
- another interface that defines the events that should be
ComVisible
.
Now, my question is: why is that ? What is the reason for this ?
Why are the ComVisible
events defined in another interface, and why are they just not defined in the interface that contains the methods and properties that should be ComVisible
?
What is the reasoning behind this ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是由于 COM 事件的工作方式造成的。 COM 不知道委托是什么,因此它的事件是使用回调接口来实现的。希望接收事件的对象实现事件接口,将其传递给发送者(您的代码),然后发送者调用其上的方法。因此,事件接口是独立的,因为您不希望对您的事件感兴趣的人必须实现接口的其余部分。
在幕后,事件接口是使用“连接点”进行管理的,“连接点”允许接收者将其回调接口连接到发送者。此实现需要各种 COM 接口(IConnectionPoint、IConnectionPointContainer、IEnumConnectionPoints、IEnumConnections)和一些繁琐的内务处理。如果您在本机 C++ 中实现 COM 事件,则必须关心这些接口。幸运的是,作为 .NET 程序员,您不必实现它们,因为 .NET 会为您做这件事。
This is due to the way that COM events work. COM doesn't have any idea what a delegate is, and so its events are implemented using a callback interface. The object which wishes to receive events implements the events interface, passes it to the sender (your code), and the sender calls methods on it. The event interface is thus separate because you don't want someone interested in your events to have to implement the rest of your interface.
Behinds the scenes, event interfaces are managed using "connection points" which allow recipients to connect their callback interfaces to the sender. This implementation requires an assortment of COM interfaces (IConnectionPoint, IConnectionPointContainer, IEnumConnectionPoints, IEnumConnections) and some tedious housekeeping. If you're implementing COM events in e.g. native C++, you have to care about these interfaces. Fortunately as a .NET programmer you don't have to implement them, since .NET will do it for you.
事件始终在单独的接口上定义。这并不是 .NET 实现的 COM 接口所特有的,而是所有 COM 接口。在我看来,接口代表方法和属性的集合,但事件接口上的方法不像其中任何一个那样被调用。它们由服务器而不是客户端调用,这与正常方法的行为不匹配。因此,通过在单独的接口上实现这些方法,您可以将可以由服务器调用的函数与可以由客户端调用的方法分开。客户端不应该能够调用事件方法。应该要求在服务器可以调用的对象上实现接口。同样,客户端不应该实现服务器中已经实现的接口。它应该调用服务器中实现的那些接口的现有实现。处理此问题的最简单方法是为客户端提供一个接口来实现事件处理,并由服务器实现另一个接口,客户端可以调用已实现的功能。
Events have always been defined on a separate interface. This is not unique to COM interfaces implemented by .NET, but all COM interfaces. The way I see it, an interface represents a collection of methods and properties, but methods on an event interface are not invoked like either of those. They are invoked by the server instead of the client, which doesn't match the behavior of normal methods. So by implementing these methods on a separate interface, you can separate the functions that can be invoked by the server from the methods that can be invoked by the client. The client should not be able to invoke event methods. It should be required to implement the interface on an object which the server can invoke. Likewise, the client should not be implementing interfaces that are already implemented in the server. It should be calling the existing implementation of those interfaces implemented in the server. The simplest way to handle this is to have one interface provided for the client to implement for event handling, and another implemented by the server that the client can call for already-implemented functions.