CnPackTip#8 什么是运行期包与设计期包
参与讨论: JingYu, Passion, 小夏
整理: SkyJacker 2007.10.16, 2007.11.05
======================================================================
1. 内容简介
======================================================================
本文档深入明了的阐述了什么是运行期包、设计期包
同时解释了产生 DesignIntf 错误的原因
======================================================================
2. 正文
======================================================================
本文以 CnPack.dpk (运行期包)、dclCnPack.dpk (设计期包)为例说明。这
两个包,一个是运行期包,另一个是设计期包,设计期包包含有组件编辑器。
组件包通常按运行期包和设计期包两个包来发布,其中运行期包中包含了应
用程序编译实际需要的单元,而组件编辑器、属性编辑器这些专门为 IDE 设计
期编写的代码在应用程序的 exe 中是不需要的,所以组件源码中会将这些设计
编辑器的代码放到单独的 pas 文件中,这些包含设计期 pas 的单元只在设计期
包的 dpk 中包含,甚至于那些向 IDE 中注册组件的 Register 函数也可以不放
在组件单元中。
设计期包引用了运行期包, Delphi 的包技术是基于 unit 的,实际上
build with runtime package 时,是在连接期,将对程序引用到的单元的连接
变成对运行包的外部引用。
这样来说吧,我们要编写一个在 IDE 中可以安装使用的组件,需要有一个
TMyComp 组件的实现,然后有一个 Register 函数将组件注册到 IDE 控件面板。
如果这个组件的属性需要编辑器,或者组件本身有编辑器,还需要写一些编
辑器的代码。这些在 IDE 中用来编辑组件及其属性的代码,对应用程序来说是
没有意义的注册组件,编辑器的 Register 函数对应用程序也是没有意义的,
而且这些编辑器是依赖于 IDE 的 ToolsAPI、DesnIntf 等 OTA 单元。
如果和 TMyComp 的代码放在一个 pas 中编译的时候,应用程序就还需要间
接引用到 IDE 的这些 OTA 单元,而事实上这样处理是不适当的。
所以开发组件包的作者,就引入了运行期包和设计期包两个概念,将那些应
用程序需要编译到 exe 中的源代码放在组件实现的 pas 单元中,比如
dclCnPack_D7.dpk的内容,里头包括的 unit,都是应用程序中用不到的,只在
IDE 里头使用。
这些 pas 都包含在运行期包的 dpk 文件中。运行期包在工程选项中,是设
置为 Runtime only 模式。只能用于运行期,不能进行安装。所以我们在 IDE
中打开 CnPack_D7.dpk 文件,点 Install 是会提示错误的组件的注册、编辑器
这些内容,很显然是要引用到组件本身的代码的。
当然,对于单个组件,可能觉得分开写这两个单元太麻烦。但对于大型的组
件包,这样分开设计就很明了了。
CnPack 的组件代码结构基本上就是按这个原则来处理的。
比如包含 TMyComp 组件的代码在 MyComp.pas 里,而针对 TMyComp 的组件
注册和编辑器,则放在 MyCompEditor.pas 里头。在 MyCompEditor.pas 中
uses MyComp 这个单元就行了,一份是纯运行期包,一份是在运行期包外附加的
设计期代码。
Register 函数也应该放在 MyCompEditor.pas 中,这个函数应用程序的
exe 是不调用的。当然,放在 MyComp 中也不会出错。
如果只是注册组件,由于 RegisterComponents 在 Classes 中定义,所以
没什么问题,但是如果要注册属性编辑器 RegisterPropertyEditor ,则是在
DesignIntf 中定义的。DesignIntf 这个单元对应用程序来说根本没有用处的只
是 IDE 提供的设计期接口。如果将 Register 函数放在组件实现代码中,间接
引用到单元,就可能导致用户在安装编译组件时出现找不到DesignIntf 的错误,
因为 DesignIntf 等单元默认是不在 IDE 的搜索路径中的。
从 D6 开始,有个设计期的单元没有放出源码来(Proxies.dcu),在 D6
以上版本的 DesignEditor.pas 中,实现部分引用到了这个单元,而 Borland
没有提供源码,导致大量组件运行期编译不过。
Proxies 这个单元好象是在 dsnIDEXX.bpl 里头引用了 DesignEditor 的组
件,安装到 IDE 中时没有问题,是因为设计期包是带 dsnIDE.bpl 编译的,而
应用程序编译就通不过了。
所以我们提倡设计期包与运行期包分开,基本上正规点的组件包都是按这个
方法做的。
下面是一个关于 CnPack.dpk (运行期包)、dclCnPack.dpk 的安装顺序例子:
1、如果先安装 CnPack.dpk 会提示以下错误:
Error:
Package c:\program files\Borland\delphi6\Projects\Bpl\CnPack_D6.bpl
can't be installed because it is not a design time package.
2、如果直接安装 dclCnPack 就不会有这个问题。
因为 dclCnPack 引用了 CnPack.dpk,IDE 会自动先去编译后者
(CnPack.dpk),再来安装前者(dclCnpack.dpk)。
前面也提到了,运行期包的工程中设置了 Runtime only,不允许做为设计期包
安装,而设计期包的工程选项中设置了 Design only,不允许作为运行期包使用,
这样就强制对两个包的用途区分开了。