Решение для исключения PInvokeStackImbalance (вызов неуправляемой C ++ dll из C #) - VS2010 - PullRequest
0 голосов
/ 14 января 2011

Я провел целый день в своей жизни, решая эту проблему, и я не хочу, чтобы кто-то другой делал то же самое.Итак, вот и проблема, и решение:

Проблема : вы получаете исключение PInvokeStackImbalance при попытке использовать методы в DLL C ++ в вашем коде C #.Вот типичное объявление, которое вы видите в примерах ...

Пример, который не работает

(C++ .h file)
extern "C" {
    __declspec(dllexport) int Addints(int a, int b);
    }

(C++ .cpp file)
extern int Addints(int a, int b) {
        return a+b;
    }

(C# .cs file)
[DllImport("testdll.dll")]
        static extern int Addints(int a, int b);

 static void Main(string[] args)
        {
            Console.WriteLine("Hello world lets add some stuff");
            Int32 a = 3;
            Int32 b = 5;

            Console.WriteLine(Addints(a,b));
        }

Когда вы запускаете это, он жалуется, что выразбалансируйте стек (на нет!) и что вам действительно не следует продолжать.Это также говорит о том, что вы должны проверить подпись вашего метода, чтобы убедиться, что они совпадают.

Ложь всякая ложь.

Исправление : Вам нужно добавить одну ~ крошечную вещь в выражение DLLImport, например:

Это исправление

[DllImport("testdll.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern int Addints(int a, int b);

Да, это вещь CallingConvention?Reeeeeeeeeeealy важно.

Несколько других советов:
- Убедитесь, что вы создаете как dll, так и C # exe для одной и той же цели.Win32 и x86 (например) соответственно
- Убедитесь, что ваша dll собрана с параметром / clr (Свойства проекта - Свойства конфигурации - Общие)
- Имейте в виду, что ваши C ++ int, float, string могут не бытьтот же размер на другой стороне границы (проверьте здесь , чтобы увидеть, как типы совпадают)
- И для действительно хорошего пошагового примера проверьте programmersnotebook.wordpress.com/2010/01/ 18 / призвание-а-каст-длл-из-сСта

Ответы [ 4 ]

1 голос
/ 14 января 2011

shedemon

Я ненавижу это делать, но ваш ответ - не полный ответ.По умолчанию C / C ++ использует соглашение о вызовах Cdecl, поэтому причина, по которой вы должны декалировать, очевидна.

Реальное решение - просто объявить соглашение о вызовах в коде C ++.

http://msdn.microsoft.com/en-us/library/zxk0tw93(v=VS.100).aspx

Существуют и другие соглашения о вызовах http://msdn.microsoft.com/en-us/library/984x0h58.aspx, поэтому ваш ответ действительно зависит от соглашения о вызовах неуправляемого кода C / C ++.

Я подозреваю, что VS2008 имеет больше возможностейс .NET Framework 3.5, то что угодно.

Просто измените свою функцию следующим образом:

__declspec(dllexport) int __stdcall Addints(int a, int b); 
0 голосов
/ 14 января 2011

Извините за ранее неработающую ссылку Типы данных вызова платформы можно найти здесь:

http://msdn.microsoft.com/en-us/library/ac7ay120.aspx

0 голосов
/ 14 января 2011

Да, это мило.Однако это также работает - читая то, что я написал, чуть внимательнее, я сказал, что это исправление «типичной декларации, которую вы видите в примерах».Какие примеры вы могли бы спросить?Вот несколько примеров:

dotnetperls.com / dllimport
programmersnotebook.wordpress.com/2010/01/18/calling-a-cpp-dll-from-cs/
blogs.msdn.ru / b / jonathanswift / archive / 2006/10/02 / 780637.aspx
msdn.microsoft.com/en-us/library/aa984739(VS.71).aspx
msdn.microsoft.com/en-us / library / 26thfadc.aspx
www.codeguru.com/columns/kate/article.php/c3947
www.apachetechnology.net/KC/NativeDLL2Net.aspx

Asпока я не видел этот вариант.Тем не менее, если они оба работают, то в чем проблема?Если вам нужна слава, тогда вы идете: браво!престижность!Теперь у людей есть два варианта на выбор.Да, и между прочим, ваш "ответ не полный ответ":

 (C++ .h) extern "C" {
     __declspec(dllexport) int __stdcall Addints(int a, int b);  }


 (C++ .cpp) int __stdcall Addints(int a, int b) {
 return a+b; }

Вам также необходимо изменить файл cpp.

Еще раз - я на VS2010 с .Net4 (не уверен, что вы имели в виду там с комментарием о VS2008.)

0 голосов
/ 14 января 2011

Короткая версия:

Убедитесь, что ваш оператор DllImport в C # включает параметр CallingConvention, установленный в CallingConvention.Cdecl

Подробнее см. Выше

...