谁能提供一个PACKAGE的开发资料?
由于 用bcb在dll里面操作vcl组件 ansistring等等对象
都有些莫名其妙的问题
我想以后用package来封装 类和函数
但是我看开发指南 指写了很简单的一章节 没有详细说明
如何导出一个类 一个函数
我恳求大家提供我一些package开发的资料
最好能给我看看代码,package 部分 以及 如何在代码里面 象用dll那样调用package
[解决办法]
作者:李维
相信许多人和我一样,在使用Delphi开发应用系统的时候,一定会想到如何的切割整个应用系统。是把所有的子系统撰写成一个很大(可能会有数M.Bytes的大小)的EXE檔呢?还是应该把每一个模组撰写在不同的EXE檔案之中的好。
事实上这两种方法都有它们自己的问题。如果是把所有的模组撰写在一个EXE檔案之中的话,那么不但执行檔太大,不易更新和维护。在开发时也不甚方便,因为要让数个人撰写同一支应用程式的确比较麻烦。那么如果我们把每一个模组让不同的程式师撰写成独立的EXE檔案,再由一个主程式分别启动不同的EXE檔不就好了吗?没错这是许多人使用的方法(包括我在内),但是这样切割应用系统有一个问题,那就是如果每一个独立的EXE模组,都需要使用资料库的话,那么当主程式启动个别的EXE檔案时,每一个EXE都必须重新再连结到资料库,开启资料库表格,再取得它需要的资料。这个过程通常都需要不少的时间。例如连结到Oracle并且开启一个资料库表格的话,通常需要五到十秒。如果EXE开启的资料库表格或是查询比较多的话,那么主程式在启动独立的EXE檔案时,通常需要30几秒到一分钟不等。这对于许多的使用者而言是非常不方便的。这样的状状甚至会造成你的专案无法交货(例如使用者要求在五秒之内EXE程式的画面必须出现)。除此之外,每一个独立的EXE又使用了额外的连结以便存取资料库,造成了资源的浪费。面对这种二难的局面,你现在的选择是什么呢?
事实上这个问题在我的心中也盘旋了许久。因为这一是我想要解决的问题,只是由于工作的繁忙让我一直无法花时间解决它。最近在手上的事情告一段落之后,又接到许多朋友的询问,所以决定花一些时间试着解决这个重要的问题。
增加应用程式载入的效率
如果我们仔细的思考这个问题的话,就可以发现问题出在每一支独立的EXE都需要重复的连结资料库所至。所以如果我们可以让连结到资料库的次数减少的话,不就可以加快应用程式载入的效率了吗?
这个想法当然很简单,但是问题是要如何的减少应用程式连结资料库的次数呢?事实上这个想法也很简单,最好是让应用系统连结资料库的次数变成一次,如此一来除了主程式需要连结资料库之外,其他的应用模组都能够公同使用由主程式载入的资料模组的话,那么一切问题不都解决了吗?请注意,在这里我所说的其他模组代表独立的EXE或是其他形式的应用程式,而不是指在单一一个EXE之中不同的表格或是子系统。
我们可以使用图一来表示这个想法。在这个构想中,我希望由应用主程式先负责载入公用的资料模组。在这个资料模组之中有其他子系统需要使用各个资料库表格,如此一来当主程式启动其他的子系统时,就不需要再让每一个子系统再连结,开启资料库表格了。
当这样还有一些设计上的问题,我们稍后再回来讨论这个问题,现在先我们看看如何的把这个构想实做出来,并且测试一下实际的结果是不是真的比较有效率。
要实做这个构想,我们必须想办法让公用的资料模组能够让每一个子系统存取到,并且不再需要每一个子系统都分别的和资料库建立一个连结的Session。我的第一个想法是使用DLL来解决这个问题。但是事实上使用DLL无法解决这个问题。在我花费了许多的时间之后,使用DLL仍然有会有AccessViolation的错误。我也曾在网路上搜寻相关的问题或是资料,我在宝兰的DiscussForum中也看到有人提出类似的问题,但是似乎都没有人确实的回答这个问题。我也想过干脆拿出我的Soft-Ice和Bounds-Checker看看为什么使用DLLAssembly打交道,这实在不是件好玩的事情。正打算放弃之时,突然想到Delphi3.0之中的Package不正是解决这个问题的好方法吗?于是我就决定试试看,果然一击中地,顺利的解决了这个问题。当然,要知道为什么使用Package可以解决这个问题,你需要知道Package和DLL的异同。
DLL和Package
为什么在我一开始使用DLL时无法解决多个模组共用一个资料模组DLL的问题呢?这主要是因为在Win95/NT中当每一个模组载入DLL时,对于每一个DLL之中的全域变数而言,每一个模组都会有一份独立的变数。这是什么意思呢?我们可以使用图二来说明。
图 二 Win 95/NT 中 全 域 变 数 和 模 组 的 关 系
当图二中的模组一和模组二分别的载入它们共用的DLL时,虽然在这个共用的DLL中有一个全域变数gAccount。但是模组一和模型二会分别的拥有一个gAccount变数。这也就是说模组一对于gAccount变数数值所做的修改并不会影响模组二中的gAccount变数数值。在Wn95/NT中的DLL行为是和Win3.x不同的,因为在Win3.x中所有的模组都使是共用一份DLL中的全域变数。
由于Win95/NT中DLL全域变数的这种特性,所以当你想把资料模组撰写在DLL之中让多个模组共同使用时,问题就来了。因为在这种情形下,每一个模组都会有一份它自己的资料模组。所以当每一个应用程式模组载入资料模组的DLL时,它仍然会连结资料库一次,所以你并无法减少连结资料库的次数。
那么使用Package有什么不同吗?在回答这个问题之前,请你先回想一下。在Delphi3.x中它允许你使用Package的功能来编译你的应用程式,如图三所示。
图 三 Delphi 3.x 允 许 你 使 用Package 的 功 能 编 译 应 用 程序
使用Package编译应用程式的好处除了可以减少应用程式的大小之外,事实上Package还有一个很重要的特性,那就是Package允许多个模组共用所有的全域变数。
我们可以使用图四来说明Package的特性。请你想一想,当你的应用程式使用Package的功能时,事实上它必须载入许多不同的Packages。不管你的应用程式是否使用了全域变数Application,许多的Packages都会使用Application这个全域变数。由于全域变数Application是存在于VCL.DPL之中,所以如果Application会对于每一个载入它的模组都产生一份独立的全域变数的话,那么整个应用程式便会产生不正确的结果。 所以由这个说明我们可以知道,在图四中的Application和Screen等全域变数对于所有使用它的模组而言一定是只有一份全域变数。
图 四 Package 中 全 域 变 数 的 特 性
事实上在Forms.PAS之中的程式码也透露着这些蛛丝马迹。例如下面便是Forms.PAS宣告Application和Screen这二个变数的程式码。从它们的注释中我们可以清楚的看到,它们是全域物件,即使是编译成Package时也是一样。