我有一个c ++类,可以触发一些类似事件的方法。
class Blah {
virtual void Event(EventArgs e);
}
如何在调用方法时将其包装起来,将调用C#(托管)事件?
我想继承该类并重载事件方法,然后以某种方式调用托管事件。 我只是不确定如何实际做到这一点。
答案 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()方法,当它被调用时,您只需将该方法转发到您正在存储的托管包装类实例。
请注意,您不能从包含类的外部引发事件,因此您必须使其成为普通委托,或者在托管类上调用帮助程序方法来为您引发它。