PInvokeStackImbalance C # вызов неуправляемой функции C ++ - PullRequest
39 голосов
/ 06 марта 2010

После переключения на VS2010, управляемый помощник по отладке отображает ошибку о несбалансированном стеке при вызове неуправляемой функции C ++ из приложения C #.

Обычные подозреваемые, кажется, не вызывают проблему. Есть что-то еще, что я должен проверить? Созданные на VS2008 приложения C ++ dll и C # никогда не имели проблем, никаких странных или таинственных ошибок - да, я знаю, что это мало что значит.

Вот что было проверено:

  • Имя dll правильное.
  • Имя точки входа правильное и проверено с помощью depen.exe - код должен использовать искаженное имя, и это действительно так.
  • Соглашение о вызовах правильное.
  • Размеры и типы кажутся правильными.
  • Набор символов правильный.
  • Кажется, что после игнорирования ошибки не возникает никаких проблем, и при запуске вне отладчика проблем не возникает.

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

Вот ошибка:

Помощник по управляемой отладке «PInvokeStackImbalance» обнаружил проблема в «Управляемом пути приложения».

Дополнительная информация: звонок в Функция PInvoke SuperSpecialOpenFileFunc имеет разбалансировать стек. Это скорее всего потому что управляемая PInvoke подпись не соответствует неуправляемой цели подпись. Проверьте, что звонящий условности и параметры PInvoke подпись соответствует цели неуправляемая подпись.

Ответы [ 5 ]

60 голосов
/ 07 августа 2010

Как уже упоминалось в комментарии Дейна Роуза , вы можете либо использовать __stdcall в своей функции C ++, либо объявить CallingConvention = CallingConvention.Cdecl в своей DllImport.

Это ответ, который решает мою проблему.

9 голосов
/ 06 марта 2010

Вы указываете stdcall в C #, но не в C ++, здесь несоответствие приведет к тому, что функция и вызывающая сторона вытолкнут аргументы из стека.

С другой стороны, есть переключатель компилятора, который включит stdcall в качестве соглашения о вызовах по умолчанию, (-Gz) вы используете это?

Или попробуйте это в вашем C ++

short __stdcall SuperSpecialOpenFileFunc(SuperSpecialStruct * stuff);
3 голосов
/ 06 марта 2010

Вы не указываете заполнение в своем объявлении C # структуры, но не в версии C ++. Поскольку вы смешиваете массивы символов, которые не являются кратными четырем и нечетным числом 2-байтовых шортов, компилятор, вероятно, вставляет заполнение в структуру и добавляет конец.

Попробуйте обернуть структуру в #pragma pack, чтобы избежать заполнения.

#pragma pack(push)
#pragma pack(1)

// The struct

#pragma pack(pop)
2 голосов
/ 26 мая 2010

У меня была та же проблема, что и описанная - неуправляемое приложение C ++, которое отлично работало в течение многих лет. Когда мы обновились до VS2010, мы начали получать сообщения PInvokeStackUnbalanced.

добавление "__stdcall" к сигнатуре C ++, как описано выше, устраняет проблему.

1 голос
/ 21 сентября 2015

Это хорошо. Я функцию обновления определяю следующим образом:

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

Хорошо работает.

...