(C++/CLI) 如何在 C++ CLI 中获取从本机代码到托管代码的回调?

Posted

技术标签:

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

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

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

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

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

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

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

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

【问题讨论】:

这能回答你的问题吗? c++/cli pass (managed) delegate to unmanaged code 该答案已有 11 年历史,并且使用了漫长而复杂的方法,但可以以更简单的方式完成。 【参考方案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);

【讨论】:

您能否更详细地指出我们这里发生了什么?你的代码是做什么的? 它是一个示例,模仿现实世界的应用程序互操作。

以上是关于(C++/CLI) 如何在 C++ CLI 中获取从本机代码到托管代码的回调?的主要内容,如果未能解决你的问题,请参考以下文章

如何从我的 C++/CLI 代码进入非托管 C++ 库

如何将 C++ 本机对象编组到托管 C++ CLI

C++/CLI + C++ Native 会提高性能吗? [关闭]

DeviceIoControl 在 C++ 和 C# 中工作,但在 C++/CLI 中调用时返回 ERROR_INVALID_FUNCTION

如何通过 C++-CLI 回调和委托将字符串从 C++-CLI 传递到 C#

本机 C++ 程序在使用 C++/CLI 和 C# 互操作 DLL 启动时崩溃