程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> Delphi中的包(二):關於bpl

Delphi中的包(二):關於bpl

編輯:Delphi

寫自己的dpk工程,以更改地檢測我們的猜想。我們首先建立一個project group,包含三個工程:

program ProjectEXE;
uses
Forms,
Windows,
UnitFormMain in 'UnitFormMain.pas' {FormMain};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TFormMain, FormMain);
Application.Run;
end.
unit UnitFormMain;
interface
uses
Windows, StdCtrls, Forms, Classes, Controls;
type
TFormMain = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
FormMain: TFormMain;
implementation
{$R *.dfm}
procedure TFormMain.Button1Click(Sender: TObject);
var
LForm:TForm2;
begin
  LForm:=TForm2.Create(Application);
LForm.ShowModal;
LForm.Free;
end;
end.
package Package1;
requires
vcl,
rtl;
contains
UnitFormAnother in 'UnitFormAnother.pas' {FormAnother},
UnitForm1 in 'UnitForm1.pas' {Form1};
end.
unit UnitFormAnother;
interface
uses
Forms;
type
TFormAnother = class(TForm)
private
{ Private declarations }
public
{ Public declarations }
end;
implementation
{$R *.dfm}
end.
unit UnitForm1;
interface
uses
UnitFormAnother;
type
TForm1 = class(TFormAnother)
private
{ Private declarations }
public
{ Public declarations }
end;
implementation
{$R *.dfm}
end.
package Package2;
requires
rtl,
vcl;
contains
UnitForm2 in 'UnitForm2.pas' {Form2};
end.
unit UnitForm2;
interface
uses
UnitFormAnother;
type
TForm2 = class(TFormAnother)
private
{ Private declarations }
public
{ Public declarations }
end;
implementation
{$R *.dfm}
end.

小技巧:delphi對project group的編譯是按照列表順序從上到下進行的,因 此在有些時候,被require或者use的文件如果在下面,那麼可能會提示找不到文 件。因此最好用文本編輯器調整一下bpg文件中的列表順序。

現在我們看到,package工程的入口dpr文件結構中沒有uses子句,但是取而 代之的是contains子句。從字面上說,這好像是指明這個包將會由哪些Unit組成 。這些Unit再去use別的unit,這樣就又形成了一張有向圖。是這樣的嗎?我們 將Package1的contain部分改成

contains

UnitForm1 in 'UnitForm1.pas' {Form1};

這樣僅包含UnitForm1。而UnitForm1中因為存在繼承關系,必然要use UnitFormAnother。於是自然package1中必須包含三個Unit:Package1.dpk、 UnitFormAnother.pas、UnitForm1.pas。然後編譯,結果報警說:隱式地引入了 UnitFormAnother。先不管這個警告,然後改exe工程:把FormMain的 button1Click改成

procedure TFormMain.Button1Click(Sender: TObject);
var
LForm:TForm1;
begin
LForm:=TForm1.Create(Application);
LForm.ShowModal;
LForm.Free;
end;

當然,還要在FormMain的Uses裡面加上UnitForm1,然後修改runtime package列表,加上package1。然後編譯,調試,檢查Module情況。結果發現 ProjectExe裡面包含FormMain,而Package1.pbl裡面包含我們所推測的三個Unit 。另一個試驗是,如果在編譯exe的時候,去掉列表中的package1,並且恰好能 讓編譯器找到FormAnother和Form1(源文件也好,dcu也好),也可以成功編譯 。但是此時三個Form都跑到exe中間去了。

類似地,驗證package2,發現:package2也可以編譯過,前提是它能夠找到 FormAnother,此時package2中包含兩個Form;如果把package2的require部分改 成只依賴package1,那麼最終編譯出來的package2中則只含Form2。如果兩個 package都包含FormAnother,而exe同時使用兩個package的話,那麼會產生編譯 錯誤。(是啊,兩個package同時加載一個類,當我要使用的時候,到底是誰提 供服務呢?)這種情況很容易發生,因為一方面FormAnother是Form1和Form2的 公共基類;另一方面,在Contain子句裡面很容易不小心漏掉FormAnother。所以 編譯器的提示還是很不錯的,寫程序還是按規矩辦事,把contain寫完整比較好 。

因此,現在基本可以得到結論:

由dpr文件的runtime library(或者dpk文件的requires子句)出發,再繼續 搜索這些bpl require的bpl,直到獲得所需的所有bpl文件。設這些bpl中包含的 Unit組成集合A。然後從dpr文件的uses子句(或dpk文件的contains子句)出發 ,生成工程所需Unit的集合B。則最後編譯目標僅包含B-A。

集合B中的Unit,如果存在於集合A中,則在連接時不需要對應的dcu文件,有 bpl和bpc就好了。而B-A部分,要麼必須有pas文件,要麼需要有dcu文件。

現在,編譯和連接的問題基本解決了,現在來研究加載。加載有兩種,一種 是自動的,由delphi控制;一種是手動的,在程序中寫LoadPackage。先來搞清 楚什麼情況下會自動加載library。

測試是這樣的,ProjectExe use UnitForm1, Package2 contains UnitForm2 requires package1,package1 contains UnitForm1和 UnitFormAnother。在ProjectExe的Package list裡面僅有package2。運行結果 是:加載的包有rtl、vcl和package1,package2並沒有出現。也就是說,自動裝 入內存的包是那些存在於A集合中,且跟B集合有交集的包。所有想要完全手工加 載包,還必須要注意一些問題,起碼它不能直接和間接地被require,包中的 Unit也不能在Use裡面出現。換句話說,調用者完全不知道被調用包的情況下才 能避免自動裝載。

既然調用者完全不知道被調用的包的信息,憑什麼去調用呢?Delphi裡面似 乎沒有頭文件之類的東西。怎麼獲取這個包的接口呢?

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved