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

时间:2012-03-24 20:42:40

标签: c# .net visual-studio click pinvoke

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

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

4 个答案:

答案 0 :(得分:14)

您的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的{{1} }是一个32位无符号整数。在这种情况下,您将使用有符号整数(因为标志和其他参数都不会大到足以导致符号溢出),但这绝对不是这样。 pinvoke.net声明是正确的,如下所示:

DWORD

这个问题的另一个答案已经提供了这个正确的声明,并且在评论中也指出了public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, uint dwExtraInfo); 问题。我编辑了自己的答案,使其更加明显;其他SO参与者也应该随时编辑错误的帖子,BTW。

答案 1 :(得分:5)

您必须使用uint代替long

请注意,在Microsoft C / C ++实现中,longint相同,均为32位(即使在64位平台上)。所以它们实际上是可以互换的。 64位int是long long。相反,在C#中,int映射到Int32long映射到Int64。所以它们不可互换!

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

答案 2 :(得分:4)

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

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

答案 3 :(得分: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);

做了这个伎俩。