如何解决通过使用 SuppressGCTransition 修饰的 P/Invoke 调用将 UnmanagedCallersOnly 函数指针传递给 C++ 时崩溃
假设我们有以下 C++ 代码:
typedef int (*getIntPtr)(void);
extern "C" __declspec(dllexport) void InvokeFuncPtr(getIntPtr funcPtr) {
std::wcout << funcPtr();
}
我们可以在 C# 中匹配这个定义:
[DllImport("NativeLib.dll",CallingConvention = CallingConvention.Cdecl),SuppressGCTransition]
public static unsafe extern void InvokeFuncPtr(delegate* unmanaged[Cdecl]<int> funcPtr);
然后我们可以像这样使用这个函数:
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
public static int ReturnInt() => 123;
// ... Elsewhere:
unsafe {
InvokeFuncPtr(&ReturnInt);
}
当 InvokeFuncPtr
被标记为 SuppressGCTransition
时,这会导致程序崩溃并出现错误“致命错误。无效程序:试图从托管代码调用 UnmanagedCallersOnly 方法。”.如果我们删除 SuppressGCTransition
属性,它会按预期工作,并且 123
会打印到控制台。
这是预期的行为吗?我想这相当于运行时将 ReturnInt()
视为从托管代码调用,只需几个额外的间接步骤。如果是这样,有什么办法可以解决这个问题,还是我应该直接关闭 SuppressGCTransition
属性?
解决方法
是的,您应该省略 SuppressGCTransition
,因为堆栈是运行时用来识别调用者是托管还是非托管的。
如果堆栈中没有转换,则运行时无法判断堆栈已转换为非托管。
或者,您可以不使用 UnmanagedCallersOnly
,而是使用 Marshal.GetFunctionPointerForDelegate
封送委托。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。