久久精品水蜜桃av综合天堂,久久精品丝袜高跟鞋,精品国产肉丝袜久久,国产一区二区三区色噜噜,黑人video粗暴亚裔

動(dòng)態(tài)數(shù)據(jù)交換

來自站長(zhǎng)百科
Jiaomh討論 | 貢獻(xiàn)2010年11月22日 (一) 16:58的版本
(差異) ←上一版本 | 最后版本 (差異) | 下一版本→ (差異)
跳轉(zhuǎn)至: 導(dǎo)航、? 搜索

動(dòng)態(tài)鏈接庫英文為DLL,是Dynamic Link Library 的縮寫形式,DLL是一個(gè)包含可由多個(gè)程序同時(shí)使用的代碼數(shù)據(jù)的庫,DLL不是可執(zhí)行文件。動(dòng)態(tài)鏈接提供了一種方法,使進(jìn)程可以調(diào)用不屬于其可執(zhí)行代碼的函數(shù)。

函數(shù)的可執(zhí)行代碼位于一個(gè)DLL中,該DLL包含一個(gè)或多個(gè)已被編譯、鏈接并與使用它們的進(jìn)程分開存儲(chǔ)的函數(shù)。DLL還有助于共享數(shù)據(jù)和資源。多個(gè)應(yīng)用程序可同時(shí)訪問內(nèi)存中單個(gè)DLL 副本的內(nèi)容。

概述[ ]

DLL是微軟公司在微軟視窗操作系統(tǒng)中實(shí)現(xiàn)共享函數(shù)庫概念的一種實(shí)作方式。這些庫函數(shù)的擴(kuò)展名是.DLL、.OCX(包含ActiveX控制的庫)或者.DRV(舊式的系統(tǒng)驅(qū)動(dòng)程序)。

所謂動(dòng)態(tài)鏈接,就是把一些經(jīng)常會(huì)共用的代碼(靜態(tài)鏈接的OBJ程序庫)制作成DLL檔,當(dāng)可執(zhí)行文件調(diào)用到DLL檔內(nèi)的函數(shù)時(shí),windows操作系統(tǒng)才會(huì)把DLL檔加載存儲(chǔ)器內(nèi),DLL檔本身的結(jié)構(gòu)就是可可執(zhí)行文件,當(dāng)程序需求函數(shù)才進(jìn)行鏈接。通過動(dòng)態(tài)鏈接方式,存儲(chǔ)器浪費(fèi)的情形將可大幅降低。

DLL的文檔格式與視窗EXE文檔一樣——也就是說,等同于32位視窗的可移植執(zhí)行文檔(PE)和16位視窗的New Executable(NE)。作為EXE格式,DLL可以包括源代碼、數(shù)據(jù)和資源的多種組合。在更廣泛的意義上說,任何同樣文檔格式的電腦文件都可以稱作資源DLL。這樣的DLL的例子有有擴(kuò)展名ICL為的圖標(biāo)庫、擴(kuò)展名為FON和FOT的字體文檔。

通過使用 DLL,程序可以實(shí)現(xiàn)模塊化,由相對(duì)獨(dú)立的組件組成。例如,一個(gè)計(jì)帳程序可以按模塊來銷售??梢栽谶\(yùn)行時(shí)將各個(gè)模塊加載到主程序中(如果安裝了相應(yīng)模塊)。因?yàn)槟K是彼此獨(dú)立的,所以程序的加載速度更快,而且模塊只在相應(yīng)的功能被請(qǐng)求時(shí)才加載。

此外,可以更為容易地將更新應(yīng)用于各個(gè)模塊,而不會(huì)影響該程序的其他部分。例如,您可能具有一個(gè)工資計(jì)算程序,而稅率每年都會(huì)更改。當(dāng)這些更改被隔離到 DLL 中以后,您無需重新生成或安裝整個(gè)程序就可以應(yīng)用更新。

DLL的產(chǎn)生[ ]

DOS時(shí)代,程序員是通過編寫程序來達(dá)到預(yù)期的目的的,每實(shí)現(xiàn)一個(gè)目的就需要編寫一個(gè)程序,這樣下去,簡(jiǎn)單的還好,要是復(fù)雜的程序話,那是既浪費(fèi)時(shí)間,又浪費(fèi)青春。于是聰明的程序員們想出了一個(gè)辦法,把的實(shí)現(xiàn)一定功能的程序模塊存放在一個(gè)文件當(dāng)中,以API函數(shù)形式存放在dll當(dāng)中,當(dāng)編寫程序的時(shí)候,需要用到這個(gè)功能,那么直接從這個(gè)文件當(dāng)中調(diào)用就可以了,于是就出現(xiàn)了dll——?jiǎng)討B(tài)連接庫。

這樣,程序員把一些模塊壓入dll文件之后,在要運(yùn)行程序的時(shí)候只需要調(diào)用動(dòng)態(tài)鏈接庫就可以了,而并不需要把dll加載到內(nèi)存中。通過使用 DLL,程序可以實(shí)現(xiàn)模塊化,由相對(duì)獨(dú)立的組件組成。

特征[ ]

DLL 的優(yōu)點(diǎn)[ ]

  • 擴(kuò)展了應(yīng)用程序的特性;
  • 可以用許多種編程語言來編寫;
  • 簡(jiǎn)化了軟件項(xiàng)目的管理;
  • 有助于節(jié)省內(nèi)存;
  • 有助于資源共享;
  • 有助于應(yīng)用程序的本地化;
  • 有助于解決平臺(tái)差異;
  • 可以用于一些特殊的目的。windows使得某些特性只能為DLL所用

內(nèi)存管理[ ]

在Win32中,DLL文檔按照片段(sections)進(jìn)行組織。每個(gè)片段有它自己的屬性,如可寫或是只讀、可執(zhí)行(代碼)或者不可執(zhí)行(數(shù)據(jù))等等。

DLL代碼段通常被使用這個(gè)DLL的進(jìn)程所共享;也就是說它們?cè)谖锢韮?nèi)存中占據(jù)一個(gè)地方,并且不會(huì)出現(xiàn)在頁面文檔中。如果代碼段所占據(jù)的物理內(nèi)存被收回,它的內(nèi)容就會(huì)被放棄,后面如果需要的話就直接從DLL文檔重新加載。

與代碼段不同,DLL的數(shù)據(jù)段通常是私有的;也就是說,每個(gè)使用DLL的進(jìn)程都有自己的DLL數(shù)據(jù)副本。作為選擇,數(shù)據(jù)段可以設(shè)置為共享,允許通過這個(gè)共享內(nèi)存區(qū)域進(jìn)行進(jìn)程間通信。但是,因?yàn)橛脩魴?quán)限不能應(yīng)用到這個(gè)共享DLL內(nèi)存,這將產(chǎn)生一個(gè)安全漏洞;也就是一個(gè)進(jìn)程能夠破壞共享數(shù)據(jù),這將導(dǎo)致其它的共享進(jìn)程異常。例如,一個(gè)使用訪客賬號(hào)的進(jìn)程將可能通過這種方式破壞其它運(yùn)行在特權(quán)賬號(hào)的進(jìn)程。這是在DLL中避免使用共享片段的一個(gè)重要原因。

當(dāng)DLL被如UPX這樣一個(gè)可執(zhí)行的packer壓縮時(shí),它的所有代碼段都標(biāo)記為可以讀寫并且是非共享的??梢宰x寫的代碼段,類似于私有數(shù)據(jù)段,是每個(gè)進(jìn)程私有的并且被頁面文檔備份。這樣,壓縮DLL將同時(shí)增加內(nèi)存和磁盤空間消耗,所以共享DLL應(yīng)當(dāng)避免使用壓縮DLL。

符號(hào)解析和綁定[ ]

DLL輸出的每個(gè)函數(shù)都由一個(gè)數(shù)字序號(hào)唯一標(biāo)識(shí),也可以由可選的名字標(biāo)識(shí)。同樣,DLL引入的函數(shù)也可以由序號(hào)或者名字標(biāo)識(shí)。對(duì)于內(nèi)部函數(shù)來說,只輸出序號(hào)的情形很常見。對(duì)于大多數(shù)視窗API函數(shù)來說名字是不同視窗版本之間保留不變的;序號(hào)有可能會(huì)發(fā)生變化。這樣,我們不能根據(jù)序號(hào)引用視窗API函數(shù)。

按照序號(hào)引用函數(shù)并不一定比按照名字引用函數(shù)性能更好:DLL輸出表是按照名字排列的,所以對(duì)半查找可以用來在在這個(gè)表中根據(jù)名字查找這個(gè)函數(shù)。另外一方面,只有線性查找才可以用于根據(jù)序號(hào)查找函數(shù)。

將一個(gè)可執(zhí)行文件綁定到一個(gè)特定版本的DLL也是可能的,這也就是說,可以在編譯時(shí)解析輸入函數(shù)(imported functions)的地址。對(duì)于綁定的輸入函數(shù),連結(jié)工具保存了輸入函數(shù)綁定的DLL的時(shí)間戳和校驗(yàn)和。在運(yùn)行時(shí)Windows檢查是否正在使用同樣版本的庫,如果是的話,Windows將繞過處理輸入函數(shù);否則如果庫與綁定的庫不同,Windows將按照正常的方式處理輸入函數(shù)。

綁定的可執(zhí)行文件如果運(yùn)行在與它們編譯所用的環(huán)境一樣,函數(shù)調(diào)用將會(huì)較快,如果是在一個(gè)不同的環(huán)境它們就等同于正常的調(diào)用,所以綁定輸入函數(shù)沒有任何的缺點(diǎn)。例如,所有的標(biāo)準(zhǔn)Windows應(yīng)用程序都綁定到它們各自的Windows發(fā)布版本的系統(tǒng)DLL。將一個(gè)應(yīng)用程序輸入函數(shù)綁定到它的目的環(huán)境的好機(jī)會(huì)是在應(yīng)用程序安裝的過程。

運(yùn)行時(shí)顯式鏈接[ ]

對(duì)每個(gè)DLL來說,Windows存儲(chǔ)了一個(gè)全局計(jì)數(shù)器,每多一個(gè)進(jìn)程使用便多額外一個(gè)。LoadLibrary與FreeLibrary指令影響每一個(gè)進(jìn)程內(nèi)含的計(jì)數(shù)器;動(dòng)態(tài)連結(jié)則不影響。因此借由調(diào)用FreeLibrary多次,從存儲(chǔ)器反加載一DLL是很重要的。一個(gè)進(jìn)程可以從它自己的VAS注銷此計(jì)數(shù)器。

DLL文檔能夠在運(yùn)行時(shí)使用LoadLibrary(或者LoadLibraryEx)API函數(shù)進(jìn)行顯式調(diào)用,這個(gè)的過程微軟簡(jiǎn)單地稱為運(yùn)行時(shí)動(dòng)態(tài)調(diào)用。API函數(shù)GetProcAddress根據(jù)查找輸出名稱符號(hào)、FreeLibrary卸載DLL。這些函數(shù)類似于POSIX標(biāo)準(zhǔn)API中的dlopen、dlsym、和dlclose。

注意微軟簡(jiǎn)單稱為運(yùn)行時(shí)動(dòng)態(tài)鏈接的運(yùn)行時(shí)隱式鏈接,如果不能找到鏈接的DLL文檔,Windows將提示一個(gè)錯(cuò)誤消息并且調(diào)用應(yīng)用程序失敗。應(yīng)用程序開發(fā)人員不能通過編譯鏈接來處理這種缺少DLL文檔的隱式鏈接問題。另外一方面,對(duì)于顯式鏈接,開發(fā)人員有機(jī)會(huì)提供一個(gè)完善的出錯(cuò)處理機(jī)制。

運(yùn)行時(shí)顯式鏈接的過程在所有語言中都是相同的,因?yàn)樗蕾囉赪indows API而不是語言結(jié)構(gòu)。

DLL的分類[ ]

微軟的Visual C++支持三種DLL,它們分別是Non-MFC Dll(非MFC動(dòng)態(tài)庫)、Regular Dll(常規(guī)DLL)、Extension Dll(擴(kuò)展DLL)。

Non-MFCDLL(非MFC動(dòng)態(tài)庫)[ ]

這種動(dòng)態(tài)鏈接庫指的是不用MFC的類庫結(jié)構(gòu),直接用C語言寫的DLL,其導(dǎo)出的函數(shù)是標(biāo)準(zhǔn)的C接口,能被非MFC或MFC編寫的應(yīng)用程序所調(diào)用。如果建立的DLL不需要使用MFC,那么應(yīng)該建立Non-MFCDLL,因?yàn)槭褂肕FC會(huì)增大用戶庫的大小,從而浪費(fèi)用戶的磁盤和內(nèi)存空間。

RegularDLL(常規(guī)DLL)[ ]

這種動(dòng)態(tài)鏈接庫和下述的ExtensionDll一樣,是用MFC庫編寫的,它的一個(gè)明顯的特點(diǎn)是在源文件里有一個(gè)繼承CWinApp的類(注意:此類DLL雖然從CWinApp派生,但沒有消息循環(huán)),被導(dǎo)出的函數(shù)是C函數(shù)、C++類或者C++成員函數(shù)(注意不要把術(shù)語C++類與MFC的微軟基礎(chǔ)C++類相混淆),調(diào)用常規(guī)DLL的應(yīng)用程序不必是MFC應(yīng)用程序,只要是能調(diào)用類C函數(shù)的應(yīng)用程序就可以,它們可以是在VisualC++、Delphi、VisualBasic、BorlandC等編譯環(huán)境下利用DLL開發(fā)應(yīng)用程序。常規(guī)DLL又可細(xì)分成靜態(tài)鏈接到MFC和動(dòng)態(tài)鏈接到MFC兩種:    

  1. 靜態(tài)連接到MFC的動(dòng)態(tài)連接庫只被VC的專業(yè)般和企業(yè)版所支持。該類DLL里的輸出函數(shù)可以被任意Win32程序使用,包括使用MFC的應(yīng)用程序。輸出函數(shù)有如下形式:
extern"C"EXPORTYourExportedFunction();

如果沒有extern"C"修飾,輸出函數(shù)僅僅能從C++代碼中調(diào)用。

  1. 動(dòng)態(tài)鏈接到MFC的常規(guī)DLL里的輸出函數(shù)可以被任意Win32程序使用,包括使用MFC的應(yīng)用程序。所有從DLL輸出的函數(shù)應(yīng)該以如下語句開始:
AFX_MANAGE_STATE(AfxGetStaticModuleState())

此語句用來正確地切換MFC模塊狀態(tài)。

ExtensionDll(擴(kuò)展DLL)[ ]

這種動(dòng)態(tài)鏈接庫是使用MFC的動(dòng)態(tài)鏈接版本所創(chuàng)建的,并且它只被用MFC類庫所編寫的應(yīng)用程序所調(diào)用。例如你已經(jīng)創(chuàng)建了一個(gè)從MFC的CtoolBar類的派生類用于創(chuàng)建一個(gè)新的工具欄,為了導(dǎo)出這個(gè)類,你必須把它放到一個(gè)MFC擴(kuò)展的DLL中。

擴(kuò)展DLL和常規(guī)DLL不一樣,它沒有一個(gè)從CWinApp繼承而來的類的對(duì)象,所以,開發(fā)人員必須在DLL中的DllMain函數(shù)添加初始化代碼和結(jié)束代碼。與常規(guī)DLL相比,擴(kuò)展的DLL有如下不同點(diǎn):

  • 它沒有一個(gè)從CWinApp派生的對(duì)象;
  • 它必須有一個(gè)DLLMain函數(shù);
  • DLLMain調(diào)用AfxInitExtensionModule函數(shù),必須檢查該函數(shù)的返回值,如果返回0,DLLMmain也返回0;  
  • 如果它希望輸出CRuntimeClass類型的對(duì)象或者資源(Resources),則需要提供一個(gè)初始化函數(shù)來創(chuàng)建一個(gè)CDynLinkLibrary對(duì)象。并且,有必要把初始化函數(shù)輸出;
  • 使用擴(kuò)展DLL的MFC應(yīng)用程序必須有一個(gè)從CWinApp派生的類,而且,一般在InitInstance里調(diào)用擴(kuò)展DLL的初始化函數(shù)。

DLL的調(diào)用[ ]

動(dòng)態(tài)鏈接庫的調(diào)用可以分為兩種:一種是隱式調(diào)用,一種是顯示調(diào)用。

隱式的調(diào)用[ ]

這種調(diào)用方式需要把產(chǎn)生動(dòng)態(tài)連接庫時(shí)產(chǎn)生的.LIB文件加入到應(yīng)用程序的工程中,在使用DLL中的函數(shù)時(shí),只須說明一下后就可以直接通過函數(shù)名調(diào)用DLL的輸出函數(shù),調(diào)用方法和程序內(nèi)部其他的函數(shù)是一樣的。隱式調(diào)用不需要調(diào)用LoadLibrary()FreeLibrary()。程序員在建立一個(gè)DLL文件時(shí),鏈接程序會(huì)自動(dòng)生成一個(gè)與之對(duì)應(yīng)的LIB導(dǎo)入文件。該文件包含了每一個(gè)DLL導(dǎo)出函數(shù)的符號(hào)名和可選的標(biāo)識(shí)號(hào),但是并不含有實(shí)際的代碼。LIB文件作為DLL的替代文件被編譯到應(yīng)用程序項(xiàng)目中。

當(dāng)程序員通過隱式調(diào)用方式編譯生成應(yīng)用程序時(shí),應(yīng)用程序中的調(diào)用函數(shù)與LIB文件中導(dǎo)出符號(hào)相匹配,這些符號(hào)或標(biāo)識(shí)號(hào)被寫入到生成的EXE文件中。LIB文件中也包含了對(duì)應(yīng)的DLL文件名(但不是完全的路徑名),鏈接程序也將其存儲(chǔ)在EXE文件內(nèi)部。當(dāng)應(yīng)用程序運(yùn)行過程中需要加載DLL文件時(shí),Windows根據(jù)這些信息發(fā)現(xiàn)并加載DLL,然后通過符號(hào)名或標(biāo)識(shí)號(hào)實(shí)現(xiàn)對(duì)DLL函數(shù)的動(dòng)態(tài)鏈接。所有被應(yīng)用程序調(diào)用的DLL文件都會(huì)在應(yīng)用程序EXE文件加載時(shí)被加載在到內(nèi)存中。

顯式調(diào)用[ ]

這種調(diào)用方式是指在應(yīng)用程序中用LoadLibrary或MFC提供的AfxLoadLibrary顯式的將自己所做的動(dòng)態(tài)連接庫調(diào)進(jìn)來,并指定DLL的路徑作為參數(shù)。LoadLibary返回HINSTANCE參數(shù),應(yīng)用程序在調(diào)用GetProcAddress函數(shù)時(shí)使用這一參數(shù)。當(dāng)完成對(duì)動(dòng)態(tài)鏈接庫的導(dǎo)入以后,再使用GetProcAddress()獲取想要引入的函數(shù),該函數(shù)將符號(hào)名或標(biāo)識(shí)號(hào)轉(zhuǎn)換為DLL內(nèi)部的地址,之后就可以象使用本應(yīng)用程序自定義的函數(shù)一樣來調(diào)用此引入函數(shù)了。在應(yīng)用程序退出之前,應(yīng)該用FreeLibrary或MFC提供的AfxFreeLibrary釋放動(dòng)態(tài)連接庫。

編程實(shí)例[ ]

創(chuàng)建DLL輸出函數(shù)[ ]

下面的例子展示了與特定語言相關(guān)的從DLL輸出符號(hào)表的方法。

Delphi:

library Example;

// Function that adds two numbers
function AddNumbers(a, b: Double): Double; cdecl;
begin
AddNumbers := a + b
end;

// Export this function
exports
AddNumbers;

// DLL initialization code: no special handling needed
begin
end.

C 或 C++

#include <windows.h>

// Export this function
extern "C" __declspec(dllexport) double AddNumbers(double a, double b);

// DLL initialization function
BOOL APIENTRY
DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
	return TRUE;
}

// Function that adds two numbers
double
AddNumbers(double a, double b)
{
	return a + b;
}

使用DLL輸入[ ]

下面的例子展示了與特定語言相關(guān)的如何在編譯時(shí)鏈接DLL輸入符號(hào)表的方法。

Delphi

program Example;
{$APPTYPE CONSOLE}

// Import function that adds two numbers
function AddNumbers(a, b: Double): Double; cdecl; external 'Example.dll';

var result: Double;
begin
result := AddNumbers(1, 2);
Writeln('The result was: ', result)
end.

C 或 C++

#include <windows.h>
#include <stdio.h>

// Import function that adds two numbers
extern "C" __declspec(dllimport)double AddNumbers(double a, double b);

int
main(int argc, char **argv)
{
	double result = AddNumbers(1, 2);
	printf("The result was: %f\n", result);
	return 0;
}

運(yùn)行時(shí)使用顯式調(diào)用[ ]

下面的例子先是如何使用不同語言特有的WIN32 API綁定進(jìn)行運(yùn)行時(shí)的調(diào)用和鏈接。

Microsoft Visual Basic

Option Explicit
Declare Function AddNumbers Lib "Example.dll" (ByVal a As Double, ByVal b As Double) As Double

Sub Main()
    Dim Result As Double
    Result = AddNumbers(1, 2)
    Debug.Print "The result was: " & Result
End Sub

C 或 C++

#include <windows.h>
#include <stdio.h>

// DLL function signature
typedef double (*importFunction)(double, double);

int
main(int argc, char **argv)
{
    importFunction addNumbers;
    double result;

    // Load DLL file
    HINSTANCE hinstLib = LoadLibrary("Example.dll");
    if (hinstLib == NULL) {
        printf("ERROR: unable to load DLL\n");
        return 1;
    }

    // Get function pointer
    addNumbers = (importFunction)GetProcAddress(hinstLib, "AddNumbers");
    if (addNumbers == NULL) {
        printf("ERROR: unable to find DLL function\n");
        return 1;
    }

    // Call function.
    result = addNumbers(1, 2);

    // Unload DLL file
    FreeLibrary(hinstLib);

    // Display result
    printf("The result was: %f\n", result);

    return 0;
}

相關(guān)條目[ ]

參考來源[ ]