2013-09-27 65 views
1

的非託管函數,回調函數表示爲std :: function()obj,而不是更常用的函數指針結構。將託管函數傳遞給在我的C++代碼中使用std :: function()

MYCALLBACK myCBFunc; // some member variable 
void SetCallbackFunction(MYCALLBACK cbFunc) 
{ 
    myCBFunc = cbFunc; 
} 

在C#:

typedef std::function<void()> MYCALLBACK; 

在C++中的回調函數是通過設置

delegate void MyCallbackFunc(); // delegate matching the c++ callback sig 

// method matching the call back sig 
void foo() 
{ } 

[DllImport("mydll.dll")] 
static extern SetCallbackFunction(MyCallbackFunc cbfunc); 

// set the callback 
MyCallbackFunc cb = foo; 
SetCallbackFunction(cb); // crash here 

編譯OK,但AccessViolationException運行時崩潰。 我最初以爲這是因爲myCallBack函數obj是在棧上,並且需要通過引用傳遞,改變了簽名匹配,但它仍然崩潰即

MYCALLBACK myCBFunc; // some member variable 
void SetCallbackFunction(MYCALLBACK& cbFunc) 
{ 
    myCBFunc = cbFunc; 
} 

[DllImport("mydll.dll")] 
static extern SetCallbackFunction(ref MyCallbackFunc cbfunc); 

// set the callback 
MyCallbackFunc cb = foo; 
SetCallbackFunction(ref cb); // crash here 

我如何得到這個用的std ::功能工作()?使用普通的舊函數指針沒有問題。

+1

這是非託管C++的權利?將託管對象的引用傳遞給非託管代碼是個不錯的主意。垃圾回收器沒有看到委託對象的引用,並最終收集它。 – helb

+0

是的,正常的C++。但有一個委託變量應該繞過這個問題嗎? – cks2k2

+1

否,只要C++庫可以調用回調,就必須確保其他一些託管對象有引用。如果變量超出範圍,則可能會收集對象。 – helb

回答

1

std::function<void()>是一個類模板。它看起來像一個函數,因爲類重載operator()。因此,std::function<void()>是一個類,意味着它不是與非託管函數指針二進制兼容的。

你需要使用:

typedef void (*MYCALLBACK)(); 

需要注意的是此功能的cdecl。將它切換到C++中的stdcall,或者將C#委託聲明爲cdecl。我希望你知道如何去做前者。下面是後者的一個例子:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)] 
delegate void MyCallbackFunc(); 

你的PInvoke也是錯誤的,因爲它不應該通過回調作爲ref參數。它應該是:

[DllImport("mydll.dll")] 
static extern SetCallbackFunction(MyCallbackFunc cbfunc); 
相關問題