Инициирующие события, сгенерированные из управляемого класса в C ++ / CLI - PullRequest
0 голосов
/ 07 июня 2018

Я пытаюсь вызвать события из библиотеки C ++ в приложение на C #.Предыдущий вопрос, касающийся этого: Использование неуправляемого указателя для функции обратного вызова на управляемом C ++

Благодаря помощи, которую я получил в комментариях к этому вопросу, и в этом примере на предыдущий вопрос, на который ответил Ханс Пассант: C ++ / Cli Pass (управляемый) делегат для неуправляемого кода Я думал Я получил Это работает, но при тестировании на реальном оборудовании события не запускаются.Из отладчика я вижу, что функция callback_function вызывается, когда происходит событие, инициируемое аппаратным вводом / выводом, инструкции там печатают соответствующие строки, затем вызывается TriggerEvent (1), но событие не получено в коде C #, который я сделалчтобы справиться с этим.

Я подозреваю, что это связано с тем, как новый экземпляр CppDIOHandler создается непосредственно перед «Шагом 3», вместо создания делегата в оригинале.Я попытался получить дескриптор текущего объекта (похожего на «this», но с управляемым кодом, используя GCHandle) для создания объекта CallbackDelegate, но безуспешно.Я не понимаю, почему я не могу просто использовать callback = gcnew CallbackDelegate (& callback_function) вместо этой строки.

#include "stdafx.h"
#include <WDT_DIO.H>
#include <string.h>
#include <stdio.h>

using namespace System;
using namespace System::Runtime::InteropServices;

public ref class PinStateChangedEventArgs : public EventArgs
{
public:
    property int Direction;
    property DateTime TimeReached;
};

public ref class CppDIOHandler
{
public:
    CppDIOHandler() {
    }

    delegate void CallbackDelegate(COS_INT_CALLBACK_ARG*);
    static CallbackDelegate^ callback;

    void __stdcall callback_function(COS_INT_CALLBACK_ARG* arg)
    {
        printf("data=0x%02x, flag=0x%02x, seq=%02d\n",
            arg->portData, arg->intrFlag, arg->intrSeq);
        TriggerEvent(1);
    }


    static void StartDIO() {
        //Step 1, initialize DIO library by invoking InitDIO()
        if (!InitDIO())
        {
            Console::WriteLine("InitDIO --> FAILED");
            return;
        }
        Console::WriteLine("InitDIO --> PASSED");

        //Step 2, setup Change-of-State Interrupt mask and level/edge mode
        COS_INT_SETUP setup;
        memset(&setup, 0, sizeof(setup));
        setup.portMask = 0x0f; // 00001111b, enable ch.0~3
        setup.edgeMode = 0x00; // generate interrupt on level change
        setup.edgeType = 0x00; // rising/falling edge, only effective when edgeMode = 1

        if (!SetupDICOS(&setup, sizeof(setup)))
        {
            Console::WriteLine("SetupDICOS --> FAILED");
            return;
        }
        Console::WriteLine("SetupDICOS --> PASSED");

        CppDIOHandler^ cdh = gcnew CppDIOHandler();
        callback = gcnew CallbackDelegate(cdh,&callback_function);
        IntPtr stubPointer = Marshal::GetFunctionPointerForDelegate(callback);
        COS_INT_CALLBACK functionPointer = static_cast<COS_INT_CALLBACK>(stubPointer.ToPointer());
        //TO-DO: Make callback static and remove the GC instruction
        //GC::KeepAlive(callback); 

        //Step 3, register the callback function
        if (!RegisterCallbackDICOS(functionPointer))
        {
            Console::WriteLine("RegisterCallbackDICOS --> FAILED");
            return;
        }
        Console::WriteLine("RegisterCallbackDICOS --> PASSED");
        //Step 4, start the DI Change-of-State Interrupt
        if (!StartDICOS())
        {
            Console::WriteLine("StartDICOS --> FAILED");
            return;
        }
        Console::WriteLine("StartDICOS --> PASSED");
    }

    void StopDIO() {
        //Step 5, stop the DI Change-of-State Interrupt operation
        if (!StopDICOS())
        {
            Console::WriteLine("StopDICOS --> FAILED");
            return;
        }
        Console::WriteLine("StopDICOS --> PASSED");
    }

    void TriggerEvent(int direction)
    {
            PinStateChangedEventArgs^ args = gcnew PinStateChangedEventArgs();
            args->Direction = direction;
            args->TimeReached = DateTime::Now;
            OnPinStateChanged(args);
    }

    event EventHandler<PinStateChangedEventArgs^>^ PinStateChanged;

    virtual void OnPinStateChanged(PinStateChangedEventArgs^ e)
    {
        PinStateChanged(this, e);
    }
};

Код на C # тривиален, поэтому кажется маловероятным, что проблема есть, я просто сделал:

CppDIOHandler cc = new CppDIOHandler();
CppDIOHandler.StartDIO();
cc.PinStateChanged += Cs_PinStateChanged;

Но обратный вызов Cs_PinstateChanged никогда не выполняется.Как правильно решить эту проблему?Действительно ли необходимо использовать GCHandle для ссылки на текущий объект в управляемом коде, или это никак не связано с моей проблемой?

...