一个基于IPC$(共享文件夹)和 ZIP压缩算法的通用升级程序

由于公司的项目都是使用C/S模式开发,对于项目的维护肯定使用智能升级,在前几个项目中都是有针对性实现升级,反而对升级程序本身的维护也用了不少时间。为了使升级程序能达到一劳永逸,对每一个项目,多种特殊情况都能够使用,本人于是放弃了上任程序员的做法,对升级程序进行重构。具体的功能如下:

1、升级程序可以自身更新(即当发现升级程序本身存在缺陷或需求的改变等)。

2、要更智能化,适应更多的特殊情况,比如,在更新一个Windows Service 时要先把原来Windows事务删除,安装完成后要注册相关的OCX组件,启动事务等。

3、要有回滚功能,回滚后完全恢复原有的状态。

功能看起来不多,但要实现还真的要费一定的心思。

对于第二点,由于是特殊,每个项目都可能不相同,所以不能在更新程序中直接实现,否则这个更新程序就不能通用了,但又是必需的步骤才能使升级程序正常执行,于是本人使用模板设计模式,为用户留下一个执行动作的入口。用户可以自己写一些简单的插件或相关的批处理就可以实现这些特殊的需求,从而不需要对对升级程序本身进行更改。(在应用中,基本上通过批处理来实现已经达到)

所谓设计模板,是在配置文件(App.config)来实现的。先说说配置文件

1、版本号节点:记录升级包的版本,是客户端用来对比版本号使用。

    <!--文件更新版本号,只有比原来的大才能自动更新-->

    <add key="UpgradeVersion" value="2.0.0"/>

2、升级前要停止的进程名称及显示的标题。

    <!--更新标题-->

    <add key="ApplicationTitle" value ="XXXX系统"/>

    <!--进程中可能运行的程序的执行文件,用于检查进程是否在运行-->

    <add key="RunProgramName" value="XXXX系统.exe"/>

3、安装日志名称:只显示操作出错的信息

    <!--安装日志-->
    <add key="InstallLogFileName" value ="InstallLog.log"/>

 

4、升级包的根目录名称:(该配置可能是对ZIPSDK了解不够而进行的技术辅助配置)

    <!--不解压解压文件的根目录名称,为空表示全部-->

    <add key="UpZipRootName" value="LibRelease"/>

 

5、升级服务器的IP地址、用户名和密码(加密),升级目录的共享名等。此处使用自定义配置

  <!--FolderName 共享的文件夹共享名-->

  <UpgradeServerInfo

    UpgradeServerIP="172.31.112.123"

    UserID="6E50E42ED71D82F7D2A49223523EF3DB"

    UserPwd="A69A042C5FB14853DF2601A350DC22B9"

    FolderName="Upgradebag"/>

 

6、安装前的事件、回滚后事件、安装完成后的事件和要排除的更新文件:这些自定义节点为用户实现特殊功能提供入口。此处使用自定义配置,都使用同一个自定义节点元素FileInfo

    <InstallConfig>

    <!--安装前执行的批文件、其他工具等。 ExcuteType 可不写,如存在其值为 None(默认,相当于同步)SyncAsync-->

    <!--RunToolBeforeInstall工具的文件必需放在压缩包的外面,和配置文件一起-->

    <RunToolBeforeInstall>

      <add FileName="StopService.bat" ExcuteType="Sync"/>

    </RunToolBeforeInstall>

 

    <!--出错取消时回滚操作完成后执行的工具,不执行RunToolForInstallEnd配置, ExcuteType 可不写,如存在其值为 None(默认,相当于同步)SyncAsync-->

    <!--ShowWindow True 表示显示进程的Windows窗口默认为false-->

    <!--RunToolForRollBackEnd工具的文件必需放在压缩包的外面,和配置文件一起-->

    <RunToolForRollBackEnd>

      <!--<add FileName="StartService.bat" ExcuteType="Sync"/>-->

      <add FileName="notepad.exe" Arguments="InstallLog.log" ExcuteType="Async" ShowWindow="True"/>

    </RunToolForRollBackEnd>

 

    <!--需要从安装包排除的文件 ExcuteType 可不写,如存在其值为 None(默认,相当于同步)SyncAsync-->

    <ExcludeFileFromUpgrade>

      <add FileName=".xml"/>

      <add FileName="Upgrade.exe"/>

      <add FileName="Upgrade.exe.config"/>

      <add FileName="Update.exe"/>

      <add FileName="Update.exe.config"/>

    </ExcludeFileFromUpgrade>

 

    <!--完成文件的解压后运行的工具,包括.bat.exe可执行的文件, ExcuteType 值为 None(默认,相当于同步)SyncAsync-->

    <!--文件名(FileName)为主键,如果需要执行多个相同的可执行文件,可使用Bat文件来调用 在每行命令中使用start来启动可做到异步-->

    <!--ShowWindow True 表示显示进程的Windows窗口默认为false-->

    <!--Arguments 执行参数-->

    <!--RunToolForRollBackEnd工具的文件可放在压缩包的里,也可和配置文件一起-->

    <RunToolForInstallEnd>

      <!--<add FileName="StartService.bat" ExcuteType="Sync"/>-->

      <add FileName="InstallEnd.bat" ExcuteType="Async" ShowWindow="false"/>

      <add FileName="XXXX系统.exe" ExcuteType="Async" />

    </RunToolForInstallEnd>

 

    <!--所有的工具都会下载或解压到客户端,所以要做一个批文件删除这些工具,包括这个批文件本身-->

  </InstallConfig>

 

实现步骤:

1、根据指定的升级包位置判断是否存在新版本。更新前关闭主程序进程。

2、生成自更新的批处理文件和自恢复的批处理文件,该批处理文件是实现升级程序能更新自己的关键(此处只先复制配置文件,升级程序及安装前所需要的一些批处理文件,同时再次启动升级程序本身);复制前的备份操作。在关闭更新程序前启动批处理操作,进行下载升级包及抽取文件操作。

3、升级程序再次启动后(新的配置文件和更新程序及安装前的工具已经下载到本地),根据新配置执行安装前事件;从升级服务器下载所有的升级包(升级包采用ZIP压缩,因为ZIP算法是开源的)。此处使用指定缓存下载,实现下载的进度条。

4、采用SharpZLib对压缩包进行逐个文件解压,每解压一个文件前对原来存在的文件进行备份(备份也是使用SharpZLib进行压缩)。小插曲:在编码前下载最新的SharpZLib代码,也不知道源码出错Bug,还是我的了解不对,对原文件进行压缩后的压缩包不能进行再解压,后来只好使用前点的SharpZLib版本)。

5、安装完成后,执行安装后事件,包括显示安装日志,升级说明,运行主程序等。同时清除安装过程中产生的临时文件。

如果用户取消安装,执行回滚操作,删除新的解压文件,恢复原来的文件。同时清除安装过程产生的临时文件,执行自恢复的批处理文件,恢复原有的配置的升级程序本身等。(在回滚时对新建的文件夹不作处理)。

至此,事个安装程序的主要操作已完成。

安装程序的附加功能,通过带参数运行,显示加密数据工具。

手动更新时显示一个检查更新的进度条

/? 运行进显示一个控制台帮助等。

 

注:所有的安装事件是用户配置的一个同步进程或异步进程。

 

此升级程序是一个独立的可执行程序,在主程序可以通过进程调用的方式使用(主程序启动时的检查是在后台进行的,不显示任何消息,只有存在新版本时才提示用户升级);也可以通过快捷方式手动启动升级。

 

新版本预告:由于IPC$操作不是很好,很多服务器都屏蔽139445端口(或被被防火墙屏蔽),导致工程人员部署不成功,而且升级服务器为非Windows平台的OS也没有进行测试,所以决定改用Ftp服务器为升级服务器。

对比:在网络上存在一个版本是通过配置更新文件的做法,在使用上没有上升级程序方便。两种实现属优,大家按需选择。

    源码可通过QQ:179781134 索取,加为好友时需写明目的,否则一概不理。

      下一篇:一个基于csproj文件的C#编译器
      每个项目的模块都相当多,配置管理人员对每个模块进行编译的工作量很大......   

附录:App.config

app.config


附图:





posted @ 2009-08-16 21:49  Lance Yang  阅读(503)  评论(0编辑  收藏  举报