Вызов функции PInvoke '[...]' разбалансирует стек - PullRequest
44 голосов
/ 31 мая 2010

Я получаю эту странную ошибку на некоторых вещах, которые я использую уже довольно давно. Это может быть новой вещью в 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 ]

85 голосов
/ 08 февраля 2011

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

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

[DllImport(CudaLibDir)] 

Кому:

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

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

48 голосов
/ 21 июля 2011

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

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

Цитируя документ .NET Framework 4 «Проблемы миграции» : «Чтобы улучшить производительность во взаимодействии с неуправляемым кодом, неправильный вызов соглашения в вызове платформы теперь приводят к сбою приложения. В В предыдущих версиях слой маршалинга разрешал эти ошибки до стек ... Если у вас есть двоичные файлы, которые не могут быть обновлены, вы можете включить элемент <<a href="http://msdn.microsoft.com/en-us/library/ff361650%28v=vs.100%29.aspx" rel="noreferrer"> NetFx40_PInvokeStackResilience > в файле конфигурации вашего приложения для включения вызова ошибки должны решаться в стеке, как в более ранних версиях. Тем не мение, это может повлиять на производительность вашего приложения. "

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

[DllImport("foo.dll", CallingConvention = CallingConvention.Cdecl)]
22 голосов
/ 31 мая 2010

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

5 голосов
/ 07 мая 2014

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

[DllImport("MyDLL.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
public static extern void MyFunction();

это сработало для меня.

2 голосов
/ 11 ноября 2010

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

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

...