“对 PInvoke 函数的调用使堆栈不平衡”

Posted

技术标签:

【中文标题】“对 PInvoke 函数的调用使堆栈不平衡”【英文标题】:"A call to a PInvoke function has unbalanced the stack" 【发布时间】:2012-03-24 20:42:39 【问题描述】:

我在 Visual c# 中创建了一个表单应用程序,它使用一个函数来生成鼠标点击,但我收到以下错误消息:

A call to PInvoke function '...Form1::mouse_event' has unbalanced the stack.
This is likely because the managed PInvoke signature does not match the unmanaged target
signature. Check that the calling convention and parameters of the PInvoke signature match 
the target unmanaged signature.

我的代码:

[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void mouse_event(long dwFlags, long dx, long dy, long cButtons, long dwExtraInfo);

private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;

...

void GenerateMouseClick(int x, int y)

    Cursor.Position = new Point((int)x, (int)y);
    mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, Cursor.Position.X, Cursor.Position.Y, 0, 0);

【问题讨论】:

检查this answer。应该可以解决您的问题,因为 mouse_event 可能是使用 Cdecl 调用约定编写的。 【参考方案1】:

您的 Win32 API 声明不正确:“long”映射到 .NET Framework 中的 Int64,这对于 Windows API 调用几乎总是不正确的。

用 int 替换 long 应该可以:

public static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);

为了将来参考,您可能需要在寻找调用 API 函数的正确方法时查看 pinvoke.net —— 虽然它并不完美,但它会显示 correct declaration for mouse_event。

(编辑,2012 年 3 月 26 日): 虽然我提供的声明确实有效,但将 long 替换为 uint 会更好,因为 Win32 的 DWORD 是 32 位的无符号整数。在这种情况下,您可以改用有符号整数(因为标志和其他参数都不会大到足以导致符号溢出),但情况并非总是如此。 pinvoke.net 声明是正确的,如下:

public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, uint dwExtraInfo);

这个问题的另一个答案已经提供了这个正确的声明,并且在 cmets 中也指出了 uint 问题。我编辑了自己的答案以使其更加明显;顺便说一句,其他 SO 参与者也应该随时编辑不正确的帖子。

【讨论】:

其实你的声明是错误的。 C DWORD 是一个无符号的 32 位整数。所以在 C# 中你需要uint【参考方案2】:

您必须使用uint 而不是long

请注意,在 Microsoft C/C++ 实现中,longint 相同,并且都是 32 位(即使在 64 位平台上)。所以它们实际上是可以互换的。 64 位整数是 long long。相比之下,在 C# 中,int 映射到 Int32long 映射到 Int64。所以它们不能互换!

所以发生的情况是,当 P/Invoking 时,它会将 5*64 位/8 字节 = 40 字节放在堆栈上。但是native函数只使用和清理了5*32 bits/4 bytes = 20 bytes。

【讨论】:

【参考方案3】:

尝试使用以下mouse_event 签名。注意 uint 而不是 long

static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData,  int dwExtraInfo);

【讨论】:

谢谢!它对我有用,就像@mdb 的解决方案一样,但是一个简单的 int 可以比一个无符号整数更好 @Pmillan 为什么int 会比uint 更好? A C DWORD 未签名,因此 Pavel 的答案是正确的。【参考方案4】:

就我而言:

[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi)]
public static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);

成功了。

【讨论】:

以上是关于“对 PInvoke 函数的调用使堆栈不平衡”的主要内容,如果未能解决你的问题,请参考以下文章

我应该使用 scipy.pi、numpy.pi 还是 math.pi?

pi 的 pi 的 pi 的 pi 次方是否是个整数?

查看圆周率 Pi值 Pi的前百位 Pi的前百万位

C:如何将浮点数包装到区间 [-pi, pi)

pi节点申请了就能通过吗

注册过pi账号为啥重新登录成了新账号