亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Delphi > 正文

Delphi中的動態包

2019-11-11 04:58:54
字體:
來源:轉載
供稿:網友

為什么要使用包?

答案很簡單:因為包的功能強大。設計期包(design-time package)簡化了自定義組件的發布和安裝;而運行期包(run-time package) 則更是給傳統的程序設計注入了新鮮的力量。一旦把可重用的代碼編譯為運行期庫中,你就可以在多個應用程序中共享它們。所有應用程序都可以通過包訪問標準組 件,Delphi自己就是這么干的。因為應用程序不必在可執行文件中單獨復制一份組件庫,這樣就大 大節省了系統資源和磁盤空間。此外,包還可以減少花費在編譯上的時間,因為你只需編譯應用程序特有的代碼。

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

運行期包與應用程序

許多開發者只把Delphi包看作放組件的地方,事實上包可 以(而且也應該)應用于模塊化應用程序設計。

為了演示如何用包來模塊化你的應用程序,我們創建一個例子:

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

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

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

with TForm2.Create(application) do

begin

ShowModal;

Free;

End;

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

5、 保存并運行工程。

我們創建了一個簡單的應用程序,它顯示一個帶按鈕的窗體,點擊這個按鈕則會創建并顯示出另一個窗體。

但是如果想將上述例子中的Form2包含在一個可重用模塊 中,并使它依然可以正常工作,我們該怎么辦呢?

答案是:包!

要為Form2創建包需要以下工作:

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

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

3、在“New”項目列表中選擇“Package”;

4、 現在你應該可以見到包編輯器;

5、選擇“Contains”項目,然后點擊“Add”按鈕;

6、 然后點擊“Browse...”按鈕,并選擇“Unit2.pas”;

7、現在包中應該包含了“Unit2.pas”單元;

8、 最后保存并編譯包。

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

這個包已經完成了?,F在我們需要打開包選項開關

并重新編譯原先的應用程序。

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

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

3、 選中“Packages”選項頁;

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

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

6、 注意:不要從應用程序中移除Unit2;

7、 保存并運行應用程序。

應用程序會象從前一樣運行,不過區別可以從文件的大小上看出來。

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

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

想想你可以由此得到什么:你可以在包中創建一個數據訪問模塊,并且在更改數據訪問規則時(比如從BDE連接轉為ADO連接),稍作修改并重新發布這個 包?;蛘?,你可以在某個包中創建一個顯示“此選項在當前版本中不可用”信息的窗體,然后在另一個同名的包中創建一個具有完整功能的窗體?,F在我們不費吹灰 之力就有了“Pro”和“Enterprise” 兩個版本的產品。

包的動態裝載和卸載

在大多數情況下,靜態連接的DLL或BPL已經可以滿足要求了。但是如果我們不想發布BPL呢? “在指定目錄中找不到動態鏈接庫Package1.bpl”,這是在應用程序終止前,我們所能得到 的唯一消息?;蛘撸谀K化應用程序程序中,我們是否可以使用任意數量的插件?

我們需要在運行期動態連接到BPL。

對于DLL 來說,有一個簡單的方法,就是使用LoadLibrary函數:

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

裝載了DLL之后,我們可以使用GetProcAddress函數來調用DLL的導出函 數和方法:

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

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

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

下面這個例子中我們動態裝載Microsoft的HtmlHelp庫:

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;

動態裝載BPL

我們可以用同樣簡單的方法來對付BPL,或者應該說基本上同 樣簡單。

我們可以使用LoadPackage函數動態裝載包:

function LoadPackage(const Name: string): HMODULE;

然后使用GetClass 函數創建一個TPersistentClass類型對象:

function GetClass(const AclassName: string):TPersistentClass;

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

讓我們對原來的代碼作一些小小的改動:

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

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

3、 選中“Packages”選項頁;

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

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

6、 選擇“Unit2 | Form2”,并點擊OK;

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

8、 進入Button1 的OnClick時間代碼中;

9、 添加兩個HModule和TPersistentClass類型的變量:

var

PackageModule: HModule;

AClass: TPersistentClass;

10、使用LoadPackage 函數裝載Pacakge1包:

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

11、檢查PackageModule是否為0;

12、使用GetClass函數創建一個持久類型:

AClass := GetClass('TForm2');

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

一樣創建并使用該類型的對象了:

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

begin

ShowModal;

Free;

end;

14、最后,使用UnloadPackage 過程卸載包:

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;

不幸的是,并不是這樣就萬事大吉了。

問題在于,GetClass函數只能搜索到已經注冊的類型。 通常在窗體中引用的窗體類和組件類會在窗體裝載時自動注冊。但是在我們的例子中,窗體無法提前裝載。那么我們在哪里注冊類型呢?答案是,在包中。包中的每 個單元都會在包裝載的時候初始化,并在包卸載時清理。

現在回到我們的例子中:

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

2、 點擊“Contains”部分“Unit2”旁的+號;

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

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

5、 使用RegisterClass過程注冊窗體的類型:

RegisterClass(TForm2);

6、 添加一個finalization部分;

7、 使用UnRegisterClass過程反注冊窗體的類 型:

UnRegisterClass(TForm2);

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

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

尾聲

記住,無論你是靜態還是動態的使用包,都要打開Project | Options | Packages | Build with runtime packages 選項。

在你卸載一個包之前,記得銷毀所有該包中的類對象,并反注冊所有已注冊的類。下面的過程可能會對你有所幫助:

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;

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

實例

多重包:包不支持循環引用。也就是說,一個單元不能引用一個已經引用了該單元的單元(嘿嘿)。這使得調用窗體中的某 些值難以由被調用的方法設置。

解決這個問題的方法是,創建一些額外的包,這些包同時由調用對象和包中的對象引用。設想一下我們如何使Application成為所有窗體的擁有者?變量Application創 建于Forms.pas 中,并包含在VCL50.bpl包 中。你大概注意到了你的應用程序既要將VCL50.pas編譯進來,也同時你的包也需要(require) VCL50。

在我們第三個例子中,我們設計一個應用程序來顯示客戶信息,并且可根據需要(動態)顯示客戶訂單。

那么我們可以從哪里開始呢?像所有的數據庫應用

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

現在在應用程序中,我們創建一個客戶窗體,并引用DataModuleMain(我 們靜態的鏈接VCL50 和cst_main)。

然后我們創建一個新的包(cst_ordr),包中包含客戶 訂單窗體,并require cst_main?,F在我們可以在應用程序中動態的裝載cst_ordr了。既然在動態包裝載以前主數據模塊已經存在,cst_ordr就 可以直接使用應用程序的主數據模塊實例了。

上圖是此應用程序的功能示意圖:

可換包:包的另一個應用實例是創建可更換包。實現這個功能并不需要包的動態裝載能力。假設我們要發布一個有時間限制 的試用版的程序,如何實現這一點呢?

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

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

什么什么?你問這有用么?好吧,我們可以公開的發布一個試用版軟件。如果某個客戶購買了該應用程序,我們只需要發送 非試用版的包。這就大大簡化了軟件的發布過程,因為只需要一次安裝和一次注冊包升級。

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

圖片精選

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩视频精品在线| 精品视频在线导航| 亚洲欧美另类中文字幕| 国产成人福利网站| 欧美性猛交xxxx黑人猛交| 久久久久国产一区二区三区| 国产精品久久久久久久app| 久热在线中文字幕色999舞| 国产精品毛片a∨一区二区三区|国| 成人综合国产精品| 91网站免费观看| 欧美成年人视频网站欧美| 亚洲一区二区三区在线免费观看| 欧美午夜性色大片在线观看| 亚洲欧洲日本专区| 国产精品久久久久久久久久小说| 中文字幕欧美视频在线| 97香蕉超级碰碰久久免费的优势| 欧美日韩成人在线视频| 欧美日韩爱爱视频| 成年人精品视频| 亚洲自拍偷拍在线| 日韩av在线免费观看一区| 日韩成人黄色av| 国产精品入口福利| 国产丝袜视频一区| 日韩在线观看网址| 久久深夜福利免费观看| 中文字幕亚洲欧美日韩高清| 中文字幕自拍vr一区二区三区| 在线播放国产一区中文字幕剧情欧美| 欧美国产第一页| 亚洲成人教育av| 国产精品扒开腿做爽爽爽视频| 国产精品福利小视频| 国产精品丝袜高跟| 久久综合久中文字幕青草| 91精品视频免费看| 亚洲国产欧美在线成人app| 久久免费高清视频| 2020久久国产精品| 精品国产一区二区三区在线观看| 亚洲色图日韩av| 中文字幕日韩av综合精品| 久久精品精品电影网| 最近2019中文字幕大全第二页| 亚洲精美色品网站| 91久久久久久久久| 97视频网站入口| 欧美日韩综合视频网址| 亚洲精品久久久久久久久久久| 精品女同一区二区三区在线播放| 日韩精品免费视频| 一本色道久久综合狠狠躁篇怎么玩| 日韩中文字幕免费视频| 欧美日韩国产va另类| 日本久久久久久久久| 久久国产精品久久久久久| 日韩av在线播放资源| 国产精品久久久久久久久久久久| 91亚洲永久免费精品| 国产精品视频不卡| 国产69精品99久久久久久宅男| 日韩欧美中文字幕在线观看| 96pao国产成视频永久免费| www.xxxx精品| 亚洲精品国产精品自产a区红杏吧| 久久天堂电影网| 欧美性一区二区三区| 热久久视久久精品18亚洲精品| 国产欧美精品在线播放| 97久久精品人人澡人人爽缅北| 久久av在线看| 欧美另类极品videosbest最新版本| 亚洲天堂影视av| 欧美午夜宅男影院在线观看| 国产精品视频一区二区三区四| 国产精品高潮呻吟久久av无限| 爽爽爽爽爽爽爽成人免费观看| 久久久久国产精品www| 欧美日韩国产综合视频在线观看中文| 久久青草精品视频免费观看| 午夜欧美大片免费观看| 亚洲最大av网站| 精品五月天久久| 欧美在线激情网| 精品亚洲国产成av人片传媒| 欧美大胆a视频| 亚洲国语精品自产拍在线观看| 色中色综合影院手机版在线观看| 色偷偷88888欧美精品久久久| 久久久久久久一区二区| 欧美成人网在线| 欧美性xxxxx| 粉嫩老牛aⅴ一区二区三区| 国产成人aa精品一区在线播放| 国产精品视频免费在线观看| 中文字幕视频在线免费欧美日韩综合在线看| 久久久精品一区二区三区| 欧美精品一二区| 91日本在线观看| 自拍偷拍亚洲在线| 亚洲精品视频在线观看视频| 亚洲欧美日韩天堂一区二区| 日韩h在线观看| 久久激情视频免费观看| 青草成人免费视频| 国产一区二区av| 亚洲欧美福利视频| 欧美大胆在线视频| 国产热re99久久6国产精品| 亚洲色图综合久久| 国产啪精品视频网站| 久久久久久国产精品久久| 国产精品一区二区久久| 精品露脸国产偷人在视频| 成人黄色短视频在线观看| 不卡在线观看电视剧完整版| 日本高清不卡在线| 亚洲人成网在线播放| 国产欧美一区二区三区在线| 国产精品看片资源| 亚洲视频在线播放| 国产免费一区二区三区在线能观看| www.99久久热国产日韩欧美.com| 91精品国产91久久久| 国产午夜一区二区| 亚洲国产精品一区二区三区| 国产精品免费久久久久影院| 久久97精品久久久久久久不卡| 欧美日韩国产中文精品字幕自在自线| 福利一区福利二区微拍刺激| 中文字幕亚洲欧美| 国产精品入口日韩视频大尺度| 亚洲人成亚洲人成在线观看| 91中文精品字幕在线视频| 91系列在线观看| 欧美—级a级欧美特级ar全黄| 成人免费淫片aa视频免费| 欧美在线视频一区| 在线观看欧美www| 日本一欧美一欧美一亚洲视频| 欧美成人激情图片网| 日韩精品视频三区| 国产精品丝袜视频| 亚洲欧美在线免费| 亚洲日韩中文字幕| 国产中文日韩欧美| 亚洲最新av在线| 欧美大片免费看| 欧美福利在线观看| 久久久噜久噜久久综合| 91chinesevideo永久地址| 久久久久久久激情视频| 91精品国产自产在线观看永久| 成人国产精品一区二区| 国产精品久久久久福利| 538国产精品一区二区免费视频| 亚洲一区二区三区在线视频| 久久免费视频在线观看| 国产一区二中文字幕在线看| 亚洲国产精品va在看黑人| 日韩欧美在线字幕| 欧美日韩精品在线播放|