使用C ++将管理事件暴露给COM [英] Exposing manged events to COM using C++

查看:194
本文介绍了使用C ++将管理事件暴露给COM的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

可以将使用C#编写的托管事件公开并使用在使用c ++编写的COM对象中。不熟悉com和atl。你能否显示MSDN文章中显示的示例的C ++方面的内容。

It is possible to exposed managed events written in C# to be exposed and used in a COM object written using c++. not being that familiar with com and atl. Can you please show what would the C++ side of things would look like for the example shown in the MSDN article

http://msdn.microsoft.com/en-us/library/dd8bf0x3.aspx

显示的VB6代码证明它是可行的。

The VB6 code shown proves that it is doable.

提前感谢

推荐答案

在C ++中最简单的方法是,IMO将通过ATL的 IDispEventImpl 的帮助来实现一个事件接收器IDispEventSimpleImpl 模板。示例项目可以在这里找到解释

The easiest way in C++ would be, IMO, to implement an event sink with help of ATL's IDispEventImpl and IDispEventSimpleImpl templates. An explanation with sample project can be found here.

有很多关于如何做到这一点的在线资源,例如,但以下是所需步骤的列表:

There are many online resources about how to do this, e.g. this or this, but here is the list of required steps:

首先让我们来看看管理端。

First let's take a look at managed side.

为了提供事件,我们必须执行以下操作:

In order to provide events, we must do the following:


  • 声明一个事件接口( IDispatch - 基于)

  • <使用 ComSourceInterfaces 属性将coclass标记为将事件接口绑定到coclass
  • 在coclass
  • $中实现匹配事件b $ b
  • declare an event interface (IDispatch-based)
  • mark the coclass with ComSourceInterfaces attribute to bind the event interface to coclass
  • implement matching events in the coclass

这里是托管代码:

[ComVisible(true), 
 Guid("D6D3565F-..."), 
 InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] //! must be IDispatch
public interface IMyEvents
{
    [DispId(1)] // the dispid is used to correctly map the events
    void SomethingHappened(DateTime timestamp, string message);
}

[ComVisible(true)]
[Guid("E22E64F7-...")]
[ProgId("...")]
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(IMyEvents))] // binding the event interface
public class MyComServer : IMyComServer  
{
    // here we declare the delegate for the event
    [ComVisible(false)]
    public delegate void MyEventHandler(DateTime timestamp, string message);

    // and a public event which matches the method in IMyEvents
    // your code will raise this event when needed
    public event MyEventHandler SomethingHappened;
    ... 
}

现在,回到非托管方面。我将使用ATL,因为我发现它是编写COM客户端的最有效方式,但是您可以尝试MFC或手动进行。

Now, back to unmanaged side. I will use ATL, as I find it the most effective way to write COM clients, but you can try MFC or do it 'manually'.

需要执行以下步骤:


  • 接收器将继承 IDispEventSimpleImpl (或 IDispEventImpl

  • 所有需要的方法的汇图都被声明为

  • 处理方法为每个事件编写

  • 接收器最终注册了事件源

  • ,当不再需要时,接收器断开连接

  • the sink will inherit IDispEventSimpleImpl (or IDispEventImpl)
  • sink map with all the needed methods is declared
  • handler methods are written for each event
  • the sink is registered with event source
  • eventually, when not needed anymore, the sink is disconnected

这是ATL C ++客户端中的代码:

Here's the code in an ATL C++ client:

// import the typelib of your COM server
// 'named_guids' ensures friendly ID of event interface
#import "myserver.tlb" named_guids 
const UINT SINK_ID = 234231341; // we need some sink id

class MyClient : public IDispEventSimpleImpl<SINK_ID, MyClient, &MyServer::DIID_IMyEvents >
{
    public:
    // now you need to declare a sink map - a map of methods handling the events
    BEGIN_SINK_MAP(MyClient)
      SINK_ENTRY_INFO(SINK_ID, MyServer::DIID_IMyEvents, 0x1, OnSomethingHappened, &someEvent)
                                                   ^      ^      ^                   ^
      // event interface id (can be more than 1)---+      |      |                   |
      // must match dispid of your event -----------------+      |                   |
      // method which handles the event  ------------------------+                   |
      // type information for event, see below --------------------------------------+
    END_SINK_MAP()

// declare the type info object. You will need one for each method with different signature.
// it will be defined in the .cpp file, as it is a static member
static _ATL_FUNC_INFO someEvent;  // 'placeholder' object to carry event information (see below)

// method which handles the event
STDMETHOD (OnSomethingHappened)(DATE timestamp, BSTR message)
{ 
   // usually it is defined it in the .cpp file
}

... 

}

现在,我们需要在cpp文件中定义类型信息成员(即 someEvent

Now, we need to define the type info members in the cpp file (i.e. the someEvent instance from example above):

_ATL_FUNC_INFO MyClient::traceEvent = { CC_STDCALL, VT_EMPTY, 2 , {VT_DECIMAL, VT_BSTR} };  // dispid = 1
                                               ^        ^     ^              ^
// calling convention (always stdcall) --------+        |     |              |
// type of return value (only VT_EMPTY makes sense) ----+     |              |
// number of parameters to the event -------------------------+              |
// Variant types of event arguments -----------------------------------------+

这可能很棘手,因为类型映射并不总是很明显(例如,它可能很清楚管理 int 映射到 VT_I4 ,但不太明显的是 DateTime 映射到 VT_DECIMAL )。
您需要声明您计划在汇图中使用的每个事件 - 如果您不需要它们,则不要映射它们。

This can be tricky as type mappings are not always obvious (e.g. a it might be clear that managed int maps to VT_I4, but it is less obvious that DateTime maps to VT_DECIMAL). You need to declare each event you plan to use in the sink map - if you don't need all of them, don't map them.

现在,您需要将您的接收器连接到事件源:

Now you need to connect your sink to the event source:

// IUnknown* pUnk = interface to you COM server instance
pMyClient->DispEventAdvise(pUnk);
// .. from this point, events will be caught by the client
// when you are done, disconnect:
pMyClient->DispEventUnadvise(pUnk);

这是它,或多或少。使用 IDispEventImpl 而不是 IDispEventSimpleImpl 导致少一些代码,因为您不需要提供类型信息对象这可能是最丑的部分。然而,它有两个缺点:

This is it, more or less. Using IDispEventImpl instead of IDispEventSimpleImpl results in a bit less code, as you don't need to supply the type info objects which might be the ugliest part. However, it has two drawbacks:


  • 需要访问typelib(因为它需要读取界面元数据才能提供类型信息本身)

  • 有点慢(但我猜不会显着)

这篇关于使用C ++将管理事件暴露给COM的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆