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