博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
c# 自动更新程序
阅读量:3963 次
发布时间:2019-05-24

本文共 20021 字,大约阅读时间需要 66 分钟。

首先看获取和更新的接口

更新程序Program.cs

ContractedBlock.gif
ExpandedBlockStart.gif
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         ///  14         /// 更新程序启动后复制自身,使用副本进行更新 15         /// -h 不显示界面 16         /// -c 不使用copy更新程序 17         /// -d 更新完成删除自身,通常用在copy的更新程序 18         /// -b 更新下载到备份文件,不替换原文件 19         /// -r 更新完成运行的文件,下一个参数为文件路径 20         /// -k 如果系统正在运行则干掉 21         ///  22         [STAThread] 23         static void Main(string[] args) 24         { 25             Application.EnableVisualStyles(); 26             Application.SetCompatibleTextRenderingDefault(false); 27             Application.ThreadException += Application_ThreadException; 28              29             List
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

更新程序界面

ContractedBlock.gif
ExpandedBlockStart.gif
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
(json); if (rm == null) { Log.WriteLog("获取更新文件错误"); return; } if (!rm.Result) { Log.WriteLog("获取更新文件错误:" + rm.ErrorMessage); return; } //云列表 Dictionary
lstNewFiles = new Dictionary
(); 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
lstUpdateFile = new List
(); 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
(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 }; ///
/// 加密 /// ///
///
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

获取文件列表

ContractedBlock.gif
ExpandedBlockStart.gif
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             else12             {13                 //获取printupdate目录下update.exe的修改日期返回14                 string path = Path.Combine(HttpRuntime.AppDomainAppPath, "printupdate");15                 StringBuilder strXml = new StringBuilder();16                 strXml.AppendLine("
");17 strXml.AppendLine("
");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("
" + item.Substring(_p) + "
");26 }27 }28 strXml.AppendLine("
");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字符串了,你可以直接返回文件流也行

ContractedBlock.gif
ExpandedBlockStart.gif
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             else12             {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                 else21                 {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
ContractedBlock.gif
ExpandedBlockStart.gif
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
ContractedBlock.gif
ExpandedBlockStart.gif
1  bool CheckKey(string key)2         {3             return key == Encryption.Encrypt(m_strkey);4         }
View Code
ContractedBlock.gif
ExpandedBlockStart.gif
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         ///  6         /// 加密 7         ///  8         ///  9         /// 
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里面,停止服务的功能,其实是可以通过传递参数的形式来停止,我这里写死了,你们根据自己需求修改

效果

 

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

转载地址:http://wduki.baihongyu.com/

你可能感兴趣的文章
HoloGraphLibrary 源码解析
查看>>
CircularFloatingActionMenu 源码解析
查看>>
PhotoView 源码解析
查看>>
Android Lock Pattern 源码解析
查看>>
Java 动态代理
查看>>
Java 注解 Annotation
查看>>
View 绘制流程
查看>>
依赖注入
查看>>
View 事件传递
查看>>
android 各式各样progress 进度条大全
查看>>
Android事件分发机制完全解析,带你从源码的角度彻底理解
查看>>
开发Google眼镜的app
查看>>
Android base-adapter-helper 源码分析与扩展
查看>>
Android 快速开发系列 打造万能的ListView GridView 适配器
查看>>
Android 4.4从图库选择图片,获取图片路径并裁剪
查看>>
Android Fragment 你应该知道的一切
查看>>
使用AudioManager调节播放器音量的开发实例
查看>>
Android: ApiHelper
查看>>
BaseAnimation是基于开源的APP,致力于收集各种动画效果(最新版本1.3)
查看>>
安卓开发者必备的42个链接
查看>>