"Вызов функции PInvoke нарушил баланс стека"

Я создал приложение формы в 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);
}

4 ответов


объявление Win32 API неверно: "длинные" карты Int64 в .NET Framework, что почти всегда неверно для вызовов Windows API.

замена long на int должна работать:

публичный статический пустота Экстерн mouse_event(инт элемент dwflags, ДХ инт, инт ды, cButtons инт, инт dwExtraInfo);

для будущей справки, вы можете проверить pinvoke.net всякий раз, когда вы ищете правильный способ вызова функций API , хотя это не идеально, это показало бы правильное объявление для mouse_event.

(правка, 26 марта 2012): и хотя декларация, которую я предоставил, действительно работает, заменяя 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 всегда должны чувствовать себя свободно редактировать неправильные сообщения, кстати.


попробуйте использовать folowing mouse_event signeture. Примечание uint с вместо долго.

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

вы должны использовать uint вместо long.

обратите внимание, что в реализации Microsoft C/C++long это то же самое, что int, и оба 32bit (даже на 64-битной платформе). Поэтому они практически взаимозаменяемы. 64-битный int-это long long. Напротив, в C#,int карты Int32 и long карты Int64. Так что они не взаимозаменяемы!

Итак, что происходит, когда P / Invoking помещает 5 * 64 бит/8 байт = 40 байт в стек. Но собственная функция использует и очищает только 5 * 32 бит / 4 байта = 20 байтов.


в моем случае:

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

сделал свое дело.