在Delphi中靜態調用DLL


在Delphi中靜態調用DLL top 

  調用一個DLL比寫一個DLL要容易一些。首先給大家介紹的是靜態調用方法,稍后將介紹動態調用方法,並就兩種方法做一個比較。同樣的,我們先舉一個靜態調用的例子。

unit Unit1; 

interface 

uses 
Windows, Messages, SysUtils, Classes, Graphics, 
Controls, Forms, Dialogs, StdCtrls; 

type 
TForm1 = class(TForm) 
Edit1: TEdit; 
Button1: TButton; 
procedure Button1Click(Sender: TObject); 
private 
{ Private declarations } 
public 
{ Public declarations } 
end; 

var 
Form1: TForm1; 

implementation 

{$R *.DFM} 

//本行以下代碼為我們真正動手寫的代碼 

function TestDll(i:integer):integer;stdcall; 
external ’Delphi.dll’; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
Edit1.Text:=IntToStr(TestDll(1)); 
end; 

end.

 

  上面的例子中我們在窗體上放置了一個編輯框(Edit)和一個按鈕(Button),並且書寫了很少的代碼來測試我們剛剛編寫的Delphi.dll。大家可以看到我們唯一做的工作是將TestDll函數的說明部分放在了implementation中,並且用external語句指定了Delphi.dll的位置。(本例中調用程序和Delphi.dll在同一個目錄中。)讓人興奮的是,我們自己編寫的TestDll函數很快被Delphi認出來了。您可做這樣一個實驗:輸入“TestDll(”,很快Delphi就會用fly-by提示條提示您應該輸入的參數是什么,就像我們使用Delphi中定義的其他函數一樣簡單。注意事項有以下一些: 
一、調用參數用stdcall 
  和前面提到的一樣,當引用DLL中的函數和過程時也要使用stdcall參數,原因和前面提到的一樣。 

二、用external語句指定被調用的DLL文件的路徑和名稱 
  正如大家看到的,我們在external語句中指定了所要調用的DLL文件的名稱。沒有寫路徑是因為該DLL文件和調用它的主程序在同一目錄下。如果該DLL文件在C:\,則我們可將上面的引用語句寫為external ’C:\Delphi.dll’。注意文件的后綴.dll必須寫上。 

三、不能從DLL中調用全局變量 
  如果我們在DLL中聲明了某種全局變量,如:var s:byte 。這樣在DLL中s這個全局變量是可以正常使用的,但s不能被調用程序使用,既s不能作為全局變量傳遞給調用程序。不過在調用程序中聲明的變量可以作為參數傳遞給DLL。 

四、被調用的DLL必須存在 
  這一點很重要,使用靜態調用方法時要求所調用的DLL文件以及要調用的函數或過程等等必須存在。如果不存在或指定的路徑和文件名不正確的話,運行主程序時系統會提示“啟動程序時出錯”或“找不到*.dll文件”等運行錯誤。


在Delphi中動態調用DLL top 

  動態調用DLL相對復雜很多,但非常靈活。為了全面的說明該問題,這次我們舉一個調用由C++編寫的DLL的例子。首先在C++中編譯下面的DLL源程序。

#include 

extern ”C” _declspec(dllexport) 
int WINAPI TestC(int i) 

return i; 
}



  編譯后生成一個DLL文件,在這里我們稱該文件為Cpp.dll,該DLL中只有一個返回整數類型的函數TestC。為了方便說明,我們仍然引用上面的調用程序,只是將原來的Button1Click過程中的語句用下面的代碼替換掉了。

procedure TForm1.Button1Click(Sender: TObject); 
type 
TIntFunc=function(i:integer):integer;stdcall; 
var 
Th:Thandle; 
Tf:TIntFunc; 
Tp:TFarProc; 
begin 
Th:=LoadLibrary(’Cpp.dll’); {裝載DLL} 
if Th>0 then 
try 
Tp:=GetProcAddress(Th,PChar(’TestC’)); 
if Tp<>nil 
then begin 
Tf:=TIntFunc(Tp); 
Edit1.Text:=IntToStr(Tf(1)); {調用TestC函數} 
end 
else 
ShowMessage(’TestC函數沒有找到’); 
finally 
FreeLibrary(Th); {釋放DLL} 
end 
else 
ShowMessage(’Cpp.dll沒有找到’); 
end;


  大家已經看到了,這種動態調用技術很復雜,但只要修改參數,如修改LoadLibrary(’Cpp.dll’)中的DLL名稱為’Delphi.dll’就可動態更改所調用的DLL。 

一、定義所要調用的函數或過程的類型 
  在上面的代碼中我們定義了一個TIntFunc類型,這是對應我們將要調用的函數TestC的。在其他調用情況下也要做同樣的定義工作。並且也要加上stdcall調用參數。 

二、釋放所調用的DLL 
  我們用LoadLibrary動態的調用了一個DLL,但要記住必須在使用完后手動地用FreeLibrary將該DLL釋放掉,否則該DLL將一直占用內存直到您退出Windows或關機為止。 

  現在我們來評價一下兩種調用DLL的方法的優缺點。靜態方法實現簡單,易於掌握並且一般來說稍微快一點,也更加安全可靠一些;但是靜態方法不能靈活地在運行時裝卸所需的DLL,而是在主程序開始運行時就裝載指定的DLL直到程序結束時才釋放該DLL,另外只有基於編譯器和鏈接器的系統(如Delphi)才可以使用該方法。動態方法較好地解決了靜態方法中存在的不足,可以方便地訪問DLL中的函數和過程,甚至一些老版本DLL中新添加的函數或過程;但動態方法難以完全掌握,使用時因為不同的函數或過程要定義很多很復雜的類型和調用方法。對於初學者,筆者建議您使用靜態方法,待熟練后再使用動態調用方法。


使用DLL的實用技巧 top 

一、編寫技巧 
  1 、為了保證DLL的正確性,可先編寫成普通的應用程序的一部分,調試無誤后再從主程序中分離出來,編譯成DLL。 

  2 、為了保證DLL的通用性,應該在自己編寫的DLL中杜絕出現可視化控件的名稱,如:Edit1.Text中的Edit1名稱;或者自定義非Windows定義的類型,如某種記錄。 

  3 、為便於調試,每個函數和過程應該盡可能短小精悍,並配合具體詳細的注釋。 

  4 、應多利用try-finally來處理可能出現的錯誤和異常,注意這時要引用SysUtils單元。 

  5 、盡可能少引用單元以減小DLL的大小,特別是不要引用可視化單元,如Dialogs單元。例如一般情況下,我們可以不引用Classes單元,這樣可使編譯后的DLL減小大約16Kb。 

二、調用技巧 
  1 、在用靜態方法時,可以給被調用的函數或過程更名。在前面提到的C++編寫的DLL例子中,如果去掉extern ”C”語句,C++會編譯出一些奇怪的函數名,原來的TestC函數會被命名為@TestC$s等等可笑的怪名字,這是由於C++采用了C++ name mangling技術。這個函數名在Delphi中是非法的,我們可以這樣解決這個問題: 
改寫引用函數為

function TestC(i:integer):integer;stdcall; 
external ’Cpp.dll’;name ’@TestC$s’;


其中name的作用就是重命名。 

  2 、可把我們編寫的DLL放到Windows目錄下或者Windows\system目錄下。這樣做可以在external語句中或LoadLibrary語句中不寫路徑而只寫DLL的名稱。但這樣做有些不妥,這兩個目錄下有大量重要的系統DLL,如果您編的DLL與它們重名的話其后果簡直不堪設想,況且您的編程技術還不至於達到將自己編寫的DLL放到系統目錄中的地步吧! 

三、調試技巧
  1 、我們知道DLL在編寫時是不能運行和單步調試的。有一個辦法可以,那就是在Run|parameters菜單中設置一個宿主程序。在Local頁的Host Application欄中添上宿主程序的名字就可進行單步調試、斷點觀察和運行了。 

  2 、添加DLL的版本信息。開場白中提到了版本信息對於DLL是很重要的,如果包含了版本信息,DLL的大小會增加2Kb。增加這么一點空間是值得的。很不幸我們如果直接使用Project|options菜單中Version選項是不行的,這一點Delphi的幫助文件中沒有提到,經筆者研究發現,只要加一行代碼就可以了。如下例:

library Delphi; 

uses 
SysUtils, 
Classes; 

{$R *.RES} 
//注意,上面這行代碼必須加在這個位置 

function TestDll(i:integer):integer;stdcall; 
begin 
Result:=i; 
end; 

exports 
TestDll; 

begin 
end.



  3 、為了避免與別的DLL重名,在給自己編寫的DLL起名字的時候最好采用字符數字和下划線混合的方式。如:jl_try16.dll。 

  4 、如果您原來在Delphi 1或Delphi 2中已經編譯了某些DLL的話,您原來編譯的DLL是16位的。只要將源代碼在新的Delphi 3或Delphi 4環境下重新編譯,就可以得到32位的DLL了。 

除了上面介紹的DLL最常用的使用方法外,DLL還可以用於做資源的載體。例如,在Windows中更改圖標就是使用的DLL中的資源。另外,熟練掌握了DLL的設計技術,對使用更為高級的OLE、COM以及ActiveX編程都有很多益處。 

 

http://www.cnblogs.com/dashan9zj/archive/2009/01/06/1370386.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM