Delphi 包的设计思想及它与PAS、BPL、DCU、DLL、OXC的关系。
DCP ,BPL分别是什么文件,起什么作用?你在DELPHI中建立一个package然后保存一下,看看.
bpl和Dll比较相似.只是BPL是BORLAND自己弄出来的东西!!!调用也和调用DLL相似,loadpackage()...DCP:delphi编辑软件包;一种包含关于被编译进软件包当中的代码符号信息的文件。
这种文件并不包含编译代码,这些代码实际上存贮在dcu或bpl文件中; BPL:Borland程序包库:在delphi环境设计或应用程序运行时用到的包含有vcl组件的一种文件(这种文件在delphi3中使用.DPL扩展名)
======================================
dcp = delphi compiled package,是 package 编译时跟 bpl 一起产生出来的,记录着 package 中公开的 class、procedure、function、variable、const.... 等等的名称和相对位址。
如果 某个控件包 A 引用了 控件包 B,当 控件包 A 编译时,需要 控件包 B.dcp,若 控件包 B 有修改,更改了公开的介面,则 控件包 A 必须在 控件包 B 编译之后重新编译,以引用新的 B.dcp。否则,当 控件包 A 执行时,执行到引用自 控件包 B 的内容时,就会出现错误。
====================================================
一、Delphi中各种文件的介绍,及其关系。
OXC: ActiveX控件。会被安装到某一个组件包DPK中,在Imports中会创建PAS、DCU、DCR三个文件。
DLL: 动态链接库文件,它的Exports exports既可以写在工程文件里面,也可以写在Unit里面,没有区别。
DPK: 组件包文件,它是由多个组件(PAS)集合而成的。
BPL: 包裹文件,其实就是DLL文件,只是在DLL的基础上添加了一些特性:比如检查重复Unit之类。它是Delphi IDE集成开发环境需要的,是DPK编译产生的文件。其中Run-Time类型供运行用的EXE使用,Design-Time类型供Delphi使用。不同的版本格式不一样。它可以像DLL一样写Exports。
DCU: 编译文件,是PAS编译产生的(相当OBJ文件),连接器能使用 DCU ,将代码连接入目标输出文件中。每个Delphi的版本生成的dcu格式都不一样。
二、包的设计思想
一个包就是一个在Delphi的IDE环境中被应用程序共享的特殊的动态链接库。包允许我们通过多级应用将我们的程序的一部分当做一个分离的模块供其他应用程序来共享。因为编译之后的DPL是一种特殊的DLL,所以可在属于某个DPK的Unit里面写export语句,
1、静态链接和动态链接。
静态链接就是当一个Delphi工程被编译的时候,工程所需要的所有代码将被直接链接入你的程序执行文件。结果就是执行文件将包含程序所需要使用到的所有单元(units),你也许会说这样代码有点冗长,因为在通常默认情况下,一个Form单元的uses子句列举了至少5个基本单元(如:Windows, Messages, SysUtils等),尽管如此,Delphi还是能够智能地自动链接单元中真正要用到的代码到工程代码中,从而尽可能地减少了执行文件的大小。使用静态链接,我们的应用程序就是一个相对独立的程序,不需要任何额外的支持文件或动态链接库(暂时不考虑BDE和ActiveX构件)。DELPHI中默认使用的就是静态链接方式。
动态链接就是应用程序将和标准的动态链接库(DLL)一起运行。动态链接方式不需要将代码直接建立到每个应用程序中去,单独为多个应用程序提供多线程的库函数支持,任何程序运行期间才需用到的包才将被加载,更值得一提的是:程序在动态方式需要调用的包是自动加载的,因此你不需要专门写加载包的代码。设置方法是:选中在【Project】->【Options】->【Packages】,选中【Build With Runtime Packages】复选框后,再次编译程序,你的程序代码将自动链接到动态运行包,而不是将引用单元都静态链接入你的工程执行文件。 如果有了【Build With Runtime Packages】,那么在编译的时候,那么它是不需要什么DCU/PAS。
例如:
打开Delphi默认的工程(只有一个空白form),F9它将编译生成一个大约365 KB (Delphi7)的可执行文件。然后打开【Project】->【Options】->【Packages】,把【Build With Runtime Packages】选上再编译一下,EXE文件大小就只有17 KB左右了。
我们编译一个Delphi应用程序时默认地没有选择【Build With Runtime Packages】,编译器将把程序运行所需要的代码直接写入你的EXE文件中,因此产生的程序是一个相对独立的程序,并不需要任何附属的支持文件(例如动态运行库文件DLL),这也就知道了为什么DELPHI产生的应用程序为什么都那么大。要建立尽可能小的Delphi程序,方法之一就要充分发挥Borland Package Libraries的作用,简称BPL。
2、包的分类:
大致可分为运行期包(Run-time Packages)和设计期包(Design-time Packages):
运行期包: 当运行程序时提供VCL和库函数的支持,操作上很类似标准的动态链接库。
设计期包: 用来在Delphi的IDE环境安装控件和为控件建立特殊的属性编辑器。设计期包允许包含控件、属性和控件编辑器等等,在IDE环境中,这类包是程序设计所必需的,也仅仅是Delphi使用,并不和开发的应用程序一起分发。
3、运行期包和设计期包分开的必要性和好处:
设计时的代码在运行时不会被执行,而编译器并不能知道,把所有的代码都链接进去,因此分开设计可以防止代码膨胀。一个运行期包,一个设计期包,使应用程序的体积变小,避免所有关的单元全部链接到执行程序中去(Delphi5及前版本),使代码膨胀。
还有一个好处就是减少编译错误的发生,Delphi6版本以来,VCl结构对Delphi5及前版本有所调整,Borland用DesignIntf替换了DsgnIntf,而且属性编辑器也被放进DesignEditors、DesignMenus、DesignWindows和其它的一些设计文件里。特别是DesignEditors使用了其它的一个名叫Proxies的IDE文件。而Proxies被编译进了DesignIDE.bpl文件中。DesignIDE.bpl已经不再是一个可以分发的文件,我们只能在开发环境中使用,不用说,这时候编译应用程序时就出现“找不到文件”的问题了。这时,我们将运行期包和设计期包分开,将设计期包加入Designide.dcp文件,分别编译包文件,就能保证正确无误,编译通过!
Package组件包它类似于Dll,不过只是在Delphi和CBuilder环境中通用。很好的利用包,可以使程序模块清晰,能最大限度的代码重用,使程序的体积尽量减小,而且可以在这两种语言环境中互用。
4、为了使代码结构最优化,设计期包应该包括:
1>、所有的注册声明(最好放在一个单独的单元中);
2>、所有的属性编辑器;
3>、所有的组件编辑器;
4>、将需要DesignIDE支持的包(Designide.dcp文件,在Requires写:DesignIDE)。
注意: 组件编辑器是通过在组件上弹出快捷菜单,象Table等组件。它的制作比较类似,是从TComponentEditor下继承来的。
5、为了使代码结构最优化,运行期包应该包括:
1>、组件本身。
2>、组件可能在运行时调用的窗体(属性编辑器用到的)。
注意: Package根据版本不同而进行不同的设计,Delphi 6.0的编辑器版本是VER140,Delphi 5.0的编辑器版本是VER130,如果我们想适应不同的版本需要使用 {$IFDEF VER140}。。。{$ELSE}。。。{$ENDIF};在Uses域进行控制,这点大家稍加注意。
三、适时运用包裹BPL和DLL
一般都认为加入Windows操作系统中的动态运行库是一种最有用最高效的应用。因为在Windows系统中,很多应用程序同时运行可能会引起了内存方面的问题,而很多程序执行相似的操作任务,但各自又由不同的代码来控制并完成。动态运行库的作用就是将你的执行程序中的这些代码放到一个系统共享环境下的DLL中去。可能最为直观的动态链接库例子就是Windows操作系统自己和它本身所带的API了。
动态链接库通常都是用来集合过程(procedure)和函数(function)以供程序调用。当然我们在编写动态链接库的同时,也可以把一个Delphi Form放到一个DLL中去(例如一个AboutBox Form),此外我们也可以在DLL中存储程序所需要的资源(resources)。
相对于DLL而言,包裹的概念是Delphi开发中所特有的,其他语言编写的应用程序不能引用Delphi建立的包裹。包是Delphi编写的应用程序能使用的一种动态链接库,它也同时给了Delphi程序员更多的库函数支持。
通常我们在Delphi中建立动态链接库(DLL)是用来存储不同环境下应用程序所需要使用到的过程和函数,而包不仅能够包含代码单元(unit)、构件和窗体(Form),还能包含Delphi中的类(如classes,这样的话,我们就能在其中引用对象向导编码(Object Oriented Code)。在包裹中,我们可以保存完整的通用Delphi构件,而动态运行库(DLL)对此则无能为力了。
此外,在缩减程序代码上,DLL和BPL扮演着同样重要的角色,其主要原因就是在使用包裹或动态链接库技术后,都直接地减少了程序的文件大小。当然,执行程序需要加载的DLL或BPL也可能会是很庞大的。尽管如此,如果你要分发共享同个包的多个应用程序,就可以省很多事了。当用户方系统中已经存在程序运行需要的部分文件(如:标准的Delphi Bpl)后,就只需要下载程序的最小执行文件了。如果程序工程主要是通过Internet等方式分发和开展,那效率显然有很大的提高。
包的应用也节省系统内存,因为动态链接的结果就是:只有一个VCL被读入内存供所有使用运行期包的Delphi应用程序使用。
四、建立包的基本步骤:
1、 启动DELPHI,并选择【File】->【Close All】关闭默认的工程。
2、 选择【File】->【New..】,弹出New Items对话框;然后【New】->【Package】,双击就会出现包裹编辑器。包裹编辑器包含2个文件夹:Contains和Requires。
3、 点击【Add】就可以增加一个单元文件(构件或是一个简单的代码单元文件)。
(注意:你添加的是PAS源码文件而不是编译后的DCU文件。当你添加单元文件的同时,包中的单元的名字就显示在包裹编辑器的Contains文件夹中了。打开Requires文件夹,展开的列表表示包裹所需要的包的DCP文件,包裹文件最基本的就是需要引用含有绝大部分标准可视控件的vcl.dcp文件。也可以看到必
须增加的其他包裹)
4、 然后单击【Options】,在【Description】面板中的【Usage Options】组中你需要选择包裹种类。
(设计期包、运行期包、或者两者都是。如果选择Runtime only(仅运行期包),其他包的使用者将无
法将构件安装到IDE环境中去)
5、 使用【File】->【Save】保存包工程文件(DPK),然后保存包文件,如AboutDP70。
6、 在包裹编辑器中,单击Compile按钮来编译包。如果不出错误,编译包后将建立一个包裹文件(BPL文件)。
7、 完成,BPL文件已经成功建立,就等着使用了。
8、 在包裹编辑器中有一个Install按钮,就是用来将当前包裹安装成一个设计期包的。如果包裹是
run-time only(仅运行期包),那Install按钮将无法使用。
关于所建立的这些文件除了DPK文件和那些单元源码文件,DELPHI还使用包裹的动态链接版本产生一个BPL文件和一个含有包内标识信息DCP文件,DCP文件就是包中所包含单元文件的编译文件(DCU)的标识信息的集合。
发布包需要包含:DCP(含有包的头信息和各个单元文件)和.BPL文件,所有单元文件的.DCU文件。