首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > .NET >

请教,如果都是动态加载调用,BPL与DLL相比有什么优点

2012-04-01 
请问,如果都是动态加载调用,BPL与DLL相比有什么优点?如果动态加载调用BPL的话我觉得完全可以用DLL替代,BPL

请问,如果都是动态加载调用,BPL与DLL相比有什么优点?
如果动态加载调用BPL的话我觉得完全可以用DLL替代,BPL没有优点。大家都来说两句。

[解决办法]
That is correct. A BPL is a DLL. (But not all DLLs are BPLs.) 

> But I still found some different, such as that I can create a 
> object from the Host exe and that pass to a BPL and modify it safely, but 
> if I do same to a dll, I can not modify any referenced property of the object. 

When you use packages, there is only ever one copy of any unit in 
memory. One copy of Forms, one copy of SysUtils, one copy of System 
(well, most of it), one copy of StdCtrls, etc. 

All class-related operations, such as the "is" and "as" operators, rely 
on class references. Class references are actually just addresses. They 
point to definitions for the layouts of the classes' internals. (They 
point to what's called the virtual-method table, the VMT.) Two classes 
are the same if they point to the same VMT -- if the addresses are equal. 

When you have a class defined in the EXE's copy of StdCtrls and the same 
class defined in a DLL's copy of StdCtrls, those classes will really 
have different addresses. The "is" and "as" operators won't work with 
cross-module clases. But when you use packages, there is only one copy 
of the class, kept in vcl70.bpl, so all modules that reference that 
package will share a single class definition. 

Another factor is the memory manager in System. All string allocations 
ultimately call GetMem and FreeMem. If the EXE allocates a string, it 
uses its own GetMem. It then passes the string to a DLL, and the DLL 
might try to free it. The DLL will call its own copy of FreeMem, which 
won't have access to the EXE's memory-manager structures, and you'll get 
errors. With packages, everything will use the same memory manager from 
rtl70.bpl. (This can also be solved by using a shared memory manager 
between the EXE and the DLL; ShareMem is one example. That won't solve 
the class-comparison problem, though.) 

Above, I said the major difference between BPLs and DLLs is the number 
of exported functions. With a DLL, the only things exported are what 
appear in the "exports" clause that you write yourself. With a BPL, 
everything from all the units' "interface" sections gets exported, 
including global variables and class definitions. Also exported are the 
addresses of the "initialization" and "finalization" sections. And, 
internally, that is indeed the major difference. A BPL exports the 
functions necessary for the RTL to recognize the file as being a BPL and 
not just a generic DLL. If you call LoadPackage, i will call LoadLibrary 
to load it like a normal DLL, and then it will call all the package's 
units' initialization sections and do a fe other housekeeping 
operations. Calling a package's functions generates the same kind of 
assembler code as is generated when you call a DLL function.
[解决办法]
一般我们编写编译一个DELPHI应用程序时,会产生一个EXE文件,也就是一个独立的WINDOWS应用程序。很重要的一点:区别于Visual Basic,DELPHI产生的是预先包裹的应用程序是不需要大量的运行库(DLL's)。

假设:打开Delphi默认的工程(只有一个空白form),F9她将编译生成一个大约295 KB (Delphi 5)的可执行文件。然后打开Project | Options,把‘Build with runtime packages’选上再编译一下,EXE文件大小就只有15 KB左右了。

我们编译一个DELPHI应用程序时默认地没有选择'Build with runtime packages',编译器将把程序运行所需要的代码直接写入你的EXE文件中,因此产生的程序是一个相对独立的程序,并不需要任何附属的支持文件(例如动态运行库文件DLL),这也就知道了为什么DELPHI产生的应用程序为什么都那么大。

要建立尽可能小的DELPHI程序,方法之一就要充分发挥Borland package libraries的作用,简称BPL。



先说什么是包?

简而言之,一个包就是一个在DELPHI的IDE环境中被DELPHI应用程序共享的特殊的动态链接库。包允许我们通过多级应用将我们的程序的一部分当做一个分离的模块供其他应用程序来共享。

包大致可分为运行期包(Run-time packages)和设计期包(Design-time packages):

运行期包-当运行程序时提供VCL和库函数的支持,操作上很类似标准的动态链接库。

设计期包-用来在DELPHI的IDE环境安装控件和为控件建立特殊的属性编辑器。设计期包允许包含控件、属性和控件编辑器等等,在IDE环境中,这类包是程序设计所必需的,也仅仅是DELPHI使用,并不和开发的应用程序一起分发。

知道这些包的运用,我们也就知道了运行期包是如何做处理和它们对DELPHI程序员有什么帮助了。

有一点必须说明:想很好地运用包并不要求你先成为一个成熟的控件编写者。DELPHI编程初学者也可以和应该尝试去接触包的概念,这将有利于你更好地理解包和DELPHI的工作关系。
[解决办法]
如果一定要只比较动态加载,我觉得意义不大。

当然,如果BPL是要完全动态加载的话,一般是要拆分成接口和实现包,静态依赖接口包,动态加载实现包。常需要使用FindClass,根据名称来找接口实现。

可以做成配置来动态决定加载哪个包里面的实现。可以了解下IOC思想,如spring容器等,其思想的实现也会用到BPL。
[解决办法]
前几天做过的试验,bpl 和 dll 差不多。
delphi 下解耦,请使用“接口”

Delphi(Pascal) code
unit uMain;interfaceuses  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  Dialogs, StdCtrls;type  IMyTest = interface // 主接口    ['{9A1E99F7-5B77-4E31-991E-46DEAD30B650}']    procedure Hellow;stdcall;    function Hello(const a,b:Integer):Integer;stdcall;    procedure SetBase(const X:Integer);stdcall;  end;  IMySub = interface // 后来发现需要拓展一些内容    ['{81936A15-DC1A-49B7-B5DC-791C0C5A35F9}']    procedure ttt;stdcall;  end;  TMyTest = class(TInterfacedObject,IMyTest,IMySub) // 接口实现类  private    FBase:Integer;  public    procedure Hellow;stdcall;    function Hello(const a,b:Integer):Integer;stdcall;    procedure SetBase(const X:Integer);stdcall;    procedure ttt;stdcall;  end;  IMyDLLTest = interface // 这里接口的实现在 dll 中    ['{D40DF4C9-4CFA-44E7-A1A3-0B2668BF1502}']    procedure Hello;stdcall;  end;  TForm1 = class(TForm)    Button1: TButton;    Button2: TButton;    Button3: TButton;    procedure Button1Click(Sender: TObject);    procedure FormCreate(Sender: TObject);    procedure Button2Click(Sender: TObject);    procedure Button3Click(Sender: TObject);  private    { Private declarations }  public    { Public declarations }  end;var  Form1: TForm1;  _Test:procedure (const intf);stdcall;  _RegApp:procedure (App:TApplication;out intf);stdcall;//procedure Test(const intf);stdcall;external 'MyDll.dll';implementation{$R *.dfm}{ TMyTest }function TMyTest.Hello(const a, b: Integer): Integer;begin  Result := a + b + FBase;end;procedure TMyTest.Hellow;begin  ShowMessage('Hellow');end;procedure TMyTest.SetBase(const X: Integer);begin  FBase := x;end;procedure TMyTest.ttt;begin  ShowMessage('ttt');end;procedure TForm1.Button1Click(Sender: TObject);var intf:IMyTest;begin  // 这里创建实例,给 dll 中用  intf := TMyTest.Create;  _Test(intf);  ShowMessage(IntToStr(intf.Hello(1,2)));  intf := nil;end;procedure TForm1.Button2Click(Sender: TObject);var intf:IMyDLLTest;begin  // 从 dll 中找到实现类  _RegApp(Application,intf);  if intf <> nil then    intf.Hello;end;procedure TForm1.Button3Click(Sender: TObject);var hh:THandle;pp:TProcedure;begin  hh := LoadPackage('MyBPL.bpl');  if hh <> 0 then  begin    @pp := GetProcAddress(hh,'@Ubpl@DuoTest$qqrv');    if @pp <> nil then      pp;  end;end;procedure TForm1.FormCreate(Sender: TObject);var hh:THandle;begin  hh := LoadLibrary('MyDll.dll');  @_Test := GetProcAddress(hh,'Test');  @_RegApp := GetProcAddress(hh,'RegApp');end;end.
[解决办法]
DLL比BPL好的地方:
1、DLL 语言无关,自然与Delphi版本无关了。 BPL则不一样,D2010编译的程序加载D7编译的BPL是会出错的。
2、DLL可以被其他语言调用。BPL仅限于对应版本的Delphi编译器。

BPL的好处,无论动态加载或静态加载:
1、多个BPL可以方便自然地共享全局变量。DLL不能或者说要很复杂地做才能在多个DLL间共享全局变量。
2、类的支持。BPL有类的信息,可以方便地从其他BPL中继承类,包括Form继承。DLL不行。
3、BPL中可以地选择延迟加载其他DLL,编程起来与静态加载一样,DLL中加载其他DLL时,只能作静态或动态二选一。

说的不一定对,只是这个问题与动态或静态加载关系并不大。

热点排行