Вызов функции 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 ответов:
Возможно, проблема заключается в соглашении о вызове. Вы уверены, что неуправляемая функция была скомпилирована как 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.