在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
■印象中的Package
在一般的AP开发时,我们知道在Delphi7.0整合环境中将Project->Options->选到Packages卷标页,Builder with runtime packages选项打勾,就会让编译出来的执行文件Size变小很多(以空白的Form1为例,编译出来的Size由367kb变成20kb),因为它把一些VCL共享模块的Loding放到*.bpl中;换句话说这个变小的EXE文件在执行时是需要那些*.bpl的,而原本较大的执行文件执行时则不需要那些*.bpl,这样看来其实只是换汤不换药罢了。 这种编译架构的差异有什么优点?试想,如果Project1.exe&Project2.exe都不使用Builder with runtime packages选项,Project1.exe跟Project2.exe编译出来的Size都是367kb,若有10个ProjectN.exe,则占用的Size将是全部exe加起来的总和,若是我们将其中共享的部分(如VCL共享模块)独立出来,每个EXE都将只有20K(以测试用的空白Form而言),缺点则只有每个exe执行时都要在系统搜寻路径中找得到那些VCL的共享模块(以*.bpl文件名存在);所以这种架构适用于一个项目系统内有多个独立执行文件或独立业务模块存在的情况,多个执行文件就可以分散给多个人去开发,也可依照应用程序不同的业务性质去区隔并分别设计。 将执行文件分散开来开发,这种做法跟一个主执行文件配合多个不同业务别的DLL开发没有什么差别,而降低每支执行文件的Size也只是Package最普通的应用;使用Package有一个更强大的优点——可以共享变量,如果将数据模块当成一个共享变量的观念去看待,我们不用在每次启动或关闭不同的子系统业务模块时,重新连接或释放数据库的Connection。不过,要真正能共享数据库模块是需要每个业务模块皆以*.bpl的方式存在,这也是实际应用上的状况。
注: 1.MIS主系统(Project0.exe)可能只是一个选单(Menu),用来当作启动各子系统的Shell 2.VCL共享模块(*.bpl)是Delphi在安装时即安装至C:"WINNT"SYSTEM32"中的那些*.bpl档案,不管你EXE文件是否Builderwithruntimepackages,那些*.bpl早已存在,端看你要不要用它而已(Builderwithruntimepackages是否打勾) 3.当AP开发是以Builderwithruntimepackages(打勾)编译时,RELEASE到客户端同时也要将C:"WINNT"SYSTEM32"中的那些*.bpl档案COPY到客户端,因为客户端没有安装Delphi,所以没有那些VCL共享模块(*.bpl) 4.BPL跟EXE一样是可以“LOAD”其它的*.bpl;如Project1.bpl(会计子系统)会”LOAD”VCL共享模块(*.bpl)以及DataMoudle(db.bpl) 5.在类型三中,作为唯一的EXE文件,Project0.exe编译时一定要Builderwithruntimepackages(打勾),否则在动态加载其它子系统模块时,会出现找不到类别的错误
■Package架构的优缺点
使用Package的优点: 1.类似DLL-应用程序可以被高度的模块化 2.优于DLL之处-可以共享变量 使用Package的缺点: 1.架构较复杂,需要花比较多的心思在模块化的设计 2.需要程度较高的开发人员,若对package的使用不熟,容易出trouble
■哪些东西可以开发成为Package
前面讲过,Package其实就是类似DLL的一种架构,但是是专门属于Borland C++Builder/Delphi使用的一种DLL架构,举凡有含Form的Unit文件、无Form的Unit文件(如自己写的函数库)、组件等等,都可以编译成为Package
■Package档案的类型
Package中的DCP文件,跟DLL项目的LIB文件类似,DCP是提供为静态连结编译之用(注意:只是静态连结的“编译过程”用之),BPL则是直接提供为执行环境之用;DCP只有在提供给别的EXE或BPL静态连结的“编译过程”中会用到,所以不用RELEASE到客户端;在执行环境中,Package不管是被静态联结或是动态连结使用,一律以BPL型式存在。 例如Project0.exe以“静态连结”方式使用到Package1,Project0.exe在编译时需要Package1.dcp的档案存在,但编译后分发到客户端的档案则为roject0.exe以及Package1.bpl(Package1.dcp不用release),虽然它们之间是使用静态连结(加载)… 如果Project0.exe以“动态连结”方式使用到Package1,Project0在编译过程中根本不需要任何Package1的档案,而分发到客户端一样仍然只有roject0.exe以及Package1.bpl。
■Package的载入(从EXE载入BPL的角度来看)
静态加载–不管用得用不到,该*.dcp是一定都要加载的,也就是在exe项目选项中的Builder with runtime packages->Add加入,如Project0.exe(MIS主系统)一定要加载VCL共享模块(*.dcp),否则无法产生GUI接口;所以就用静态加载的方式加载它;静态加载的*.dcp,是在编译时就已决定的 动态加载–使用到时,才透过LoadPackage()这个API来呼叫,如Project0.exe(MIS主系统)呼叫各个子系统的*.bpl,是透过Coding的方式去加载子系统的*.bpl,Project0.exe(MIS主系统)并不需要在编译时将所有子系统加载编译
■Package的载入(从BPL载入BPL的角度来看)
静态加载–放在Package项目之Requires区段中的*.dcp文件,反正是“一定要用到”的,不需要利用动态加载的就放在这儿 动态加载–跟EXE动态加载BPL方式相同,使用到时,才透过Coding方式利用LoadPackage()这个API来加载的
■Package项目的建立
在Delphi7.0整合环境中,主菜单->File->Close ALL关掉所有的Form及项目;然后再一次:主菜单->File->New->Other...->选择Package,建立一个全新的Package项目 一个全新的Package应该是长的如下图所示,分为两个部分:Contains内放的是项目的主题,也就是我们要为这个Package开发的程序代码;Require内放的是要“静态连结” 的其它Package(*.dcp文件),也就是不需要利用LoadPackage()这个API来加载(动态加载)的Package就放到Require中;rtl.dcp是系统内建就已Require的Package,应该是VCL之类的东西吧 接下来我们要开始设计项目内容,帮这个Package项目加入一个空白的Form,到Delphi主菜单->File->New->Form;我们再回到Project Manager看看在Contains区段是否多了Unit1(Form1);前面说过,Contains内放的是项目的主题,也就是我们要为这个Package开发的程序代码,接下来要在Form1中放什么组件,写什么程序代码,都跟一般的Form没什么两样,只是若这个Form是写在一般的项目中(Project1.dpr)它可以被编译成EXE文件,而在Package项目中(Package1.dpk),它只能被编译成Package1.dcp(给别的项目静态连结编译时用)和Package1.bpl Package1.dcp以及Package1.bpl这两个编译后的结果,Default是放到Delphi7.0目录的."Projects"Bpl"中;若要改变,请至Delphi主菜单->Project->Options(如下图),修改项目的输出目录路径为目前路径(.") 还有,很重要的一点,在Package项目中的Form由于将来会被别人加载使用(不管被静态或被动态加载);它都需要先向系统注册它的类别;所以在前面的例子中,将Unit1(Form1)开发好后,最后要在end.之前插入注册(RegisterClass)/注销(UnRegisterClass)的程序代码,注册内容就是自己的Form类别(如TForm1、TForm2等等)
■Package的应用限制
如果只是一个EXE文件附带一个BPL文件,这种架构还算单纯,但如果如文章开始所述:一个MIS主系统(Project0.exe)带着多个子系统(*.bpl),那会有什么限制发生呢? 1.各个Package(*.bpl)在开发过程中,彼此的Contains区段中不能有同名的Unit 2.共享的unit一定要放在package,也就是要把共享模块变成Package 我们现在来想想,如果是我们来主导这个系统,我们会如何设计呢? 1.虽然各项子系统是各自独立开发,甚至是交由不同的开发TEAM来完成,但为了接口的风格一致及操作统一(如Button的大小及位置),我们会有一个共通的BaseForm的雏形,让所有的子系统的主Form都由这个BaseForm继承而来,这样会让子系统(Package)的Contains区段都会有一个共同uses的BaseForm.pas 2.为了程序代码的一致性,也为了增加Coding速度,公司累积了程序代码经验,可能会有一个公用副函数集MySub供各个子系统呼叫,这样也会让子系统(Package)的Contains区段都会有一个共同uses的MySub.pas 为了不让BaseForm.pas及MySub.pas成为Package开发的限制瓶颈,所以我们要将BaseForm及MySub也变成Package(成为BaseForm.dcp及MySub.dcp),然后让各个子系统Package放在Requires中静态连结编译。
■Package的动态加载
前面已介绍了Package在静态加载以及编译的方法,现在要介绍Package应用的重头戏-动态加载;一般来说,共通的副函数或共享分享的数据库模块以及共享的继承样板会先被制作成Package,然后被主程序(EXE文件)及各个子系统模块(BPL文件)作为静态连结之用;而整个系统开发的主角,也就是各个子系统模块会被主程序或子系统模块(BPL文件)间,当成动态加载的目标。
注: 1.在上列的程序代码中,加载Package的LoadPackage()是系统内建函数 2.带出Package中的Form资源或是释放Package的函数由于要多做一些处理,所以把它包在CreateFormByClassName()以及UnloadAddInPackage()两个自订函数中
■完整的Package项目架构范例
全部评论
专题导读
热门推荐
热门话题
阅读排行榜
|
请发表评论