【问题标题】:(C++/CLI) How to get callbacks from Native Code to Managed Code in C++ CLI?(C++/CLI) 如何在 C++ CLI 中获取从本机代码到托管代码的回调?
【发布时间】:2021-12-03 17:10:57
【问题描述】:

咆哮开始 在直接进入已经回答的乐队之前,请阅读这篇关于 SE 过时答案的论文https://ieeexplore.ieee.org/document/8669958

事情会在一段时间后发生变化,我担心计算机科学是 API 和接口变化非常非常快的领域中最多的领域之一。不用说,在将最新功能添加到平台/框架之后,上个月可能有效的解决方案可能不会。当许多主流事物甚至不存在时,我谦虚地请求您不要将这个问题标记为十年前的帖子已回答。如果您不知道最新的解决方案,请不要为此烦恼,并将问题留给可能的其他人。

对于计算机科学的社区代表来说,创新是日常事物,这是非常有毒的,新来者不友好和保守。 结束-RANT

我已经回答了这个问题,明天将被接受(SE 政策)。感谢您的关注。

很多时候你在非托管上下文中有函数指针,它们被某种事件调用,我们将看到如何使用顶级函数以及托管类的成员函数来实现它。

同样,请不要通过链接到十年前的帖子将其标记为已回答。

PS: 由于第三世界国家的互联网不稳定而进行了如此多的编辑,是的,咬我!

【问题讨论】:

标签: c++-cli interop clr


【解决方案1】:

unmanaged.cpp

#pragma unmanaged

// Declare an unmanaged function type that takes one int arguments and callbacks
// our function after incrementing it by 1 
// Note the use of __stdcall for compatibility with managed code
// if your unmanaged callback uses any other calling convention you can 
// UnmanagedFunctionPointerAttribute (check msdn for more info) on your delegate

typedef int(__stdcall* ANSWERCB)(int);//Signature of native callback 

int TakesCallback(ANSWERCB fp, int a) {

    if (fp) {
        return fp(a+1);//Native Callback
    }
    // This code will be executed when passed without fp
    return 0;
}

#pragma managed

托管.cpp

using namespace System;
using namespace System::Runtime::InteropServices;
namespace Callbacks {
    //  Following delegate is for unmanaged code and must match its signature
    public delegate void MyNativeDelegate(int i); 
    //  This delegate is for managed/derived code and ideally should have only managed parameters
    public delegate void MyManagedDelegate(int i); 

    public ref class TestCallback {// Our demo Managed class
    private:
        GCHandle gch;// kept reference so that it can be freed once we are done with it
        void NativeCallbackListener(int i);//unmanaged code will call this function
    public:
        void TriggerCallback(int i); // Its here for demo purposes, usually unmanaged code will call automatically
        event MyManagedDelegate^ SomethingHappened;//plain old event
        ~TestCallback();//free gch in destructor as its managed.
    };
};

void Callbacks::TestCallback::NativeCallbackListener(int i) {
    // Callback from Native code,
    // If you need to transform your arguments do it here, like transforming void* to somekind of native structure.
    // and then pass SomethingHappened::raise with Managed Class/Struct 
    return SomethingHappened::raise(i); // similar to SomethingHappened.Invoke() in c#
}

void Callbacks::TestCallback::TriggerCallback(int i)
{
    MyNativeDelegate^ fp = gcnew MyNativeDelegate(this, &TestCallback::NativeCallbackListener);
        // use this if your nativecallback function is not a member function MyNativeDelegate^ fp = gcnew MyNativeDelegate(&NativeCallbackListener);
        gch = GCHandle::Alloc(fp);
        IntPtr ip = Marshal::GetFunctionPointerForDelegate(fp);
        ANSWERCB cb = static_cast<ANSWERCB>(ip.ToPointer());// (ANSWERCB)ip.ToPointer(); works aswell
        // Simulating native call, it should callback to our function ptr NativeCallbackListener with 2+1;
        // Ideally Native code keeps function pointer and calls back without pointer being provided every time.
        // Most likely with a dedicated function for that.
        TakesCallback(cb, i);
                        
    }
void Callbacks::TestCallback::~TestCallBack() {
    gch.Free();//Free GCHandle so GC can collect
}

implementation.cpp

using namespace System;
void OnSomethingHappened(int i);
int main(array<System::String^>^ args)
{
    auto cb = gcnew Callbacks::TestCallback();
    cb->SomethingHappened += gcnew Callbacks::MyManagedDelegate(&OnSomethingHappened);
    cb->TriggerCallback(1);
    return 0;
}

void OnSomethingHappened(int i)
{
    Console::WriteLine("Got call back with " + i);
}

【讨论】:

  • 您能否更详细地指出我们这里发生了什么?你的代码是做什么的?
  • 它是一个示例,模仿现实世界的应用程序互操作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多