PInvokeStackImbalance C# вызов неуправляемой функции C++

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

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

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

  • Имя dll правильное.
  • Имя точки входа правильное и было проверено с помощью зависящего от.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 ответов

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

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

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

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

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

short __stdcall SuperSpecialOpenFileFunc(SuperSpecialStruct * stuff);

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

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

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

// The struct

#pragma pack(pop)

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

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

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

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

Это работает хорошо.

Другие вопросы по тегам