在你的代碼,你上面顯示SetProgressHandlerCallback
功能如下:
void Importer::SetProgressHandlerCallBack(...) { ... }
有2個問題,這一點,這兩者都可以用一個簡單的最小完全可驗證的例子來說明,我創建一個新的Visual Studio解決方案,包含一個C#(WinForms)項目和一個C++ Dll(非託管而不是C++/CLI)。
在DLL(dllmain.cpp)我把下面的代碼:
typedef void (__stdcall *HandlerCallBack)(float);
extern "C" {
// extern "C" ignored for C++ classes
class __declspec(dllexport) TestClass
{
public:
static void CallMeBack(HandlerCallBack callback)
{
callback(1.0f);
}
};
void __declspec(dllexport) CallRightBack(HandlerCallBack callback)
{
TestClass::CallMeBack(callback);
}
}
你可以看到回調簽名匹配您正在使用的一個,和靜態類方法和導出函數。建立這個,啓動Visual Studio命令提示符並運行
dumpbin /exports <dllname>.dll
這使您從DLL,它看起來像這樣導出的函數:
(Trimmed to just show what we care about)
ordinal hint RVA name
1 0 00011082 [email protected]@[email protected][email protected]@Z = @ILT+125([email protected]@[email protected][email protected]@Z)
2 1 000110E1 [email protected]@[email protected]@@Z = @ILT+220([email protected]@[email protected]@@Z)
3 2 00011069 [email protected]@@[email protected]@Z = @ILT+100([email protected]@@[email protected]@Z)
4 3 00011014 CallRightBack = @ILT+15(CallRightBack)
你會發現,經常全局函數與其未裝飾名稱一起導出,但靜態方法導出,裝飾(已損壞)名稱爲。
現在讓我們向C#項目添加一些代碼,看看爲什麼這會成爲問題。添加2個按鈕(按鈕1和按鈕2 )。到形式,我添加以下代碼:
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
delegate void HandlerCallbackDelegate(float value);
[DllImport("CppDllTestProj.dll")]
static extern void CallRightBack([MarshalAs(UnmanagedType.FunctionPtr)]HandlerCallbackDelegate callback);
[DllImport("CppDllTestProj.dll")]
static extern void CallMeBack([MarshalAs(UnmanagedType.FunctionPtr)]HandlerCallbackDelegate callback);
HandlerCallbackDelegate callbackDel;
// in the designer associated with button1
private void button1_Click(object sender, EventArgs e)
{
if (this.callbackDel == null)
{
this.callbackDel = new HandlerCallbackDelegate(this.Callback);
}
CallRightBack(callbackDel);
}
// in the designer associated with button2
private void button2_Click(object sender, EventArgs e)
{
if (this.callbackDel == null)
{
this.callbackDel = new HandlerCallbackDelegate(this.Callback);
}
CallMeBack(callbackDel);
}
void Callback(float value)
{
MessageBox.Show(value.ToString());
}
編譯,將dll文件拷貝到C#項目的構建目錄,並運行。單擊button1,調用回調,並顯示消息框。單擊按鈕2和程序崩潰,但例外:
無法在DLL'CppDllTestProj.dll'中找到名爲'CallMeBack'的入口點。 at ScratchApp.Form1.CallMeBack(HandlerCallbackDelegate callback) at Form1中的ScratchApp.Form1.button2_Click(Object sender,EventArgs e)。cs:第49行
無法找到名爲「CallMeBack」的入口點,表示它無法在該DLL中找到具有該名稱的函數。如果我現在在C#測試應用程序改變CallMeBack
定義:
[DllImport("CppDllTestProj.dll", EntryPoint="[email protected]@@[email protected]@Z")]
static extern void CallMeBack([MarshalAs(UnmanagedType.FunctionPtr)]HandlerCallbackDelegate callback);
重新編譯,並重新啓動,現在兩個按鈕正常工作。 (您錯位/裝飾名稱可能有所不同。用你的dumpbin得到任何價值。)
這個問題的根源在於extern "c"
存儲類說明是爲C++類和類成員忽略。
,你會盡快解決你上面有另一個問題,是這樣的代碼:
void SomeFunction() {
HandlerCallBack cb = new HandlerCallBack (AssimpCallBack);
SetProgressHandlerCallBack (cb);
}
你會注意到,cb
垃圾收集可用從呼叫控制返回瞬間SetProgressHandlerCallBack
。一旦該代表被垃圾收集,任何回調都將失敗。壯觀。
技術上同樣的項目,我使用所有的測試,但每次我清除代碼。
創意的名字,我知道。
來源:Is it possible to export a C++ member method with C linkage in a DLL?
什麼異常,你所看到的? –
你認爲C++ \ CLI包裝是否可行?這是一種非常乾淨自然的方式來規避所有聲明式編組的東西。 –
_SetProgressHandlerCallBack 在(包裝託管到本機)ModellInstantiator:SetProgressHandlerCallBack(ModellInstantiator/HandlerCallBack)_ 這是我所看到的。 – gev29