将非托管方法作为回调传递给托管 C++/CLI 类

Posted

技术标签:

【中文标题】将非托管方法作为回调传递给托管 C++/CLI 类【英文标题】:Passing unmanaged method as callback to managed C++/CLI class 【发布时间】:2020-04-10 18:41:34 【问题描述】:

我想将 C++ 成员函数作为回调传递给 C# 项目。我在 C++/CLI 中有其他项目,我想通过它来完成。

因此,在我的 C++/CLI 项目的非托管 C++ 中,我有一个函数对象:std::function<void(int)>callback;

这个函数来自我的 C++ 项目,它工作正常,我将它保存在那里作为示例以避免上一步。现在,我想将此回调函数传递给我的 C# 项目。为此,我在非托管 C++ 中创建了一个方法,将其传递给托管 C++,然后最终将其传递给 C#。我想要这样的东西:

// Unmanaged class
public class Wrapper

public:
    std::function<void(int)>callback;

    void ReturnToCallback(int data)
    
        callback(data);
    

    void PassCallback()
    
        NETWrapper netWrapper;
        netWrapper.TestCallback(ReturnToCallback);
    
;

//Managed class
public ref class NETWrapper

public:
    void TestCallback(Action<int>^ callback)
    
       StartGenerator^ startGen = gcnew StartGenerator(callback);
    
;

// C# 
public class StartGenerator

    private Communication comm;

    public StartGenerator(Action<int> callback)
    
        comm = Communication.Instance;
        comm.callback = callback;
    

当然,这个解决方案在编译时会给我一个错误:

错误 3 错误 C3867: 'IfaceXXX::Wrapper::ReturnToCallback': 函数调用缺少参数列表;使用 '&IfaceXXX::Wrapper::ReturnToCallback' 创建指向成员 d:\XXX.h

的指针

我尝试了其他方法,例如获取函数指针的委托,以便我可以在托管 C++ 上工作并将其传递给 C#,但我无法正确实现它。您认为最好的尝试方法是什么?

【问题讨论】:

【参考方案1】:
    使Wrapper::callback 成为指向std::function 的指针。 将 Wrapper 更改为 ref class

就是这样。

public ref class Wrapper

public:
    std::function<void(int)>* callback;

    void ReturnToCallback(int data)
    
        (*callback)(data);
    

    void PassCallback()
    
        NETWrapper netWrapper;
        netWrapper.TestCallback(gcnew Action<int>(this, &Wrapper::ReturnToCallback));
    
;

那么你现在需要管理std::function 的生命周期,也许my clr_scoped_ptr 可以告诉你如何做到这一点。

【讨论】:

您好,我尝试将您的解决方案用于智能指针,但当 C# 项目调用保存的委托并使用此指针时,对象为空(Wrapper ref 类的实例不是)。 clr_scoped_ptr<:function>> ptr; public: Wrapper(std::function& callbackptr) : ptr(new std::function(callbackptr)) @MariosanzGómez:我没有遇到这个问题。检查您正在创建多少个 Wrapper 实例,可能您没有使用与回调指针关联的那个。 我已经检查过了,但没有...我只实例化包装类一次。我在这里为这个问题创建了另一个问题。如果你可以看看...***.com/questions/61170340/… 您可以通过在clr_scoped_ptr 的析构函数和终结器上放置断点来调试它。您不是在寻找我的课程中的错误,而是在您无意中导致清理过早发生时调用堆栈是什么。

以上是关于将非托管方法作为回调传递给托管 C++/CLI 类的主要内容,如果未能解决你的问题,请参考以下文章

将非托管GUID转换为托管Guid ^

如何使用 C++/CLI Wrapper 将变量参数从托管传递到非托管?

将回调参数从 C# 传递到非托管 C++

将非托管数据复制到托管数组中

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

如何将非托管库引用添加到 NUnit 测试