Delphi Package无痛使用

来源:互联网 发布:java 打印gc日志 编辑:程序博客网 时间:2024/06/02 21:14

作者:Deven Tzu 

日期:Sep-3-2001

相信很多使用Delphi的人都有想过将自己的应用系统分割成好几个Package, 这样的好处是可以只更新单一的Package (.BPL)就可以了, 而且.BPL还有一个.DLL没有的好处, 所有的.BPL 可以有一份大家共用的记忆区块(变数, function, procedure 等), 使用上就很方便了, 但是事实上很多人都因为Package使用上的限制而放弃(我曾经就是一个) , 现在我就来介绍Delphi Package的使用方法(不过实际处理方式请参考程式码, 本说明不多作说明):

简介

Package 和"斯斯" 一样分为二种:

静态载入:

一般大家在用Delphi时都是使用『静态载入』, 像VCL的Package就是这个方式, 这个方式的好处是设计者不用去理会Package 的载入及释放, 其实设计者根本感觉不到有使用这项技术; 当然您也可以手动将Package挂上系统(project->Options->Packages->Build with runtime packages中加入, 记得Package Name彼此的分隔符号是『;』)

动态载入:

至于『动态载入』当然就和『静态载入』相反, 不论是载入及释放都要自己来处理, 看起来好像『动态载入』一无是处, 其实也不是这样, 『动态载入』可以作到要使用时才载入, 有点像PnP (随插即用)的功能, 这是『静态载入』作不到的. 

当然如果您高兴的话二种混用也是很好的方式, 也算是各取其优点来使用(本范例就是使用此方式) 

限制

  1. 有些情形下使用Package只能间接参考的方式取得资料(变数, 元件, 物件…).
  2. Package Name 不能重覆.
  3. Contains 中的Unit Name 不能在『所有』的Package中重覆出现(只能出现一次).
  4. PackageA有使用到PackageB必需要在Requires中引用其.dcp 档(Unit及Package的Head File, C++使用.DLL不是也要Include Head File吗?), 但是PackageA及PackageB不能彼此循环引用.

范例说明

本范例主要目的是要让程式可以像"独立执行档" (就是系统程式都是在一个Proejct中未分割)一样, 在设计时可以直接引用参考另一个单元(Unit)的东西, 和原来的写法没有什么不同, 不过最好是作成二个Project 一个是Design Time 版本(不分割系统), 一个是分发版本(分割系统), 这样Debug会比较方便些; 本范例是改自蔡焕麟先生所写pkgdemo2. zip 

首先要使用Package必需将project->Options->Packages->Build with runtime packages的选项勾选, 再将共用的Package Name 加入(如图一)

(图一)

然后在Requires 中引用使用到的Package dcp 档(如图二)

(图二)

选Options->Description->Runtime only (如图三), 因为我们是将系统分割不用Design Time Package , 如果选Designtime and runtime也可以不过会在系统上留一堆Design Time package并没有意义, 而且会比较占用记忆体; 至于Designtime only 就不用说了吧! 您的应用系统应该是要run的吧!

(图三)

Package1 有使用到Appaddin及PkgDATA所以在Requires 中引用(如图四)

图四)

Package1 中只有一个TForm1(可以放很多的TForm就不用我多说了吧), 内容如下:

unit Unit1;interfaceuses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,  StdCtrls, Grids, DBGrids, Db, DBTables;type  TForm1 = class(TForm)    Label1: TLabel;    btnForm2: TButton;    Edit1: TEdit;    DBGrid1: TDBGrid;    btnGetField: TButton;    btnGetVar: TButton;    procedure btnForm2Click(Sender: TObject);    procedure Edit1Exit(Sender: TObject);    procedure FormActivate(Sender: TObject);    procedure btnGetFieldClick(Sender: TObject);    procedure btnGetVarClick(Sender: TObject);  private { Private declarations }  public { Public declarations } end;var  Form1: TForm1;implementationuses PkgUtils, DATA;{$R *.DFM} { The following call Registers the addin with the application. Once this occurs the application can create instances of this form. }procedure TForm1.btnForm2Click(Sender: TObject);begin  inherited;  LoadAddinPackage('Package2', 'Package2.bpl');  ShowModalFormByClassName('TForm2');end;procedure TForm1.Edit1Exit(Sender: TObject);begin  COMPANY_NO := Edit1.Text;  // 对共用变数处理end ;procedure TForm1.FormActivate(Sender: TObject);beginEdit1.Text := COMPANY_NO; // 对共用变数处理end ;procedure TForm1.btnGetFieldClick(Sender: TObject);var A: TTable;begin // 以下这二行是用间接参考方式对 TDataModule1 处理 , 比较麻烦 //A := FindTable('Table1'); //Edit1.Text := A.FieldByName('CustNo').AsString; // 对 TDataModule1 处理Edit1.Text := DataModule1.Table1.FieldByName('CustNo').AsString;end ;procedure TForm1.btnGetVarClick(Sender: TObject);beginDataModule1.COMPANY_NAME := Edit1.Text; end ;initialization RegisterClass (TForm1); // 记得要用 GetClass 取得需在此注册 ( 提供 RTTI 资讯 )end .

当然如果您实在懒得处理Package的载入及释放, 也可以全部的Package全部使用『静态载入』由Delphi帮您处理.Delphi的『动态载入』和『静态载入』似乎处理的方法不同, 『静态载入』可以和系统整合的很好(像本例), 但『动态载入』是使用LoadPackage 处理, 但是共用的部份却无法直接参考, 但是用『静态载入』却可以, 我还查不出为何有此差异.