動(dòng)態(tài)鏈接庫(kù)
動(dòng)態(tài)連接庫(kù)(Dynamic link library),是一些編譯過(guò)的可以執(zhí)行的代碼模塊,后綴為.dll
1 DLL的基本理論
? 在使用普通函數(shù)庫(kù)時(shí),可以在程序連接時(shí)將庫(kù)中的代碼拷貝到執(zhí)行文件中,這時(shí)靜態(tài)鏈接,在多個(gè)同樣程序執(zhí)行時(shí),體統(tǒng)保留了許多
代碼副本,造成了內(nèi)存資源的浪費(fèi)。在使用dll時(shí),不必將dll鏈接到程序中,而是在應(yīng)用程序運(yùn)行時(shí)動(dòng)態(tài)的裝載dll,裝載dll被映射
到進(jìn)程的地址空間中。同時(shí),使用dll 并不時(shí)將庫(kù)代碼拷貝,只是在程序中記錄了函數(shù)的入口點(diǎn)和接口。
2 DLL 的優(yōu)點(diǎn)
?1) 節(jié)省系統(tǒng)資源
?2) 不僅可以包括可執(zhí)行代碼,還可以包括數(shù)據(jù)和各種資源
?3)支持多語(yǔ)言
?4)升級(jí)可以僅僅覆蓋dll 文件
?5)dll 獨(dú)立編程語(yǔ)言,c++builder 中的dll vc 也可以使用
3導(dǎo)入導(dǎo)出匹配
??? DLL函數(shù)一般有兩種函數(shù),內(nèi)部函數(shù)(internal)和導(dǎo)出函數(shù)(export).在實(shí)際情況下,許多DLL 調(diào)用了其他DLL里面的函數(shù),因此
DLL可以同時(shí)有導(dǎo)入和導(dǎo)出函數(shù)。
???? DLL 包含有一個(gè)導(dǎo)出函數(shù)表,可以通過(guò)函數(shù)的符號(hào)化的名字和稱為序號(hào)的正書來(lái)識(shí)別這些函數(shù),函數(shù)表中包含了函數(shù)在dll內(nèi)部的
地址。在動(dòng)態(tài)鏈接進(jìn)程好建立一張表,把客戶的調(diào)用與dll里的函數(shù)的地址連接起來(lái)。
??? double dbValue(value);//內(nèi)部函數(shù)
??? double dbValue(value);//內(nèi)部函數(shù)
??? extern"c" _declspec(dllexpoert) double changeValue(double,bool);//外部函數(shù)
?? double dblValue(double value)
?? {
?????? return value*vlaue;
?? }
?? double changeValue(double value,bool whichOp)
? {
???? return whichOp?doublValue(value):halfValue(value);
?? }
? 如果我們希望dll可以用于其他語(yǔ)言或不同版本的c++ 需要在聲明導(dǎo)出函數(shù)的時(shí)候加上extern "C."
?4 隱式的鏈接和顯示的鏈接
?? 隱式鏈接(前面所講)在創(chuàng)建dll 的時(shí)候,鏈接器產(chǎn)生一個(gè)lib 文件把拿獲了dll中的導(dǎo)出符號(hào)和序號(hào)
?? 顯示鏈接調(diào)用Win32 的LoadLibrary 函數(shù),使用完后,調(diào)用 FreeLibrary.
?5 查找dll
?? 依次順序?yàn)榘琫xe 的目錄,進(jìn)程的當(dāng)前目錄,Windows 目錄,path 環(huán)境變量里列出的目錄。
?6 創(chuàng)建動(dòng)態(tài)鏈接庫(kù)
?? (如何查看dll 文件的定義)
?7 導(dǎo)出函數(shù):extern "C" __declspec(dllexport) ExportType FunctionName(Parameter)
??? extern "C" __declspec(dllimport) __stdcall void CreateFromFunct();
??? extern "C" __declspec(dllexport) __stdcall void CreateFromFunct();//導(dǎo)出函數(shù)
??? 導(dǎo)出類:class __declspec(dllexport) ExportType ClassName{...}
??? class __declspec(dllexport) __stdcall MyDllClass { //導(dǎo)出類
???? public:
??? MyDllClass();
??? void CreateAForm();
??? TDllFrm* DllMyForm;
??? };
???? __declspec(dllimport) class __stdcall MyDllClass {
?????? public:
?????? MyDllClass();
?????? void CreateAForm();
?????? TDllFrm* DllMyForm;
??? };
??? 靜態(tài)調(diào)用,build 生成dll 文件和lib 文件,并把lib 文件導(dǎo)入到工程中
???? void __fastcall TForm1::Button1Click(TObject *Sender)
??? { // 導(dǎo)出類實(shí)現(xiàn),導(dǎo)出類只能使用靜態(tài)方式調(diào)用
?????? DllClass = new MyDllClass();
?????? DllClass->CreateAForm();??
??? }
??? void __fastcall TForm1::Button2Click(TObject *Sender)
??? { // 導(dǎo)出函數(shù)實(shí)現(xiàn)
?????? CreateFromFunct();
???? }
???? void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
??? {
???????? delete DllClass;
???? }
?? 動(dòng)態(tài)調(diào)用
?? class TForm1 : public TForm
? {
???????? ...
????? private: // User declarations
????? void (__stdcall *CreateFromFunct)();
?????????? ...
?? }
? HINSTANCE DLLInst = NULL;
? void __fastcall TForm1::Button2Click(TObject *Sender)
? {??
???? if( NULL == DLLInst ) DLLInst = LoadLibrary("DLL.dll"); //上面的 Dll
???? if (DLLInst) {
???????????? CreateFromFunct = (void (__stdcall*)()) GetProcAddress(DLLInst,
????????????????????????? "CreateFromFunct");
????? if (CreateFromFunct) CreateFromFunct();
????? else ShowMessage("Could not obtain function pointer");
?? }
????? else ShowMessage("Could not load DLL.dll");
? }
?? void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
? {
???? if ( DLLInst ) FreeLibrary (DLLInst);
? }
8? bcb 調(diào)用vc 編寫的DLL
? 1) 名字分解
?? 1. 名字分解:
? 沒(méi)有名字分解的函數(shù)
??? TestFunction1 // __cdecl calling convention
??? @TestFunction2 // __fastcall calling convention
??? TESTFUNCTION3 // __pascal calling convention
??? TestFunction4 // __stdcall calling convention
? 有名字分解的函數(shù)
??? @TestFunction1$QV // __cdecl calling convention
??? @TestFunction2$qv // __fastcall calling convention
??? TESTFUNCTION3$qqrv // __apscal calling convention
??? @TestFunction4$qqrv // __stdcall calling convention
? 使用 extern "C" 不會(huì)分解函數(shù)名
?? 2)
????? __cdecl 缺省
?? 是 Borland C++ 的缺省的 C 格式命名約定,它在標(biāo)識(shí)符前加一下劃線,以保留
? 它原來(lái)所有的全程標(biāo)識(shí)符。參數(shù)按最右邊參數(shù)優(yōu)先的原則傳遞給棧,然后清棧。
??? extaern "C" bool __cdecl TestFunction();
?? 在 def 文件中顯示為
??? TestFunction @1
?? 注釋: @1 表示函數(shù)的順序數(shù),將在“使用別名”時(shí)使用。
? __pascal Pascal格式
?? 這時(shí)函數(shù)名全部變成大寫,第一個(gè)參數(shù)先壓棧,然后清棧。
??? TESTFUNCTION @1 //def file
? __stdcall 標(biāo)準(zhǔn)調(diào)用
?? 最后一個(gè)參數(shù)先壓棧,然后清棧。
??? TestFunction @1 //def file
? __fastcall 把參數(shù)傳遞給寄存器
?? 第一個(gè)參數(shù)先壓棧,然后清棧。
??? @TestFunction @1 //def file
? 3)
?? 3. 解決調(diào)用約定:
?? Microsoft 與 Borland 的 __stdcall 之間的區(qū)別是命名方式。 Borland 采用
? __stdcall 的方式去掉了名字起前的下劃線。 Microsoft 則是在前加上下劃線,在
? 后加上 @ ,再后跟為棧保留的字節(jié)數(shù)。字節(jié)數(shù)取決于參數(shù)在棧所占的空間。每一個(gè)
? 參數(shù)都舍入為 4 的倍數(shù)加起來(lái)。這種 Miocrosoft 的 DLL 與系統(tǒng)的 DLL 不一樣。
?4 查看dll 的調(diào)用接口tdump -ee MyDll.dll >1.txt (查看 1.txt 文件即可)
5 編輯c++ builder build 為一個(gè)可以直接調(diào)用的 .exe 。 點(diǎn)擊project option? 中l(wèi)inker 標(biāo)簽 去掉user dynamic RTL 選項(xiàng) 和package 中 去掉builder with runtime package 選項(xiàng).
6 調(diào)用代參數(shù)的vl 編寫的dll 調(diào)用的實(shí)例。
int (__cdecl *fun)(char*,char*,char*);
HINSTANCE DLLInst = NULL;
void __fastcall TForm1::Button1Click(TObject *Sender)
{
if( NULL == DLLInst )
{
DLLInst = LoadLibrary("HollyIVRCard.dll");
}
if(DLLInst)
{
? fun=(int (__cdecl*)(char*,char*,char*))GetProcAddress(DLLInst,"hTrade");
? if(fun)
? {
??? cardid=Edit1->Text.c_str();
??? num=Edit2->Text.c_str();
??? ShowMessage(fun(cardid,num,res));
??? //cout<<cardid<<endl;
??? //cout<<num<<endl;
? }
} else{
?? ShowMessage("load dll fail");
}
?? ShowMessage(AnsiString(res));
}
posted on 2006-09-06 18:13 康文 閱讀(390) 評(píng)論(0) 編輯 收藏 所屬分類: c\c++