C ++ / CLI - C#事件的托管类

时间:2011-03-27 18:57:14

标签: events c++-cli

我有一个c ++类,可以触发一些类似事件的方法。

class Blah {

   virtual void Event(EventArgs e);
}

如何在调用方法时将其包装起来,将调用C#(托管)事件?

我想继承该类并重载事件方法,然后以某种方式调用托管事件。 我只是不确定如何实际做到这一点。

3 个答案:

答案 0 :(得分:6)

像这样(现在经过编译测试):

#include <vcclr.h>

struct blah_args
{
    int x, y;
};

struct blah
{
    virtual void Event(const blah_args& e) = 0;
};

public ref class BlahEventArgs : public System::EventArgs
{
public:
    int x, y;
};

public ref class BlahDotNet
{
public:
    event System::EventHandler<BlahEventArgs^>^ ItHappened;
internal:
    void RaiseItHappened(BlahEventArgs^ e) { ItHappened(this, e); }
};

class blah_event_forwarder : public blah
{
    gcroot<BlahDotNet^> m_managed;

public:
    blah_event_forwarder(BlahDotNet^ managed) : m_managed(managed) {}

protected:
    virtual void Event(const blah_args& e)
    {
        BlahEventArgs^ e2 = gcnew BlahEventArgs();
        e2->x = e.x;
        e2->y = e.y;
        m_managed->RaiseItHappened(e2);
    }
};

答案 1 :(得分:4)

您需要做一些工作来反映Event()方法调用,以便它可以被托管类挂钩。让我们实现一个具体的blah类:

#pragma managed(push, off)

struct EvenAtrgs {};

class blah {
public:
   virtual void Event (EvenAtrgs e) = 0;
};

typedef void (* CallBack)(EvenAtrgs);

class blahImpl : blah {
    CallBack callback;
public:
    blahImpl(CallBack fp) {
        this->callback = fp;
    }
    virtual void Event(EvenAtrgs e) { 
        callback(e); 
    }
};
#pragma managed(pop)

现在可以构造一个blahImpl并传递一个函数指针,该函数指针在调用Event()方法时调用。您可以使用Marshal :: GetFunctionPointerForDelegate()来获取这样的函数指针,它为委托创建存根,该存根使得从非托管代码转换为托管代码并且也可以存储实例。结合样板代码来包装非托管类:

public ref class blahWrapper {
    blahImpl* instance;
    delegate void managedCallback(EvenAtrgs e);
    managedCallback^ callback;
    void fireEvent(EvenAtrgs e) {
        // Todo: convert e to a managed EventArgs derived class
        //...
        Event(this, EventArgs::Empty);
    }
public:
    event EventHandler<EventArgs^>^ Event;
    blahWrapper() {
        callback = gcnew managedCallback(this, &blahWrapper::fireEvent);
        instance = new blahImpl((CallBack)(void*)System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(callback));
    }
    ~blahWrapper() { delete instance; }
    !blahWrapper() { delete instance; }
};

C#代码现在可以为Event事件编写事件处理程序。我完全没有留下拼写错误,你需要做一些工作来将EvenAtrgs转换为派生自EventArgs的托管类。相应地修改托管事件。

答案 2 :(得分:1)

创建一个继承自blah的类,并让它在构造函数中引用托管包装器。重写Event()方法,当它被调用时,您只需将该方法转发到您正在存储的托管包装类实例。

请注意,您不能从包含类的外部引发事件,因此您必须使其成为普通委托,或者在托管类上调用帮助程序方法来为您引发它。