Dll:動態連接庫 程序員
動態連接庫(dll)是包含共享函數庫的二進制文件,能夠被多個應用程序同時使用。創建應用程序的可執行文件時,沒必要將DLL鏈接到應用程序中,而是在運行時動態裝載DLL,裝載時DLL被映射到調用進程的地址空間中。一般咱們在調用DLL時所需的DLL文件必須位於如下三個目錄之一:
——(1)Windows的系統目錄:/windows/system;
——(2)DOS中path所指出的任何目錄;
——(3)程序所在的目錄; express
windows中有不少的dll文件,包括kernel.dll是內存管理的一些函數。含有圖像處理的內存函數等等。 windows
在VC中有兩種導出函數的方法: 函數
關鍵字_declspec 該方法比較簡單。 操作系統
模塊定義文件。 命令行
dll主要有兩部分組成,一是模塊定義文件(.DEF),另外一個是實現導出函數功能的源文件(C或C++文件)。函數分爲內部函數和導出函數。 線程
模塊定義文件: 指針
主要由語句說明: htm
1.LIBRARY 語句指出dll文件的名稱。第一個語句必須是這個語句。 接口
2.EXPORT語句指出被導出函數的名稱。 EXPORT Add(),必備語句
3.可使用DESCRIPTION語句對dll的用途進行說明,這個是可選項。
4.「;」對一行進行註釋,可選項。
實現源文件:
實現入口函數的.cpp或.c文件,包括dll入口點的API函數和導出函數的代碼。
在VC中好像很簡單,並不須要寫def,
我使用的是Visual C++ 2008 express Edition,當我新建一個工程時,選擇編寫dll文件,直接生成不少文件,包括dll入口文件dllmain.cpp和stdafx.cpp。和源文件sample.cpp以及頭文件targetver.h stdafx.h,sample.h。
在dllmain.cpp中:
一個DLL必須有一個入口點,這就象咱們用C編寫的應用程序同樣,必須有一個WINMAIN函數同樣。
DllMain是一個缺省的入口函數,你不須要編寫本身的DLL入口函數,並用linker的命令行的參數開關/ENTRY聲明。用這個缺省的入口函數就能使動態鏈接庫被調用時獲得正確的初始化,固然了,你不要在初始化的時候填寫使系統崩潰的代碼了。參數中,hMoudle是動態庫被調用時所傳遞來的一個指向本身的句柄(實際上,它是指向_DGROUP段的一個選擇符)ul_reason_for_call是一個說明動態庫被調緣由的標誌。當進程或線程
裝入或卸載動態鏈接庫的時候,操做系統調用入口函數,並說明動態鏈接庫被調用的緣由。它全部的可能值爲:
DLL_PROCESS_ATTACH: 進程被調用
DLL_THREAD_ATTACH: 線程被調用
DLL_PROCESS_DETACH: 進程被中止
DLL_THREAD_DETACH: 線程被中止
lpReserved是一個被系統所保留的參數。
因爲相同的緣由,多個應用程序還能夠同時共享DLL在內存中的同一份拷貝,這樣就有效的節省了應用程序所佔用的內存資源,減小了頻繁的內存交換,從而提升了應用程序的執行效率。
因爲DLL是獨立於可執行文件的,所以,若是須要向DLL中增長新的函數或是加強現有函數的功能,只要原有函數的參數和返回值等屬性不變,那麼,全部使用該DLL的原有應用程序均可以在升級後的DLL的支持下運行,而不須要從新編譯。這就極大的方便了應用程序的升級和售後支持。
DLL除了包括函數的執行代碼之外,還能夠只包括如圖標、位圖、字符串和對話框之類的資源,所以能夠把應用程序所使用的資源獨立出來作成DLL。對於一些經常使用的資源,把它們作到DLL中後,就可爲多個應用程序所共享。
便於創建多語言的應用程序。咱們能夠把多語言應用程序中所使用的與語言相關的函數作到DLL中,只要不一樣語言的應用程序所調用的函數都具備相同的接口,這樣就能夠經過簡單地更換DLL來實現多語言支持。
sample.h
這是VC提供的一個關鍵字,用它可在動態鏈接庫中輸出一個數據、一個函數或一個類。用這個關鍵字可省你很多事,你不用在.DEF文件
中說明我要輸出這個類、那個函數的.
#ifdef FIRST_EXPORTS
#define FIRST_API __declspec(dllexport)
#else
#define FIRST_API __declspec(dllimport)
#endif
// This class is exported from the First.dll
class FIRST_API CFirst {
public:
CFirst(void);
// TODO: add your methods here.
};
extern FIRST_API int nFirst;
extern 「C" FIRST_API int fnFirst(void);
編寫DLL文件和調用DLL文件總結:
一、編寫時要編寫源文件和頭文件。源文件定義函數原型、類。
若是是C++,能夠定義類
若是是C,注意要以C的方式編譯,要加上 extern 「C」(這個很關鍵,不然利用取地址函數不分配函數地址,剛開始就這犯錯誤了)
2.在調用程序中,要設置函數指針。以及調用指針
typedef int(*phai)(int a,int b);
phai hai;//函數指針
HINSTANCE hDLL=NULL;
hDLL=LoadLibrary("sample.dll");//加載動態連接庫MyDll.dll文件;
if (hDLL==NULL)
{
printf("Can not open");
return 0;
}
printf("test");
hai=(phai)GetProcAddress(hDLL,"Sum");
HINSTANCE 是「句柄型」數據類型。至關於裝入到了內存的資源的ID。HINSTANCE對應的資源是instance.句柄其實是一個 無符號長整數。但它是「句柄型」,因此你不能把它當成真的無符號長整數,拿來派別的用處,例如,不能拿來作四則運算。HINSTANCE常出如今 API 程序。
HMODULE 是表明應用程序載入的模塊,win32系統下一般是被載入模塊的線性地址。
HINSTANCE 在win32下與HMODULE是相同的東西,在Win32下還存在主要是由於win16
對於DLL的調用有兩種:顯示調用和隱式調用。
我前面所說的是顯示調用,這種方法不須要.lib文件。頭文件中要包含windows.h,#include "windows.h"
這種調用方式是指在應用程序中用LoadLibrary或MFC提供的AfxLoadLibrary顯式的將本身所作的動態鏈接庫調進來,並指定DLL的路徑做爲參數。LoadLibary返回HINSTANCE參數,應用程序在調用GetProcAddress函數時使用這一參數。當完成對動態連接庫的導入之後,再使用GetProcAddress()獲取想要引入的函數,該函數將符號名或標識號轉換爲DLL內部的地址,以後就能夠象使用本應用程序自定義的函數同樣來調用此引入函數了。在應用程序退出以前,應該用FreeLibrary或MFC提供的AfxFreeLibrary釋放動態鏈接庫。
隱式的調用
這種調用方式須要把產生動態鏈接庫時產生的.LIB文件加入到應用程序的工程中,在使用DLL中的函數時,只須說明一下後就能夠直接經過函數名調用DLL的輸出函數,調用方法和程序內部其餘的函數是同樣的。隱式調用不須要調用LoadLibrary()和FreeLibrary()。程序員在創建一個DLL文件時,連接程序會自動生成一個與之對應的LIB導入文件。該文件包含了每個DLL導出函數的符號名和可選的標識號,可是並不含有實際的代碼。LIB文件做爲DLL的替代文件被編譯到應用程序項目中。
當程序員經過隱式調用方式編譯生成應用程序時,應用程序中的調用函數與LIB文件中導出符號相匹配,這些符號或標識號被寫入到生成的EXE文件中。LIB文件中也包含了對應的DLL文件名(但不是徹底的路徑名),連接程序也將其存儲在EXE文件內部。當應用程序運行過程當中須要加載DLL文件時,Windows根據這些信息發現並加載DLL,而後經過符號名或標識號實現對DLL函數的動態連接。全部被應用程序調用的DLL文件都會在應用程序EXE文件加載時被加載在到內存中。
隱式連接要連接相應的lib文件,在調用程序中,要包含對應dll文件的頭文件(該頭文件有相應函數和類的說明),不須要有windows.h頭文件。