1. 程式人生 > >c++中靜態庫和動態庫的建立與連結

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檔案。。。