C++ cli 从C++/CLI 我试图从C++库中触发事件到C语言中的一个应用程序。关于这一点的上一个问题:

C++ cli 从C++/CLI 我试图从C++库中触发事件到C语言中的一个应用程序。关于这一点的上一个问题:,c++-cli,clr,C++ Cli,Clr,多亏了我在那个问题上得到的帮助,以及Hans Passant回答的前一个问题的例子:我认为我已经让它工作了,但是当在真正的硬件上测试时,事件不会触发。从调试器中,我可以看到当硬件I/O触发事件时调用回调函数,那里的指令打印相应的行,然后调用TriggerEvent(1),但在我处理它的C代码中没有接收到该事件 我怀疑这与如何在“步骤3”之前创建CppDIOHandler的新实例有关,而不是在原始文件中创建委托。我尝试获取当前对象的句柄(类似于“this”,但使用托管代码,使用GCHandle)来

多亏了我在那个问题上得到的帮助,以及Hans Passant回答的前一个问题的例子:我认为我已经让它工作了,但是当在真正的硬件上测试时,事件不会触发。从调试器中,我可以看到当硬件I/O触发事件时调用回调函数,那里的指令打印相应的行,然后调用TriggerEvent(1),但在我处理它的C代码中没有接收到该事件

我怀疑这与如何在“步骤3”之前创建CppDIOHandler的新实例有关,而不是在原始文件中创建委托。我尝试获取当前对象的句柄(类似于“this”,但使用托管代码,使用GCHandle)来创建CallbackDelegate对象,但没有成功。我不明白为什么不能简单地使用callback=gcnewcallbackdelegate(&callback\u函数)而不是那一行

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

但Cs_PinstateChanged回调永远不会执行。解决这个问题的正确方法是什么?是否真的需要使用GCHandle引用托管代码中的当前对象,或者这与我的问题无关?

代码基本上是正确的,将StartDIO()设为静态会带来麻烦。这迫使您使用新的CppDIOHandler。现在这个类有两个对象,一个是由C#代码创建的,它有一个事件处理程序。另一个是由没有事件处理程序的C++/CLI代码创建的。因此,没有提出任何事件。只是不要让它是静态的,简单的,把它传递给委托构造函数。您应该通过验证回调变量是否为nullptr来强制执行一个简单且正确的单例,如果不是,则抛出一个异常。@HansPassant saving my life似乎是:-)。使用CallbackDelegate(此函数和callback_函数)时仍然无法编译它,错误为C3364/C2276(委托目标必须是指向成员函数的指针)。但是我不明白,因为它是一个成员函数。使回调函数为静态可能会给我带来另一系列问题(比如不能调用“TriggerEvent(n)”)语法有点笨拙,使用实例函数也需要命名类。因此,它是gcnewcallbackdelegate(这个,&CppDIOHandler::callback\u函数)。“语言标准可读性很强,而且,你会想让它方便使用的”。@HansPassant我向你保证,我尝试了一些繁琐的语法,其中一些非常接近你提供的解决方案,但我没有成功地将其正确使用。”。现在它工作得完美无缺。我会在有机会的时候实施单身安全检查标准,谢谢大家的帮助。
CppDIOHandler cc = new CppDIOHandler();
CppDIOHandler.StartDIO();
cc.PinStateChanged += Cs_PinStateChanged;