C++/CLI - Managed class to C# events

前端 未结 3 1910
别跟我提以往
别跟我提以往 2021-01-21 20:31

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 t

相关标签:
3条回答
  • 2021-01-21 21:12

    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.

    0 讨论(0)
  • 2021-01-21 21:27

    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.

    0 讨论(0)
  • 2021-01-21 21:38

    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);
        }
    };
    
    0 讨论(0)
提交回复
热议问题