Вызов функции PInvoke '[ ... ] ' разбалансировал стек


Я получаю эту странную ошибку на некоторых вещах, которые я использую в течение довольно долгого времени. Это может быть новая вещь в Visual Studio 2010, но я не уверен.
Я пытаюсь вызвать неангажированную функцию, написанную на C++ из C#.
Из того, что я прочитал в интернете, и самого сообщения об ошибке, это как-то связано с тем, что подпись в моем файле C# не такая же, как в C++, но я действительно не могу ее увидеть.
Прежде всего, это моя неизменяемая функция ниже:

TEngine GCreateEngine(int width,int height,int depth,int deviceType);

А вот моя функция в C#:

[DllImport("Engine.dll", EntryPoint = "GCreateEngine", CallingConvention = CallingConvention.StdCall)]  
        public static extern IntPtr CreateEngine(int width,int height,int depth,int device);

Когда я отлаживаю в C++ , я вижу все аргументы просто отлично, поэтому я могу только думать, что это имеет какое-то отношение к преобразованию из TEngine (который является указателем на класс cengine) в IntPtr. Я использовал это раньше в VS2008 без проблем.

5 43

5 ответов:

Возможно, проблема заключается в соглашении о вызове. Вы уверены, что неуправляемая функция была скомпилирована как stdcall, а не что-то другое ( я бы предположил fastcall ) ?

У меня была библиотека dll _cdecl c++, которую я без проблем вызвал из Visual Studio 2008, а затем идентичный код в Visual Studio 2010 не работал. Я получил тот же самый Пинвоук ... также разбалансировал ошибку стека.

Решением для меня было указать соглашение о вызове в DllImport(...) атрибут: Откуда:

[DllImport(CudaLibDir)] 

Кому:

[DllImport(CudaLibDir, CallingConvention = CallingConvention.Cdecl)]

Я думаю, они изменили соглашение о вызовах по умолчанию для DLLImport между .NET 3.5 и .NET 4.0?

Возможно также, что в .NET Framework версии 3.5 MDA pInvokeStackImbalance по умолчанию отключена. Под 4.0 (или, может быть, VS2010) он включен по умолчанию.

Да. Технически, код всегда был неправильным, и предыдущие версии фреймворк молча поправил его.

Процитируем документ .NET Framework 4 Migration Issues : "для улучшения производительность при взаимодействии с неуправляемым кодом, некорректный вызов конвенций в вызов платформы теперь вызывает сбой приложения. В в предыдущих версиях уровень маршалинга разрешал эти ошибки до стек... Если у вас есть двоичные файлы, которые не могут быть обновлены, вы можете включить элемент NetFx40_PInvokeStackResilience> в файле конфигурации вашего приложения для включения вызова ошибки, которые будут устранены в стеке, как и в предыдущих версиях. Однако, это может повлиять на производительность вашего приложения."

Простой способ исправить это-указать соглашение о вызове и убедитесь, что оно такое же, как в DLL. Формат __declspec(dllexport) должен давать формат cdecl.

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

Используйте следующий код, если, скажем, ваша библиотека DLL имеет имя MyDLL.dll и вы хотите использовать функцию MyFunction внутри Dll

[DllImport("MyDLL.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
public static extern void MyFunction();
Это сработало для меня.

В моем случае (VB 2010 и DLL, скомпилированные с Intel Fortran 2011 XE) проблема существует, когда мое приложение нацелено на .NET Framework 4. Если я изменю targeted framework на версию 3.5, то все будет работать нормально, как и ожидалось. Итак, я бы предположил, что причина в чем-то введенном в .Net Framework 4, но я понятия не имею, какой из них

Update: проблема была решена путем перекомпиляции библиотеки DLL Fortran и явного указания STDCALL в качестве вызывающего соглашения для имен экспорта в файл DLL.