MFC下的DLL編程學習

一、DLL庫與LIB庫對比:

靜態連接庫Lib(Static Link Library),是在編譯的連接階段將庫函數嵌入到應用程序的內部。若是系統中運行的多個應用程序都包含所用到的公共庫函數,則必然形成很大的浪費。這樣即增長了連接器的負擔,也增大了可執行程序的大小,還加大了內存的消耗。Lib的好處是應用程序能夠獨立運行,而不須要在操做系統中另外安裝對應的DLL。html

而DLL採用動態連接,對公用的庫函數,系統只有一個拷貝(通常是位於系統目錄的*.DLL文件),並且只有在應用程序真正運行階段調用時,才加載到內存。在內存中的庫函數,也只有一個拷貝,可供全部運行的程序調用。當再也沒有程序須要調用它時,系統會自動將其卸載,並釋放其所佔用的內存空間。DLL的缺點是應用程序不能獨立運行,須要在操做系統中另外安裝對應的DLL。例如,若是你的MFC項目被設置成「在共享DLL中使用MFC」的,則雖然生成的可執行程序很小,可是在其餘沒有安裝Visual C++(運行環境)的機器上是不能直接運行的,須要另外安裝MFC的動態連接庫(如mfc90.dll)。ios

二、DLL庫與LIB庫區別:

(1)lib是編譯時用到的,dll是運行時用到的。
(2)
若是有dll文件,那麼lib的大小會很小,通常是一些索引信息,記錄了dll中函數的入口和位置,dll中是函數的具體內容;若是隻有lib文件,那麼這個lib文件是靜態編譯出來的,索引和實現都在其中。使用靜態編譯的lib文件,在運行程序時不須要再掛動態庫,缺點是致使應用程序比較大,失去了動態庫的靈活性,發佈新版本時要發佈新的應用程序才行。windows

(3)動態連接的狀況下,有兩個文件:一個是LIB文件,一個是DLL文件。連接方式也相應的可分爲:隱式連接和顯式連接。LIB包含被DLL導出的 函數名稱和位置,DLL包含實際的函數和數據,應用程序使用LIB文件連接到DLL文件。隱式連接時,在應用程序的可執行文件中,存放的不是被調用的函數代碼,而是 DLL中相應函數代碼的地址,從而節省了內存資源。DLL和LIB文件必須隨應用程序一塊兒發行,不然應用程序會產生錯誤。顯式連接時,若是不想用lib文件或者沒有 lib文件,能夠用WIN32 API函數LoadLibrary、GetProcAddress裝載。安全

三、DLL庫與LIB庫的調用方法:

 

使用LIB庫的方法:
靜態lib中,一個lib文件其實是任意個obj文件的集合,obj文件是cpp文件編譯生成的。在編譯這種靜態庫工程時,根本不會遇到連接錯誤;即便有錯,也只會在使用這個lib的EXT文件或者DLL工程裏暴露出來。
在VC中新建一個static library類型的工程Lib,加入test.cpp文件和test.h文件(頭文件內包括函數聲明),而後編譯,就生成了Lib.lib文件。
別的工程要使用這個lib有兩種方式:
(1)在project->link->Object/Library Module中加入Lib.lib文件(先查詢工程目錄,再查詢系統Lib目錄);或者在源代碼中加入指令#pragma comment(lib, 「Lib.lib」)。
(2)將Lib.lib拷入工程所在目錄,或者執行文件生成的目錄,或者系統Lib目錄中。
(3)加入相應的頭文件test.h。

使用DLL庫的方法:
使用動態連接中的lib,不是obj文件的集合,即裏面不會有實際的實現,它只是提供動態連接到DLL所須要的信息(包括DLL響應函數的信息、地址等),這種lib能夠在編譯一個DLL工程時由編譯器自動生成。
(1)隱式連接
第 一種方法是:經過project->link->Object/Library Module中加入.lib文件(或者在源代碼中加入指令#pragma comment(lib, 「Lib.lib」)),並將.dll文件置入工程所在目錄,而後添加對應的.h頭文件。函數

 

【轉】LIB和DLL的區別與使用#include "stdafx.h"
【轉】LIB和DLL的區別與使用#include "DLLSample.h"
【轉】LIB和DLL的區別與使用
【轉】LIB和DLL的區別與使用#pragma comment(lib, "DLLSample.lib")    //你也能夠在項目屬性中設置庫的連接
【轉】LIB和DLL的區別與使用
【轉】LIB和DLL的區別與使用int main()
【轉】LIB和DLL的區別與使用{
【轉】LIB和DLL的區別與使用        TestDLL(123);   //dll中的函數,在DllSample.h中聲明
【轉】LIB和DLL的區別與使用        return(1);
【轉】LIB和DLL的區別與使用} 【轉】LIB和DLL的區別與使用

 

(2)顯式連接
須要函數指針和WIN32 API函數LoadLibrary、GetProcAddress裝載,使用這種載入方法,不須要.lib文件和.h頭文件,只須要.dll文件便可(將.dll文件置入工程目錄中)。spa

 

【轉】LIB和DLL的區別與使用#include <</span>iostream>
【轉】LIB和DLL的區別與使用#include <</span>windows.h>         //使用函數和某些特殊變量
【轉】LIB和DLL的區別與使用typedef void (*DLLFunc)(int);
【轉】LIB和DLL的區別與使用int main()
【轉】LIB和DLL的區別與使用{
【轉】LIB和DLL的區別與使用        DLLFunc dllFunc;
【轉】LIB和DLL的區別與使用        HINSTANCE hInstLibrary = LoadLibrary("DLLSample.dll");//率先在當前可執行程序目錄下尋找DLL庫文件
【轉】LIB和DLL的區別與使用
【轉】LIB和DLL的區別與使用        if (hInstLibrary == NULL)
【轉】LIB和DLL的區別與使用        {
【轉】LIB和DLL的區別與使用          FreeLibrary(hInstLibrary);
【轉】LIB和DLL的區別與使用        }
【轉】LIB和DLL的區別與使用        dllFunc = (DLLFunc)GetProcAddress(hInstLibrary, "TestDLL");
【轉】LIB和DLL的區別與使用        if (dllFunc == NULL)
【轉】LIB和DLL的區別與使用        {
【轉】LIB和DLL的區別與使用          FreeLibrary(hInstLibrary);
【轉】LIB和DLL的區別與使用        }
【轉】LIB和DLL的區別與使用        dllFunc(123);
【轉】LIB和DLL的區別與使用        std::cin.get();
【轉】LIB和DLL的區別與使用        FreeLibrary(hInstLibrary);
【轉】LIB和DLL的區別與使用        return(1);
【轉】LIB和DLL的區別與使用}
【轉】LIB和DLL的區別與使用 【轉】LIB和DLL的區別與使用LoadLibrary函數利用一個名稱做爲參數,得到DLL的實例(HINSTANCE類型是實例的句柄),一般調用該函數後須要查看一下函數返回是否成功,若是不成功則返回NULL(句柄無效),此時調用函數FreeLibrary釋放DLL得到的內存。GetProcAddress函數利用DLL的句柄和函數的名稱做爲參數,返回相應的函數指針,同時必須使用強轉;判斷函數指針是否爲NULL,若是是則調用函數FreeLibrary釋放DLL得到的內存。此後,可使用函數指針來調用實際的函數。最後要記得使用FreeLibrary函數釋放內存。

 

四、MFC中DLL中函數的導出方法

使用MFC建立DLL時,從項目中導出(export)函數到DLL文件的方法有:操作系統

(1) 使用模塊定義文件(.def)。命令行

(2)使用__declspec(dllexport)關鍵字或其替代宏AFX_EXT_CLASS。指針

這兩種方法是互斥的,對每一個函數只需用一種方法便可。另外,DEF文件只能用來導出函數,不能用於導出整個類。導出C++類,必須用__declspec(dllexport)關鍵字或其替代宏AFX_EXT_CLASS。htm

 

DEF文件

模塊定義(module definition)文件(.def)是包含一個或多個描述DLL各類屬性的模塊語句的文本文件。DEF文件必須至少包含下列模塊定義語句:

文件中的第一個語句必須是LIBRARY語句。此語句將.def文件標識爲屬於DLL。LIBRARY語句的後面是DLL的名稱(缺省爲DLL項目名)。連接器將此名稱放到DLL的導入庫中。

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

即,DEF文件的格式爲:(在這兩個語句之間,還能夠加上可選的描述語句:DESCRIPTION "庫描述串"。分號;後的文本內容行爲註釋)

庫名.def

LIBRARY 庫名

EXPORTS

函數名1 @1

函數名2 @2

……

函數名n @n

在使用MFC DLL嚮導建立MFC DLL項目時,VC會自動建立一個與項目同名但沒有任何函數導出項的DEF文件(項目名.def),格式爲:

項目名.def : 聲明 DLL 的模塊參數。 

LIBRARY      "項目名"

EXPORTS

。。。

 

例如,項目名爲RegDll的DEF文件(RegDll.def)的內容爲:

; RegDll.def : 聲明 DLL 的模塊參數。

LIBRARY      "RegDll"

EXPORTS

。。。

 

當生成DLL時,連接器使用.def文件建立導出(.exp)文件和導入庫(.lib)文件。而後,連接器使用導出文件生成DLL文件。隱式連接到DLL的可執行文件在生成時連接到導入庫。請注意,MFC自己就是使用.def文件從MFCx0.dll導出函數和類的。

 

關鍵字或宏 

除了使用DEF文件來導出函數外,還能夠在源程序中使用__declspec(dllexport)關鍵字或其替代宏AFX_EXT_CLASS:

#define AFX_EXT_CLASS  AFX_CLASS_EXPORT (定義在頭文件afxv_dll.h中)

#define AFX_CLASS_EXPORT  __declspec(dllexport) (定義在頭文件afxver_.h中)

來導出函數和整個C++類。

具體的格式爲:

導出整個類:

class AFX_EXT_CLASS 類名[ : public基類]

{

……

}

導出類的成員函數:

class 類名[ : public基類]

{

AFX_EXT_CLASS 返回類型 函數名1(……) ;

AFX_EXT_CLASS 返回類型 函數名2(……) ;

……

}

導出外部C格式的(全局)函數:

extern "C" __declspec(dllexport) 返回類型 函數名(……) 

{

……

}

若是但願用MFC(C++)編寫的規則DLL中的函數,也可以被非MFC程序來調用,須要爲函數聲明指定extern "C"。否則,C++編譯器會使用C++類型安全命名約定(也稱做名稱修飾)和C++調用約定(使用此調用約定從C調用會很困難)。

爲了使用方便,能夠定義宏:

#define DllExport extern "C" __declspec(dllexport)

而後再使用它,例如:

DllExport int Add(int d1, int d2) {……}

五、VC查找DLL及LIB庫的目錄優先順序

爲了使須要動態連接庫的應用程序能夠運行,須要將庫文件放在操做系統可以找到的地方。Windows操做系統查找庫的目錄順序爲:

  1. 所在目錄——當前進程的可執行模塊所在的目錄,即應用程序的可執行文件(*.exe)所在的目錄。
  2. 當前目錄——進程的當前目錄。
  3. 系統目錄——Windows操做系統安裝目錄的系統子目錄,如C:\Windows\ System32。可用GetSystemDirectory函數檢索此目錄的路徑。
  4. Windows目錄——Windows操做系統安裝目錄,如C:\Windows\。可用GetWindowsDirectory函數檢索此目錄的路徑。
  5. 搜索目錄——PATH環境變量中所包含的自動搜索路徑目錄,通常包含C:\Windows\和C:\Windows\System32\等目錄。可在命令行用Path命令來查看和設置,也能夠經過(在「個人電腦」右鍵菜單中選「屬性」菜單項)「系統屬性」中的環境變量,來查看或編輯「Path」系統變量和「PATH」用戶變量。

參考:https://www.cnblogs.com/405845829qq/p/4108450.html

參考:https://www.cnblogs.com/19910101zj/p/4611695.html

相關文章
相關標籤/搜索