日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Delphi中DLL的創(chuàng)建和使用

 老魏的書架 2012-08-03

Delphi中DLL的創(chuàng)建和使用

分類: Delphi 92人閱讀 評(píng)論(0) 收藏 舉報(bào)

Delphi中DLL的創(chuàng)建和使用   
  1.DLL簡(jiǎn)介;   2.調(diào)用DLL;   3.創(chuàng)建DLL;   4.兩個(gè)技巧;   5.初始化;   6.例外處理。     
    
   1、DLL簡(jiǎn)介  
    DLL是Dynamic-Link   Libraries(動(dòng)態(tài)鏈接庫(kù))的縮寫,庫(kù)里面是一些可執(zhí)行的模塊以及資源(如位圖、圖標(biāo)等)??梢哉J(rèn)為DLL和EXE基本上是一回事,只是DLL不能直接執(zhí)行,而必須由應(yīng)用程序或者其他DLL調(diào)用。DLL為應(yīng)用程序間的資源共享提供了方便,同時(shí)也是多語(yǔ)言混合編程的重要手段。由此可見學(xué)習(xí)使用DLL是Windows程序員必須掌握的一項(xiàng)重要技術(shù)。   
  
  2、如何調(diào)用DLL  
    在Delphi中有兩種方法調(diào)用DLL中的函數(shù)和過程,即外部聲明或者動(dòng)態(tài)加載。  
   
  <1>外部聲明  
    在Delphi中外部聲明是訪問外部例程最容易和最常用的方式,有兩種聲明方式:通過名字、通過索引號(hào)。舉例如下:在MYDLL.DLL中有兩個(gè)函數(shù)和一個(gè)過程,則其外部聲明可以寫成:  
   
  function   test1:integer;external   'mydll';  
  //直接通過名稱調(diào)用test1(注意名稱大小寫敏感)。    
  function   test11:integer;external   'mydll'   name   'test1';  
  //通過名稱調(diào)用test1,在程序中使用新名稱(原名稱仍然大小寫敏感)。    
  procedure   test2;external   'mydll'   index   1;  
  //通過索引號(hào)調(diào)用TEST2。程序中可以用與DLL中不一樣的名稱.    
    使用外部聲明的缺點(diǎn)是程序啟動(dòng)時(shí)如果找不到mydll.dll將無法運(yùn)行,即使沒有調(diào)用其中的模塊。   動(dòng)態(tài)加載的方法可以避免這種情況。  
   
  <2>動(dòng)態(tài)加載  
    通過調(diào)用Windows   API中的相關(guān)函數(shù),將DLL調(diào)入內(nèi)存并獲得指向函數(shù)或過程的指針,執(zhí)行完模塊后釋放內(nèi)存。除了節(jié)約內(nèi)存外,這種方法的一個(gè)很大的優(yōu)點(diǎn)是能處理找不到dll或者在裝入過程中出錯(cuò)的情況。這樣即使某個(gè)dll有問題,應(yīng)用程序的其他部分仍然能夠正常運(yùn)行。動(dòng)態(tài)加載的例子如下:  
   
  var   hDll:THandle;  
    Test1:function:integer;  
  begin  
    hDll:=LoadLibrary('mydll.dll');  
    if   hDll<32   then   exit;//如果Dll無法加載則跳出  
    @Test1:=GetProcAddress(hDll,MakeIntResource(1));  
      //取得mydll中的第一個(gè)函數(shù)的地址。  
    ...  
    FreeLibrary(hDll);  
  end;     
    
  3、用Delphi創(chuàng)建DLL  
    用Delphi創(chuàng)建一個(gè)DLL是十分簡(jiǎn)單的,首先需要新建一個(gè)DLL的Porject(如果使用Delphi3.0則可以在File->New對(duì)話框中選擇DLL),當(dāng)然也可以自己寫,現(xiàn)在這個(gè)Project是這樣的:  
   
  library   Project1;  
  uses   SysUtils,Classes;  
  begin  
  end.    
   
    當(dāng)然這是一個(gè)空DLL,現(xiàn)在讓我們來加入一個(gè)函數(shù),讓他成為我們的第一個(gè)可以使用的DLL。完成后的文件是這樣的:  
   
  library   dll1;  
  uses   SysUtils,Classes;  
   
  function   Test1(a,b:integer):integer;  
  begin  
  Result:=a+b;  
  end;  
   
  exports  
  Test1   index   1;  
   
  begin  
  end.    
   
    在這個(gè)DLL里我們聲明了一個(gè)加法函數(shù),然后用exports語(yǔ)句輸出它,只有被輸出的函數(shù)或過程能被其他程序調(diào)用。exports語(yǔ)句后的語(yǔ)法是:函數(shù)名   [index   <n>],index   <n>是為函數(shù)手工指定索引號(hào),以便其他程序確定函數(shù)地址;也可以不指定,如果沒有使用Index關(guān)鍵字,Delphi將按照exports后的順序從1開始自動(dòng)分配索引號(hào)。現(xiàn)在我們可以調(diào)用這個(gè)DLL了,下面給出一個(gè)實(shí)例,運(yùn)行后form1的標(biāo)題將變成“1+2=3”:  
   
  聲明部分:function   Test1(a,b:integer):integer;external   'dll1';  
         注意此處是大小寫敏感的。  
  運(yùn)行部分:form1.caption:='1+2='+inttostr(test1(1,2));     
      
  4、使用DLL的兩個(gè)技巧  
  <1>把現(xiàn)有的項(xiàng)目改成DLL  
    學(xué)會(huì)制作DLL以前,大多數(shù)程序員手中都積攢下來不少已經(jīng)完成了的項(xiàng)目,如果現(xiàn)在需要把這些項(xiàng)目做成DLL而不是可執(zhí)行文件,重新寫一遍顯然是沒有必要的,只要按照下面的步驟對(duì)已有的項(xiàng)目文件進(jìn)行修改就可以了:  
   ?、佟〈蜷_項(xiàng)目文件(.DPR),刪除單元底部begin和end.之間的所有語(yǔ)句(一般情況下這些語(yǔ)句是由Delphi自動(dòng)生成的)。如果項(xiàng)目中沒有用到Form,則從uses子句中刪除表單單元(Form),然后轉(zhuǎn)到第③步。  
    ② 對(duì)項(xiàng)目進(jìn)行修改,令除Main   Form之外的所有Form都是動(dòng)態(tài)生成的,這樣我們只要在DLL輸出的一個(gè)函數(shù)或者過程中生成Main   Form,即可調(diào)用執(zhí)行整個(gè)項(xiàng)目。我們假設(shè)Main   Form的名字是MyMainForm,項(xiàng)目的名字是MyDll,現(xiàn)在在單元底部的begin語(yǔ)句之前加入一個(gè)過程,過程的名字為RunMyDll,這個(gè)過程將動(dòng)態(tài)生成Main   Form,從而運(yùn)行整個(gè)項(xiàng)目。RunMyDll的寫法如下:  
      procedure   InitDll2;  
      begin  
      Application.CreateForm(TMyMainForm,   MyMainForm);  
      MyMainForm.Show;   //如果MyMainForm不可視則需要這一句.  
      end;  
   ?、邸∪绻胍敵銎渌瘮?shù)或者過程,而原來的項(xiàng)目中沒有,則可以在單元底部的begin語(yǔ)句之前加入這些代碼。  
    ④ 在單元底部的begin語(yǔ)句之前加入一個(gè)exports小節(jié),然后寫出所有想要輸出的函數(shù)或過程的名字(最好指定索引號(hào))。注意如果執(zhí)行了第②步,一定要輸出RunMyDll過程。  
   ?、荨㈨?xiàng)目文件頂部的保留字program改為library。  
   ?、蕖【幾g。  
    現(xiàn)在就可以在其他程序中調(diào)用本項(xiàng)目中的函數(shù)和過程了,只要執(zhí)行RunMyDll就可以執(zhí)行這個(gè)項(xiàng)目,和執(zhí)行原來的可執(zhí)行文件一模一樣。  
   
  <2>創(chuàng)建一個(gè)引入文件  
    如果DLL比較復(fù)雜,則為它的聲明專門創(chuàng)建一個(gè)引入程序單元將是十分有意義的,并且會(huì)使這個(gè)DLL變得更加容易維護(hù)。引入單元的格式如下:  
    unit   MyImport;   {Import   unit   for   MyDll.Dll}  
    interface  
    procedure   RunMyDll;  
    implementation  
    procedure   RunMyDll;external   'MyDll'   index   1;  
    end.  
  這樣以后想要使用MyDll中的例程時(shí),只要簡(jiǎn)單的在程序模塊中的uses子句中加上MyImport即可。   
    
  5、DLL的初始化和善后工作  
    一般的DLL不需要做初始化和善后工作,因此大部分讀者可以跳過這一節(jié)。但如果你想讓你的DLL在被載入時(shí)先作一些初始設(shè)定,或者退出時(shí)釋放資源,則可以有三種方法達(dá)到目的:  
   
  <1>利用Unit的Initalization與Finalization這兩個(gè)小節(jié)  
    可以在Unit的這兩個(gè)小節(jié)中安排Unit的進(jìn)入和退出,但是Program與Library并沒有這兩個(gè)部分,所以只能寫在Unit中。  
   
  <2>利用ExitProc變量  
    在Library的begin..end.中間是可以寫代碼的,這里可以放置DLL初始化代碼。如果想要做善后工作,則可以利用ExitProc變量。我們首先在初始化代碼中把ExitProc中包含的默認(rèn)的善后過程地址保存下來,然后把自定義的過程的地址賦給它,這樣DLL退出時(shí)就會(huì)執(zhí)行我們制定的程序;在自定義的過程的最后,把ExitProc恢復(fù)原來的默認(rèn)值,以便DLL能夠繼續(xù)完成原來默認(rèn)的善后工作。下面是示例:  
    library   MyDLL;  
    ...  
    OldExitProc:   pointer;  
    ...  
    procedure   MyExitProc;  
    begin  
    ...   //善后程序  
    ExitProc   :=   OldExitProc;  
    end;  
    ...  
    begin  
    ...   //初始化程序  
    OldExitProc   :=   ExitProc;  
    ExitProc   :=   @MyExitProc;  
    end.  
   
  <3>利用DllProc變量  
    和ExitProc一樣,DllProc也是一個(gè)在Systemd單元中預(yù)定義的變量。在使用DLLProc時(shí),   必須先寫好一個(gè)具有以下原型的程序:  
    procedure   DLLHandler(Reason:   integer);  
  并在library的begin..end.之間,   將這個(gè)DLLHandler程序的執(zhí)行地址賦給DLLProc中,   這時(shí)就可以根據(jù)參數(shù)Reason的值分別作出相應(yīng)的處理。另外注意要將Windows單元加入uses子句。示例如下:  
    library   TestDLL;  
    ...  
    procedure   MyDLLHandler(Reason:   integer);  
    begin  
     case   Reason   of  
      DLL_Process_Attach:   //整個(gè)DLL的初始化代碼  
      DLL_Process_Detach:   //整個(gè)DLL的善後程序  
      DLL_Thread_Attach:   //當(dāng)主叫端開始一個(gè)Thread時(shí)  
      DLL_Thread_Detach:   //當(dāng)主叫端終止一個(gè)Thread時(shí)  
     end;  
    end;  
    ...  
    begin  
    ...   //初始化代碼  
    DLLProc   :=   @MyDLLHandler;  
    MyDLLHandle(DLL_Process_Attach);  
    end.  
  由上例可以知道,當(dāng)DLL支援多進(jìn)程(Thread)的處理時(shí),   DllProc非常適合使用。   
    
  6、DLL中的例外處理  
    在用Delphi制作DLL時(shí),   在例外處理方面請(qǐng)留意以下三點(diǎn):    
   
  如果uses子句中沒有SysUtils話,無法使用例外處理。    
  如果DLL中沒有對(duì)例外進(jìn)行處理的話,這個(gè)例外會(huì)想完傳導(dǎo)到主叫端的應(yīng)用程序。如果該應(yīng)用程序也是Delphi寫的話,   這個(gè)例外可以由主叫端進(jìn)行處理。    
  承上,   如果主叫端的程式不是Delphi或Borland   C++   Builder,則例外以作業(yè)系統(tǒng)錯(cuò)誤的形式來處理,例外編號(hào)是$0EEDFACE,ExceptionInformation中第一個(gè)進(jìn)入點(diǎn)是例外發(fā)生的地址,第二個(gè)進(jìn)入點(diǎn)是指向的Delphi例外物件的引用。     
     
  {   Important   note   about   DLL   memory   management:   ShareMem   must   be   the  
      first   unit   in   your   library's   USES   clause   AND   your   project's   (select  
      Project-View   Source)   USES   clause   if   your   DLL   exports   any   procedures   or  
      functions   that   pass   strings   as   parameters   or   function   results.   This  
      applies   to   all   strings   passed   to   and   from   your   DLL--even   those   that  
      are   nested   in   records   and   classes.   ShareMem   is   the   interface   unit   to  
      the   BORLNDMM.DLL   shared   memory   manager,   which   must   be   deployed   along  
      with   your   DLL.   To   avoid   using   BORLNDMM.DLL,   pass   string   information  
      using   PChar   or   ShortString   parameters.   }  
   
  uses  
      SysUtils,  
      Classes,  
      Unit1   in   'Unit1.pas';  
      Exports  
      EnableMouseHook,   //只要把這兩個(gè)函數(shù)輸出就可以了,  
      DisableMouseHook;//不會(huì)不懂函數(shù)的意思吧^_^。  
   
  {$R   *.res}  
   
  begin  
  end.  
   
   
  unit1  
   
  unit   Unit1;  
   
  interface  
  Uses   Messages,Windows;  
   
  var  
  hHk:   HHOOK;//鉤子的句柄值。  
  function   MouseHookProc(nCode:   Integer;WParam:   WPARAM;LParam:   LPARAM):   LRESULT;stdcall;  
  //鼠標(biāo)鉤子的回調(diào)函數(shù),即是用它來處理得到消息后要干什么。這里我只是發(fā)送一個(gè)//WM_PASTE消息。  
  //nCode參數(shù)是Hook的標(biāo)志,一般只關(guān)心小于0時(shí)??聪旅娴脑敿?xì)說明  
  //WParam參數(shù)表示鼠標(biāo)消息的類型  
  //LParam參數(shù)是一個(gè)指向   TMOUSEHOOKSTRUCT   結(jié)構(gòu)的指針。結(jié)構(gòu)包含了鼠標(biāo)消息的狀態(tài),我只用了hwnd一個(gè)  
  //即鼠標(biāo)消息要傳遞給的窗口句柄。  
  //返回值如果不是0的話windows就把這個(gè)消息丟掉,其它的程序就不會(huì)再收到這個(gè)消息了。  
   
  function   EnableMouseHook:Boolean;   stdcall;   export;  
  function   DisableMouseHook:Boolean;   stdcall;   export;//兩個(gè)函數(shù)都是Boolean類型,成功都是返回True  
   
   
  implementation  
  function   MouseHookProc(nCode:   Integer;WParam:   WPARAM;LParam:   LPARAM):   LRESULT;stdcall;  
  var  
          MouseHookStruct:   ^TMOUSEHOOKSTRUCT;//這個(gè)結(jié)構(gòu)Delphi在Windows單元有定義,直接用就可以了。  
          nState:   SHORT;//得到鍵盤狀態(tài)的GetKeyState函數(shù)的返回值。這是一個(gè)16位的數(shù)。  
  begin  
          Result   :=   0;   //最好首先給他一個(gè)返回值,不然會(huì)有警告的!記住這可不是C語(yǔ)言。  
          //當(dāng)nCode小于0時(shí)表示還有其它的Hook,必須把參數(shù)傳給他。  
          //此時(shí)就要用Api函數(shù)CallNextHookEx讓他調(diào)用下一個(gè)Hook!!!當(dāng)然不用好像也可以。  
          if   nCode   <   0   then  
          Result   :=   CallNextHookEx(hHk,nCode,WParam,LParam)//參數(shù)是現(xiàn)成的,直接用就可以了,  
          //詳細(xì)的說明可以參考Win32   SDK  
          else   if   wParam   =   WM_LBUTTONDBLCLK   then   //判斷是不是鼠標(biāo)左鍵雙擊事件  
          begin  
          nState   :=   GetKeyState(VK_CONTROL);//這個(gè)函數(shù)只有一個(gè)參數(shù),就是要得到的鍵的  
          //鍵值,這里用windows的虛擬鍵值表示ctrl鍵。  
          if   (nState   and   $8000)   =   $8000   then//如果按下了,那么返回值的最高位為1  
          begin   //即是16進(jìn)制的8000,如果沒有按下就返回0  
          MouseHookStruct   :=   Pointer(LParam);//轉(zhuǎn)換指針并付值給MouseHookStruct變量。  
          SendMessage(MouseHookStruct.hwnd,WM_PASTE,0,0);//如果條件都滿足了就發(fā)送WM_PASTE(粘貼)消息  
          end;  
  end;  
   
  end;  
   
  function   EnableMouseHook:Boolean;   stdcall;   export;  
  begin  
          if   hHk   =   0   then   //為了安全,必須判斷一下再設(shè)置鉤子。  
          Begin    
          //   第三個(gè)參數(shù)的Hinstance   在Delphi中有定義,用就可以了。第四個(gè)參數(shù)必須為0  
          hHk   :=   SetWindowsHookEx(WH_MOUSE,@MouseHookProc,Hinstance,0);  
          Result   :=   True;  
          end  
          else  
          Result   :=   False;  
  end;  
   
  function   DisableMouseHook:Boolean;   stdcall;   export;  
  begin  
          if   hHk   <>   0   then   //如果有鉤子就卸掉他。  
          begin  
          UnHookWindowsHookEx(hHk);  
          hHk   :=   0;  
          Result   :=   True;  
          end  
          else  
          Result   :=   False;  
  end;  
   
   
  end. 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多