如何将函数指针从C#传递给C ++ Dll?

C ++ dll中定义的函数是:

static double (*Func1)(double); EXTERN_C __declspec(dllexport) __stdcall double TestDelegate(double (*fun)(double)) { Func1 = fun; return Func1(25.0); } void My_Real_purpose() { SomeClass a; a.SetFunction(Func1);//Define behaviour of a by C# in runtime a.DoSomething();//Even I want it runs in another thread! } 

我试着用C#这样称呼它:

  class A { [DllImport("DllName.dll")] public extern static double TestDelegate(IntPtr f); public delegate double MyFuncDelegate(double x); public static double MyFunc(double x) { return Math.Sqrt(x); } static MyFuncDelegate ff; static GCHandle gch; public static double Invoke() { ff = new MyFuncDelegate(MyFunc); gch = GCHandle.Alloc(ff); double c = TestDelegate(Marshal.GetFunctionPointerForDelegate(ff));//Error occurs this line gch.Free(); return c; } } 

它编译时没有错误。但是当它运行时,VS2012会显示“访问冲突exception”错误。

我已经搜索并尝试了很多方法,例如传递委托而不是IntPtr,但所有这些都certificate是失败的。

那么,在包含函数指针的dll中使用API​​函数的正确方法是什么?或者如何实现“My_Real_purpose”函数?

您的委托使用cdecl调用约定。 因此,在C#中,您将声明代理如下:

 [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate double CallbackDelegate(double x); 

作为替代方案,您可以决定将C ++中的函数指针声明为__stdcall ,在这种情况下,您将删除UnmanagedFunctionPointer属性并依赖于默认调用约定CallingConvention.StdCall

像这样实现它:

 public static double MyFunc(double x) { return Math.Sqrt(x); } 

为了使非托管函数指针保持活动状态(防止GC),您需要在变量中保存委托的实例。

 private static CallbackDelegate delegateInstance; .... delegateInstance = MyFunc; 

在这里的简单示例中,C ++代码不使用TestDelegate之外的非托管函数指针,但在更复杂的示例中,您可以这样做,在这种情况下,您必须保持非托管函数指针处于活动状态。

您导入的函数声明如下:

 [DllImport("DllName.dll")] public extern static double TestDelegate(CallbackDelegate f); 

然后你可以像这样调用它:

 double retval = TestDelegate(delegateInstance); 

在C ++方面,我明确指定了回调的调用约定 ,例如__stdcall (你的代码中没有这样做,我认为默认是__cdecl ):

 // Include the calling convention (__stdcall) for the Callback typedef double (__stdcall * Callback)(double); // Just use "Callback" here, instead of repeating // the above function prototype extern "C" __declspec(dllexport) __stdcall double TestDelegate(Callback func) { return func(25.0); } // BTW: Can export also using .DEF file to avoid __stdcall name mangling 

在C#方面,您可以尝试这样的事情:

 public delegate double CallbackDelegate(double x); // PInvoke declaration for the native DLL exported function [DllImport("YourDLL.dll", CallingConvention = CallingConvention.StdCall)] public static extern double TestDelegate(CallbackDelegate func); private double MyFunctionCallback(double x) { // ... Implement your C# callback code ... } CallbackDelegate managedDelegate = new CallbackDelegate(MyFunctionCallback); // Call into the native DLL, passing the managed callback TestDelegate(managedDelegate);