引言
解压缩软件不应该固步自封,完全可以扩展到安装制作领域,本文引入触发器的概念,权作抛砖引玉。
一 、触发器
纯粹的解包过程就是把包里的目录和文件还原到指定物理路径中的过程,我们常用的winzip、winrar等解压缩软件就属于这一类。安装过程实际上就是解包过程加上某种配置和控制过程,例如,需要自注册com组件,需要创建虚拟目录,需要向注册表写信息,需要创建快捷方式等等。触发器就是用来控制和扩展解包过程的插件,通过定制触发器就可以完成大部分的安装配制过程。软件厂商可以提供事先定制好的具有某些功能的触发器,用户只要按指定格式配置就能完成需要的配置和控制操作,同时用户又可以自定义触发器。共有四种类型的触发器:
(1) 解包前
(2) 分解元素前
(3) 分解元素后
(4) 解包后
元素:指文件或目录,包也是一种元素。
分解:指还原。
分解元素:指还原文件或还原目录。
“分解目录后”是指该目录下的所有子目录和文件都被还原结束后。
二、设计触发器
触发器是按照一定规范开发出来的普通dll,该dll必须导出一个名为execute的函数。
每个元素都可以有多个触发器。也就是说,每个元素可以有多个分解前触发器,也可以有多个分解后触发器,这些触发器会被依次执行。但是,只要有一个分解前触发器表示反对,则该元素的分解过程将被取消,分解后触发器也将不会被执行。
(1)原型声明:
extern “c” __declspec(dllexport) long __stdcall execute(element *pele)
(2)枚举常量:
enum {etfile, etdir, etpack}; // 元素类型:文件、目录、包。
enum {tsbefore, tsafter}; // 触发条件:分解前、分解后。
(3)输入参数:
typedef struct
{
hwnd m_hwnd; // 主窗口句柄
idispatch* m_pxmldoc; // 解包用xml控制文件
char m_szpackpath[max_path]; // 用户指定的解包物理全路径。
char m_szelementpath[max_path]; // 当前要分解的文件或目录在包里的全路径。
long m_nelementtype; // 元素类型。
long m_ntriggersituation; // 触发条件。
} element;
(4)返回值:
(a)-1:退出整个解包过程;
(b)0:取消本元素的分解过程;(仅对分解前触发器有效)
(c)1:成功;
(5)错误描述
解包过程在调用触发器时可能会发生错误,原因如下:
(a) 不是有效的dll文件;
(b) dll文件不存在;
(c) 未导出execute函数;
(d) execute函数原型不正确;
(e) execute函数体执行异常;
解包过程在检测到上述错误时将询问是继续运行还是退出整个解包过程。
显然,如果上述错误发生在元素分解前,则该元素的分解过程将被取消,分解后触发器也将不会被执行。
三、配置触发器
(1)格式
<xyunpack package=”xysetup.cpd” unpackpath=”c:\program files\software\freesky\budget”>
<trigger>
<common filename="xx1.dll" for="file/dir/pack/all" when="before/after/all" />
<single filename="xx1.dll" for="test1\1.doc" when="before/after/all" />
<single filename="xx2.dll" for="test1\test2" when="before/after/all" />
<single filename="xx3.dll" for="" when="before/after/all" />
</trigger>
</xyunpack>
(2)说明
(a) 可以为每个元素配置独立触发器,此时使用<single>标记,filename表示触发器的文件名,for表示目标元素在包里的全路径,when表示触发条件。特别注意的是,for=""表示的是包。
(b) 可以为所有元素设置通用触发器,此时使用<common>标记,filename表示触发器的文件名,for表示元素类型,when表示触发条件。
(c) 如果一个元素上既有“通用触发器”又有“独立触发器”,则不管是在分解前还是在分解后,总是先执行“通用触发器”后执行“独立触发器”。
四、内置触发器
比如,解包过程可以内置一些“包分解后”类型的触发器,功能及配置如下所述。
(1) 创建虚拟目录
<xyunpack>
<trigger>
</trigger>
<virtualdirectory>
<add name=”budget” path=”test1” />
<add name=”budgetwebservice1” path=”test2\test3” createnew=”1” />
<add name=”budgetwebservice2” path=”” />
</virtualdirectory>
</xyunpack>
注:name表示虚拟目录名,path表示和该虚拟目录对应的包里的目录的全路径。特别注意的是,path=""表示的是用户指定的解包的物理路径。当虚拟目录已经存在且createnew=”1”时则先删除再创建。
(2) 注册com组件
<xyunpack>
<trigger>
</trigger>
<virtualdirectory>
</virtualdirectory>
<regserver>
<add path=”test1\1.dll” />
<add path=”test1\test2\2.dll” copyto=”%win%” />
<add path=”test1\test2\3.dll” copyto=”%win%” noreg=”1” />
</regserver>
</xyunpack>
注:path表示需要注册的包里的文件的全路径。copyto表示先拷贝到指定的物理目录(也可以是%win%,%sys%,%temp%)再注册,指定的物理目录如果不存在将自动创建。有时可能仅仅要把文件拷贝到其他物理目录而不需要注册,就可以设置noreg属性。
(3) 写注册表
<xyunpack>
<trigger>
</trigger>
<virtualdirectory>
</virtualdirectory>
<regserver>
</regserver>
<regedit>
<add key=” hkey_local_machine\software\microsoft” name=”user” value=”sa” />
<add key=” hkey_current_user\software\microsoft” name=”user” value=”sa” />
</regedit>
</xyunpack>
(4) 运行exe程序
<xyunpack>
<trigger>
</trigger>
<virtualdirectory>
</virtualdirectory>
<regserver>
</regserver>
<regedit>
</regedit>
<exename>