【发布时间】:2010-11-27 12:31:09
【问题描述】:
所以我有一个我正在使用的本地 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;
}
对控制台的所有写入都已完成,然后我们在返回时看到可怕的崩溃:
在 0x04d1004c 中未处理的异常 helloworld.exe: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
现在,我知道在调试和发布之间,在 Microsoft 世界中有些事情是完全不同的。我当然担心变量的字节填充和初始化,所以如果有什么我没有在这里提供,请告诉我,我会添加到(已经很长的)帖子中。我还认为托管代码可能不会释放所有所有权,然后本机 C++ 内容(我没有代码)可能会尝试删除或终止 pData 对象,从而使应用程序崩溃。
更全面的披露,在调试模式下一切正常(似乎)!
一个真正的头疼问题,希望得到任何帮助!
【问题讨论】:
标签: c# c++ c++-cli callback access-violation