2017-04-05 207 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);