Dephil之使用程序包(Using Packages)


應用程序編寫完后,可以用兩種方法展開(deploy)它(“展開”( Deploying)的含義是指把應用程序分發給用戶)。可將應用程序分發給公眾,或者分發給某個公司內的用戶。不論用何種方法,都需要知道哪些選項是可用的。從根本上講,有兩種選擇:靜態鏈接或動態鏈接使用程序包,下面將討論這些選項,以便編程人員作出適當的選擇來展開其應用程序。下面先講講選項。

什么是程序包(What's a Package?)

在討論選項之前,先給出程序包的定義。

一個程序包(package)就是一段編譯過的代碼,駐留在BPL擴展名的文件中。

這個解釋可能還是讓人不好明白,下面來進一步講解。移去外表包裝,程序包實質上就是帶bpl擴展名的DLL(這樣講可能有點過,但在這里還是很貼切的)。Delphi中有兩種類型的程序包:運行階段(runtime)程序包和設計階段(design)程序包。下面分別講述這兩種類型的程序包,以便大家理解程序包是如何工作的。

1、 運行階段程序包(Runtime Packages)

運行階段程序包包含應用程序需要運行的代碼。雖然Delphi提供了眾多不同的程序包,但最主要的程序包是VCL70.BPL,這個程序包包含了全部的基礎VCL代碼。如果要在應用程序中使用程序包,就要裝入VCL70.BPL程序包並根據需要從中調用例程。如果應用程序是數據庫應用程序,同樣也要裝入VCLDB70.BPL,並按需要從中調用例程。除這里提到的兩個程序包外,還有其他的Delphi程序包。

除VCL程序包外,應用程序可能要用到其他程序包,當使用第三方組件或任何自己編寫的組件時,就會出現這種情況。必須查看第三方組件的文檔,搞清楚應用程序需要運行哪些程序包。下面先介紹設計階段程序包,然后回過頭來展開使用程序包的應用程序。

2、 設計階段程序包(Design Packages)

大多數的Delphi組件都包含一個運行階段程序包和一個設計階段程序包。運行階段程序包包含組件要運行的全部代碼;設計階段程序包包含組件在設計時要在窗體上運行的代碼,包括屬性編輯器和組件編輯器。

設計階段程序包有一個Requires列表,用以通知Delphi要運行哪些程序包。設計階段程序包總是要用運行時程序包中的代碼,還可能需要一個或多個VCL程序包中的代碼。一個程序包可以包含多個組件的代碼,運行階段程序包與設計階段程序包都是如此,沒有必要一個組件對應一個單獨的程序包。

由於設計階段程序包只包含在設計時顯示組件所需的代碼,所以它通常比相應的運行階段程序包要小很多。Delphi僅僅在設計時使用設計階段程序包,應用程序不使用設計階段程序包。

靜態鏈接與動態鏈接(Static Linking Versus Dynamic Linking)

上面,已經對程序包有了一些基本的了解,下面開始學靜態鏈接和動態鏈接。

1、 靜態鏈接(Static Linking)

當應用程序使用VCL靜態鏈接時,它不再需要使用程序包;應用程序要運行的全部代碼都直接鏈接到應用程序的可執行文件中,它是一個獨立的程序,不需要任何的支持文件(程序包或DLLs)。

Note

任何規則都有例外,靜態鏈接應用程序不需要任何DLLs支持的二個前提條件:

  1. 假定應用程序不是數據庫應用程序。Delphi數據庫應用程序運行時需要Borland Database Engine(BDE),BDE主要是由DLLs組成的集合,因此該應用程序是靜態鏈接,也是需要使用DLLs的。
  2. 假定應用程序不使用任何的ActiveX控件。實際上ActiveX控件是DLL的一種形式,因此,當應用程序使用ActiveX控件時,它就不再是一個獨立的應用程序。

Delphi提供了鏈接選項,可對其進行選擇。靜態鏈接是缺省選擇,與動態鏈接相比,靜態鏈接有兩條主要優點:

  1. 編程人員不需要操心附件文件的安裝,應用程序包含了全部要運行的代碼,不需要運行時程序庫的支持。
  2. 靜態鏈接的應用程序一般總比需要程序包的應用程序要小。在講動態鏈接的優點和缺點時還要談到這一點。

靜態鏈接有一個重要缺陷,但它只在使用到很多用戶定義的DLLs的應用給程序中顯露出來。這一缺陷是:在每個模塊(主應用程序本身)和每個DLL中,VCL和RTL代碼是重復的,這意味着代碼中有不必要的重復。

例如,假設每個模塊至少要200KB的VCL基本代碼和RTL代碼,並假定一個主應用程序要求10個支持它的DLLs(動態鏈接庫)。這意味着當實際只用200KB的代碼時,卻要使用2200KB的代碼(11個模塊x 200KB)。應用程序和DLLs都是靜態鏈接,在它們之間不能共享VCL和RTL代碼。

2、 動態鏈接(Dynamic Linking)

動態鏈接,是指應用程序在運行階段動態地裝入它要用的程序庫代碼。對於Delphi應用程序,這意味着任何需要的程序包都是在運行階段裝入。需要的程序包中肯定會包括一個或多個VCL程序包,並且可能還要用第三方程序包。

Note

應用程序裝入程序包是自動進行的,不必編寫代碼來裝入程序包,Delphi負責程序包裝入的工作。在靜態鏈接的基礎上選擇動態鏈接不需要對代碼做任何修改,只需要改變一下分發應用程序的方式。這一點在后面很快就會講到。

動態鏈接相對於靜態鏈接有一個主要優點:多個模塊可共享代碼。還記得前面舉的“一個應用程序與10個支持它的DLLs”的例子么?使用動態鏈接,應用程序和它所有的DLLs可共享來自VCL程序包中的全部代碼。每個模塊至少可以減少200KB,因為所有的基本代碼都包含在運行階段DLLs中。當大型軟件產品包含多個應用程序或許多DLLs時,這一優點就更加明顯。

動態鏈接也存在兩個問題。第一個問題是需要與應用程序一起傳送的程序包和DLLs可能非常大,光一個主要的VCL程序包VCL70.BPL就要1.3MB。除基本VCL程序包外,應用程序可能還需要用到其他的程序包,這意味應用程序至少需要1.3MB的DLLs才可以運行。第二個問題是動態鏈接更加難以捉摸、更麻煩,這個問題可以歸結成“版本問題”。為了講清楚這個問題可以打個比方。假定有兩個版本的Delphi,用Delphi7.02創建了一個應用程序,並選擇動態鏈接,這就要求傳送VCL程序包和RTL DLL,客戶在他的機器上安裝上這個應用程序后一切工作正常。與此同時,可用Delphi4.0創建一個應用程序,也采用動態鏈接。客戶購買了該應用程序並安裝它。這個安裝程序是家庭制作的,不那么正規,它會覆蓋原有的應用程序安裝的程序包和DLLs。由於用Delphi4.0創建的程序包版本比另一種的低,兩者不兼容,應用程序會突然退出運行。是否看出問題所在?

現實中,諸如Inprise的商用軟件公司是這樣解決這一個問題的:對一個軟件的不同版本,用不同的文件名來命名其程序包和DLLs,並將版本信息嵌入到程序包和DLLs中(一個好的安裝程序會自動檢查版本號,並且只安裝版本比系統中已存在的程序包版本高的程序包)。Borland公司的程序包不會出問題。

如果使用的組件出自一家不負責任的公司,那就很可能出問題。隨着Internet的迅速發展,組件的來源范圍非常廣,更要重視這個問題。在很多情況下,無法預料會出什么亂子,所以在購買便宜組件或使用免費組件時要特別小心。

3、 到底哪個好?(So Which Is Better?)

大家可能會問:應該用靜態鏈接還是動態鏈接?這個問題的答案取決於所編寫的應用程序的類型。一般來說,如果編寫小規模或中等規模的應用程序,應該用靜態鏈接;如果編寫大規模的應用給程序或用到很多DLLs的應用給程序,則應該用動態鏈接。

考察一個簡單例子可能會使這個問題更直觀些。前面我們創建了程序ScratchPad,使用靜態鏈接,該程序編譯后是427KB左右;如果使用動態鏈接,則EXE文件大小可降至22KB左右,但必須傳送1.3MB的程序包。在這種情況下,動態鏈接不是一個好的選擇。

在應用程序中使用運行階段程序包(Using Runtime Packages in Your Applications)

如果選擇使用動態鏈接,則只需修改工程選項中的一個設置。請按以下步驟操作:

(1)從主菜單上選【Project | Options】菜單項,彈出“Project Options”對話框;

(2)點擊“Project Options”對話框中的Packages頁面,並選中位於對於對話框底部的“Build with runtime package”選項;

0254

(3)點擊OK關閉“Project Options”對話框;

(4)重建(Rebuilt)該程序;

這就是全部要做的事情。切記:使用動態鏈接,不需要對代碼作任何修改。

分發使用程序包的應用程序(Deploying Applications Using Packages)

要分發采用動態鏈接的應用程序,必須知道應用程序使用了哪些程序包。如果按照上一步的步驟,則可以肯定知道需要VCL70.BPL,可能還需要其他的VCL程序包,這取決於應用程序中使用的組件。

要照抄應用程序中用到的程序包,必須運行諸如TDUMP.EXE的工具並檢查EXE引用的入口;TDUMP在Delphi安裝目錄的Bin目錄下,要運行TDUMP,只需要打開命令提示符並轉到應用程序所在目錄,然后在命令行輸入以下命令:

tdump scratchPad.exe

TDUMP立即以滾屏方式顯示出信息,可按Pause鍵暫停以便查看顯示信息。當然滾屏可能太快,可將TDUMP的輸出定向到一個文本文件,這樣查看文本文件即可。例如:

tdump scratchPad.exe > dump.txt

然后可在Code Editor中打開dump.txt文件查看其中的內容。

在TDUMP生成的文件中能看到類似下面的內容:

Section:             Import
  ImportLookUpTblRVA:00000000
  Time Stamp:        00000000
  Forwarder Chain:   00000000 (index of first forwarder reference)

Imports from rtl70.bpl
                  __fastcall System::initialization()
                  __fastcall System::Finalization()
                  __fastcall System::RegisterModule(System::TLibModule *)
                  System::__linkproc__ __fastcall LStrAsg(void *, const void *)
                  System::__linkproc__ __fastcall LStrArrayClr(void *, int)
                  System::__linkproc__ __fastcall LStrClr(void *)
                  System::__linkproc__ __fastcall Halt0()
                  System::__linkproc__ __fastcall StartExe(System::PackageInfoTable *, System::TLibModule *)
                  System::__linkproc__ __fastcall HandleFinally()
                  __fastcall System::TObject::Dispatch(void *)
                  __fastcall System::TObject::FreeInstance()
                  __fastcall System::TObject::NewInstance(System::TMetaClass *)

Imports from kernel32.dll
                  GetModuleHandleA

Imports from vcl70.bpl
                  __fastcall Forms::initialization()
                  __fastcall Forms::Finalization()
                  __fastcall Forms::TApplication::MessageBox(const char *, const char *, int)
                  __fastcall Forms::TApplication::Run()
                  __fastcall Forms::TApplication::CreateForm(System::TMetaClass *, void *)
                  __fastcall Forms::TApplication::Initialize()
                  __fastcall Forms::TApplication::SetTitle(const System::AnsiString)
                  __stdcall Forms::TCustomForm::QueryInterface(const _GUID&, void *)
                  __fastcall Forms::TCustomForm::UpdateActions()
                  __fastcall Forms::TCustomForm::ShowModal()
                  __fastcall Forms::TCustomForm::SetFocus()
                  __fastcall Forms::TCustomForm::CloseQuery()

從這里面找出所有帶.bpl擴展名的文件並記錄下它們的文件名。記錄下的文件名就是那些必須與應用程序一起分發的程序包。

Note

擁有一個好的安裝程序可以節省很多時間並省去許多麻煩,Delphi7專業版和企業版中帶有InstallShield Express打包程序,Wise Install打包程序也不錯。好的安裝程序能指示出應用程序所需的程序包,並自動將它們包括進去。不建議在任何環境下都自己編寫安裝程序,因為編寫安裝程序要考慮的問題太多,很容易因考慮不周而出問題。

大多數時候不需要在應用程序中使用運行階段程序包,但有時候卻又非使用程序包不可。


免責聲明!

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



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