首頁 考試吧論壇 Exam8視線 考試商城 網絡課程 模擬考試 考友錄 實用文檔 求職招聘 論文下載 | ||
![]() |
2011中考 | 2011高考 | 2012考研 | 考研培訓 | 在職研 | 自學考試 | 成人高考 | 法律碩士 | MBA考試 MPA考試 | 中科院 |
|
![]() |
四六級 | 職稱英語 | 商務英語 | 公共英語 | 托福 | 雅思 | 專四專八 | 口譯筆譯 | 博思 | GRE GMAT 新概念英語 | 成人英語三級 | 申碩英語 | 攻碩英語 | 職稱日語 | 日語學習 | 法語 | 德語 | 韓語 |
|
![]() |
計算機等級考試 | 軟件水平考試 | 職稱計算機 | 微軟認證 | 思科認證 | Oracle認證 | Linux認證 華為認證 | Java認證 |
|
![]() |
公務員 | 報關員 | 銀行從業資格 | 證券從業資格 | 期貨從業資格 | 司法考試 | 法律顧問 | 導游資格 報檢員 | 教師資格 | 社會工作者 | 外銷員 | 國際商務師 | 跟單員 | 單證員 | 物流師 | 價格鑒證師 人力資源 | 管理咨詢師考試 | 秘書資格 | 心理咨詢師考試 | 出版專業資格 | 廣告師職業水平 駕駛員 | 網絡編輯 |
|
![]() |
衛生資格 | 執業醫師 | 執業藥師 | 執業護士 | |
![]() |
會計從業資格考試(會計證) | 經濟師 | 會計職稱 | 注冊會計師 | 審計師 | 注冊稅務師 注冊資產評估師 | 高級會計師 | ACCA | 統計師 | 精算師 | 理財規劃師 | 國際內審師 |
|
![]() |
一級建造師 | 二級建造師 | 造價工程師 | 造價員 | 咨詢工程師 | 監理工程師 | 安全工程師 質量工程師 | 物業管理師 | 招標師 | 結構工程師 | 建筑師 | 房地產估價師 | 土地估價師 | 巖土師 設備監理師 | 房地產經紀人 | 投資項目管理師 | 土地登記代理人 | 環境影響評價師 | 環保工程師 城市規劃師 | 公路監理師 | 公路造價師 | 安全評價師 | 電氣工程師 | 注冊測繪師 | 注冊計量師 |
|
![]() |
繽紛校園 | 實用文檔 | 英語學習 | 作文大全 | 求職招聘 | 論文下載 | 訪談 | 游戲 |
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.
10.2.2 調用DLLs
有兩種方法可用于調用一個儲存在DLLs中的過程。
1.靜態調用或顯示裝載
使用一個外部聲明子句,使DLLs在應用程序開始執行前即被裝入。例如:
function Instr(SourceStr : PChar;Check : Char); Integer; far; external 'UseStr';
使用這種方法,程序無法在運行時間里決定DLLs的調用。假如一個特定的DLLs在運行時無法使用,則應用程序將無法執行。
2.動態調用或隱式裝載
使用Windows API函數LoadLibray和GetProcAddress可以實現在運行時間里動態裝載DLLs并調用其中的過程。
若程序只在其中的一部分調用DLLs的過程,或者程序使用哪個DLLs, 調用其中的哪個過程需要根據程序運行的實際狀態來判斷,那么使用動態調用就是一個很好的選擇。
使用動態調用,即使裝載一個DLLs失敗了,程序仍能繼續運行。
10.2.3 靜態調用
在靜態調用一個DLLs中的過程或函數時,external指示增加到過程或函數的聲明語句中。被調用的過程或函數必須采用遠調用模式。這可以使用far過程指示或一個{$F +}編譯指示。
Delphi全部支持傳統Windows動態鏈接庫編程中的三種調用方式,它們是:
● 通過過程/函數名
● 通過過程/函數的別名
● 通過過程/函數的順序號
通過過程或函數的別名調用,給用戶編程提供了靈活性,而通過順序號(Index)調用可以提高相應DLL的裝載速度。
10.2.4 動態調用
10.2.4.1 動態調用中的API函數
動態調用中使用的Windows API函數主要有三個,即:Loadlibrary,GetProcAddress和Freelibrary。
1.Loadlibrary: 把指定庫模塊裝入內存
語法為:
function Loadlibrary(LibFileName: PChar): THandle;
LibFileName指定了要裝載DLLs的文件名,如果LibFileName沒有包含一個路徑,則Windows按下述順序進行查找:
(1)當前目錄;
(2)Windows目錄(包含win.com的目錄)。函數GetWindowDirectory返回這一目錄的路徑;
(3)Windows系統目錄(包含系統文件如gdi.exe的目錄)。函數GetSystemDirectory返回這一目錄的路徑;
(4)包含當前任務可執行文件的目錄。利用函數GetModuleFileName可以返回這一目錄的路徑;
(5)列在PATH環境變量中的目錄;
(6)網絡的映象目錄列表。
如果函數執行成功,則返回裝載庫模塊的實例句柄。否則,返回一個小于HINSTANCE_ERROR的錯誤代碼。錯誤代碼的意義如下表:
表10.2 Loadlibrary返回錯誤代碼的意義
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
錯誤代碼 意 義
——————————————————————————————————————
0 系統內存不夠,可執行文件被破壞或調用非法
2 文件沒有被發現
3 路徑沒有被發現
5 企圖動態鏈接一個任務或者有一個共享或網絡保護錯
6 庫需要為每個任務建立分離的數據段
8 沒有足夠的內存啟動應用程序
10 Windows版本不正確
11 可執行文件非法;蛘卟皇荳indows應用程序,或者在.EXE映
像中有錯誤
12 應用程序為一個不同的操作系統設計(如OS/2程序)
13 應用程序為MS DOS4.0設計
14 可執行文件的類型不知道
15 試圖裝載一個實模式應用程序(為早期Windows版本設計)
16 試圖裝載包含可寫的多個數據段的可執行文件的第二個實例
19 試圖裝載一個壓縮的可執行文件。文件必須被解壓后才能被裝裁
20 動態鏈接庫文件非法
21 應用程序需要32位擴展
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
假如在應用程序用Loadlibrary調用某一模塊前,其它應用程序已把該模塊裝入內存,則Loadlibrary并不會裝載該模塊的另一實例,而是使該模塊的“引用計數”加1。
2.GetProcAddress:撿取給定模塊中函數的地址
語法為:
function GetProcAddress(Module: THandle; ProcName: PChar): TFarProc;
Module包含被調用的函數庫模塊的句柄,這個值由Loadlibrary返回。如果把Module設置為nil,則表示要引用當前模塊。
ProcName是指向含有函數名的以nil結尾的字符串的指針,或者也可以是函數的次序值。如果ProcName參數是次序值,則如果該次序值的函數在模塊中并不存在時,GetProcAddress仍返回一個非nil的值。這將引起混亂。因此大部分情況下用函數名是一種更好的選擇。如果用函數名,則函數名的拼寫必須與動態鏈接庫文件EXPORTS節中的對應拼寫相一致。
如果GetProcAddress執行成功,則返回模塊中函數入口處的地址,否則返回nil。
3.Freelibrary:從內存中移出庫模塊
語法為:
procedure Freelibrary(Module : THandle);
Module為庫模塊的句柄。這個值由Loadlibrary返回。
由于庫模塊在內存中只裝載一次,因而調用Freelibrary首先使庫模塊的引用計數減一。如果引用計數減為0,則卸出該模塊。
每調用一次Loadlibrary就應調用一次FreeLibray,以保證不會有多余的庫模塊在應用程序結束后仍留在內存中。
10.2.4.2 動態調用舉例
對于動態調用,我們舉了如下的一個簡單例子。系統一共包含兩個編輯框。在第一個編輯框中輸入一個字符串,而后在第二個編輯框中輸入字符。如果該字符包含在第一個編輯框的字符串中,則標簽框顯示信息:“位于第n位。”,否則顯示信息:“不包含這個字符。”。如圖是程序的運行界面。
輸入檢查功能的實現在Edit2的OnKeyPress事件處理過程中,程序清單如下。
procedure TForm1.Edit2KeyPress(Sender: TObject; var Key: Char);
var
order: Integer;
txt: PChar;
PFunc: TFarProc;
Moudle: THandle;
begin
Moudle := Loadlibrary('c:\dlls\example.dll');
if Moudle > 32 then
begin
Edit2.text := '';
Pfunc := GetProcAddress(Moudle,'Instr');
txt := StrAlloc(80);
txt := StrPCopy(txt,Edit1.text);
Order := TInstr(PFunc)(txt,Key);
if Order = -1 then
Label1.Caption := '不包含這個字符 '
else
Label1.Caption := '位于第'+IntToStr(Order+1)+'位';
end;
Freelibrary(Moudle);
end;
在利用GetProcAddess返回的函數指針時,必須進行強制類型轉換:
Order := TInstr(PFunc)(text,Key);
TInStr是一個定義好了的函數類型:
type
TInStr = function(Source: PChar;Check: Char): Integer;
10.3 利用DLLs實現數據傳輸
10.3.1 DLLs中的全局內存
Windows規定:DLLs并不擁有它打開的任何文件或它分配的任何全局內存塊。這些對象由直接或間接調用DLLs的應用程序擁有。這樣,當應用程序中止時,它擁有的打開的文件自動關閉,它擁有的全局內存塊自動釋放。這就意味著保存在DLLs全局變量中的文件和全局內存塊變量在DLLs沒有被通知的情況下就變為非法。這將給其它使用該DLLs的應用程序造成困難。
為了避免出現這種情況,文件和全局內存塊句柄不應作為DLLs的全局變量,而是作為DLLs中過程或函數的參數傳遞給DLLs使用。調用DLLs的應用程序應該負責對它們的維護。
但在特定情況下,DLLs也可以擁有自己的全局內存塊。這些內存塊必須用gmem_DDEShare屬性進行分配。這樣的內存塊直到被DLLs顯示釋放或DLLs退出時都保持有效。
由DLLs管理的全局內存塊是應用程序間進行數據傳輸的又一途徑,下面我們將專門討論這一問題。
10.3.2 利用DLLs實現應用程序間的數據傳輸
利用DLLs實現應用程序間的數據傳輸的步驟為:
1. 編寫一個DLLs程序,其中擁有一個用gmem_DDEShare屬性分配的全局內存塊;
2. 服務器程序調用DLLs,向全局內存塊寫入數據;
3. 客戶程序調用DLLs,從全局內存塊讀取數據。
10.3.2.1 用于實現數據傳輸的DLLs的編寫
用于實現數據傳輸的DLLs與一般DLLs的編寫基本相同,其中特別的地方是:
1. 定義一個全局變量句柄:
var
hMem: THandle;
2. 定義一個過程,返回該全局變量的句柄。該過程要包含在exports子句中。如:
function GetGlobalMem: THandle; export;
begin
Result := hMem;
end;
3. 在初始化代碼中分配全局內存塊:
程序清單如下:
begin
hMem := GlobalAlloc(gmem_MOVEABLE and gmem_DDEShare,num);
if hMem = 0 then
MessageDlg('Could not allocate memory',mtWarning,[mbOK],0);
end.
num是一個預定義的常數。
Windows API函數GlobalAlloc用于從全局內存堆中分配一塊內存,并返回該內存塊的句柄。該函數包括兩個參數,第一個參數用于設置內存塊的分配標志。可以使用的分配標志如下表所示。
相關推薦:2010年9月計算機等級考試試題及答案解析專題北京 | 天津 | 上海 | 江蘇 | 山東 |
安徽 | 浙江 | 江西 | 福建 | 深圳 |
廣東 | 河北 | 湖南 | 廣西 | 河南 |
海南 | 湖北 | 四川 | 重慶 | 云南 |
貴州 | 西藏 | 新疆 | 陜西 | 山西 |
寧夏 | 甘肅 | 青海 | 遼寧 | 吉林 |
黑龍江 | 內蒙古 |