2015-09-06 36 views
1

我創建了一個DLL文件,其中包括兩個空函數。stdcall調用約定和在C#中使用pinvoke#

extern "C" __declspec(dllexport) void __stdcall myFunc1() { 
    // just empty function 
} 

extern "C" __declspec(dllexport) void __cdecl myFunc2() { 
    // just empty function 
} 

在C#中,我可以打電話給使用DLLImport屬性類似下面的功能。

[DllImport("myDLL", CallingConvention=CallingConvention.StdCall)] 
private extern static void myFunc1(); 

[DllImport("myDLL", CallingConvention=CallingConvention.Cdecl)] 
private extern static void myFunc2(); 

所以我又直接與KERNEL32.DLL,而不是DllImport屬性的LoadLibrary()嘗試。

[UnmanagedFunctionPointer(CallingConvention.StdCall)] 
private delegate void MyFunc1(); 

[UnmanagedFunctionPointer(CallingConvention.Cdecl)] 
private delegate void MyFunc2(); 

當我打電話MyFunc1但是發生運行時錯誤()其中myfunc2所()的作品

因此,我用C++中的__cdecl代替__stdcall,重新編譯了DLL,然後再次在C#中調用MyFunc1()。

而且它工作。

爲什麼地球上沒有__stdcall調用約定與C#中的pinvoke工作?

+2

'DllImport' *是* P/Invoke。你想要做什麼? :D'UnmanagedFunctionPointer'將一個託管委託編組爲一個非託管函數指針(顧名思義) - 它與調用DLL中的非託管函數無關。好吧,不是「沒有」 - 顯然,你有一個委託你可以從非託管方傳遞或接收,但這不是你要在這裏做的。 – Luaan

+1

此外,根據'UnmanagedFunctionPointer'的文檔,'如果您沒有指定字段名稱,則忽略UnmanagedFunctionPointerAttribute.' - 我沒有看到您指定任何名稱。 – Luaan

+0

是的,你說得對。這次我使用「kernel32.dll」的LoadLibrary(),FreeLibrary()和GetProcAddress()。我沒有發佈其他代碼,因爲我認爲這對高手們來說只是一件基本的事情。 – Jenix

回答

6

這裏發生的事情是,當您在C++代碼中從__cdecl切換到__stdcall時,編譯器修飾了函數導出的名稱。它不是myFunc1而是作爲[email protected]或可能是[email protected]導出。同樣,這個名字是裝飾的。你可以用dumpbin或Dependency Viewer來檢查。

當您撥打GetProcAddress時,它找不到名爲myFunc1的函數,因此返回NULL。你不檢查返回值,所以不管。當您嘗試調用該函數時,將引發運行時錯誤。

我不得不猜測大部分,因爲你沒有顯示完整的代碼。另一大教訓是在調用Win32函數時檢查錯誤。

+0

謝謝,我會檢查它,如你所說。如果原因是名字裝飾,我該怎麼辦?我認爲關鍵字extern「C」可以防止與命名相關的問題。 – Jenix

+2

需要使用def文件導出 –

+0

好吧,我明白了,謝謝! – Jenix