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

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

來自站長百科
跳轉(zhuǎn)至: 導(dǎo)航、? 搜索

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

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

概述[ ]

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

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

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

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

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

DLL的產(chǎn)生[ ]

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

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

特征[ ]

DLL 的優(yōu)點[ ]

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

內(nèi)存管理[ ]

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

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

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

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

符號解析和綁定[ ]

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

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

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

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

運行時顯式鏈接[ ]

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

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

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

運行時顯式鏈接的過程在所有語言中都是相同的,因為它依賴于Windows API而不是語言結(jié)構(gòu)。

DLL的分類[ ]

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

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

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

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

這種動態(tài)鏈接庫和下述的ExtensionDll一樣,是用MFC庫編寫的,它的一個明顯的特點是在源文件里有一個繼承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又可細分成靜態(tài)鏈接到MFC和動態(tài)鏈接到MFC兩種:    

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

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

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

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

ExtensionDll(擴展DLL)[ ]

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

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

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

DLL的調(diào)用[ ]

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

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

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

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

顯式調(diào)用[ ]

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

編程實例[ ]

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

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

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)的如何在編譯時鏈接DLL輸入符號表的方法。

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;
}

運行時使用顯式調(diào)用[ ]

下面的例子先是如何使用不同語言特有的WIN32 API綁定進行運行時的調(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)條目[ ]

參考來源[ ]