1. 程式人生 > >DLL 匯出方法(兩種)

DLL 匯出方法(兩種)

.def 檔案必須至少包含下列模組定義語句:

  • 檔案中的第一個語句必須是 LIBRARY 語句。 此語句將 .def 檔案標識為屬於 DLL。 LIBRARY 語句的後面是 DLL 的名稱。 連結器將此名稱放到 DLL 的匯入庫中。

  • EXPORTS 語句列出名稱,可能的話還會列出 DLL 匯出函式的序號值。 通過在函式名的後面加上 @ 符和一個數字,給函式分配序號值。 當指定序號值時,序號值的範圍必須是從 1 到 N,其中 N 是 DLL 匯出函式的個數。 

例如,包含實現二進位制搜尋樹的程式碼的 DLL 看上去可能像下面這樣:

  1. LIBRARY BTREE
  2. EXPORTS
  3. Insert @1
  4. Delete @2
  5. Member @3
  6. Min @4

如果使用 MFC DLL 嚮導建立 MFC DLL,則嚮導將為您建立主幹 .def 檔案並將其自動新增到專案中。 新增要匯出到此檔案的函式名。 對於非 MFC DLL,必須親自建立 .def 檔案並將其新增到專案中。

如果匯出 C++ 檔案中的函式,必須將修飾名放到 .def 檔案中,或者通過使用外部“C”定義具有標準 C 連結的匯出函式。 如果需要將修飾名放到 .def 檔案中,則可以通過使用 DUMPBIN 工具或 /MAP 連結器選項來獲取修飾名。 請注意,編譯器產生的修飾名是編譯器特定的。 如果將 Visual C++ 編譯器產生的修飾名放到 .def 檔案中,則連結到 DLL 的應用程式必須也是用相同版本的 Visual C++ 生成的,這樣呼叫應用程式中的修飾名才能與 DLL 的 .def 檔案中的匯出名相匹配。

如果生成 擴充套件 DLL 並使用 .def 檔案匯出,則將下列程式碼放在包含匯出類的標頭檔案的開頭和結尾:

  1. #undef AFX_DATA
  2. #define AFX_DATA AFX_EXT_DATA
  3. // <body of your header file>
  4. #undef AFX_DATA
  5. #define AFX_DATA

這些程式碼行確保內部使用的 MFC 變數或新增到類的變數是從擴充套件 DLL 匯出(或匯入)的。 例如,當使用 DECLARE_DYNAMIC 派生類時,該巨集擴充套件以將 CRuntimeClass 成員變數新增到類。 省去這四行程式碼可能會導致不能正確編譯或連結 DLL,或在客戶端應用程式連結到 DLL 時導致錯誤。

當生成 DLL 時,連結器使用 .def 檔案建立匯出 (.exp) 檔案和匯入庫 (.lib) 檔案。 然後,連結器使用匯出檔案生成 DLL 檔案。 隱式連結到 DLL 的可執行檔案在生成時連結到匯入庫。

請注意,MFC 本身使用 .def 檔案從 MFCx0.dll 匯出函式和類。

網址:https://msdn.microsoft.com/zh-cn/d91k01sh(v=vs.90)

使用 __declspec(dllexport) 從 DLL 匯出  

Microsoft 在 Visual C++ 的 16 位編譯器版本中引入了 __export,使編譯器得以自動生成匯出名並將它們放到一個 .lib 檔案中。 然後,此 .lib 檔案就可以像靜態 .lib 那樣用於與 DLL 連結。

在更新的編譯器版本中,可以使用 __declspec(dllexport) 關鍵字從 DLL 匯出資料、函式、類或類成員函式。 __declspec(dllexport) 會將匯出指令新增到物件檔案中,因此您不需要使用 .def 檔案。

當嘗試匯出 C++ 修飾函式名時,這種便利最明顯。 由於對名稱修飾沒有標準規範,因此匯出函式的名稱在不同的編譯器版本中可能有所變化。 如果使用 __declspec(dllexport),僅當解決任何命名約定更改時才必須重新編譯 DLL 和依賴 .exe 檔案。

許多匯出指令(如序號、NONAME 和 PRIVATE)只能在 .def 檔案中建立,並且必須使用 .def 檔案來指定這些特性。 不過,在 .def 檔案的基礎上另外使用 __declspec(dllexport) 不會導致生成錯誤。

若要匯出函式,__declspec(dllexport) 關鍵字必須出現在呼叫約定關鍵字的左邊(如果指定了關鍵字)。 例如:

__declspec(dllexport) void __cdecl Function1(void);

若要匯出類中的所有公共資料成員和成員函式,關鍵字必須出現在類名的左邊,如下所示:

  1. class __declspec(dllexport) CExampleExport : public CObject
  2. { ... class definition ... };
System_CAPS_note說明

__declspec(dllexport) 不能應用於具有 __clrcall 呼叫約定的函式。

生成 DLL 時,通常建立一個包含正在匯出的函式原型和/或類的標頭檔案,並將 __declspec(dllexport) 新增到標頭檔案中的宣告中。 若要提高程式碼的可讀性,請為 __declspec(dllexport) 定義一個巨集並對正在匯出的每個符號使用該巨集:

#define DllExport   __declspec( dllexport ) 

__declspec(dllexport) 將函式名儲存在 DLL 的匯出表中。 

System_CAPS_note說明

將 DLL 原始碼從 Win16 移植到 Win32 時,請用 __declspec(dllexport) 替換 __export 的每個例項。

作為參考,請在 Win32 Winbase.h 標頭檔案中搜索。 它包含 __declspec(dllimport) 的用法示例。

網址:https://msdn.microsoft.com/zh-cn/a90k134d(v=vs.90)

模組定義 (.Def) 檔案  

模組定義 (.def) 檔案為連結器提供有關被連結程式的匯出、特性及其他方面的資訊。 生成 DLL 時,.def 檔案最有用。 由於存在可代替模組定義語句使用的 連結器選項,通常不需要 .def 檔案。 

在連結器階段可以使用 /DEF(指定模組定義檔案)連結器選項呼叫 .def 檔案。

如果生成的 .exe 檔案沒有匯出,使用 .def 檔案將使輸出檔案較大並降低載入速度。

有關更多資訊,請參見下列章節:

網址:https://msdn.microsoft.com/zh-cn/28d6s79h(VS.90).aspx