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

本文关键字:堆栈 不平衡 调用 PInvoke 函数 | 更新日期: 2023-09-27 18:28:50

我在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);
}

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

您的 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 - 尽管它并不完美,但它会显示正确的mouse_event声明。

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

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

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

你必须使用 uint 而不是 long

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

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

尝试使用下面的mouse_event符号。注意 uint 而不是 long

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

就我而言:

[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);

做到了。