程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> C語言基礎知識 >> Windows的動態鏈接庫原理及使用1

Windows的動態鏈接庫原理及使用1

編輯:C語言基礎知識
  1.Windows的動態鏈接庫原理
  
     動態鏈接庫(DLLs)是從C語言函數庫和Pascal庫單元的概念發展而來的。所有的C語言標准庫函數都存放在某一函數庫中,同時用戶也可以用LIB程序創建自己的函數庫。在鏈接應用程序的過程中,鏈接器從庫文件中拷貝程序調用的函數代碼,並把這些函數代碼添加到可執行文件中。這
   種方法同只把函數儲存在已編譯的.OBJ文件中相比更有利於代碼的重用。
     但隨著Windows這樣的多任務環境的出現,函數庫的方法顯得過於累贅。假如為了完成屏幕輸出、消息處理、內存治理、對話框等操作,每個程序都不得不擁有自己的函數,那麼Windows程序將變得非常龐大。Windows的發展要求答應同時運行的幾個程序共享一組函數的單一拷貝。動態
   鏈接庫就是在這種情況下出現的。動態鏈接庫不用重復編譯或鏈接,一旦裝入內存,Dlls函數可以被系統中的任何正在運行的應用程序軟件所使用,而不必再將DLLs函數的另一拷貝裝入內存。
  
   1.1 動態鏈接庫的工作原理
  
     "動態鏈接"這幾字指明了DLLs是如何工作的。對於常規的函數庫,鏈接器從中拷貝它需要的所有庫函數,並把確切的函數地址傳送給調用這些函數的程序。而對於DLLs,函數儲存在一個獨立的動態鏈接庫文件中。在創建Windows程序時,鏈接過程並不把DLLs文件鏈接到程序上。直到程
   序運行並調用一個DLLs中的函數時,該程序才要求這個函數的地址。此時Windows才在DLLs中尋找被調用函數,並把它的地址傳送給調用程序。采用這種方法,DLLs達到了復用代碼的極限。
     動態鏈接庫的另一個方便之處是對動態鏈接庫中函數的修改可以自動傳播到所有調用它的程序中,而不必對程序作任何改動或處理。
     DLLs不僅提供了函數重用的機制,而且提供了數據共享的機制。任何應用程序都可以共享由裝入內存的DLLs治理的內存資源塊。只包含共享數據的DLLs稱為資源文件。如Windows的字體文件等。
  
   1.2  Windows系統的動態鏈接庫
  
     Windows本身就是由大量的動態鏈接庫支持的。這包括Windows API函數 ( KRNLx86.EXE,USER.EXE,GDI.EXE,…),各種驅動程序文件,各種帶有.Fon和.Fot  
   擴展名的字體資源文件等。Windows還提供了針對某一功能的專用DLLs,如進行DDE編程的ddeml.dll,進行程序安裝的ver.dll等。
     雖然在編寫Windows程序時必然要涉及到DLLs,但利用Delphi ,用戶在大部分時候並不會注重到這一點。這一方面是因為Delphi提供了豐富的函數使用戶不必直接去使用Windows API;另一方面即使使用Windows API,由於Delphi把API函數和其它Windows  
   DLLs函數重新組織到了幾個庫單元中,因而也不必使用非凡的調用格式。所以本章的重點放在編寫和調用用戶自定義的DLLs上。
     使用傳統的Windows編程方法來創建和使用一個DLLs是一件很令人頭痛的事,正如傳統的Windows編程方法本身就令人生畏一樣。用戶需要對定義文件、工程文件進行一系列的修改以適應創建和使用DLLs的需要。Delphi的出現,在這一方面,正如在其它許多方面所做的那樣,減輕了開發
   者的負擔。更令人興奮的是Delphi利用DLLs 實現了窗體的重用機制。用戶可以將自己設計好的窗體儲存在一個DLLs中,在需要的時候可隨時調用它。
  
   2  DLLs的編寫和調用
  
   2.1 DLLs的編寫
  
     在Delphi環境中,編寫一個DLLs同編寫一個一般的應用程序並沒有太大的區別。事實上作為DLLs 主體的DLL函數的編寫,除了在內存、資源的治理上有所不同外,並不需要其它非凡的手段。真正的區別在工程文件上。
     在絕大多數情況下,用戶幾乎意識不到工程文件的存在,因為它一般不顯示在屏幕上。假如想查看工程文件,則可以打開View菜單選擇Project Source項,此時工程文件的代碼就會出現在屏幕的Code Editor(代碼編輯器)中。
     一般工程文件的格式為:
  
     program    工程標題;
     uses   子句;
     程序體
  
     而DLLs工程文件的格式為:
  
     library    工程標題;
     uses       子句;
     eXProts    子句;
     程序體
  
     它們主要的區別有兩點:
     1.一般工程文件的頭標用program要害字,而DLLs工程文件頭標用library 要害字。不同的要害字通知編譯器生成不同的可執行文件。用program要害字生成的是.exe文件,而用library要害字生成的是.dll文件;
  
     2.假如DLLs要輸出供其它應用程序使用的函數或過程,則必須將這些函數或過程列在exports子句中。而這些函數或過程本身必須用export編譯指令進行編譯。
     根據DLLs完成的功能,我們把DLLs分為如下的三類:
       1.完成一般功能的DLLs;
       2.用於數據交換的DLLs;
       3.用於窗體重用的DLLs。
     這一節我們只討論完成一般功能的DLLs,其它內容將在後邊的兩節中討論。
  
   2.1.1 編寫一般DLLs的步驟
  
     編寫一般DLLs的步驟如下:
     1.利用Delphi的應用程序模板,建立一個DLLs程序框架。
     對於Delphi 1.0的用戶,由於沒有DLLs模板,因此:
     (1).建立一個一般的應用程序,並打開工程文件;
     (2).移去窗體和相應的代碼單元;
     (3).在工程文件中,把program改成library,移去Uses子句中的Forms,並添加適當的庫單元(一般SysUtils、Classes是需要的),刪去begin...end之間的所有代碼。
     2.以適當的文件名保持文件,此時library後跟的庫名自動修改;
     3.輸入過程、函數代碼。假如過程、函數預備供其它應用程序調用,則在過程、函數頭後加上export 編譯指示;
     4.建立exports子句,包含供其它應用程序調用的函數和過程名。可以利用標准指示 name 、Index、resident以方便和加速過程/函數的調用;
     5.輸入庫初始化代碼。這一步是可選的;
     6.編譯程序,生成動態鏈接庫文件。
  
   2.1.2        動態鏈接庫中的標准指示
  
     在動態鏈接庫的輸出部分,用到了三個標准指示:name、Index、resident。
     1.name
     name後面接一個字符串常量,作為該過程或函數的輸出名。如:
  
           exports
                   InStr name MyInstr;
  
     其它應用程序將用新名字(MyInstr)調用該過程或函數。假如仍利用原來的名字(InStr),則在程序執行到引用點時會引發一個系統錯誤。
     2.Index
     Index指示為過程或函數分配一個順序號。假如不使用Index指示,則由編譯器按順序進行分配。
     Index後所接數字的范圍為1...32767。使用Index可以加速調用過程。
     3.resident
     使用resident,則當DLLs裝入時特定的輸出信息始終保持在內存中。這樣當其它應用程序調用該過程時,可以比利用名字掃描DLL入口降低時間開銷。
     對於那些其它應用程序經常要調用的過程或函數,使用resident指示是合適的。例如:
  
           exports
                   InStr name MyInStr resident;
  
   2.1.3  DLLs中的變量和段
  
       一個DLLs擁有自己的數據段(DS),因而它聲明的任何變量都為自己所私有。調用它的模塊不能直接使用它定義的變量。要使用必須通過過程或函數界面才能完成。而對DLLs來說,它永遠都沒有機會使用調用它的模塊中聲明的變量。
     一個DLLs沒有自己的堆棧段(SS),它使用調用它的應用程序的堆棧。因此在DLL中的過程、函數絕對不要假定DS = SS。一些語言在小模式編譯下有這種假設,但使用Delphi可以避免這種情況。Delphi絕不會產生假定DS =  
   SS的代碼,Delphi的任何運行時間庫過程/函數也都不作這種假定。需注重的是假如讀者想嵌入匯編語言代碼,絕不要使SS和DS登錄同一個值。
  
   2.1.4        DLLs中的運行時間錯和處理
  
     由於DLLs無法控制應用程序的運行,導致很難進行異常處理,因此編寫DLLs時要十分小心,以確保被調用時能正常執行  
   。當DLLs中發生一個運行時間錯時,相應DLLs並不一定從內存中移去(因為此時其它應用程序可能正在用它),而調用DLLs的程序異常中止。這樣造成的問題是當DLLs已被修改,重新進行調用時,內存中保留的仍然可能是以前的版本,修改後的程序並沒有得到驗證。對於這個問題,有以下
  
   兩種解決方法:
     1.在程序的異常處理部分顯式將DLL卸出內存;
     2.完全退出Windows,而後重新啟動,運行相應的程序。
     同一般的應用程序相比,DLL中運行時間錯的處理是很困難的,而造成的後果也更為嚴重。因此要求程序設計者在編寫代碼時要有充分、周到的考慮。
  
   2.1.5        庫初
  
 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved