2017-04-05 210 views
2

在C中定义的函数++ DLL是:如何将函数指针从C#传递给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; 
     } 

    } 

它不error.But被编译当它运行时,VS2012显示错误“访问违规例外”。

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

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

+0

的可能的复制[妙传C++函数指针由C#调用 - 函数的参数包括宽字符串(LPCWSTR)](http://stackoverflow.com/questions/6282264/pass-a-function-pointer-from-c-to-be-called-by-c-sharp-函数参数) –

+0

我删除了COM标签,因为这个问题与COM无关; PInvoke标签更合适。 –

+1

委托声明是错误的,但这不足以解释AVE。确保您知道如何调试C++代码,以便您可以诊断此崩溃。显示你得到的堆栈跟踪。 –

回答

2

你委托的用途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); 
0

在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);