我尝试将 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)
{
}
我试图使ip
和cb
全球化,所以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;
...
}