调用PInvoke函数时,堆栈不平衡。

8

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

请查看这个答案。很可能你的问题会得到解决,因为mouse_event函数使用了Cdecl调用约定。 - Masood Khaari
4个回答

15

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

将long替换为int应该可以解决问题:

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

以后,您可能希望在查找调用API函数的正确方法时检查pinvoke.net--虽然它不完美,但它会显示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);

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


实际上,你的声明是错误的。C中的DWORD是一个无符号32位整数。因此在C#中你需要使用uint - David Heffernan

5
你需要使用uint而不是long
请注意,在Microsoft的C/C++实现中,longint相同,都是32位(即使在64位平台上也是如此)。因此它们几乎可以互换。64位的int是long long。相比之下,在C#中,int映射到Int32,而long映射到Int64。因此它们不能互换!
因此,在P/Invoking时,它会将5*64位/8字节=40字节放置在堆栈上。但本地函数只使用和清理了5*32位/4字节=20字节。

4
尝试使用以下mouse_event签名。请注意,uint替代了long
static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData,  int dwExtraInfo);

谢谢!这对我有用,就像@mdb的解决方案一样,但是一个简单的int可能比无符号整数更好。 - Pmillan
@Pmillan 为什么 intuint 更好?C 中的 DWORD 是无符号的,所以 Pavel 的答案是正确的。 - David Heffernan

0
在我的情况下:
[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);

解决了问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接