好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

一个升级程序

一个升级程序

一个升级程序

日前收到一个小任务,要做一个通用的在线升级程序。更新的内容包括一些dll或exe或、配置文件。升级的大致流程是这样的,从服务器获取一个更新的配置文件,经过核对后如有新的更新,则会从服务器下载相应的文件更新到被升级的程序目录下。如果被升级的程序在升级之前已经启动,程序则会强制关闭它,待到升级完成之后重新启动相应的程序。在升级之前程序会自动备份一次,以防升级失败造成程序不能运行。

首先来的是数据实体

  1       public   class   FileENT
   2       {
   3           public   string  FileFullName {  get ;  set  ; }
   4  
  5           public   string  Src {  get ;  set  ; }
   6  
  7           public   string  Version {  get ;  set  ; }
   8  
  9           public   int  Size {  get ;  set  ; }
  10  
 11           public  UpdateOption Option {  get ;  set  ; }
  12       }
  13  
 14       public   enum   UpdateOption
  15       {
  16           add,
  17           del
  18      }

下面这个类时程序的一些参数,包括了系统的配置参数,为了程序能通用一点,就加了配置上去。

  1       public   class   AppParameter
   2       {
   3           ///   <summary> 
  4           ///   备份路径
   5           ///   </summary> 
  6           public   static   string  BackupPath = ConfigurationManager.AppSettings[ "  backupPath  "  ];
   7  
  8           ///   <summary> 
  9           ///   更新的URL
  10           ///   </summary> 
 11           public   static   string  ServerURL = ConfigurationManager.AppSettings[ "  serverURL  "  ];
  12  
 13           ///   <summary> 
 14           ///   本地更新文件全名
  15           ///   </summary> 
 16           public   static   string  LocalUPdateConfig = ConfigurationManager.AppSettings[ "  localUPdateConfig  "  ];
  17  
 18           ///   <summary> 
 19           ///   版本号
  20           ///   </summary> 
 21           public   static   string  Version = ConfigurationManager.AppSettings[ "  version  "  ];
  22  
 23           ///   <summary> 
 24           ///   更新程序路径
  25           ///   </summary> 
 26           public   static   string  LocalPath =  AppDomain.CurrentDomain.BaseDirectory;
  27  
 28           ///   <summary> 
 29           ///   主程序路径
  30           ///   </summary> 
 31           public   static   string  MainPath = ConfigurationManager.AppSettings[ "  mainPath  "  ];
  32  
 33           ///   <summary> 
 34           ///   有否启动主程序
  35           ///   </summary> 
 36           public   static   bool  IsRunning =  false  ;
  37  
 38           ///   <summary> 
 39           ///   主程序名
  40           ///   </summary> 
 41           public   static  List< string > AppNames = ConfigurationManager.AppSettings[ "  appName  " ].Split( '  ;  '  ).ToList();
  42      }

接着就介绍程序的代码

程序是用窗体来实现的,下面三个是窗体新添加的三个字段

 1           private   bool  isDelete= true ;  //  是否要删除升级配置 
 2           private   bool  runningLock =  false ; //  是否正在升级 
 3           private  Thread thread;  //  升级的线程 

载入窗体时需要检查更新,如果没有更新就提示”暂时无更新”;如果有更新的则先进行备份,备份失败的话提示错误退出更新。

  1               if   (CheckUpdate())
   2               {
   3                   if  (! Backup())
   4                   {
   5                      MessageBox.Show( "  备份失败!  "  );
   6                      btnStart.Enabled =  false  ;
   7                      isDelete =  true  ;
   8                       return  ;
   9                   }
  10  
 11               }
  12               else 
 13               {
  14                  MessageBox.Show( "  暂时无更新  "  );
  15                   this .btnFinish.Enabled =  true  ;
  16                   this .btnStart.Enabled =  false  ;
  17                  isDelete =  false  ;
  18                   this  .Close();
  19              }

在这些操作之前还要检测被更新程序有否启动,有则将其关闭。

  1              List< string > processNames =  new  List< string > ();
   2               string  mainPro =  string  .Empty;
   3               processNames.AddRange(AppParameter.AppNames);
   4               for  ( int  i =  0 ; i < processNames.Count; i++ )
   5               {
   6                  processNames[i] = processNames[i].Substring(processNames[i].LastIndexOf( '  \\  ' )).Trim( '  \\  ' ).Replace( "  .exe  " ,  ""  );
   7               }
   8              mainPro =  processNames.FirstOrDefault();
   9              AppParameter.IsRunning =  ProcessHelper.IsRunningProcess(mainPro);
  10               if   (AppParameter.IsRunning)
  11               {
  12                  MessageBox.Show( "  此操作需要关闭要更新的程序,请保存相关数据按确定继续  " ,  "  提示  "  , MessageBoxButtons.OK, MessageBoxIcon.Warning);
  13                   foreach  ( string  item  in   processNames)
  14                       ProcessHelper.CloseProcess(item);
  15              }

另外上面用到的CheckUpdate( )和Backup( )方法如下

  1             ///   <summary> 
  2           ///   检查更新 有则提示用户 确认后下载新的更新配置
   3           ///   </summary> 
  4           ///   <returns>  用户确认信息  </returns> 
  5           public   static   bool   CheckUpdate()
   6           {
   7               bool  result =  false  ;
   8  
  9              HttpHelper.DownLoadFile(AppParameter.ServerURL, AppParameter.LocalPath +  "  temp_config.xml  "  );
  10               if  (! File.Exists(AppParameter.LocalUPdateConfig))
  11                  result =  true  ;
  12               else 
 13               {
  14                   long  localSize =  new   FileInfo(AppParameter.LocalUPdateConfig).Length;
  15                   long  tempSize =  new  FileInfo(AppParameter.LocalPath +  "  temp_config.xml  "  ).Length;
  16  
 17                   if  (localSize >= tempSize) result =  false  ;
  18  
 19                   else  result =  true  ;
  20               }
  21  
 22               if   (result)
  23               {
  24                   if   (File.Exists(AppParameter.LocalUPdateConfig)) File.Delete(AppParameter.LocalUPdateConfig);
  25                  File.Copy(AppParameter.LocalPath +  "  temp_config.xml  "  , AppParameter.LocalUPdateConfig);
  26               }
  27               else 
 28                  result =  false  ;
  29  
 30              File.Delete(AppParameter.LocalPath +  "  temp_config.xml  "  );
  31               return   result;
  32           }
  33  
 34           ///   <summary> 
 35           ///   备份
  36           ///   </summary> 
 37           public   static   bool   Backup()
  38           {
  39               string  sourcePath = Path.Combine(AppParameter.BackupPath, DateTime.Now.ToString( "  yyyy-MM-dd HH_mm_ss  " )+ "  _v_  " +AppParameter.Version +  "  .rar  "  );
  40               return   ZipHelper.Zip(AppParameter.MainPath.Trim() , sourcePath);
  41          }

下面则是更新的部分的代码,使用了多线程,出于两方面的考虑,一是进度条需要;二是如果用单线程,万一更新文件下载时间过长或者更新内容过多,界面会卡死。

   1           ///   <summary> 
   2           ///   更新
    3           ///   </summary> 
   4           public   void   UpdateApp()
    5           {
    6               int  successCount =  0  ;
    7               int  failCount =  0  ;
    8               int  itemIndex =  0  ;
    9              List<FileENT> list =  ConfigHelper.GetUpdateList();
   10               if  (list.Count ==  0  )
   11               {
   12                  MessageBox.Show( "  版本已是最新  " ,  "  提示  "  , MessageBoxButtons.OK, MessageBoxIcon.Information);
   13                   this .btnFinish.Enabled =  true  ;
   14                   this .btnStart.Enabled =  false  ;
   15                  isDelete =  false  ;
   16                   this  .Close();
   17                   return  ;
   18               }
   19              thread =  new  Thread( new  ThreadStart( delegate 
  20               {
   21                   #region  thread method
  22  
  23                  FileENT ent =  null  ;
   24  
  25                   while  ( true  )
   26                   {
   27                       lock  ( this  )
   28                       {
   29                           if  (itemIndex >=  list.Count)
   30                               break  ;
   31                          ent =  list[itemIndex];
   32  
  33  
  34                           string  msg =  string  .Empty;
   35                           if   (ExecUpdateItem(ent))
   36                           {
   37                              msg = ent.FileFullName +  "  更新成功  "  ;
   38                              successCount++ ;
   39                           }
   40                           else 
  41                           {
   42                              msg = ent.FileFullName +  "  更新失败  "  ;
   43                              failCount++ ;
   44                           }
   45  
  46                           if  ( this  .InvokeRequired)
   47                           {
   48                               this .Invoke((Action) delegate  ()
   49                               {
   50                                   listBox1.Items.Add(msg);
   51                                   int  val = ( int )Math.Ceiling(1f / list.Count *  100  );
   52                                  progressBar1.Value = progressBar1.Value + val >  100  ?  100  : progressBar1.Value +  val;
   53                               });
   54                           }
   55  
  56  
  57                          itemIndex++ ;
   58                           if  (successCount + failCount == list.Count &&  this  .InvokeRequired)
   59                           {
   60                               string  finishMessage =  string  .Empty;
   61                               if  ( this  .InvokeRequired)
   62                               {
   63                                   this .Invoke((Action) delegate  ()
   64                                   {
   65                                      btnFinish.Enabled =  true  ;
   66                                   });
   67                               }
   68                              isDelete = failCount !=  0  ;
   69                               if  (! isDelete)
   70                               {
   71                                  AppParameter.Version =  list.Last().Version;
   72                                  ConfigHelper.UpdateAppConfig( "  version  "  , AppParameter.Version);
   73                                  finishMessage =  "  升级完成,程序已成功升级到  "  +  AppParameter.Version;
   74                               }
   75                               else 
  76                                  finishMessage =  "  升级完成,但不成功  "  ;
   77                              MessageBox.Show(finishMessage,  "  提示  "  , MessageBoxButtons.OK, MessageBoxIcon.Information);
   78                              runningLock =  false  ;
   79                           }
   80                       }
   81                   }
   82                   #endregion 
  83               }));
   84              runningLock =  true  ;
   85               thread.Start();
   86           }
   87  
  88           ///   <summary> 
  89           ///   执行单个更新
   90           ///   </summary> 
  91           ///   <param name="ent"></param> 
  92           ///   <returns></returns> 
  93           public   bool   ExecUpdateItem(FileENT ent)
   94           {
   95               bool  result =  true  ;
   96  
  97               try 
  98               {
   99  
 100                   if  (ent.Option ==  UpdateOption.del)
  101                       File.Delete(ent.FileFullName);
  102                   else 
 103                       HttpHelper.DownLoadFile(ent.Src, Path.Combine(AppParameter.MainPath, ent.FileFullName));
  104               }
  105               catch  { result =  false  ; }
  106               return   result;
  107          }

  只开了一个子线程,原本是开了5个子线程的,但是考虑到多线程会导致下载文件的顺序不确定,还是用回单线程会比较安全。线程是用了窗体实例里的thread字段,在开启线程时还用到runningLock标识字段,表示当前正在更新。当正在更新程序时关闭窗口,则要提问用户是否结束更新,若用户选择了是则要结束那个更新进程thread了,下面则是窗口关闭的时间FormClosing事件的方法。

 

  1               if   (runningLock )
   2               {
   3                   if  (MessageBox.Show( "  升级还在进行中,中断升级会导致程序不可用,是否中断  "  ,
   4                             "  提示  " , MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk) ==  DialogResult.Yes)
   5                   {
   6                       if  (thread !=  null  ) thread.Abort();
   7                      isDelete =  true  ;
   8                      AppParameter.IsRunning =  false  ;
   9                   }
  10                   else  
 11                   {
  12                      e.Cancel =  true  ;
  13                       return  ;
  14                   }
  15               }
  16               if  (isDelete) File.Delete(AppParameter.LocalUPdateConfig);

在这里还要做另一件事,就是把之前关了的程序重新启动。

 1               try 
 2               {
  3                   if   (AppParameter.IsRunning) ProcessHelper.StartProcess(AppParameter.AppNames.First());
  4               }
  5               catch   (Exception ex)
  6               {
  7  
 8                  MessageBox.Show( "  程序无法启动!  "  + ex.Message,  "  错误  "  , MessageBoxButtons.OK, MessageBoxIcon.Error);
  9              }

在这里展示一下更新的界面。挺丑的,别笑哈。

更新程序的配置信息如下

 1     <  appSettings  > 
 2       <  add   key  ="backupPath"   value  ="C:\Users\Administrator\Desktop\temp\backup"  /> 
 3       <  add   key  ="serverURL"   value  ="http://localhost:8015/updateconfig.xml"  /> 
 4       <  add   key  ="localUPdateConfig"   value  ="E:\HopeGi\Code\MyUpdate\MyUpdate\bin\Debug\updateconfig.xml"  /> 
 5       <  add   key  ="version"   value  ="2"  /> 
 6       <  add   key  ="mainPath"   value  ="C:\Users\Administrator\Desktop\temp\main"  /> 
 7       <  add   key  ="appName"   value  ="D:\test.exe"  /> 
 8     </  appSettings  > 

 这里有个链接下代码 MyUpdate.rar

 

 

分类:  C#

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于一个升级程序的详细内容...

  阅读:41次

上一篇: C#发送DKIM签名的邮件

下一篇:推荐系统