c++中靜態庫和動態庫的建立與連結
2、動態庫
在使用動態庫的時候,往往提供兩個檔案:一個引入庫(.lib)和一個DLL(.dll)檔案。雖然引入庫的字尾也是.lib ,但是動態庫的引入庫檔案和靜態庫檔案有著本質的區別,對一個DLL來說,其引入庫檔案(.lib)包含DLL匯出的函式和變數的符號名,而.dll檔案包含該DLL實際的函式和資料。在使用動態庫的情況下,在編譯連結可執行檔案時,只需要連結該DLL的引入庫檔案,該DLL中的函式程式碼和資料並不複製到可執行檔案中。釋出產品時,需要同時釋出.exe和動態連結庫。動態連結庫的載入包含:隱式連結和顯式載入
2.1隱式連結
2.1.1動態庫的建立
A:File->New->Projects->Win32 Dynamic-Link Library(這裡我建立的是dllTest1)
B:File->New->Files(dll.h)
////dll.h
#ifdef DLL_API
#else
#define DLL_API extern "C" _declspec(dllimport) ////表示該函式是從動態連結庫中引入的
#endif
DLL_API int add(int a,int b);
C:File->New->Files(dll.cpp)
#define DLL_API extern "C" _declspec(dllexport) ////表示該函式是動態連結庫的匯出函式
#include "dll.h"
int add(int a,int b)
{
return a+b;
}
D:編譯,生成dllTest1.lib和dllTest1.dll檔案
上面 extern "C" 表示我們希望動態連結庫檔案在編譯時,匯出函式的名稱不要改變。注意雙引號中的C一定大寫。但是extern "C"不能用於匯出一個類的成員函式,只能用於匯出全域性函式這種情況。
2.1.2動態庫的隱式連結
我採用基於對話方塊的MFC應用程式進行測試,具體步驟不一一詳解。只介紹下需要包含的檔案。
將建立的動態庫dll.h dllTest1.lib dllTest1.dll三個檔案copy到測試程式資料夾內
A:在cpp檔案中包含標頭檔案#include"dll.h"
B:然後再Projects->Settings->Link->Objects/library modules下加入dllTest1.lib 完成
C:執行就OK
今天學習了動態庫的顯式載入,其中有兩個問題特別重要,一個是名字改編問題,一個是顯式載入函式指標定義問題。在這裡記錄下來,以便以後寫這方面程式時查閱。因為才學習這個,如果朋友們看了,有什麼不同意見,可以留言。萬分感激!!!
2.2 顯式載入
2.2.1動態庫的建立
A:File->New->Projects->Win32 Dynamic-Link Library(這裡我建立的是Dll_3)
B:File->New->Files(Dll_3.h)
////Dll_3.h
#ifndef DLL_API
#define DLL_API _declspec(dllimport)
#endif
DLL_API float add(float a,float b);
DLL_API float subtract(float a,float b);
DLL_API float multiplex(float a,float b);
DLL_API float divide(float a,float b);
C:File->New->Files(Dll_3.cpp)
#define DLL_API _declspec(dllexport)
#include "Dll_3.h"
float add(float a,float b)
{
return a+b;
}
float multiplex(float a,float b)
{
return a*b;
}
float subtract(float a,float b)
{
return a-b;
}
float divide(float a,float b)
{
return a/b;
}
D:開啟Dll_3資料夾,在裡面新建一個“.def”檔案(我這裡建立的是Dll_3.def,就是先建立個.txt檔案,然後將字尾修改成.def就OK)
然後將.def檔案新增到Dll_3工程中,並新增如下程式碼:
LIBRARY Dll_3 //指定動態庫的內部名稱,在這裡是Dll_3 。一定注意
EXPORTS //表明DLL將要匯出的函式(如下)
add
subtract
multiplex
divide
*****新增這個檔案的好處是:可以解決函式名稱發生改編的問題。所謂名稱發生改編問題,我理解的就是,不同編譯器在編譯連結時,.dll檔案中匯出函式的名稱發生了改變,而我們在呼叫這個函式時,還是寫的函式原來的名字。這樣就會造成找不到此函式的問題。而用模組定義檔案的方式,讓其在匯出時,不改變其名稱樣式。這樣就可以使一個.dll檔案可以在多種編譯器之間呼叫。
(具體的名稱改變,以及改變成何種樣式,可以在命令列操作介面用dumpbin -exports 命令進行檢視。)
D:編譯,生成dllTest1.lib和dllTest1.dll檔案
2.2.2 動態庫的顯式連結
新建一個測試程式,本人在測試時,建立一個基於對話方塊的簡單計算器的程式來進行測試的。
在這裡我列出add函式呼叫方法。在滑鼠點選事件下,執行下面程式:
HINSTANCE hInst; ///定義例項控制代碼
hInst = LoadLibrary("Dll_3.dll"); //通過函式LoadLibrary() 動態載入DLL。此函式的作用是將指定的可執行模組對映到呼叫程序的地址空間,返回載入模組的控制代碼。
typedef float(*ADDPROC) (float a,float b); //定義函式指標型別。在這裡定義函式指標型別,並且它表示的函式有兩個float型別的引數,返回的也是float型別,和我們即將用到的函式一樣。之所以這樣做,主要是為了在需要時,可以產生一個函式指標變數,用來接收通過GetProcAddress函式返回的函式地址。
ADDPROC Add = (ADDPROC)GetProcAddress(hInst,"add"); //獲取函式地址
if (!Add)
{
MessageBox("獲取函式地址失敗!");
return ;
}
UpdateData(TRUE);
m_edit3 = Add(m_edit1,m_edit2); //呼叫
UpdateData(FALSE);
FreeLibrary(hInst);
在顯式載入過程中,只需要將Dll_3.dll檔案copy到測試程式檔案中就OK。不需要標頭檔案和.lib檔案。。。