Delphi中DLL的創建和使用


參考:http://blog.csdn.net/ninetowns2008/article/details/6311663

結合這篇博客:http://www.cnblogs.com/xumenger/p/4372289.html

再結合:http://blog.csdn.net/lailai186/article/details/8770487

 

1.DLL簡介;2.調用DLL;3.創建DLL;4.兩個技巧;5.初始化;6.例外處理

 

1.DLL簡介

  DLL是Dynamic-Link Libraries(動態鏈接庫)的縮寫,庫里面是一些可執行的模塊以及資源(如:位圖、圖標……)。可以認為DLL和EXE基本上是一回事,只是DLL不能直接執行,而必須通過應用程序或者其他DLL調用。

  DLL為應用程序間的資源共享提供了方便,同時也是多種語言混合編程的重要手段。由此可見學習使用DLL是Windows程序員必須掌握的一項重要技術

 

2.如何調用DLL

在Delphi中有兩種方法調用DLL中的函數和過程,即外部聲明或動態加載

  <1>外部聲明

  在Delphi中外部聲明時訪問外部例程最容易和最常用的方式,有兩種聲明方式:通過名字、通過索引號。舉例如下:在MYDLL.DLL中有兩個函數和一個過程,則其外部聲明可以寫成

function test1: Integer;  external 'mydll';  //或者external 'mydll.dll';
//直接通過名稱調用test1(注意名稱大小寫敏感)

function test11: Integer; external 'mydll' name 'test1';
//通過名稱調用test1,在程序中使用新名稱(原名稱仍然大小寫敏感)

procedure test2; external 'mydll' index 1;
//通過索引號調用TEST2。程序中可以使用與DLL中不一樣的名稱

  使用外部聲明的缺點是程序啟動時如果找不到mydll.dll將無法運行,即使沒有調用其中的模塊。動態加載的方法可以避免這種情況

  <2>動態加載

  通過調用Windows API中的相關函數,將DLL調入內存並獲得指向函數或過程的指針,執行完模塊后釋放內存。除了節約內存之外,這種方法的很大的優點是能處理找不到dll或者裝入過程中出錯的情況。這樣即使某個dll有問題,應用程序的其他部分仍然能夠正常運行。動態加載的例子如下

var hDll : THandle;
    Test1 : function : integer;
begin
    hDll := LoadLibrary('mydll.dll');  //注意LoadLibrary函數的參數是一個PChar類型的,不是string,該參數是指要加載的DLL的DLL名
    if hDll < 32 then
        exit;    //如果Dll無法記載則跳出
    @Test1 := GetProcAddress(hDll, MakeIntResource(1));  //取得mydll.dll中的第一個函數的地址。
    //取得mydll 中的第一個函數的地址
   
    ....
    FreeLibrary(hDll);
end;

  

3.用Delphi創建DLL

  用Delphi創建一個DLL是十分簡單的,首先需要新建一個DLL的Project(如果使用Delphi3.0則可以在File->New對話框中選擇DLL),當然也可以自己寫,現在這個Project是這樣的

library Project1;
uses SysUtils, Classes;
begin
end.

  當然這是一個空的DLL,現在讓我們來加入一個函數,讓它成為我們的第一個可以使用的DLL。完成后的文件是這樣的

library dll1;
uses SysUtils, Classes;

function Test1(a, b: Integer): Integer;
begin
    Result := a+b;
end;

exports
    Test1 index 1;

begin
end.

  在這個DLL里我們聲明了一個加法函數,然后用exports語句輸出它,只有被輸出的函數或過程才能被其他程序調用。exports語句的語法是

exports
    函數名 [index <n>];

  index<n>是為函數手工指定索引號,以便其他程序確定函數地址;也可以不指定,如果沒有使用index 關鍵字,Delphi將按照exports 后的順序從1開始自動分配索引號。現在我們可以調用這個DLL了,下面給出一個實例,運行后form1 的標題將變成 1+2=3

//聲明部分
function Test1(a, b: Integer): Integer; external 'dll1';    //注意此處是大小寫敏感的

//運行部分
form1.caption := '1+2=' + IntToStr(test1(1,2));

  

4.使用DLL的兩個技巧

  <1>把現有的項目改成DLL

  學會制作DLL之前,大多數程序員手中都積攢下來不少已經完成的項目,如果現在需要把這些項目做成DLL而不是可執行文件,重新寫一遍顯然是沒有必要的,只要按照下面的步驟對已有的項目文件進行修改就可以了

    (1)打開項目文件(.DPR),刪除單元底部 begin 和 end. 之間的所有語句(一般情況下這些語句是有Delphi 自動生成的)。如果項目中沒有用到Form,則從uses 子句中刪除表單單元(Form),然后轉向(2)

    (2)對項目進行修改,令除了 Main Form之外的所有Form 都是動態生成的,這樣我們只要在DLL 輸出的一個函數或過程中生成Main Form,即可調用執行整個項目。我們假設Main Form的名字是MyMainForm,項目的名字是MyDll,現在在單元底部的begin語句加入之前加入一個過程,過程的名字是RunMyDll,這個過程動態生成Main Form,從而運行整個項目。RunMyDll的寫法如下

procedure InitDll2;
begin
    Application.CreateForm(TMyMainForm, MyMainForm);
    MyMainForm.Show;    //如果MyMainForm不可視就不用加這一句
end;

    (3)如果想要輸出其他函數或者過程,而原來的項目中沒有,則可以在單元底部的begin語句之前加上這些代碼

    (4)在單元底部的begin 語句之前加上一個 exports小節,然后寫出所有想輸出的函數或過程的名字(最好指定索引號)。注意如果執行了第(2)補,一定要輸出 RunMyDll的過程

    (5)將項目文件頂部的保留字program改為library

    (6)編譯

    現在就可以在其他程序中調用本項目中的函數和過程了,只要執行 RunMyDll 就可以執行這個項目,和執行原來的可執行文件一模一樣

  <2>創建一個引入文件

  如果DLL比較復雜,則為它的聲明專門創建一個引入程序單元將是十分有意義的,並且會使這個DLL變得更加容易維護。引入單元的格式如下

unit MyInport;    {Import unit for MyDll.Dll}
interface
    procedure RunMyDll;
implementation
    procedure RunMyDll; external 'MyDll' index 1;
end.

  這樣以后想要使用MyDll的例程時,只要簡單的在程序模塊中的uses子句中加上 MyImport就可以了

 

5.DLL的初始化和善后工作

一般的DLL不需要做初始化和善后工作。但是如果你想讓你的DLL在被載入時先設定一些初始設定,或者退出時釋放資源,則可以有三種方法達到目的

  <1>利用在 Unit 的Initialization 與 Finalization這兩個小節

    可以在Unit的這兩個小節里安排Unit 的進入和退出,但是 Program 與 Library並沒有這兩個部分,所以只能寫在Unit里面

  <2>利用 ExitProc 變量

    在Library 的begin .. end.中間是可以寫代碼的,這里可以放置DLL初始化代碼。如果想要做善后工作,則可以利用ExitProc 變量。我們首先在初始化代碼中把 ExitProc中包含的默認的善后過程地址保存下來,然后把自定義的過程的地址賦給他,這樣DLL退出時就會執行我們制定的程序;在自定義的過程的最后,把ExitProc恢復原來的默認值,以便DLL 能股繼續完成原來默認的善后工作。下面是示例

library MyDLL;
...
OldExitProc : pointer;
...
procedure MyExitProc;
begin
...//善后程序
ExitProc := OldExitProc;
end;
...
begin
...//初始化程序
OldExitProc := ExitProc;
ExitProc := @MyExitProc;
end.

     以上的代碼同樣是關於Delphi的指針和函數指針的一個很好的應用的例子,值得研究一下

  <3>利用DllProc變量

    和ExitProc 一樣,DllProc也是一個在Systemd單元里預定義的變量。在使用DLLProc時,必須先寫好一個具有以下原型的程序:  騙人哦測讀熱 DLLHandler(Reason : Integer);

    並在Library 的 begin ... end.之間,將這個DLLHandle程序的執行地址賦值給DLLProc,這時候就可以根據參數Reason的值分別作出相應的處理。另外注意將 windows單元加入uses子句中。示例

library TestDLL;
...
procedure MyDLLHandler(Reason : Integer);
begn
    case Reason of
        DLL_Process_Attach;    //整個DLL的初始化代碼
        DLL_Process_Detach;    //整個DLL的善后程序
        DLL_Thread_Attach;    //當主叫端開始一個Thread時
        DLL_Thread_Detach;    //當主叫端終止一個Thread時
    end;
end;
...
begin
..    //初始化代碼
DLLProc := @MyDLLHandler;
MyDLLHandler(DLL_Process_Attach);
end;

     由上例可知,當DLL支持多進程的處理是,DLLProc非常適合使用

 

6.DLL中的例外處理

  在用Delphi制作DLL的時候,在例外處理方面請注意以下三點

    <1>如果uses子句中沒有SysUtils的話,無法使用例外處理

    <2>如果DLL中沒有對例外進行處理的話,這個例外會向外傳導到主叫端的應用程序。如果該應用程序也是Delphi寫的話,這個例外可以由主叫端進行處理

    <3>承上,如果主叫端的程序不是Delphi 或Borland C++ Builder,則例外以作業系統錯誤的形式來處理,例外編號是$0EEDFACE,ExceptionInformation中地第一個進入點是例外發生的地址,第二個進入點是指向Delphi 例外物件的引用


免責聲明!

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



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