DLLs中的變量和段
一個DLLs擁有自己的數據段(DS)因而它聲明的任何變量都為自己所私有調用它的模塊不能直接使用它定義的變量要使用必須通過過程或函數界面才能完成而對DLLs來說它永遠都沒有機會使用調用它的模塊中聲明的變量
一個DLLs沒有自己的堆棧段(SS)它使用調用它的應用程序的堆棧因此在DLL中的過程函數絕對不要假定DS = SS一些語言在小模式編譯下有這種假設但使用Delphi可以避免這種情況Delphi絕不會產生假定DS = SS的代碼Delphi的任何運行時間庫過程/函數也都不作這種假定需注意的是如果讀者想嵌入匯編語言代碼絕不要使SS和DS登錄同一個值
DLLs中的運行時間錯和處理
由於DLLs無法控制應用程序的運行導致很難進行異常處理因此編寫DLLs時要十分小心以確保被調用時能正常執行 當DLLs中發生一個運行時間錯時相應DLLs並不一定從內存中移去(因為此時其它應用程序可能正在用它)而調用DLLs的程序異常中止這樣造成的問題是當DLLs已被修改重新進行調用時內存中保留的仍然可能是以前的版本修改後的程序並沒有得到驗證對於這個問題有以下兩種解決方法
在程序的異常處理部分顯式將DLL卸出內存
完全退出Windows而後重新啟動運行相應的程序
同一般的應用程序相比DLL中運行時間錯的處理是很困難的而造成的後果也更為嚴重因此要求程序設計者在編寫代碼時要有充分周到的考慮
庫初始化代碼的編寫
傳統Windows中動態鏈接庫的編寫需要兩個標准函數LibMain和WEP用於啟動和關閉DLL在LibMain中可以執行開鎖DLL數據段分配內存初始化變量等初始化工作而WEP在從內存中移去DLLs前被調用一般用於進行必要的清理工作如釋放內存等Delphi用自己特有的方式實現了這兩個標准函數的功能這就是在工程文件中的begin…end部分添加初始化代碼和傳統Windows編程方法相比它的主要特色是
初始化代碼是可選的一些必要的工作(如開鎖數據段)可以由系統自動完成所以大部分情況下用戶不會涉及到
可以設置多個退出過程退出時按順序依次被調用
LibMain和WEP對用戶透明由系統自動調用
初始化代碼完成的主要工作是
初始化變量分配全局內存塊登錄窗口對象等初始化工作在()節利用DLLs實現應用程序間的數據傳輸中用於數據共享的全局內存塊就是在初始化代碼中分配的
設置DLLs退出時的執行過程Delphi有一個預定義變量ExitProc用於指向退出過程的地址用戶可以把自己的過程名賦給ExitProc系統自動調用WEP函數把ExitProc指向的地址依次賦給WEP執行直到ExitProc為nil
下邊的一段程序包含一個退出過程和一段初始化代碼用來說明如何正確設置退出過程
library Test;
{$S}
uses WinTypes WinProcs;
var
SaveExit: Pointer;
procedure LibExit; far;
begin
if ExitCode = wep_System_Exit then
begin
{ 系統關閉時的相應處理 }
end
else
begin
{ DLL卸出時的相應處理 }
end;
ExitProc := SaveExit; { 恢復原來的退出過程指針 }
end;
begin
{DLL的初始化工作 }
SaveExit := ExitProc; { 保存原來的退出過程指針 }
ExitProc := @LibExit; { 安裝新的退出過程 }
end
在初始化代碼中首先把原來的退出過程指針保存到一個變量中而後再把新的退出過程地址賦給ExitProc而在自定義退出過程LibExit結束時再把ExitProc的值恢復由於ExitProc是一個系統全局變量所以在結束時恢復原來的退出過程是必要的
退出過程LibExit中使用了一個系統定義變量ExitCode用於標志退出時的狀態 ExitCode的取值與意義如下
表 ExitCode的取值與意義
━━━━━━━━━━━━━━━━━━━━━
取 值 意 義
WEP_System_Exit Windows關閉
WEP_Free_DLLx DLLs被卸出
━━━━━━━━━━━━━━━━━━━━━
退出過程編譯時必須關閉stack_checking因而需設置編譯指示 {$S}
編寫一般DLLs的應用舉例
在下面的程序中我們把一個字符串操作的函數儲存到一個DLLs中以便需要的時候調用它應該注意的一點是為了保證這個函數可以被其它語言編寫的程序所調用作為參數傳遞的字符串應該是無結束符的字符數組類型(即PChar類型)而不是Object Pascal的帶結束符的Srting類型程序清單如下
library Example;
uses
SysUtils
Classes;
{返回字符在字符串中的位置}
function InStr(SourceStr: PChar;Ch: Char) Integer; export;
var
Leni: Integer;
begin
Len := strlen(SourceStr)
for i := to Len do
if SourceStr[i] = ch then
begin
Result := i;
Exit;
end;
Result := ;
end;
exports
Instr Index name MyInStr resident;
begin
end
調用DLLs
有兩種方法可用於調用一個儲存在DLLs中的過程
[] [] [] []
From:http://tw.wingwit.com/Article/program/Delphi/201311/25208.html