麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁(yè) > 編程 > Delphi > 正文

Delphi中的動(dòng)態(tài)包

2019-11-11 04:58:54
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

為什么要使用包?

答案很簡(jiǎn)單:因?yàn)榘墓δ軓?qiáng)大。設(shè)計(jì)期包(design-time package)簡(jiǎn)化了自定義組件的發(fā)布和安裝;而運(yùn)行期包(run-time package) 則更是給傳統(tǒng)的程序設(shè)計(jì)注入了新鮮的力量。一旦把可重用的代碼編譯為運(yùn)行期庫(kù)中,你就可以在多個(gè)應(yīng)用程序中共享它們。所有應(yīng)用程序都可以通過(guò)包訪問(wèn)標(biāo)準(zhǔn)組 件,Delphi自己就是這么干的。因?yàn)閼?yīng)用程序不必在可執(zhí)行文件中單獨(dú)復(fù)制一份組件庫(kù),這樣就大 大節(jié)省了系統(tǒng)資源和磁盤空間。此外,包還可以減少花費(fèi)在編譯上的時(shí)間,因?yàn)槟阒恍杈幾g應(yīng)用程序特有的代碼。

如果可以動(dòng)態(tài)的使用包,那么我們還可以獲得更多的好處。包提供了一種新穎的模塊化方法來(lái)開(kāi)發(fā)應(yīng)用程序。有些時(shí)候你也 許想把某些模塊作為應(yīng)用程序的可選部件,例如一個(gè)記帳系統(tǒng)附帶一個(gè)可選的HR模塊。某些情況下,你 只需安裝基本的應(yīng)用程序,而在另外一些情況下你就可能需要額外安裝HR模塊。這種模塊化的方法可以 通過(guò)包技術(shù)很容易的實(shí)現(xiàn)。在過(guò)去,這只能通過(guò)動(dòng)態(tài)裝載DLL實(shí)現(xiàn),但是使用Delphi的包技術(shù),你就可以把應(yīng)用程序的各個(gè)模塊類型分別打“包”成捆。特別是從包中創(chuàng)建的類對(duì)象則屬于應(yīng) 用程序所有,因此可以與應(yīng)用程序中的對(duì)象交互。

運(yùn)行期包與應(yīng)用程序

許多開(kāi)發(fā)者只把Delphi包看作放組件的地方,事實(shí)上包可 以(而且也應(yīng)該)應(yīng)用于模塊化應(yīng)用程序設(shè)計(jì)。

為了演示如何用包來(lái)模塊化你的應(yīng)用程序,我們創(chuàng)建一個(gè)例子:

1、 新建一個(gè)具有兩個(gè)窗體的Delphi程序:Form1和Form2;

2、 將Form2從自動(dòng)創(chuàng)建窗體列表中移除(PRoject |Options | Forms);

3、 在Form1上放一個(gè)按鈕,并且在按鈕的OnClick事件處理器中輸入如下代碼:

with TForm2.Create(application) do

begin

ShowModal;

Free;

End;

4、記住添加Unit2到Unit1的uses子句中;

5、 保存并運(yùn)行工程。

我們創(chuàng)建了一個(gè)簡(jiǎn)單的應(yīng)用程序,它顯示一個(gè)帶按鈕的窗體,點(diǎn)擊這個(gè)按鈕則會(huì)創(chuàng)建并顯示出另一個(gè)窗體。

但是如果想將上述例子中的Form2包含在一個(gè)可重用模塊 中,并使它依然可以正常工作,我們?cè)撛趺崔k呢?

答案是:包!

要為Form2創(chuàng)建包需要以下工作:

1、 打開(kāi)工程管理器(View | Project Manager);

2 、右擊Project Group,選擇“Add NewProject...”;

3、在“New”項(xiàng)目列表中選擇“Package”;

4、 現(xiàn)在你應(yīng)該可以見(jiàn)到包編輯器;

5、選擇“Contains”項(xiàng)目,然后點(diǎn)擊“Add”按鈕;

6、 然后點(diǎn)擊“Browse...”按鈕,并選擇“Unit2.pas”;

7、現(xiàn)在包中應(yīng)該包含了“Unit2.pas”單元;

8、 最后保存并編譯包。

現(xiàn)在我們完成了這個(gè)包。在你的Project/BPL目錄中 應(yīng)該有一個(gè)名叫“package1.bpl”的文件。(BPL是Borland Package Library的縮寫,DCP是Delphi CompiledPackage 的縮寫。)

這個(gè)包已經(jīng)完成了?,F(xiàn)在我們需要打開(kāi)包選項(xiàng)開(kāi)關(guān)

并重新編譯原先的應(yīng)用程序。

1、 在工程管理器中雙擊“Project1.exe”以選中 該工程;

2、 右擊并選擇“Options...”(你也可以從菜單中 選擇Project | Options...);

3、 選中“Packages”選項(xiàng)頁(yè);

4、 選中“Build with runtime packages” 檢查框;

5、 編輯“Runtime packages”編輯框:“Vcl50;Package1”,并點(diǎn)擊“OK”按鈕;

6、 注意:不要從應(yīng)用程序中移除Unit2;

7、 保存并運(yùn)行應(yīng)用程序。

應(yīng)用程序會(huì)象從前一樣運(yùn)行,不過(guò)區(qū)別可以從文件的大小上看出來(lái)。

Project1.exe現(xiàn)在只有14K大 小,而從前則是293K。如果你用資源瀏覽器查看EXE和BPL文件的內(nèi)容,你就會(huì)發(fā)現(xiàn)Form2的DFM和代碼現(xiàn)在都保存在包中。

Delphi在編譯期完成對(duì)包的靜態(tài)連接。(這就是為什么你不能從EXE工 程中移除Unit2。)

想想你可以由此得到什么:你可以在包中創(chuàng)建一個(gè)數(shù)據(jù)訪問(wèn)模塊,并且在更改數(shù)據(jù)訪問(wèn)規(guī)則時(shí)(比如從BDE連接轉(zhuǎn)為ADO連接),稍作修改并重新發(fā)布這個(gè) 包?;蛘撸憧梢栽谀硞€(gè)包中創(chuàng)建一個(gè)顯示“此選項(xiàng)在當(dāng)前版本中不可用”信息的窗體,然后在另一個(gè)同名的包中創(chuàng)建一個(gè)具有完整功能的窗體?,F(xiàn)在我們不費(fèi)吹灰 之力就有了“Pro”和“Enterprise” 兩個(gè)版本的產(chǎn)品。

包的動(dòng)態(tài)裝載和卸載

在大多數(shù)情況下,靜態(tài)連接的DLL或BPL已經(jīng)可以滿足要求了。但是如果我們不想發(fā)布BPL呢? “在指定目錄中找不到動(dòng)態(tài)鏈接庫(kù)Package1.bpl”,這是在應(yīng)用程序終止前,我們所能得到 的唯一消息?;蛘?,在模塊化應(yīng)用程序程序中,我們是否可以使用任意數(shù)量的插件?

我們需要在運(yùn)行期動(dòng)態(tài)連接到BPL。

對(duì)于DLL 來(lái)說(shuō),有一個(gè)簡(jiǎn)單的方法,就是使用LoadLibrary函數(shù):

function LoadLibrary(lpLibFileName: Pchar): HMODULE;stdcall;

裝載了DLL之后,我們可以使用GetProcAddress函數(shù)來(lái)調(diào)用DLL的導(dǎo)出函 數(shù)和方法:

function GetProcAddress(hModule: HMODULE; lpProcName:LPCSTR): FARPROC; stdcall;

最后,我們使用FreeLibrary卸載DLL:

function FreeLibrary(hLibModule: HMODULE): BOOL;stdcall;

下面這個(gè)例子中我們動(dòng)態(tài)裝載Microsoft的HtmlHelp庫(kù):

function TForm1.ApplicationEvents1Help(Command: Word; Data: Integer; var CallHelp: Boolean):Boolean;

type

TFNHtmlHelpA = function(hwndCaller: HWND; pszFile: PansiChar; uCommand: UINT;dwData: Dword): HWND; stdcall;

var

HelpModule: Hmodule;

HtmlHelp: TFNHtmlHelpA;

begin

Result := False;

HelpModule := LoadLibrary('HHCTRL.OCX');

if HelpModule <> 0 then

begin

@HtmlHelp := GetProcAddress(HelpModule, 'HtmlHelpA');

if @HtmlHelp <> nil then

Result := HtmlHelp(Application.Handle,Pchar(Application.HelpFile), Command,Data) <> 0;

FreeLibrary(HelpModule);

end;

CallHelp := False;

end;

動(dòng)態(tài)裝載BPL

我們可以用同樣簡(jiǎn)單的方法來(lái)對(duì)付BPL,或者應(yīng)該說(shuō)基本上同 樣簡(jiǎn)單。

我們可以使用LoadPackage函數(shù)動(dòng)態(tài)裝載包:

function LoadPackage(const Name: string): HMODULE;

然后使用GetClass 函數(shù)創(chuàng)建一個(gè)TPersistentClass類型對(duì)象:

function GetClass(const AclassName: string):TPersistentClass;

完成所有操作后,使用UnLoadPackage(Module:HModule);

讓我們對(duì)原來(lái)的代碼作一些小小的改動(dòng):

1、 在工程管理器中選中“Project1.exe”;

2、 右擊之并選擇“Options...”;

3、 選中“Packages”選項(xiàng)頁(yè);

4 、 從“Runtime packages”編輯框中移除“Package1”,并點(diǎn)擊OK按鈕;

5、 在Delphi的工具欄中,點(diǎn)擊“Remove file from project”按鈕;

6、 選擇“Unit2 | Form2”,并點(diǎn)擊OK;

7、 現(xiàn)在在“Unit1.pas”的源代碼中,從uses子句中移除Unit2;

8、 進(jìn)入Button1 的OnClick時(shí)間代碼中;

9、 添加兩個(gè)HModule和TPersistentClass類型的變量:

var

PackageModule: HModule;

AClass: TPersistentClass;

10、使用LoadPackage 函數(shù)裝載Pacakge1包:

PackageModule := LoadPackage('Package1.bpl');

11、檢查PackageModule是否為0;

12、使用GetClass函數(shù)創(chuàng)建一個(gè)持久類型:

AClass := GetClass('TForm2');

13、如果這個(gè)持久類型不為nil,我們就可以向從前

一樣創(chuàng)建并使用該類型的對(duì)象了:

with TComponentClass(AClass).Create(Application) as TcustomForm do

begin

ShowModal;

Free;

end;

14、最后,使用UnloadPackage 過(guò)程卸載包:

UnloadPackage(PackageModule);

15、保存工程。

下面是OnClick事件處理器的完整清單:

procedure TForm1.Button1Click(Sender: Tobject);

var

PackageModule: HModule;

AClass: TPersistentClass;

begin

PackageModule := LoadPackage('Package1.bpl');

if PackageModule <> 0 then

begin

AClass := GetClass('TForm2');

if AClass <> nil then

with TComponentClass(AClass).Create(Application) as TcustomForm do

begin

ShowModal;

Free;

end;

UnloadPackage(PackageModule);

end;

end;

不幸的是,并不是這樣就萬(wàn)事大吉了。

問(wèn)題在于,GetClass函數(shù)只能搜索到已經(jīng)注冊(cè)的類型。 通常在窗體中引用的窗體類和組件類會(huì)在窗體裝載時(shí)自動(dòng)注冊(cè)。但是在我們的例子中,窗體無(wú)法提前裝載。那么我們?cè)谀睦镒?cè)類型呢?答案是,在包中。包中的每 個(gè)單元都會(huì)在包裝載的時(shí)候初始化,并在包卸載時(shí)清理。

現(xiàn)在回到我們的例子中:

1、 在工程管理器雙擊“Package1.bpl”;

2、 點(diǎn)擊“Contains”部分“Unit2”旁的+號(hào);

3、 雙擊“Unit2.pas”激活單元源代碼編輯器;

4、 在文件的最后加入initialization部分;

5、 使用RegisterClass過(guò)程注冊(cè)窗體的類型:

RegisterClass(TForm2);

6、 添加一個(gè)finalization部分;

7、 使用UnRegisterClass過(guò)程反注冊(cè)窗體的類 型:

UnRegisterClass(TForm2);

8、 最后,保存并編譯包。

現(xiàn)在我們可以安全的運(yùn)行“Project1”,它還會(huì)像從前 一樣工作,但是現(xiàn)在你可以隨心所欲的裝載包了。

尾聲

記住,無(wú)論你是靜態(tài)還是動(dòng)態(tài)的使用包,都要打開(kāi)Project | Options | Packages | Build with runtime packages 選項(xiàng)。

在你卸載一個(gè)包之前,記得銷毀所有該包中的類對(duì)象,并反注冊(cè)所有已注冊(cè)的類。下面的過(guò)程可能會(huì)對(duì)你有所幫助:

procedure DoUnloadPackage(Module: HModule);

var

i: Integer;

M: TMemoryBasicInformation;

begin

for i := Application.ComponentCount - 1 downto 0 do

begin

VirtualQuery(GetClass(Application.Components[i].ClassName), M, Sizeof(M));

if (Module = 0) or (HMODULE(M.AllocationBase) = Module) then

Application.Components[i].Free;

end;

UnregisterModuleClasses(Module);

UnloadPackage(Module);

end;

在裝載包之前,應(yīng)用程序需要知道所有已注冊(cè)類的名字。改善這一情況的方法是建立一個(gè)注冊(cè)機(jī)制,以便告訴應(yīng)用程序所有 由包注冊(cè)的類的名字。

實(shí)例

多重包:包不支持循環(huán)引用。也就是說(shuō),一個(gè)單元不能引用一個(gè)已經(jīng)引用了該單元的單元(嘿嘿)。這使得調(diào)用窗體中的某 些值難以由被調(diào)用的方法設(shè)置。

解決這個(gè)問(wèn)題的方法是,創(chuàng)建一些額外的包,這些包同時(shí)由調(diào)用對(duì)象和包中的對(duì)象引用。設(shè)想一下我們?nèi)绾问笰pplication成為所有窗體的擁有者?變量Application創(chuàng) 建于Forms.pas 中,并包含在VCL50.bpl包 中。你大概注意到了你的應(yīng)用程序既要將VCL50.pas編譯進(jìn)來(lái),也同時(shí)你的包也需要(require) VCL50。

在我們第三個(gè)例子中,我們?cè)O(shè)計(jì)一個(gè)應(yīng)用程序來(lái)顯示客戶信息,并且可根據(jù)需要(動(dòng)態(tài))顯示客戶訂單。

那么我們可以從哪里開(kāi)始呢?像所有的數(shù)據(jù)庫(kù)應(yīng)用

程序一樣,我們需要連接。我們創(chuàng)建一個(gè)主數(shù)據(jù)模塊,包含一個(gè)TDataBase連 接。然后我們將這個(gè)數(shù)據(jù)模塊封裝在一個(gè)包中(cst_main)。

現(xiàn)在在應(yīng)用程序中,我們創(chuàng)建一個(gè)客戶窗體,并引用DataModuleMain(我 們靜態(tài)的鏈接VCL50 和cst_main)。

然后我們創(chuàng)建一個(gè)新的包(cst_ordr),包中包含客戶 訂單窗體,并require cst_main?,F(xiàn)在我們可以在應(yīng)用程序中動(dòng)態(tài)的裝載cst_ordr了。既然在動(dòng)態(tài)包裝載以前主數(shù)據(jù)模塊已經(jīng)存在,cst_ordr就 可以直接使用應(yīng)用程序的主數(shù)據(jù)模塊實(shí)例了。

上圖是此應(yīng)用程序的功能示意圖:

可換包:包的另一個(gè)應(yīng)用實(shí)例是創(chuàng)建可更換包。實(shí)現(xiàn)這個(gè)功能并不需要包的動(dòng)態(tài)裝載能力。假設(shè)我們要發(fā)布一個(gè)有時(shí)間限制 的試用版的程序,如何實(shí)現(xiàn)這一點(diǎn)呢?

首先我們創(chuàng)建一個(gè)“Splash”窗體,通常情況下是一幅帶 有“試用”字樣的圖片,并在應(yīng)用程序啟動(dòng)的過(guò)程中顯示它。然后我們創(chuàng)建一個(gè)“About”窗體,提 供一些關(guān)于應(yīng)用程序的信息。最后,我們創(chuàng)建一個(gè)用于測(cè)試軟件是否過(guò)期的函數(shù)。我們把這兩個(gè)窗體和這個(gè)函數(shù)封裝到一個(gè)包中,并將它隨試用版軟件發(fā)布。

對(duì)于付費(fèi)版軟件,我們也創(chuàng)建一個(gè)“Splash”窗體和一個(gè) “About”窗體——要和前面的兩個(gè)窗體類名相同——以及一個(gè)測(cè)試函數(shù)(什么也不做),并將它們 封裝到同名的包中。

什么什么?你問(wèn)這有用么?好吧,我們可以公開(kāi)的發(fā)布一個(gè)試用版軟件。如果某個(gè)客戶購(gòu)買了該應(yīng)用程序,我們只需要發(fā)送 非試用版的包。這就大大簡(jiǎn)化了軟件的發(fā)布過(guò)程,因?yàn)橹恍枰淮伟惭b和一次注冊(cè)包升級(jí)。

包為Delphi和C++ Builder開(kāi)發(fā)社群打開(kāi)了另一扇通往模塊化設(shè)計(jì)的大門。通過(guò)包你不再需要到處傳遞窗體句柄,不再需要回調(diào)函數(shù),不再需要其它DLL技術(shù)。由此也縮短了模塊化程序設(shè)計(jì)的開(kāi)發(fā)周期。我們所要做的僅僅是讓Delphi的包為我們工作。
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表

圖片精選

主站蜘蛛池模板: 中文字幕网在线 | 久久艹精品视频 | 久草在线播放视频 | 亚洲成人免费网站 | 草碰人人 | 欧美亚洲综合网 | 日韩一级片一区二区三区 | 娇喘视频在线观看 | 久久99精品久久久久久青青日本 | 福利在线小视频 | 国产精品久久久久久影院8一贰佰 | 国产又白又嫩又紧又爽18p | 91九色视频观看 | 久久久新| 孕妇体内谢精满日本电影 | 一区播放 | 国产精品久久久久久模特 | 亚洲无毛av | 女人裸体让男人桶全过程 | av在线1| 看免费5xxaaa毛片 | 亚洲成人中文字幕在线 | 2021av视频| www.48xx.com | 久久久免费观看完整版 | 欧美中文在线 | 美女羞羞视频网站 | 久久久久二区 | 久久久一区二区三区视频 | 日本免费aaa观看 | 久久久久久久久久久高潮一区二区 | 鲁丝一区二区三区不属 | 激情黄页 | 91成人午夜性a一级毛片 | 久久久久97国产精 | chinesehd天美原创xxxx | 国产午夜精品久久久久久久蜜臀 | 在线97视频 | 久久成人激情视频 | 精品久久久久久久久久久下田 | 国产日韩在线观看一区 |