将 C# 函数传递给 CLI/C++ 代码时出现垃圾回收器错误



我尝试将 C# 函数指针传递到 CLI/C++ 代码中,就像这里一样? 当我使用以下代码时,出现以下错误

A callback was made on a garbage collected delegate of type 'MyProject!MyClass.CallbackFunc::Invoke'. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called.

C# 项目 A

private void Init()
{
MyWrapper.Instance.SetCallbackFunc(MyFunc);
}
private void MyFunc(int id, bool success)
{
}

C++/CLI 项目 B

//MyWrapper.cpp
public delegate void CallbackFunc(int, bool);
System::Void SetCallbackFunc(CallbackFunc^ callback)
{
System::IntPtr ip = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(callback);
auto cb = static_cast<void(*)(int, bool)>(ip.ToPointer());      
unmanagedCppClass->SetCallbackFunc(cb);
}

unmanagedCppClass.cpp

typedef void(*funcPtr)(int, bool);
void SetCallbackFunc(funcPtr callback)
{
}

我试图使ipcb全球化,所以GC不会收集,但它没有帮助

System::IntPtr ip;
funcPtr cb;
System::Void SetCallbackFunc(CallbackFunc^ callback)
{
ip = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(callback);
cb = static_cast<funcPtr>(ip.ToPointer());      
unmanagedCppClass->SetCallbackFunc(cb);
}

您需要保留委托对象,以免它被垃圾回收。要保留的重要对象是托管委托对象,而不是非托管函数指针。

在当前实现中,当您调用SetCallbackFunc(MyFunc)时,将从MyFunc创建一个委托对象,并将该委托对象传递给 C++/CLI 方法。当SetCallbackFunc返回时,不再有对委托对象的引用,因此会收集它。GetFunctionPointerForDelegate的结果是一个愚蠢的原始函数指针,它无法使托管对象保持活动状态,因此保持该函数指针没有任何作用。

可以在 C# 或 C++/CLI 中使委托保持活动状态。

在 C# 中:

private CallbackFunc keepalive_myfunc;
private void Init()
{
keepalive_myfunc = MyFunc;
MyWrapper.Instance.SetCallbackFunc(keepalive_myfunc);
}

或者在 C++/CLI 中:

CallbackFunc^ keepalive_callback;
System::Void SetCallbackFunc(CallbackFunc^ callback)
{
keepalive_callback = callback;
...
}

相关内容

  • 没有找到相关文章

最新更新