Intereting Posts
Как передать определение макроса из аргументов командной строки «make» (-D) в исходный код C? подсчитать количество смежных прямоугольников адрес указателя malloc в основной и в другой разнице функций Как неинициализированная переменная получает случайное значение? MAP_ANONYMOUS с стандартом C99 c массив сквозной передачи типа int Изменение объекта const – нет предупреждения? Кроме того, в этом случае это UB? Преобразовать «нормальный» прямоугольник в набор векторов GLes? Использование X-списков и директив препроцессора для создания настраиваемого кода C Во время компиляции Включение строгого режима с плавающей запятой в GCC Почему int _ $ [:> = <% – !. 0,}; компилировать? Компилировать без генерации выходного файла в GCC Как можно определить макроопределение в качестве аргумента? Как компилировать и отлаживать C ++ в Notepad ++ с помощью компилятора Turbo C ++ Ошибка при попытке определить бит 1024 бит (128 байт)

Правильный способ вызова C DLL-метода из C #

Я пытаюсь выполнить некоторые методы (в данном конкретном случае, rdOnAllDone) из сторонней библиотеки DLL, написанные на C, и глядя через файлы заголовков, я нашел это:

#ifndef TDECLSDONE #ifdef STDCALL #define CCON __stdcall #else #define CCON __cdecl #endif #define TDECLSDONE #endif #define DLLIMP __declspec (dllimport) DLLIMP int CCON rdOnAllDone (void(CCON *)(int)); 

Ознакомившись с методом вызова этого метода, я сделал следующее:

 [DllImport("sb6lib.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int rdOnAllDone(Delegate d); public delegate void rdOnAllDoneCallbackDelegate(); private static void rdOnAllDoneCallback() { Console.WriteLine("rdOnAllDoneCallback invoked"); } 

Метод был вызван правильно, за исключением того, что я не смог получить параметр int. Поэтому я попытался добавить входной параметр int как это

 [DllImport("sb6lib.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int rdOnAllDone(Delegate d); public delegate void rdOnAllDoneCallbackDelegate(int number); private static void rdOnAllDoneCallback(int number) { Console.WriteLine("rdOnAllDoneCallback invoked " + number); } 

Но теперь делегат вызывается дважды, и он сбой программы со следующей ошибкой «vshosts32.exe перестала работать»

Каков правильный способ вызова этого метода DLL?

EDIT: Забыл добавить Основной метод:

 public static void Main() { rdOnAllDoneCallbackDelegate del3 = new rdOnAllDoneCallbackDelegate(rdOnAllDoneCallback); rdOnAllDone(del3); while (true) { Thread.Sleep(1000); } } 

Три вещи, которые вам нужно сделать, чтобы сделать эту работу правильной:

  • вам нужно указать маркеру pinvoke о фактическом типе делегата, используя делегат, недостаточно. Это создаст неправильный thunk, который не будет должным образом маршалировать аргумент. Это то, что вы видели.
  • вам нужно сообщить маршаллеру о вызывающем соглашении, если он не __stdcall с атрибутом [UnmanagedFunctionPointer]. Получение этого неправильного дисбаланса в стеке с хорошими шансами на жесткий крушение.
  • вам нужно сохранить ссылку на объект делегата, чтобы сборщик мусора не собирал его. Он не может видеть ссылки, хранящиеся в собственном коде. Если вы ошибетесь, это приведет к сбою внутреннего кода с жестким сбоем после следующей сборки мусора.

Так что это должно работать лучше, по мере необходимости настраивать:

 [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void rdOnAllDoneCallbackDelegate(int parameter); [DllImport("sb6lib.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int rdOnAllDone(rdOnAllDoneCallbackDelegate d); class Foo { private static rdOnAllDoneCallbackDelegate callback; // Keeps it referenced public static void SetupCallback() { callback = new rdOnAllDoneCallbackDelegate(rdOnAllDoneCallback); rdOnAllDone(callback); } private static void rdOnAllDoneCallback(int parameter) { Console.WriteLine("rdOnAllDoneCallback invoked, parameter={0}", parameter); } } 

Подпись вашего делегата должна совпадать с сигнатурой обратного вызова, также она должна иметь соответствующий UnmanagedFunctionPointerAttribute .

В вашем случае:

 [UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] public delegate void rdOnAllDoneCallbackDelegate(int parameter); [DllImport("sb6lib.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int rdOnAllDone(rdOnAllDoneCallbackDelegate callback); 

Использование:

 { rdOnAllDone(rdOnAllDoneCallback); } private static void rdOnAllDoneCallback(int parameter) { Console.WriteLine("rdOnAllDoneCallback invoked, parameter={0}", parameter); }