c# 自动更新程序

  • A+
所属分类:.NET技术
摘要

首先看获取和更新的接口更新程序Program.cs更新程序界面定义服务端接口,你可以用任意接口都行,我这里用webapi

首先看获取和更新的接口

更新程序Program.cs

c# 自动更新程序c# 自动更新程序

  1 using System;   2 using System.Collections.Generic;   3 using System.Diagnostics;   4 using System.IO;   5 using System.Linq;   6 using System.Threading.Tasks;   7 using System.Windows.Forms;   8    9 namespace Update  10 {  11     static class Program  12     {  13         /// <summary>  14         /// 更新程序启动后复制自身,使用副本进行更新  15         /// -h 不显示界面  16         /// -c 不使用copy更新程序  17         /// -d 更新完成删除自身,通常用在copy的更新程序  18         /// -b 更新下载到备份文件,不替换原文件  19         /// -r 更新完成运行的文件,下一个参数为文件路径  20         /// -k 如果系统正在运行则干掉  21         /// </summary>  22         [STAThread]  23         static void Main(string[] args)  24         {  25             Application.EnableVisualStyles();  26             Application.SetCompatibleTextRenderingDefault(false);  27             Application.ThreadException += Application_ThreadException;  28               29             List<string> lst = args.ToList();  30             if (!lst.Contains("-b") && !lst.Contains("-k"))  31             {  32                 //这里判断成程序是否退出  33                 if (Process.GetProcessesByName("serviceclient").Length > 0)  34                 {  35                     MessageBox.Show("服务正在运行,请退出后重试。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);  36                     return;  37                 }  38             }  39   40             if (lst.Contains("-k"))  41             {  42                 var ps = Process.GetProcessesByName("serviceclient");  43                 if (ps.Length > 0)  44                 {  45                     ps[0].Kill();  46                 }  47             }  48   49             //副本更新程序运行  50             if (!lst.Contains("-c"))//不存在-c 则进行复制运行  51             {  52                 string strFile = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), Guid.NewGuid().ToString() + ".exe");  53                 File.Copy(Application.ExecutablePath, strFile);  54                 lst.Add("-c");  55                 lst.Add("-d");  56                 Process.Start(strFile, string.Join(" ", lst));  57             }  58             else  59             {  60                 Action actionAfter = null;  61                 //将更新文件替换到当前目录  62                 if (!lst.Contains("-b"))  63                 {  64                     actionAfter = () =>  65                     {  66                         string strUpdatePath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "UpdateCache\");  67                         if (Directory.Exists(strUpdatePath) && Directory.GetFiles(strUpdatePath).Length > 0)  68                         {  69                             CopyFile(strUpdatePath, System.AppDomain.CurrentDomain.BaseDirectory, strUpdatePath);  70                             if (File.Exists(Path.Combine(strUpdatePath, "ver.xml")))  71                                 File.Copy(Path.Combine(strUpdatePath, "ver.xml"), Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "ver.xml"), true);  72                             Directory.Delete(strUpdatePath, true);  73                         }  74                     };  75                 }  76                 try  77                 {  78                     //隐藏运行  79                     if (!lst.Contains("-h"))  80                     {  81                         Application.Run(new FrmUpdate(actionAfter, true));  82                     }  83                     else  84                     {  85                         FrmUpdate frm = new FrmUpdate(actionAfter);  86                         frm.Down();  87                     }  88                 }  89                 catch (Exception ex)  90                 { }  91                 //运行更新后的文件  92                 if (lst.Contains("-r"))  93                 {  94                     int index = lst.IndexOf("-r");  95                     if (index + 1 < lst.Count)  96                     {  97                         string strFile = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, lst[index + 1]);  98                         if (File.Exists(strFile))  99                         { 100                             Process.Start(strFile, "-u"); 101                         } 102                     } 103                 } 104                 //删除自身 105                 if (lst.Contains("-d")) 106                 { 107                     DeleteItself(); 108                 } 109             } 110             Application.Exit(); 111             Process.GetCurrentProcess().Kill(); 112         } 113  114         private static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) 115         { 116             throw new NotImplementedException(); 117         } 118         private static void CopyFile(string strSource, string strTo, string strBasePath) 119         { 120             string[] files = Directory.GetFiles(strSource); 121             foreach (var item in files) 122             { 123                 string strFileName = Path.GetFileName(item).ToLower(); 124  125                 if (strFileName == "ver.xml ") 126                 { 127                     continue; 128                 } 129                 //如果是版本文件和文件配置xml则跳过,复制完成后再替换这2个文件 130                 string strToPath = Path.Combine(strTo, item.Replace(strBasePath, "")); 131                 var strdir = Path.GetDirectoryName(strToPath); 132                 if (!Directory.Exists(strdir)) 133                 { 134                     Directory.CreateDirectory(strdir); 135                 } 136                 File.Copy(item, strToPath, true); 137             } 138             string[] dires = Directory.GetDirectories(strSource); 139             foreach (var item in dires) 140             { 141                 CopyFile(item, strTo, strBasePath); 142             } 143         } 144  145  146         private static void DeleteItself() 147         { 148             ProcessStartInfo psi = new ProcessStartInfo("cmd.exe", "/C ping 1.1.1.1 -n 1 -w 1000 > Nul & Del " + Application.ExecutablePath); 149             psi.WindowStyle = ProcessWindowStyle.Hidden; 150             psi.CreateNoWindow = true; 151             Process.Start(psi); 152         } 153     } 154 }

View Code

更新程序界面

c# 自动更新程序c# 自动更新程序

using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Net; using System.Security.Cryptography; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using System.Xml;  namespace HW.Print.ServiceClient.Update {     public partial class FrmUpdate : Form     {         private static string m_strkey = "sdfadsfdsfasdf";//定义一个密钥用以验证权限,不适用ticket         Random r = new Random();         Action m_actionAfter = null;         bool m_blnShow = false;         public FrmUpdate(Action actionAfter, bool blnShow = false)         {             m_blnShow = blnShow;             m_actionAfter = actionAfter;             InitializeComponent();         }          private void Form1_VisibleChanged(object sender, EventArgs e)         {             if (Visible)             {                 var rect = Screen.PrimaryScreen.WorkingArea;                 this.Location = new Point(rect.Right - this.Width, rect.Bottom - this.Height);             }         }          private void FrmUpdate_Load(object sender, EventArgs e)         {             Thread th = new Thread(() =>             {                 Down();                 this.BeginInvoke(new MethodInvoker(delegate ()                 {                     this.Close();                 }));             });             th.IsBackground = true;             th.Start();         }         private string CheckIsXP(string strUrl)         {             bool blnXp = false;             if (Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor == 1)             {                 blnXp = true;             }             if (blnXp && strUrl.StartsWith("https"))             {                 strUrl = "http" + strUrl.Substring(5);             }             return strUrl;         }          private void SetProcess(string strTitle, int? value, int? maxValue = null)         {             this.lblMsg.BeginInvoke(new MethodInvoker(delegate ()             {                 if (maxValue.HasValue)                 {                     this.progressBar1.Maximum = maxValue.Value;                 }                 if (value.HasValue)                 {                     this.progressBar1.Value = value.Value;                 }                 if (!string.IsNullOrEmpty(strTitle))                 {                     this.lblMsg.Text = strTitle;                 }                 lblValue.Text = this.progressBar1.Value + "/" + this.progressBar1.Maximum;             }));         }          public void Down()         {             if (m_blnShow)                 SetProcess("正在检查版本", null);             try             {                 //先清理掉旧文件                 try                 {                     if (Directory.Exists(System.AppDomain.CurrentDomain.BaseDirectory + "UpdateCache"))                     {                         Directory.Delete(System.AppDomain.CurrentDomain.BaseDirectory + "UpdateCache", true);                     }                 }                 catch { }                 if (!File.Exists(System.AppDomain.CurrentDomain.BaseDirectory + "setting.dat"))                 {                     Log.WriteLog("配置文件setting.dat不存在!");                     return;                 }                 string strFileUrl = File.ReadAllText(System.AppDomain.CurrentDomain.BaseDirectory + "setting.dat");                   strFileUrl = CheckIsXP(strFileUrl);                 //获取列表文件                 string json = HttpGet(strFileUrl.Trim('/') + "/getUpdaterList?key=" + Encrypt(m_strkey), Encoding.UTF8);                 ResponseMessage rm = fastJSON.JSON.ToObject<ResponseMessage>(json);                 if (rm == null)                 {                     Log.WriteLog("获取更新文件错误");                     return;                 }                 if (!rm.Result)                 {                     Log.WriteLog("获取更新文件错误:" + rm.ErrorMessage);                     return;                 }                 //云列表                 Dictionary<string, DateTime> lstNewFiles = new Dictionary<string, DateTime>();                 XmlDocument doc = new XmlDocument();                 doc.LoadXml(rm.KeyValue);                 var documentElement = doc.DocumentElement;                 var nodes = documentElement.SelectNodes("//files/file");                 foreach (XmlNode item in nodes)                 {                     lstNewFiles[item.InnerText] = DateTime.Parse(item.Attributes["time"].Value);                 }                  List<string> lstUpdateFile = new List<string>();                 string locationXml = System.AppDomain.CurrentDomain.BaseDirectory + "ver.xml";                 if (!File.Exists(locationXml))                 {                     lstUpdateFile = lstNewFiles.Keys.ToList();                 }                 else                 {                     XmlDocument docLocation = new XmlDocument();                     docLocation.Load(locationXml);                     var documentElementLocation = docLocation.DocumentElement;                     var nodesLocation = documentElementLocation.SelectNodes("//files/file");                     foreach (XmlNode item in nodesLocation)                     {                         if (!lstNewFiles.ContainsKey(item.InnerText))                         {                             lstUpdateFile.Add(item.InnerText);                         }                         else if (lstNewFiles[item.InnerText] < DateTime.Parse(item.Attributes["time"].Value))                         {                             lstUpdateFile.Add(item.InnerText);                         }                     }                 }                 if (lstUpdateFile.Count > 0)                 {                     string strRootPath = System.AppDomain.CurrentDomain.BaseDirectory + "UpdateCache";                     if (!System.IO.Directory.Exists(strRootPath))                     {                         System.IO.Directory.CreateDirectory(strRootPath);                     }                     SetProcess("", null, lstUpdateFile.Count);                     for (int i = 0; i < lstUpdateFile.Count; i++)                     {                         if (m_blnShow)                             SetProcess("正在下载:" + lstUpdateFile[i], i + 1);                          string filejson = HttpGet(strFileUrl.Trim('/') + "/downloadUpdaterFile?key=" + Encrypt(m_strkey) + "&file=" + System.Web.HttpUtility.UrlEncode(lstUpdateFile[i]), Encoding.UTF8);                         ResponseMessage filerm = fastJSON.JSON.ToObject<ResponseMessage>(filejson);                         if (rm == null)                         {                             Log.WriteLog("下载更新文件错误");                             return;                         }                         if (!rm.Result)                         {                             Log.WriteLog("下载更新文件错误:" + rm.ErrorMessage);                             return;                         }                          string saveFile = Path.Combine(strRootPath, lstUpdateFile[i]);                         if (!Directory.Exists(Path.GetDirectoryName(saveFile)))                         {                             System.IO.Directory.CreateDirectory(Path.GetDirectoryName(saveFile));                         }                         string strbase64 = filerm.KeyValue;                            MemoryStream stream = new MemoryStream(Convert.FromBase64String(strbase64));                         FileStream fs = new FileStream(strRootPath + "\" + lstUpdateFile[i], FileMode.OpenOrCreate, FileAccess.Write);                         byte[] b = stream.ToArray();                         fs.Write(b, 0, b.Length);                         fs.Close();                      }                      doc.Save(System.AppDomain.CurrentDomain.BaseDirectory + "UpdateCache//ver.xml");                      if (m_actionAfter != null)                     {                         if (m_blnShow)                             SetProcess("替换文件", null);                         m_actionAfter();                     }                      if (m_blnShow)                         SetProcess("更新完成。", null);                 }                 else                 {                     if (m_blnShow)                         SetProcess("没有需要更新的文件。", null);                 }             }             catch (Exception ex)             {                 if (m_blnShow)                     SetProcess("获取更新列表失败:" + ex.Message, null);                 Log.WriteLog(ex.ToString());             }             finally             {                 if (m_blnShow)                     Thread.Sleep(3000);             }         }          private static string encryptKey = "111222333444555666";          //默认密钥向量         private static byte[] Keys = { 0x41, 0x72, 0x65, 0x79, 0x6F, 0x75, 0x6D, 0x79, 0x53, 0x6E, 0x6F, 0x77, 0x6D, 0x61, 0x6E, 0x3F };         /// <summary>         /// 加密         /// </summary>         /// <param name="encryptString"></param>         /// <returns></returns>         public static string Encrypt(string encryptString)         {             if (string.IsNullOrEmpty(encryptString))                 return string.Empty;             RijndaelManaged rijndaelProvider = new RijndaelManaged();             rijndaelProvider.Key = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 32));             rijndaelProvider.IV = Keys;             ICryptoTransform rijndaelEncrypt = rijndaelProvider.CreateEncryptor();              byte[] inputData = Encoding.UTF8.GetBytes(encryptString);             byte[] encryptedData = rijndaelEncrypt.TransformFinalBlock(inputData, 0, inputData.Length);              return System.Web.HttpUtility.UrlEncode(Convert.ToBase64String(encryptedData));         }         public static string HttpGet(string url, Encoding encodeing, Hashtable headht = null)         {             HttpWebRequest request;              //如果是发送HTTPS请求               //if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))             //{             //ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);             request = WebRequest.Create(url) as HttpWebRequest;             request.ServicePoint.Expect100Continue = false;             request.ProtocolVersion = HttpVersion.Version11;             request.KeepAlive = true;             //}             //else             //{             //    request = WebRequest.Create(url) as HttpWebRequest;             //}             request.Method = "GET";             //request.ContentType = "application/x-www-form-urlencoded";             request.Accept = "*/*";             request.Timeout = 30000;             request.AllowAutoRedirect = false;             WebResponse response = null;             string responseStr = null;             if (headht != null)             {                 foreach (DictionaryEntry item in headht)                 {                     request.Headers.Add(item.Key.ToString(), item.Value.ToString());                 }             }              try             {                 response = request.GetResponse();                  if (response != null)                 {                     StreamReader reader = new StreamReader(response.GetResponseStream(), encodeing);                     responseStr = reader.ReadToEnd();                     reader.Close();                 }             }             catch (Exception)             {                 throw;             }             return responseStr;         }     } }

View Code

定义服务端接口,你可以用任意接口都行,我这里用webapi

获取文件列表

c# 自动更新程序c# 自动更新程序

 1 [HttpGet]  2         public HttpResponseMessage GetUpdaterList(string key)  3         {  4             HttpResult httpResult = new HttpResult();  5             if (!CheckKey(key))  6             {  7                 httpResult.KeyValue = "";  8                 httpResult.Result = false;  9                 httpResult.ErrorMessage = "无权限访问"; 10             } 11             else 12             { 13                 //获取printupdate目录下update.exe的修改日期返回 14                 string path = Path.Combine(HttpRuntime.AppDomainAppPath, "printupdate"); 15                 StringBuilder strXml = new StringBuilder(); 16                 strXml.AppendLine("<?xml version="1.0" encoding="utf-8" ?>"); 17                 strXml.AppendLine("<files>"); 18                 if (Directory.Exists(path)) 19                 { 20                     string[] fs = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories); 21                     var _p = path.ToLower().Trim().Length + 1; 22                     foreach (var item in fs) 23                     { 24                         var dt = File.GetLastAccessTime(item); 25                         strXml.AppendLine("<file time="" + dt.ToString("yyyy-MM-dd HH:mm:ss") + "">" + item.Substring(_p) + "</file>"); 26                     } 27                 } 28                 strXml.AppendLine("</files>"); 29  30                 httpResult.KeyValue = strXml.ToString(); 31                 httpResult.Result = true; 32                 httpResult.ErrorMessage = ""; 33             } 34             return new HttpResponseMessage { Content = new StringContent(httpResult.ToJson(), Encoding.GetEncoding("UTF-8"), "application/json") }; 35         }

View Code

下载文件,我这里将文件序列号为base64字符串了,你可以直接返回文件流也行

c# 自动更新程序c# 自动更新程序

 1 [HttpGet]  2         public HttpResponseMessage DownloadUpdaterFile(string key, string file)  3         {  4             HttpResult httpResult = new HttpResult();  5             if (!CheckKey(key))  6             {  7                 httpResult.KeyValue = "";  8                 httpResult.Result = false;  9                 httpResult.ErrorMessage = "无权限访问"; 10             } 11             else 12             { 13                 string path = Path.Combine(HttpRuntime.AppDomainAppPath + "printupdate", file); 14                 if (!File.Exists(path)) 15                 { 16                     httpResult.KeyValue = ""; 17                     httpResult.Result = false; 18                     httpResult.ErrorMessage = "文件不存在"; 19                 } 20                 else 21                 { 22                     httpResult = ConvertToBase64Type(path); 23                 } 24             } 25             return new HttpResponseMessage { Content = new StringContent(httpResult.ToJson(), Encoding.GetEncoding("UTF-8"), "application/json") }; 26  27         }

View Code

c# 自动更新程序c# 自动更新程序

1   HttpResult ConvertToBase64Type(string fileName) 2         { 3             HttpResult httpResult = new HttpResult(); 4             var byts = File.ReadAllBytes(fileName); 5             httpResult.KeyValue = Convert.ToBase64String(byts); 6             return httpResult; 7         }

View Code

c# 自动更新程序c# 自动更新程序

1  bool CheckKey(string key) 2         { 3             return key == Encryption.Encrypt(m_strkey); 4         }

View Code

c# 自动更新程序c# 自动更新程序

 1  private static string encryptKey = "111222333444";  2   3         //默认密钥向量  4         private static byte[] Keys = { 0x41, 0x72, 0x65, 0x79, 0x6F, 0x75, 0x6D, 0x79, 0x53, 0x6E, 0x6F, 0x77, 0x6D, 0x61, 0x6E, 0x3F };  5         /// <summary>  6         /// 加密  7         /// </summary>  8         /// <param name="encryptString"></param>  9         /// <returns></returns> 10         public static string Encrypt(string encryptString) 11         { 12             if (string.IsNullOrEmpty(encryptString)) 13                 return string.Empty; 14             RijndaelManaged rijndaelProvider = new RijndaelManaged(); 15             rijndaelProvider.Key = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 32)); 16             rijndaelProvider.IV = Keys; 17             ICryptoTransform rijndaelEncrypt = rijndaelProvider.CreateEncryptor(); 18  19             byte[] inputData = Encoding.UTF8.GetBytes(encryptString); 20             byte[] encryptedData = rijndaelEncrypt.TransformFinalBlock(inputData, 0, inputData.Length); 21  22             return Convert.ToBase64String(encryptedData); 23         }

View Code

需要注意的地方:

1、我这里用到了json,那么不能直接饮用json的dll文件,会出现更新时候占用的问题,可以使用fastjson的开源代码,放进来解决,你可以直接使用xml格式的返回内容,这样就不需要json了,这样更方便

2、如果你的下载接口是返回的文件流,那么你更新程序里面直接接收流保存文件就行了

3、Program.cs里面,停止服务的功能,其实是可以通过传递参数的形式来停止,我这里写死了,你们根据自己需求修改

效果

c# 自动更新程序

 

 你可以根据自己的需求,修改下界面效果,这是最简单的示例界面而已。