对于这个简单的示例,为啥我会得到“检测到 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”?的主要内容,如果未能解决你的问题,请参考以下文章
错误:WatchActivity 无法解析为一种类型,为啥我会得到这个? [复制]