Delphi中Package是一件非常强大的工具,用的好可以起到非常清晰的划分程序结构的作用。
因为他内建描述信息,可以和当前代码无缝集成起来,可以保护包括类在内的任何元素,相当于VC中的MFC Extension DLL的作用。
但是一直以来的文章都只介绍静态连接的方法,这其实限制了Package的使用因为静态连接的Package失去了其灵活性,可配置性等等。
至于通过函数入口方式访问,实在是大材小用,那不如直接用DLL还方便一些。
如何动态载入Package,使用其中的类、函数、变量等等?
起始说穿了很简单,就是做一个代理包。因为在一个Delphi程序中,每个unit只能存在一份,否则发生冲突。要动态载入包,又得取得其中信息,又不能直接uses包含信息的unit(否则引起冲突),解决办法是另外建一个代理包来作为桥梁传递信息。
下面是一个简单的例子,主程序使用到两个包,
DemoPak包中有一个简单的Form;
RegPak是所谓的代理包,起到注册信息的作用。
主程序对RegPak静态使用(在Project Options里面设置了),对DemoPak动态载入(通过LoadPackage),而DemoPak依赖于RegPak(requires),并在初始化时向代理包RegPak注册自己的可用类,这里举例注册类信息,你可以方便的改成注册其他信息
unit FormReg;
interface
uses Classes, SysUtils, Forms, Contnrs;
type TFormClass = class of TForm;
procedure RegisterFormClass(const AName: string; const AFormClass: TFormClass);
procedure UnregisterFormClass(const AName: string);
function FindFormClass(const AName: string): TFormClass;
implementation
var g_lstNames: TStringList;
g_lstForms: TClassList;
procedure RegisterFormClass(const AName: string; const AFormClass: TFormClass);
begin
g_lstNames.Add(AName);
g_lstForms.Add(AFormClass);
end;
procedure UnregisterFormClass(const AName: string);
var
Index: Integer;
begin
Index := g_lstNames.IndexOf(AName);
if Index <> -1 then
begin
g_lstNames.Delete(Index);
g_lstForms.Delete(Index);
end;
end;
function FindFormClass(const AName: string): TFormClass;
var I: Integer;
begin
for I := 0 to g_lstNames.Count - 1 do
begin
if g_lstNames[I] = AName then
begin
Result := TFormClass(g_lstForms.Items[I]);
Exit;
end;
end;
Result := nil;
end;
initialization
g_lstNames := TStringList.Create;
g_lstForms := TClassList.Create;
finalization
FreeAndNil(g_lstForms);
FreeAndNil(g_lstNames);
end.
以上是RegPak的主要代码,因为举例,代码很简陋。主要思想就是保存注册信息,提供查询方法。
让我们看看在DemoPak中的使用
unit AboutForm
;interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type TfrmAbout = class(TForm)
lblAbout: TLabel;
private
public
end;
var frmAbout: TfrmAbout;
implementation
uses FormReg;
{$R *.dfm}
initialization
RegisterFormClass(TfrmAbout.ClassName, TfrmAbout);
finalization
UnregisterFormClass(TfrmAbout.ClassName);
end.
在初始化时向RegPak的FormReg单元提交自己的类信息,因为每个Package在载入时无论动态静态都会自动初始化,而RegPak被主程序静态引用,肯定已经初始化,所以直接注册即可,非常简单。
最后看看主程序中的使用
uses FormReg;
procedure TfrmMain.btnAboutClick(Sender: TObject);
var hModule: THandle;
begin
hModule := LoadPackage('DemoPak.bpl');
try
with FindFormClass('TfrmAbout').Create(nil) do
try
ShowModal;
finally
Free;
end;
finally
UnloadPackage(hModule);
end;
end;
动态载入需要的包,查询需要的类的信息,使用之,最后卸载包。