Я пытаюсь выполнить некоторые методы (в данном конкретном случае, 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); } }
Три вещи, которые вам нужно сделать, чтобы сделать эту работу правильной:
Так что это должно работать лучше, по мере необходимости настраивать:
[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); }