PInvokeStackImbalance Appel C # vers une fonction C ++ non gérée

Après avoir basculé vers VS2010, l’assistant de débogage géré affiche une erreur concernant une stack non équilibrée provenant d’un appel à une fonction C ++ non gérée à partir d’une application C #.

Les suspects habituels ne semblent pas être à l’origine du problème. Y a-t-il autre chose que je devrais vérifier? L’application C ++ dll et C # de VS2008 n’a jamais eu de problème, pas de bugs étranges ou mystérieux – oui, je sais que cela ne veut pas dire grand chose.

Voici les choses qui ont été vérifiées:

  • Le nom de la DLL est correct.
  • Le nom du point d’entrée est correct et a été vérifié à l’aide de depend.exe – le code doit utiliser le nom tronqué et c’est le cas.
  • La convention d’appel est correcte.
  • Les tailles et les types semblent tous corrects.
  • Le jeu de caractères est correct.
  • Il ne semble y avoir aucun problème après avoir ignoré l’erreur et il n’y a pas de problème lors de l’exécution en dehors du débogueur.

C #:

[DllImport("Correct.dll", EntryPoint = "SuperSpecialOpenFileFunc", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, ExactSpelling = true)] public static extern short SuperSpecialOpenFileFunc(ref SuperSpecialStruct stuff); [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] public struct SuperSpecialStruct { public int field1; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public ssortingng field2; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)] public ssortingng field3; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)] public ssortingng field4; public ushort field5; public ushort field6; public ushort field7; public short field8; public short field9; public uint field10; public short field11; }; 

C ++:

 short SuperSpecialOpenFileFunc(SuperSpecialStruct * stuff); struct SuperSpecialStruct { int field1; char field2[256]; char field3[20]; char field4[10]; unsigned short field5; unsigned short field6; unsigned short field7; short field8; short field9; unsigned int field10; short field11; }; 

Voici l’erreur:

Assistant de débogage géré ‘PInvokeStackImbalance’ a détecté un problème dans ‘Chemin d’application géré’.

Informations supplémentaires: Un appel à la fonction PInvoke ‘SuperSpecialOpenFileFunc’ a déséquilibré la stack. Cela est probablement dû au fait que la signature PInvoke gérée ne correspond pas à la signature cible non gérée. Vérifiez que la convention d’appel et les parameters de la signature PInvoke correspondent à la signature non gérée cible.

Comme mentionné dans le commentaire de Dane Rose , vous pouvez utiliser __stdcall sur votre fonction C ++ ou déclarer CallingConvention = CallingConvention.Cdecl sur votre DllImport .

C’est la réponse qui résout mon problème.

Vous spécifiez stdcall en C # mais pas en C ++, une incompatibilité entraînera à la fois la fonction et les arguments de l’appelant en dehors de la stack.

D’autre part, il existe un commutateur de compilation qui active stdcall comme convention d’appel par défaut, (-Gz) l’utilisez-vous?

Ou essayez ceci dans votre C ++

 short __stdcall SuperSpecialOpenFileFunc(SuperSpecialStruct * stuff); 

Vous ne spécifiez aucun remplissage dans votre déclaration C # de la structure, mais pas dans la version C ++. Comme vous mélangez des tableaux de caractères qui ne sont pas tous des multiples de quatre et un nombre impair de courts-circuits de 2 octets, le compilateur insère probablement un remplissage dans la structure et ajoute la fin.

Essayez d’envelopper la structure dans un #pragma pack pour vous assurer qu’il n’y a pas de remplissage.

 #pragma pack(push) #pragma pack(1) // The struct #pragma pack(pop) 

Avait le même problème que décrit – application C ++ non gérée qui a parfaitement fonctionné pendant des années. Lorsque nous avons mis à niveau vers VS2010, nous avons commencé à recevoir des messages PInvokeStackUnbalanced.

L’ajout de “__stdcall” à la signature C ++ décrite ci-dessus a fait disparaître le problème.

C’est bien. La fonction de mise à jour définit comme suit:

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

Ça marche bien.