对于这个简单的示例,为啥我会得到“检测到 PInvokeStackImbalance”?

Posted

技术标签:

【中文标题】对于这个简单的示例,为啥我会得到“检测到 PInvokeStackImbalance”?【英文标题】:Why do I get "PInvokeStackImbalance was detected" for this simple example?对于这个简单的示例,为什么我会得到“检测到 PInvokeStackImbalance”? 【发布时间】:2011-04-09 03:12:32 【问题描述】:

我正在创建一个非常简单的 PInvoke 示例:

extern "C" __declspec(dllexport) int Add(int a, int b)

    return a + b;


[DllImport("CommonNativeLib.dll")]
extern public static int Add(int a, int b);

return NativeMethods.Add(a, b);

但每当我调用上述NativeMethods.Add 方法时,我都会得到以下托管调试助手:

检测到 PInvokeStackImbalance 消息:对 PInvoke 函数 'CommonManagedLib!CommonManagedLib.NativeMethods::Add' 的调用使堆栈不平衡。这可能是因为托管 PInvoke 签名与非托管目标签名不匹配。检查 PInvoke 签名的调用约定和参数是否与目标非托管签名匹配。

然后调用以预期的返回值完成,但出现 MDA 消息既烦人又令人担忧——我还没有完全理解 PInvoke,但从我读到的内容来看,我很确定我的签名是正确 - 我做错了什么?

这一切都在 32 位操作系统上。

【问题讨论】:

【参考方案1】:

您需要改为使用 either

[DllImport("CommonNativeLib.dll", CallingConvention = CallingConvention.Cdecl)]

extern "C" __declspec(dllexport) int __stdcall Add(int a, int b) ...

因为常规 C 函数的工作方式与 Windows API 函数不同;它们的“调用约定”不同,这意味着它们传递参数的方式不同。 (这在错误中有所暗示。)

【讨论】:

实际上 Cdecl 和 StdCall 之间的区别在于,在 StdCall 中,被调用者负责清理堆栈,而在 Cdecl 中,调用者负责。因此,当您调用一个期望 Cdecl 作为 StdCall 的函数时,您的堆栈将不会被清理,因此会发出警告。 @ChrisWue:我只是在做一个手动解释,而不是深入细节,但是,是的,这是最大的不同;谢谢。 (顺便说一句,这是 StdCall,而不是 StdDecl。) 这解决了我在 32 位和 64 位操作系统上的问题,即使 OP 只有 32 位。谢谢!【参考方案2】:

堆栈不平衡的原因是签名不匹配,否则调用约定默认调用约定是stdcall。当您的调用约定是 stdcall 时,如果您希望调用者使用 cdecl 调用约定清理堆栈,则被调用者清理堆栈。你可以找到更多Here

但是如果你因为签名而面临,只需通过上面的链接 Solve Signature based Stack Imbalance issues using PInvoke extension

【讨论】:

以上是关于对于这个简单的示例,为啥我会得到“检测到 PInvokeStackImbalance”?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我会得到欧洲/柏林时区 0:53 的偏移量?

FFT 和加速度计数据:为啥我会得到这个输出?

错误:WatchActivity 无法解析为一种类型,为啥我会得到这个? [复制]

为啥我会在 Python 类定义中的生成器中得到这个 NameError?

为啥我会得到“未处理的异常类型 IOException”?

为啥这个简单的 pyqtgraph 示例不起作用?