2010-05-31 3 views
41

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

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 без проблем.

+0

Привет всем, Я столкнулся с той же проблемой, но с Visual studio 2013. Я напрямую добавил ссылку на dll C++ в мой проект C#, который отлично работал в 2010 году, но не в 2013 году. Я также упомянул CallingConvention.Cdecl – Finisher001

ответ

20

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

+0

Извините, но Я этого не понимаю. Я собрал точно так же, как я сказал по моему вопросу. Я не добавлял никаких __std или ничего подобного. До этого он работал очень хорошо без него. EDIT: но теперь, по-видимому, добавление __std в прототипе функции и декларации исправляет его. Спасибо – Sanctus2099

+0

Если бы эта точная проблема - я предположил, что declspec (dllexport) сделал их stdcall по какой-то причине, но это было не так. Изменение соглашения о вызове моей DLL для явного указания соглашения о вызове (а также указание на C# тоже) устранило мою проблему. – ArtHare

2

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

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

77

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

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

[DllImport(CudaLibDir)] 

To:

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

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

+0

У меня была та же проблема, и это предложение мгновенно исправило это. Спасибо, Скотт! (Microsoft - «Добавление ненужной сложности к вашей работе с 1987 года!») – user20493

+0

Это также зафиксировало мою проблему! Престижность. :) – eandersson

+0

@ user20493: см. Отредактированный ответ Кейта. – mafu

46

Также может быть, что в версии .NET Framework 3.5, по умолчанию отключена функция MDA pInvokeStackImbalance. До 4.0 (или VS2010) это enabled by default.

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

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

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

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

спасибо. это сработало –

4

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

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

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

+2

Что вы здесь по-другому? Почему это решило проблему? –

Смежные вопросы