1

我有一个库,我试图在 C# 中与 Dot Net 4 App 一起使用。这是一个二进制运行时,所以我无权访问库源。我收到错误

对 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 等的可能解决方案。虽然封送层应该解决这个问题,但可能会降低性能。加上它的混乱和不理想。但是,与此同时,在库更新之前,我仍然需要一个解决方案。

4

1 回答 1

1

不平衡的堆栈是一种令人讨厌的运行时问题。您倾向于在 Debug 构建中避开它,因为方法设置和拆除堆栈帧的方式可以隐藏堆栈指针值不正确的问题。堆栈指针在方法退出时恢复。在发布版本中,您获得这种运气的几率会更低。特别是由于方法内联,它删除了堆栈设置/拆卸代码。

.NET 4 中需要 NetFx40_PInvokeStackResilience 元素,因为它们优化了 pinvoke 编组器。这可能会破坏在早期版本中工作的错误代码,添加元素会禁用该优化。它对整个程序具有全局影响。这并不是要禁用 MDA,那将隐藏一个非常现实的问题。它只是为 IT 人员提供了一种解决兼容性问题的方法。

您可以通过将 pinvoke 调用放入一个单独的方法中来降低风险,该方法除了调用之外什么都不做。你必须用 [MethodImpl(MethodImplOptions.NoInlining)] 来装饰它,这样优化器就不能内联它。该辅助方法不能有任何outref参数,并且不能返回结构类型的值,并且在调用之后不应该有任何附加代码。

显然,您将希望投入尽可能多的时间来真正解决这个问题。有人可以帮助您处理原始 C 声明,但是我们无法帮助您找到他。不发布 pinvoke 声明也消除了有人猜测它的可能性。

于 2012-04-10T01:03:26.000 回答