45 votes

Un appel à la fonction PInvoke '[...]' a déséquilibré la pile.

Hey
Je reçois cette erreur bizarre sur certains trucs que j'utilise depuis un certain temps. Il s'agit peut-être d'une nouveauté de Visual Studio 2010, mais je n'en suis pas sûr.
J'essaie d'appeler une fonction inchangée écrite en C++ depuis C#.
D'après ce que j'ai lu sur Internet et le message d'erreur lui-même, cela a quelque chose à voir avec le fait que la signature de mon fichier C# n'est pas la même que celle du C++, mais je ne vois vraiment pas pourquoi.
Tout d'abord, voici ma fonction inchangée ci-dessous :
TEngine GCreateEngine(int width,int height,int depth,int deviceType); Et voici ma fonction en C# :
[DllImport("Engine.dll", EntryPoint = "GCreateEngine", CallingConvention = CallingConvention.StdCall)] public static extern IntPtr CreateEngine(int width,int height,int depth,int device);
Lorsque je débogue en C++, je vois tous les arguments sans problème. Je ne peux donc que penser que cela a quelque chose à voir avec la transformation de TEngine (qui est un pointeur vers une classe appelée CEngine) en IntPtr. J'ai déjà utilisé cette méthode dans VS2008 sans problème.
J'espère que mon problème est suffisamment clair pour que vous puissiez le comprendre.

87voto

Scott Morken Points 461

J'avais une dll c++ _cdecl que j'ai appelée sans problème depuis Visual Studio 2008, puis le code identique dans Visual Studio 2010 ne fonctionnait pas. J'ai obtenu la même erreur PInvoke ... a déséquilibré la pile également.

La solution pour moi a été de spécifier la convention d'appel dans l'attribut DllImport(...) : De : [DllImport(CudaLibDir)] Vers : [DllImport(CudaLibDir, CallingConvention = CallingConvention.Cdecl)]

Je suppose qu'ils ont changé la convention d'appel par défaut pour DLLImport entre .Net3.5 et .Net4.0.

49voto

Keith Vinson Points 516

Il se peut également que dans la version 3.5 de .NET Framework, le MDA pInvokeStackImbalance soit désactivé par défaut. Sous la version 4.0 (ou peut-être VS2010), elle est activé par défaut .

Oui. Techniquement, le code a toujours été faux, et les versions précédentes du le framework l'a corrigé silencieusement.

Pour citer le Document sur les problèmes de migration de .NET Framework 4 : "Pour améliorer performance dans l'interopérabilité avec le code non géré, les conventions d'appel d'appel incorrectes dans un invoke de plate-forme provoquent maintenant l'échec de l'application. Dans versions précédentes, la couche de marshaling résolvait ces erreurs en haut de la pile... Si vous avez des binaires qui ne peuvent pas être mis à jour, vous pouvez inclure le fichier < NetFx40_PInvokeStackResilience > dans le fichier de configuration de votre application afin d'activer l'appel des d'être résolues en haut de la pile comme dans les versions précédentes. Cependant, cela peut affecter les performances de votre application."

Une façon simple de résoudre ce problème est de spécifier la convention d'appel et de s'assurer qu'elle est la même que dans la DLL. A __declspec(dllexport) devrait donner un cdecl format.

[DllImport("foo.dll", CallingConvention = CallingConvention.Cdecl)]

22voto

PeterK Points 4218

Le problème réside peut-être dans la convention d'appel. Etes-vous sûr que la fonction non gérée a été compilée en tant que stdcall et pas autre chose (je suppose fastcall) ?

5voto

user3610819 Points 11

Utilisez le code suivant, si disons que votre DLL a le nom de MyDLL.dll et vous voulez utiliser la fonction MaFonction au sein de la Dll

[DllImport("MyDLL.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
public static extern void MyFunction();

cela a fonctionné pour moi.

2voto

Dans mon cas (VB 2010 et DLL compilé avec Intel Fortran 2011 XE), le problème se pose lorsque mon application cible .NET Framework 4. Si je change le framework ciblé pour la version 3.5, alors tout fonctionne bien comme prévu. Donc, je suppose que la raison est quelque chose d'introduit dans .Net Framework 4 mais je n'ai aucune idée pour le moment de laquelle

Mise à jour : Le problème a été résolu en recompilant Fortran DLL et en spécifiant explicitement STDCALL comme convention d'appel pour les noms d'exportation dans la DLL.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X