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

发布于 2024-10-26 11:31:54 字数 204 浏览 1 评论 0原文

我有一个 C++ 类,它触发一些方法,例如事件。

class Blah {

   virtual void Event(EventArgs e);
}

我如何包装它,以便每当调用该方法时都会调用 C#(托管)事件?

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

I have a c++ class that triggers some method like an event.

class Blah {

   virtual void Event(EventArgs e);
}

How can I wrap it so whenever the method is called a C# (managed) event will be called?

I thought of inheriting that class and overloading the event method, and then somehow call the managed event.
I'm just not sure how to actually do it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

那支青花 2024-11-02 11:31:54

像这样的东西(现已编译测试):

#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);
    }
};

Something like this (now compile-tested):

#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);
    }
};
太傻旳人生 2024-11-02 11:31:54

您需要做一些工作来反映 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 派生的托管类。相应地修改托管事件。

You need to do some work to reflect the Event() method call so it can be hooked by a managed class. Lets implement a concrete blah class that does so:

#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)

You can now construct a blahImpl and pass it a function pointer that is called when the Event() method is called. You can use Marshal::GetFunctionPointerForDelegate() to get such a function pointer, it creates a stub for a delegate that makes the transition from unmanaged code to managed code and can store a instance as well. Combined with the boilerplate code to wrap an unmanaged class:

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; }
};

The C# code can now write an event handler for the Event event. I left the spelling error in tact, you need to do some work to convert EvenAtrgs to a managed class that derives from EventArgs. Modify the managed Event accordingly.

情释 2024-11-02 11:31:54

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

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

Create a class that inherits from blah and have it take a reference to your managed wrapper in the constructor. Override the Event() method and when it gets called you can just forward that method on to the managed wrapper class instance you are storing.

Note that you can't raise an event from outside of the containing class, so you'll have to either make it a plain delegate or call a helper method on the managed class to raise it for you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文