C ++ / CLI - управляемый класс для событий C # - PullRequest
2 голосов
/ 27 марта 2011

У меня есть класс c ++, который запускает некоторый метод, такой как событие.

class Blah {

   virtual void Event(EventArgs e);
}

Как я могу обернуть его так, чтобы всякий раз, когда вызывается метод, вызывается событие C # (управляемое)?

Я думал о наследовании этого класса и перегрузке метода события, а затем каким-то образом вызывал управляемое событие.Я просто не уверен, как на самом деле это сделать.

Ответы [ 3 ]

6 голосов
/ 27 марта 2011

Примерно так (сейчас проверено компиляцией):

#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);
    }
};
4 голосов
/ 27 марта 2011

Вам нужно проделать некоторую работу, чтобы отразить вызов метода Event (), чтобы он мог быть перехвачен управляемым классом. Давайте реализуем конкретный класс бла, который делает так:

#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. Измените управляемое событие соответствующим образом.

1 голос
/ 27 марта 2011

Создайте класс, унаследованный от blah, и сделайте так, чтобы он ссылался на вашу управляемую оболочку в конструкторе.Переопределите метод Event (), и когда он будет вызван, вы можете просто переслать этот метод в экземпляр управляемого класса-оболочки, который вы храните.

Обратите внимание, что вы не можете вызвать событие извне содержащего класса,поэтому вам придется либо сделать его простым делегатом, либо вызвать вспомогательный метод в управляемом классе, чтобы вызвать его для вас.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...