首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> Delphi

Delphi 動態鏈接庫編程基礎:靜態/動態調用、LoadLibrary/GetProcAddress/FreeLibrary、外部聲明、調用約定

     編輯:Delphi

10.2 調用 DLL

10.2.1 兩種調用方式

  1. 靜態調用(顯式裝載):外部聲明子句,應用啟動前裝入 DLL。
    function Instr(SourceStr: PChar; Check: Char): Integer; far; external 'UseStr';
    缺點:運行時無法決定調用,特定 DLL 不可用則應用無法執行。
  2. 動態調用(隱式裝載):運行時用 LoadLibrary/GetProcAddress 裝載並調用。適用:部分代碼調用 DLL、根據運行狀態決定用哪個 DLL/哪個過程。優點:裝載失敗程序仍可繼續運行。

10.2.2 靜態調用詳解

external 指示加在聲明中。被調用過程/函數必須採用遠調用模式(far 指示或 {$F+} 編譯指令)。Delphi 支持三種方式:

  • 通過過程/函數名
  • 通過別名(提供編程靈活性)
  • 通過順序號 Index(提高裝載速度)

10.2.3 動態調用 API 函數

函數功能語法
LoadLibrary裝載庫模塊到內存function LoadLibrary(LibFileName: PChar): THandle;
GetProcAddress獲取模塊中函數地址function GetProcAddress(Module: THandle; ProcName: PChar): TFarProc;
FreeLibrary從內存卸載庫模塊procedure FreeLibrary(Module: THandle);

LoadLibrary 詳解

LibFileName 無路徑時按序查找:① 當前目錄 ② Windows 目錄 ③ Windows 系統目錄 ④ 當前任務可執行文件目錄 ⑤ PATH 環境變量目錄 ⑥ 網絡映射目錄。成功返回實例句柄,失敗返回 HINSTANCE_ERROR 以下錯誤碼:

錯誤碼含義
0系統內存不足/可執行文件損壞/調用非法
2文件未找到
3路徑未找到
5嘗試動態鏈接任務/共享網絡保護錯
6庫需為每任務建立獨立數據段
8內存不足啟動應用
10Windows 版本不正確
11可執行文件非法/非 Windows 應用/映像錯誤
12為其他操作系統設計(如 OS/2)
13為 MS-DOS 4.0 設計
14可執行文件類型未知
15嘗試裝載實模式應用(早期 Windows)
16嘗試裝載含可寫多數據段可執行文件第二實例
19嘗試裝載壓縮可執行文件(需解壓)
20DLL 文件非法
21需 32 位擴展

若其他應用已裝載該模塊,LoadLibrary 不重複裝載,而是增加「引用計數」。

GetProcAddress 詳解

Module 為 LoadLibrary 返回句柄,nil 表示當前模塊。ProcName 為函數名指針或順序值。用順序值時若函數不存在仍返回非 nil 易混淆,推薦用函數名(拼寫須與 DLL EXPORTS 節一致)。成功返回函數入口地址,失敗返回 nil。

FreeLibrary 詳解

模塊內存僅裝載一次,調用遞減引用計數,歸零則卸載。每次 LoadLibrary 必配對 FreeLibrary,防止殘留模塊。

10.2.4 動態調用舉例

系統含兩編輯框:第一輸入字符串,第二輸入字符。若字符包含在字符串中,標簽顯示位置,否則提示不包含。Edit2.OnKeyPress 實現:

procedure TForm1.Edit2KeyPress(Sender: TObject; var Key: Char);
var Order: Integer; txt: PChar; PFunc: TFarProc; Module: THandle;
begin
  Module := LoadLibrary('c:\dlls\example.dll');
  if Module > 32 then
  begin
    Edit2.Text := '';
    PFunc := GetProcAddress(Module, '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(Module);
end;

TInstr 為預定義函數類型:type TInstr = function(Source: PChar; Check: Char): Integer;

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved