为什么我会在这个简单的例子中得到"PInvokeStackImbalance"?

Jus*_*tin 22 .net pinvoke extern

我正在创建一个非常简单的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);
Run Code Online (Sandbox Code Playgroud)

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

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

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

这都是在32位操作系统上.

Meh*_*dad 42

您需要改用要么

[DllImport("CommonNativeLib.dll", CallingConvention = CallingConvention.Cdecl)]
Run Code Online (Sandbox Code Playgroud)

要么

extern "C" __declspec(dllexport) int __stdcall Add(int a, int b) ...
Run Code Online (Sandbox Code Playgroud)

因为常规C函数的工作方式与Windows API函数不同; 他们的"调用约定"是不同的,这意味着他们如何传递参数是不同的.(这在错误中暗示过.)

  • 实际上Cdecl和StdCall之间的区别在于,对于StdCall,被调用者负责清理堆栈,而在Cdecl中,调用者是.因此,当您调用一个期望Cdecl为StdCall的函数时,您的堆栈将不会被清除,因此警告. (3认同)