Events C++/CLI-托管类到C#事件 我有一个C++类,它触发一些方法,比如事件。 class Blah { virtual void Event(EventArgs e); }

Events C++/CLI-托管类到C#事件 我有一个C++类,它触发一些方法,比如事件。 class Blah { virtual void Event(EventArgs e); },events,c++-cli,Events,C++ Cli,如何包装它,以便在调用方法时调用C#(托管)事件 我考虑继承该类并重载event方法,然后以某种方式调用托管事件。 我只是不知道如何真正做到这一点。创建一个继承自blah的类,并让它在构造函数中引用托管包装器。重写Event()方法,当调用它时,可以将该方法转发到正在存储的托管包装器类实例上 请注意,您不能从包含类的外部引发事件,因此您必须将其设置为普通委托或调用托管类上的帮助器方法来为您引发事件。类似的内容(现在已编译测试): #包括 结构blah_args { int x,y; }; 结构废

如何包装它,以便在调用方法时调用C#(托管)事件

我考虑继承该类并重载event方法,然后以某种方式调用托管事件。
我只是不知道如何真正做到这一点。

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

请注意,您不能从包含类的外部引发事件,因此您必须将其设置为普通委托或调用托管类上的帮助器方法来为您引发事件。

类似的内容(现在已编译测试):

#包括
结构blah_args
{
int x,y;
};
结构废话
{
虚拟无效事件(const blah_args&e)=0;
};
public ref类BlahEventArgs:public System::EventArgs
{
公众:
int x,y;
};
公共参考类BlahDotNet
{
公众:
事件系统::EventHandler ^I出现;
内部:
虚空发生了(BlahEventArgs^e){Ithapped(this,e);}
};
类别blah_事件_转发器:公共blah
{
GCM_管理;
公众:
blah_事件转发器(BlahDotNet^托管):m_托管(托管){}
受保护的:
虚拟无效事件(const blah_args&e)
{
BlahEventArgs^e2=gcnew BlahEventArgs();
e2->x=e.x;
e2->y=e.y;
m_管理->发生的事件(e2);
}
};

您需要做一些工作来反映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; }
};
public ref class blahWrapper{
blahImpl*实例;
委托无效管理回拨(平均);
managedCallback^回调;
无效火灾事件(EvenAtrgs e){
//Todo:将e转换为托管EventArgs派生类
//...
事件(此,EventArgs::Empty);
}
公众:
事件处理程序^event;
说唱者{
callback=gcnew-managedCallback(this,&blahWrapper::firevent);
instance=new blahImpl((回调)(void*)System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(回调));
}
~blahwraper(){delete instance;}
!blahwraper(){delete instance;}
};

C代码现在可以为事件编写事件处理程序。我将拼写错误保留在tact中,您需要做一些工作来将EvenAtrgs转换为从EventArgs派生的托管类。相应地修改托管事件。

对,但我不确定如何实际引用托管函数,甚至不确定如何使用语言的语法创建事件
BlahEventHandler
未定义,但是在任何情况下,都应该更喜欢
System::EventHandler^
而不是定义一个新的委托。@ildjam:这需要一个额外的参数,但这是.NET的规范。我将采纳这个建议。这更像是p/invoke风格,而不是C++/CLI的首选方法。这不是Pinvoke,公共ref类在程序集外部可见,可用于任何托管语言。PAH.@ HANS:您不使用C/C++之间的P/UngCK,而是在C++/CLI和C++之间使用。代码>封送:GetFunctionPointerForDelegate是一个p/invoke API。C++互操作将使用<代码> GCROOT < /代码>。首先,您的代码有可能使委托和函数指针被垃圾回收器释放。事实上,您没有试图使委托保持活动状态,只要
blahwraper
构造函数返回,它就变得不可访问,并且有资格进行垃圾回收-1@Hans:现在,你不是肯定有问题,而是可能有问题。但至少这样更好。否决票被删除。
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; }
};