熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Delphi編程 >> 正文

Delphi中動態鏈接庫兩種調用方式的比較

2013-11-11 21:05:43  來源: Delphi編程 

動態鏈接庫的概念

動態鏈接庫(Dynamic Link Library縮寫為DLL)是一個可以被其它應用程序共享的程序模塊其中封裝了一些可以被共享的例程和資源動態鏈接庫文件的擴展名一般是dll也有可能是drvsys和fon它和可執行文件(exe)非常類似區別在於DLL中雖然包含了可執行代碼卻不能單獨執行而應由Windows應用程序直接或間接調用

動態鏈接是相對於靜態鏈接而言的所謂靜態鏈接是指把要調用的函數或者過程鏈接到可執行文件中成為可執行文件的一部分換句話說函數和過程的代碼就在程序的exe文件中該文件包含了運行時所需的全部代碼當多個程序都調用相同函數時內存中就會存在這個函數的多個拷貝這樣就浪費了寶貴的內存資源而動態鏈接所調用的函數代碼並沒有被拷貝到應用程序的可執行文件中去而是僅僅在其中加入了所調用函數的描述信息(往往是一些重定位信息)僅當應用程序被裝入內存開始運行時在Windows的管理下才在應用程序與相應的DLL之間建立鏈接關系當要執行所調用DLL中的函數時根據鏈接產生的重定位信息Windows才轉去執行DLL中相應的函數代碼

一般情況下如果一個應用程序使用了動態鏈接庫Win系統保證內存中只有DLL的一份復制品這是通過內存映射文件實現的DLL首先被調入Win系統的全局堆棧然後映射到調用這個DLL的進程地址空間在Win系統中每個進程擁有自己的位線性地址空間如果一個DLL被多個進程調用每個進程都會收到該DLL的一份映像位Windows不同在Win中DLL可以看作是每個進程自己的代碼

動態鏈接庫的優點

. 共享代碼資源和數據

使用DLL的主要目的就是為了共享代碼DLL的代碼可以被所有的Windows應用程序共享

. 隱藏實現的細節

DLL中的例程可以被應用程序訪問而應用程序並不知道這些例程的細節

. 拓展開發工具如Delphi的功能

由於DLL是與語言無關的因此可以創建一個DLL被C++VB或任何支持動態鏈接庫的語言調用這樣如果一種語言存在不足就可以通過訪問另一種語言創建的DLL來彌補

動態鏈接庫的實現方法

. Loadtime Dynamic Linking

這種用法的前提是在編譯之前已經明確知道要調用DLL中的哪幾個函數編譯時在目標文件中只保留必要的鏈接信息而不含DLL函數的代碼當程序執行時利用鏈接信息加載DLL函數代碼並在內存中將其鏈接入調用程序的執行空間中其主要目的是便於代碼共享

. Runtime Dynamic Linking

這種方式是指在編譯之前並不知道將會調用哪些DLL函數完全是在運行過程中根據需要決定應調用哪個函數並用LoadLibrary和GetProcAddress動態獲得DLL函數的入口地址

DLL的兩種調用方式在Delphi中的比較

編寫DLL的目的是為了輸出例程供其他程序調用因此在DLL的工程文件中要把輸出的例程用Exports關鍵字引出在調用DLL的應用程序中需要聲明用到的DLL中的方法聲明格式要和DLL中的聲明一樣訪問DLL中的例程有靜態調用和動態調用兩種方式靜態調用方式就是在單元的Interface部分用External指示字列出要從DLL中引入的例程動態調用方式就是通過調用Windows的API包括LoadLibrary函數GetProcAddress函數以及FreeLibrary函數動態的引入DLL中的例程

靜態調用方式所需的代碼較動態調用方式所需的少但存在著一些不足一是如果要加載的DLL不存在或者DLL中沒有要引入的例程這時候程序就自動終止運行二是DLL一旦加載就一直駐留在應用程序的地址空間即使DLL已不再需要了動態調用方式就可解決以上問題它在需要用到DLL的時候才通過LoadLibrary函數引入用完後通過FreeLibrary函數從內存中卸載而且通過調GetProcAddress函數可以指定不同的例程最重要的是如果指定的DLL出錯至多是API調用失敗不會導致程序終止以下將通過具體的實例說明說明這調用方式的使用方法

. 靜態調用方式

示例程序創建了一個DLL其中僅包含一個求兩個整數的和的函數在主程序中輸入兩個整數通過調用該DLL即可求出兩個整數的和

該DLL的程序代碼如下

library AddNum;
  uses
  SysUtils
  Classes;

{$R *res}

function AddNumber(NumNum:integer):integer;stdcall; file://定義求和函數
  begin
  result:=Num+Num;
  end;
  exports
  AddNumber; file://引出求和函數
  begin
  end
   
  主程序在調用該DLL時首先在interface部分聲明要調用的函數

function AddNum(NumNum:integer):integer;stdcall;external AddNumdll
  name AddNumber;
 
  然後在按鈕控件的事件中寫入如下代碼

procedure TFormButtonClick(Sender: TObject);
  var
  NumberNumber:integer;
  Sum:integer;
  begin
  Number:=strtoint(EditText);
  Number:=strtoint(EditText);
  Sum:=AddNum(NumberNumber); file://調用求和函數計算結果
  EditText:=inttostr(Sum);
  end;
 
  .動態調用方式

這個示例程序創建了一個顯示日期的DLL其中包含一個窗體

程序中定義了一個ShowCalendar函數返回在這個窗體中設定的日期函數定義如下

function ShowCalendar(AHandle: THandle; ACaption: String): TDateTime;
  var
  DLLForm: TDLLForm;
  begin
  ApplicationHandle := AHandle;
  DLLForm := TDLLFormCreate(Application); file://創建並顯示窗體
  try
  DLLFormCaption := ACaption;
  DLLFormShowModal; file://顯示方式為模式化
  Result := DLLFormcalDLLCalendarCalendarDate; file://返回設定日期
  finally
  DLLFormFree; file://用完後卸載該窗體
  end;
  end;
 
  在DLL的工程文件中用exports ShowCalendar; 語句引出該函數下面通過一個簡單的應用程序測試一下該DLL文件新建一個工程文件在窗體中放置一個Label控件和一個按鈕控件在按鈕控件的OnClick事件中編寫如下代碼

procedure TMainFormButtonClick(Sender: TObject);
  var
  OneHandle : THandle; file://定義一個句柄變量
  begin
  OneHandle := LoadLibrary(Clendardll); file://動態載入DLL並返回其句柄
  try
  if OneHandle <> then file://如果載入成功則獲取ShowCalendar函數的地址
  @ShowCalendar := GetProcAddress(OneHandle ShowCalendar);
  if not (@ShowCalendar = nil) then
  file://如果找到該函數則在主窗體的Label中顯示DLL窗體中設定的日期
  LabelCaption := DateToStr(ShowCalendar(ApplicationHandle Caption))
  else
  RaiseLastWinError;
  finally
  FreeLibrary(OneHandle); file://調用完畢收回DLL占用的資源
  end;
  end;
 
  從以上程序中可以看到DLL的動態調用方式比靜態調用方式的優越之處DLL例程在用到時才被調入用完後就被卸載大大減少了系統資源的占用在調用LoadLibrary函數時可以明確指定DLL的完整路徑如果沒有指定路徑運行時首先查找應用程序載入的目錄然後是Windows系統的System目錄和環境變量Path設定的路徑

結束語

由於動態鏈接庫可以實現代碼和資源的共享大大減少系統資源的占用因此在當今的應用程序開發中起著非常重要的作用Delphi是現今流行的應用軟件開發工具本文就如何在Delphi中使用動態鏈接庫給出了一定程度上的闡述


From:http://tw.wingwit.com/Article/program/Delphi/201311/8480.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.