所以我有一个我正在使用的本地 3rd 方 C++ 代码库(.lib 和 .hpp 文件),我曾经在 C++/CLI 中构建一个包装器,以便最终在 C# 中使用。
从调试模式切换到发布模式时,我遇到了一个特殊问题,即当回调的代码返回时,我得到一个访问冲突异常。
回调函数格式的原始 hpp 文件中的代码:
typedef int (*CallbackFunction) (void *inst, const void *data);
用于回调函数格式的 C++/CLI Wrapper 代码:(稍后我将解释为什么我声明了两个)
public delegate int ManagedCallbackFunction (IntPtr oInst, const IntPtr oData);
public delegate int UnManagedCallbackFunction (void* inst, const void* data);
--很快,我声明第二个“UnManagedCallbackFunction”的原因是我试图在包装器中创建一个“中介”回调,因此链从 Native C++ > C# 更改为 Native C++ > C++/CLI Wrapper > C# 的版本...完全披露,问题仍然存在,它只是被推送到 C++/CLI Wrapper 现在在同一行(返回)。
最后,来自 C# 的崩溃代码:
public static int hReceiveLogEvent(IntPtr pInstance, IntPtr pData)
{
Console.WriteLine("in hReceiveLogEvent...");
Console.WriteLine("pInstance: {0}", pInstance);
Console.WriteLine("pData: {0}", pData);
// provide object context for static member function
helloworld hw = (helloworld)GCHandle.FromIntPtr(pInstance).Target;
if (hw == null || pData == null)
{
Console.WriteLine("hReceiveLogEvent: received null instance pointer or null data\n");
return 0;
}
// typecast data to DataLogger object ptr
IntPtr ip2 = GCHandle.ToIntPtr(GCHandle.Alloc(new DataLoggerWrap(pData)));
DataLoggerWrap dlw = (DataLoggerWrap)GCHandle.FromIntPtr(ip2).Target;
//Do Logging Stuff
Console.WriteLine("exiting hReceiveLogEvent...");
Console.WriteLine("pInstance: {0}", pInstance);
Console.WriteLine("pData: {0}", pData);
Console.WriteLine("Setting pData to zero...");
pData = IntPtr.Zero;
pInstance = IntPtr.Zero;
Console.WriteLine("pData: {0}", pData);
Console.WriteLine("pInstance: {0}", pInstance);
return 1;
}
所有对控制台的写入都已完成,然后我们在返回时看到可怕的崩溃:
helloworld.exe 中 0x04d1004c 处的未处理异常:0xC0000005:访问冲突读取位置 0x04d1004c。
如果我从这里进入调试器,我所看到的只是调用堆栈上的最后一个条目是:>“04d1004c()”,其值为:80805964
仅当您查看显示以下内容的控制台时,这才是有趣的:
entering registerDataLogger
pointer to callback handle: 790848
fp for callback: 2631370
pointer to inst: 790844
in hReceiveLogEvent...
pInstance: 790844
pData: 80805964
exiting hReceiveLogEvent...
pInstance: 790844
pData: 80805964
Setting pData to zero...
pData: 0
pInstance: 0
现在,我知道在调试和发布之间,在微软世界中有些事情是完全不同的。我当然担心变量的字节填充和初始化,所以如果有什么我没有在这里提供,请告诉我,我会添加到(已经很长的)帖子中。我还认为托管代码可能不会释放所有所有权,然后本机 C++ 内容(我没有代码)可能会尝试删除或终止 pData 对象,从而使应用程序崩溃。
更全面的披露,在调试模式下一切正常(似乎)!
一个真正的头部划伤问题,将不胜感激任何帮助!