从C#调用C DLL方法的正确方法

我试图从第三方DLL执行一些方法(在这种特殊情况下,rdOnAllDone),用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方法的正确方法是什么?

编辑:忘记添加Main方法:

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

要使这项工作正确,您需要做三件事:

  • 你需要告诉pinvoke marshaller 实际的委托类型,使用Delegate不够好。 这将创造错误的thunk,不会正确地编组参数。 这就是你所看到的。
  • 如果它不是__stdcall与[UnmanagedFunctionPointer]属性,你需要告诉marshaller关于调用约定。 得到这个错误会使堆栈失败,并且有很大的可能性。
  • 您需要存储对委托对象的引用,以便垃圾收集器不会收集它。 它无法看到本机代码所持有的引用。 出现这种错误会导致本机代码在下一次垃圾收集后因硬崩溃而失败。

所以这应该更好,根据需要进行调整:

 [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); }