一、庫項目的生成
- 靜態庫:函數和數據被編譯進一個二進制文件(.LIB文件)。在使用的靜態庫編譯鏈接可執行文件時,鏈接器從庫中複製這些函數並編譯到exe文件當中。也就是說發佈exe文件時,是不需要發佈被使用的靜態庫的。
- 靜態庫的項目配置:(1)項目-> 屬性->常規->“MFC的使用”選擇“在靜態庫中使用MFC”(2)進入項目-> 屬性->C/C++->代碼生成->*“運行庫”選擇“多線程調試MTd”*或者“多線程MT”,如果是Debug模式選擇前者,Release模式選擇後者。
- 動態庫:動態庫項目生成兩個文件引入庫(.lib)和一個DLL(.dll)。注意這個lib文件時不同於上邊的LIB文件的。引入庫文件(.lib)包含改DLL導出的函數名和變量名,而.dll文件包含該庫實際的函數和數據。當使用動態庫編程生成exe文件時只需要lib文件即可,但是發佈並運行exe文件時需要加載相應的dll文件。
- 動態庫的項目配置:(1)項目-> 屬性->常規->“MFC的使用”選擇“在共享DLL中使用MFC”(2)項目-> 屬性->C/C++->代碼生成->*“運行庫”選擇“多線程調試DLL(/MDd)”*或者“多線程DLL(/MD)”,如果是Debug模式選擇前者,Release模式選擇後者。
- /MT 的意思就是使用微軟的多線程靜態鏈接庫;/MD 的意思就是使用微軟的多線程動態鏈接庫。不要混合使用運行時庫的靜態版本和動態版本。在一個進程中使用同一個庫的多個版本時會導致問題,經常提示已在.obj中定義,因爲庫副本中的靜態數據不與其他庫副本共享。鏈接器禁止在 .exe 文件內部既使用靜態版本又使用動態版本鏈接。
二、庫項目函數的導出和導入
如果我們的程序想要使用(導入/加載)某個DLL中的函數,那麼該函數必須在DLL中是已經導出的。
1、從DLL中導出函數
- def文件:只需要在
EXPORT
後邊加上要導出的函數名就行(只需要函數名,不需要形參)。其實def文件的功能相當於extern “C” __declspec(dllexport) - 使用_declspec(dllexport)聲明導出函數(既可以顯示又可以隱時)
dllexport
是在這些類、函數以及數據的申明的時候使用。使用了(dllexport)關鍵字,相當於聲明瞭緊接在(dllexport)關鍵字後面的相關內容是可以爲其他程序使用的。 - Dll文件中可以同時使用上述兩種方法,但是網上大家都推薦使用第二種,好像第一種有的時候函數名會自己變。
2、隱式鏈接方式加載DLL
首先需要配置需要的lib文件,之後再採用extern或_declspec(dllimport)聲明。配置lib文件有兩種,一種是在項目屬性中配置,另一種是在程序中加入下述代碼(比如說使用的是A.lib文件),這兩種方式效果是一樣的。
#include "A.h"
#pragma comment(lib,"A.lib")
- 可以使用extern聲明庫函數,即在使用之前,用extern聲明一下dll導出的函數即可,如
extern int add(int a,int b)
。但是還是建議用下邊這種方式: - 使用_declspec(dllimport)聲明庫函數。
dllimport
關鍵字是在外部程序需要使用DLL內相關內容時使用的關鍵字。當一個外部程序要使用DLL內部代碼(類,函數,全局變量)時,只需要在 程序內部使用(dllimport)關鍵字聲明需要使用的代碼就可以了。
_declspec(dllexport)
與_declspec(dllimport)
是相互呼應,只有在DLL內部用dllexport作了聲明,才能 在外部函數中用dllimport導入相關代碼。實際上,在應用程序訪問DLL時,實際上就是應用程序中的導入函數與DLL文件中的導出函數進行鏈接。
3、關於__declspec(dllexport)和__declspec(dllimport)的使用
經常是在.h文件中聲明函數/類/數據的導出和導入,那麼問題來了,庫文件的.h文件既被庫項目加載(這個時候應該是dllexport)又被將來使用庫文件的項目加載(這個時候應該是dllimport),那麼該怎麼辦呢,應當這麼辦:
在庫項目的開頭定義宏DLLProvider
,然後在需要的.h文件中加入這樣的代碼,以後當使用dllexport或dllimport的時候,都使用DLL_EXPORT_IMPORT
就行了。
#ifdef DLLProvider
#define DLL_EXPORT_IMPORT __declspec(dllexport) //在庫項目中使用
#else
#define DLL_EXPORT_IMPORT __declspec(dllimport)//在使用dll的項目中使用
#endif
三、其他關鍵的命令字
1、extern"C"
我們經常在程序(尤其是一些年代比較久,比如說早期的庫文件裏)裏見到這樣的代碼
#ifdef __cplusplus
extern "C" {
#endif
...
#ifdef __cplusplus
}
#endif
這個宏#ifdef __cplusplus
意思是說,如果該文件是Cpp文件,extern "C" {
和}
生效。當Cpp文件中出現這些代碼,意味着花括號裏邊的代碼是以C語言的編譯規則生成彙編語言。
雖然C++是在C語言的基礎上發展起來的,但是有些C代碼和C++的編譯規則存在一定差異。爲了兼容這部分代碼,C++創始人制定了上述的解決方法,在C++文件(也就是cpp文件)允許C語言代碼直接存在,只需要在頭上聲明一下這部分代碼需要按C語言的方法進行編譯,也就是extern "C"
的存在