程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 第十章-動態鏈接庫編程(一)(2)

第十章-動態鏈接庫編程(一)(2)

編輯:Delphi

10.2.1.3 DLLs中的變量和段 

一個DLLs擁有自己的數據段(DS),因而它聲明的任何變量都為自己所私有。調用它的模塊不能直接使用它定義的變量。要使用必須通過過程或函數界面才能完成。而對DLLs來說,它永遠都沒有機會使用調用它的模塊中聲明的變量。

一個DLLs沒有自己的堆棧段(SS),它使用調用它的應用程序的堆棧。因此在DLL中的過程、函數絕對不要假定DS = SS。一些語言在小模式編譯下有這種假設,但使用Delphi可以避免這種情況。Delphi絕不會產生假定DS = SS的代碼,Delphi的任何運行時間庫過程/函數也都不作這種假定。需注意的是如果讀者想嵌入匯編語言代碼,絕不要使SS和DS登錄同一個值。 

10.2.1.4 DLLs中的運行時間錯和處理 

由於DLLs無法控制應用程序的運行,導致很難進行異常處理,因此編寫DLLs時要十分小心,以確保被調用時能正常執行 。當DLLs中發生一個運行時間錯時,相應DLLs並不一定從內存中移去(因為此時其它應用程序可能正在用它),而調用DLLs的程序異常中止。這樣造成的問題是當DLLs已被修改,重新進行調用時,內存中保留的仍然可能是以前的版本,修改後的程序並沒有得到驗證。對於這個問題,有以下兩種解決方法:

1.在程序的異常處理部分顯式將DLL卸出內存;

2.完全退出Windows,而後重新啟動,運行相應的程序。

同一般的應用程序相比,DLL中運行時間錯的處理是很困難的,而造成的後果也更為嚴重。因此要求程序設計者在編寫代碼時要有充分、周到的考慮。 

10.2.1.5 庫初始化代碼的編寫 

傳統Windows中動態鏈接庫的編寫,需要兩個標准函數:LibMain和WEP,用於啟動和關閉DLL。在LibMain中,可以執行開鎖DLL數據段、分配內存、初始化變量等初始化工作;而WEP在從內存中移去DLLs前被調用,一般用於進行必要的清理工作,如釋放內存等。Delphi用自己特有的方式實現了這兩個標准函數的功能。這就是在工程文件中的begin...end部分添加初始化代碼。和傳統Windows編程方法相比,它的主要特色是:

1.初始化代碼是可選的。一些必要的工作(如開鎖數據段)可以由系統自動完成。所以大部分情況下用戶不會涉及到;

2.可以設置多個退出過程,退出時按順序依次被調用;

3.LibMain和WEP對用戶透明,由系統自動調用。

初始化代碼完成的主要工作是:

1.初始化變量、分配全局內存塊、登錄窗口對象等初始化工作。在(10.3.2)節“利用DLLs實現應用程序間的數據傳輸”中,用於數據共享的全局內存塊就是在初始化代碼中分配的。

2.設置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的取值與意義如下: 

表10.1 ExitCode的取值與意義

━━━━━━━━━━━━━━━━━━━━━

取 值 意 義

—————————————————————

WEP_System_Exit Windows關閉 

WEP_Free_DLLx DLLs被卸出

━━━━━━━━━━━━━━━━━━━━━ 

退出過程編譯時必須關閉stack_checking,因而需設置編譯指示 {$S-} 。 

10.2.1.6 編寫一般DLLs的應用舉例 

在下面的程序中我們把一個字符串操作的函數儲存到一個DLLs中,以便需要的時候調用它。應該注意的一點是:為了保證這個函數可以被其它語言編寫的程序所調用,作為參數傳遞的字符串應該是無結束符的字符數組類型(即PChar類型),而不是Object Pascal的帶結束符的Srting類型。程序清單如下:

library Example;

uses

SysUtils,

Classes;

{返回字符在字符串中的位置}

function InStr(SourceStr: PChar;Ch: Char): Integer; export;

var

Len,i: Integer;

begin

Len := strlen(SourceStr);

for i := 0 to Len-1 do

if SourceStr[i] = ch then

begin

Result := i;

Exit;

end;

Result := -1;

end;

exports

Instr Index 1 name 'MyInStr' resident;

begin

end. 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved