,

DLL的一堆疑問

我所遇到的都是延續前人所做好的dll,也因此對dll的使用宣告方式有疑惑。以下是我study MSDN與網路上文章後,做一些實驗的重點整理:

  • declspec(dllexport)的Client除了.dll還會使用到.h.lib,有問題的話編譯就不會過。而.def則是透過LoadLibrary去讀取對應的dll,使用完畢就要用FreeLibrary去釋放記憶體,JNA也是使用這種方式。以.def來說,如果dll內的函式宣告沒改變,只有功能增加,可以透過.def控制匯出序數,讓那你的Client應用程式不需要重新編譯。
  • declspec(dllexport)的Client寫起來就像call API一樣;.def要透過GetProcAddress去取得dll函數的位置去呼叫。
  • 在支援x64的情況下,.def可以透過LoadLibrary去決定要讀取32-bit或64-bit版本,而declspec(dllexport)要透過前處理器與編譯參數去決定要參考的.lib。
  • 對於一個dll專案來說,兩者是可以同時使用的。

Reference

這三個宣告叫呼叫慣例(Calling Conventions)。三者將參數放入Stack的順序皆為由左至右,但還有以下差異存在:

  • 暫存器: fastcall會將第一個參數與第二個參數放入暫存器中,放在暫存器存取速度會比在stack中快,顧名思義它叫fastcall。cdecl與stdcall只會使用到stack。
  • 清除Stack的時機: cdecl是由function caller清除stack;fastcall與stdcall則是由callee清除。也因此cdecl允許於不定參數。

VC++預設使用cdecl,Borland C++預設使用fastcall。另外有幾點需要注意:

  • 匯出類別: 在32位元的呼叫慣例為thiscall,64為cdecl。
  • 64-bit VS 32-bit: 32-bit會根據編譯器設定決定呼叫慣例,但64-bit不適用於這些編譯參數。

對於呼叫慣例,可以透過VC的dumpbin.exe /export看它的宣告方式:

Reference