“Un appel à une fonction PInvoke a déséquilibré la stack”

J’ai créé une application de formulaire dans Visual C #, qui utilise une fonction pour générer un clic de souris, mais j’ai le message d’erreur suivant:

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. 

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

Votre déclaration d’API Win32 est incorrecte: “long” correspond à Int64 dans le .NET Framework, ce qui est presque toujours incorrect pour les appels d’API Windows.

Remplacer long par int devrait fonctionner:

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

Pour référence ultérieure, vous pouvez vérifier sur pinvoke.net chaque fois que vous recherchez le moyen correct d’appeler des fonctions d’API – bien que ce ne soit pas parfait, il aurait affiché la déclaration correcte pour mouse_event .

(EDIT, 26 mars 2012): Et bien que la déclaration que j’ai fournie fonctionne effectivement, remplacer long par uint serait encore mieux, car le DWORD de Win32 est un entier non signé de 32 bits. Dans ce cas, vous utiliserez plutôt un entier signé (étant donné que ni les drapeaux ni les autres arguments ne seront jamais assez grands pour causer un dépassement de signature), mais ce n’est certainement pas toujours le cas. La déclaration de pinvoke.net est correcte, ainsi que ce qui suit:

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

Une autre réponse à cette question fournissait déjà cette déclaration correcte, et la question non uint était également signalée dans des commentaires. J’ai édité ma propre réponse pour rendre cela plus évident; d’autres participants à SO doivent toujours se sentir libres d’éditer des publications incorrectes, BTW.

Essayez d’utiliser la mouse_event mouse_event. Notez uint au lieu de long .

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

Vous devez utiliser uint au lieu de long .

Notez que dans l’implémentation Microsoft C / C ++, long est identique à int et les deux sont en 32 bits (même sur une plate-forme 64 bits). Ils sont donc pratiquement interchangeables. Un int de 64 bits est long long . En revanche, en C #, int correspond à Int32 et long à Int64 . Donc, ils ne sont pas interchangeables!

Donc, ce qui se passe est que lorsque P / Invoking, il place 5 * 64 bits / 8 octets = 40 octets sur la stack. Mais la fonction native n’utilise et nettoie que 5 * 32 bits / 4 octets = 20 octets.

Dans mon cas:

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

a fait le tour.