http://blog.csdn.net/likewenkaixin/article/details/7771250
1、靜態庫。 函數和數據被編譯進一個二進制文件(擴展名位 .LIB)。在使用靜態庫的情況下,在編譯器鏈接可執行文件時,鏈接器從庫中複製這些函數和數據並把它們和應用程序的其他模塊組合起來創建最終的可執行文件(.EXE)。發佈產品時,不需要發佈使用的靜態庫。
1.1 靜態庫的創建
A:File->New->Projects->Win32 Static Library (這裏我創建的工程名字爲libTest)->Finish
B:File->New->File->C/C++ Header File (lib.h)
///頭文件對add函數進行聲明:
#ifndef LIB_H
#define LIB_H
extern "C" int add(int a,int b);
#endif
C:File->New->File->C++ Source File (lib.cpp)
////定義add
#include "lib.h"
int add(int a,int b)
{
return a+b;
}
D:編譯後,打開程序文件夾。可以在debug文件看到有個libTest.lib文件。這就是生成的靜態庫文件
1.2靜態庫的鏈接
A:重新打開一個工程
File->New->Projects->Win32 Console Application
B:創建一個源文件(libCall.cpp)
這時我們將1.1節中生成的libTest.lib文件和lib.h頭文件copy到libCall文件夾中
在源文件中我們將調用lib文件中add(int a, int b)這個函數來完成簡單的加法運算。
編程如下
/// libCall.cpp
#include <iostream.h>
#include "lib.h" ///包含頭文件
#pragma comment(lib,"libTest.lib") ///鏈接靜態庫
void main()
{
cout<<add(2,3)<<endl;
return ;
}
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文件。。。