web-dev-qa-db-fra.com

PInvokeStackImbalance Appel C # à une fonction C ++ non managée

Après le passage à VS2010, l'assistant de débogage géré affiche une erreur concernant une pile non équilibrée 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 DLL + C++ construite en 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é avec depend.exe - le code doit utiliser le nom modifié 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 pas y avoir de 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 string field2;
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
   public string field3;
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
   public string 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:

L'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 pile. 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 paramètres de la signature PInvoke correspondent à la signature non gérée cible.

39
user287498

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

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

60
Graviton

Vous spécifiez stdcall en C # mais pas en C++, une incompatibilité ici mènera à la fois la fonction et les arguments de l'appelant hors de la pile.

D'un autre côté, il existe un commutateur de compilation qui activera stdcall comme convention d'appel par défaut, (-Gz) l'utilisez-vous?

Ou essayez ceci dans votre C++

short __stdcall SuperSpecialOpenFileFunc(SuperSpecialStruct * stuff);
9
John Knoeller

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

Essayez d'encapsuler la structure dans un #pragma pack pour éviter tout rembourrage.

#pragma pack(Push)
#pragma pack(1)

// The struct

#pragma pack(pop)
3
Michael

J'ai eu le même problème que celui décrit - une application C++ non gérée qui fonctionne parfaitement depuis des années. Lorsque nous sommes passés à VS2010, nous avons commencé à recevoir des messages PInvokeStackUnbalanced.

l'ajout de "__stdcall" à la signature C++ comme décrit ci-dessus a fait disparaître le problème.

2
user351059

C'est bien, la fonction de mise à jour est définie comme suit:

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

Ça marche bien.

1
Vicky