"A call to a PInvoke function has unbalanced the stack"
Asked Answered
P

4

8

I created a Form application in visual c#, that uses a function to generate mouse click, but i got the following error message:

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.

My Code:

[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);
}
Portillo answered 24/3, 2012 at 20:42 Comment(1)
Check this answer. Should resolve your problem as probably mouse_event is written using Cdecl calling convention.Matthaeus
V
15

Your Win32 API declaration is incorrect: 'long' maps to Int64 in the .NET Framework, which is almost always incorrect for Windows API calls.

Replacing long with int should work:

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

For future reference, you may want to check pinvoke.net whenever you're looking for the correct way to invoke API functions -- although it's not perfect, it would have shown the correct declaration for mouse_event.

(EDIT, 26 March 2012): And although the declaration I provided indeed works, replacing long with uint would be even better, as Win32's DWORD is a 32-bit unsigned integer. In this case, you'll get away with using a signed integer instead (as neither the flags nor the other arguments will ever be large enough to cause sign overflow), but this is definitely not always the case. The pinvoke.net declaration is correct, as is the following:

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

Another answer to this question already provided this correct declaration, and the uint issue was also pointed out in comments. I edited my own answer to make this more obvious; other SO participants should always feel free to edit incorrect posts as well, BTW.

Vinylidene answered 24/3, 2012 at 20:51 Comment(1)
Actually, your declaration is wrong. C DWORD is an unsigned 32 bit integer. So in C# you need uint.Receivership
E
5

You have to use uint instead of long.

Note that in the Microsoft C/C++ implementation, long is the same as int, and both are 32bit (even on a 64bit platform). So they are practically interchangeable. A 64bit int is long long. In contrast, in C#, int maps to Int32, and long maps to Int64. So they are not interchangeable!

So what happens is that when P/Invoking, it places 5*64 bits/8 bytes = 40 bytes on the stack. But the native function only uses and cleans up 5*32 bits/4 bytes = 20 bytes.

Edouard answered 24/3, 2012 at 20:59 Comment(0)
E
4

Try using the folowing mouse_event signeture. Note uint instead of long.

static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData,  int dwExtraInfo);
Emulsify answered 24/3, 2012 at 20:45 Comment(2)
thx! It works for me, like the solution of @mdb, but a simple int can be better than an unsigned integerPortillo
@Portillo Why would int be better than uint? A C DWORD is unsigned and so Pavel's answer is correct.Receivership
P
0

In my case:

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

did the trick.

Playsuit answered 15/3, 2018 at 15:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.