为什么在违反调用约定的情况下PInvoke不会崩溃(在.NET 3.5中)?

我的解决方案有一个非托管C DLL,它导出一个函数,一个托管应用程序PInvokes这个函数.

我刚刚将解决方案从.NET 3.5转换为.NET 4.0并得到了这个PInvokeStackImbalance“对PInvoke函数的调用[…]已经使堆栈失衡”异常.事实证明,我正在调用__cdecl’ed函数,因为它是__stdcall:

C部分(被调用者):

__declspec(dllexport) double TestFunction(int param1, int param2); // by default is __cdecl

C#部分(来电者):

[DllImport("TestLib.dll")] // by default is CallingConvention.StdCall
private static extern double TestFunction(int param1, int param2);

所以,我已经修复了这个bug,但现在我对.NET 3.5中的工作原理感兴趣吗?当没有人(既不是被叫者也不是调用者)清理堆栈时,为什么(多次重复)情况没有引起堆栈溢出或其他一些不当行为,但只是工作正常?是否有某种PInvoke支票,就像Raymond Chen在article中提到的那样?
这也很有趣,为什么相反类型的破坏约定(让__stdcall被调用者像被__cdecl一样被PInvoked)根本不起作用,导致只有EntryPointNotFoundException.

PInvokeStackImbalance也不例外.它是一个MDA警告,由托管调试助手实现.让MDA处于活动状态是可选的,您可以从“调试例外”对话框中进行配置.在没有调试器的情况下运行它永远不会处于活动状态.

使堆栈不平衡可能会导致非常令人讨厌的问题,从奇怪的数据损坏到获取SOE或AVE.很难诊断.但它也可以完全没有问题,当方法返回时,堆栈指针会恢复.

编译为64位的代码往往具有弹性,更多的函数参数通过寄存器而不是堆栈传递.当被迫在x86(VS2010的新默认值)上运行时,它将失败.

相关文章
相关标签/搜索