我正在尝试使用C#中的Dot Net 4应用程序库。这是一个binaray运行时,所以我没有访问库源。我收到了错误
对PInvoke函数'XXXXXXXXXXX.WinAPI :: GetDCEx'的调用具有 堆栈不平衡。这可能是因为托管PInvoke 签名与非托管目标签名不匹配。检查一下 调用约定和PInvoke签名匹配的参数 目标非托管签名。
如果我禁用PInvokeStackImbalance MDA,则应用程序会运行,因为调试器不再抛出它。虽然这解决了应用程序未运行的问题,但显然存在问题。
我最近读到了关于NetFx40_PInvokeStackResilience的一个元素,你可以放在app.config中,它告诉运行时使用编组层来检测和修复不正确的平台调用声明(就像之前的.Net版本一样)。
<configuration>
<runtime>
<NetFx40_PInvokeStackResilience enabled="1" />
</runtime>
.....
</configuration>
问题是这似乎对调试器没有任何作用,调试器仍会调用错误。
我的问题是,我是否还需要禁用PInvokeStackImbalance MDA?
我如何判断NetFx40_PInvokeStackResilience是否有效且编组层正在完成其工作?
PS我正在使用Visual Studio 2010 Express
PPS我已经写了库的所有者,并提供了修改他的DllImports等的可能解决方案。虽然编组层应该解决问题,但可能会有性能成本。加上它的混乱而不理想。但是,与此同时,我需要一个解决方案,直到库得到更新。
答案 0 :(得分:1)
不平衡堆栈是一种令人讨厌的运行时问题。您倾向于在Debug构建中使用它,因为方法设置和拆除堆栈帧的方式可以隐藏不正确的堆栈指针值的问题。在方法退出时恢复堆栈指针。在Release版本中,你获得这种运气的几率会更低。特别是由于方法内联,它删除了堆栈设置/拆除代码。
.NET 4中需要NetFx40_PInvokeStackResilience元素,因为它们优化了pinvoke marshaller。哪个可以破坏在早期版本中有效的坏代码,添加该元素会禁用该优化。它对整个计划具有全球影响。 不意味着禁用MDA,这将隐藏一个非常现实的问题。它只是让IT人员解决兼容性问题。
您可以通过将pinvoke调用放入一个除了拨打电话之外什么都不做的单独方法来降低风险。您必须使用[MethodImpl(MethodImplOptions.NoInlining)]修饰它,以便优化器无法内联它。该辅助方法不能包含任何 out 或 ref 参数,并且不能返回结构类型的值,并且在调用后不应该有任何其他代码。
显然,您希望尽可能多地投入时间来真正解决这个问题。那里有人可以用原始的C声明来帮助你,但是我们无法帮助你找到他。不发布pinvoke声明也消除了有人猜测它的几率。