用c# 自动更新程序
更新时间:2020年12月8日 11:34 点击:1774
作者:冰封一夏
出处:http://www.cnblogs.com/bfyx/
HZHControls官网:http://www.hzhcontrols.com
首先看获取和更新的接口
更新程序Program.cs
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Threading.Tasks; using System.Windows.Forms; namespace Update { static class Program { /// <summary> /// 更新程序启动后复制自身,使用副本进行更新 /// -h 不显示界面 /// -c 不使用copy更新程序 /// -d 更新完成删除自身,通常用在copy的更新程序 /// -b 更新下载到备份文件,不替换原文件 /// -r 更新完成运行的文件,下一个参数为文件路径 /// -k 如果系统正在运行则干掉 /// </summary> [STAThread] static void Main(string[] args) { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.ThreadException += Application_ThreadException; List<string> lst = args.ToList(); if (!lst.Contains("-b") && !lst.Contains("-k")) { //这里判断成程序是否退出 if (Process.GetProcessesByName("serviceclient").Length > 0) { MessageBox.Show("服务正在运行,请退出后重试。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } } if (lst.Contains("-k")) { var ps = Process.GetProcessesByName("serviceclient"); if (ps.Length > 0) { ps[0].Kill(); } } //副本更新程序运行 if (!lst.Contains("-c"))//不存在-c 则进行复制运行 { string strFile = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), Guid.NewGuid().ToString() + ".exe"); File.Copy(Application.ExecutablePath, strFile); lst.Add("-c"); lst.Add("-d"); Process.Start(strFile, string.Join(" ", lst)); } else { Action actionAfter = null; //将更新文件替换到当前目录 if (!lst.Contains("-b")) { actionAfter = () => { string strUpdatePath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "UpdateCache\\"); if (Directory.Exists(strUpdatePath) && Directory.GetFiles(strUpdatePath).Length > 0) { CopyFile(strUpdatePath, System.AppDomain.CurrentDomain.BaseDirectory, strUpdatePath); if (File.Exists(Path.Combine(strUpdatePath, "ver.xml"))) File.Copy(Path.Combine(strUpdatePath, "ver.xml"), Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "ver.xml"), true); Directory.Delete(strUpdatePath, true); } }; } try { //隐藏运行 if (!lst.Contains("-h")) { Application.Run(new FrmUpdate(actionAfter, true)); } else { FrmUpdate frm = new FrmUpdate(actionAfter); frm.Down(); } } catch (Exception ex) { } //运行更新后的文件 if (lst.Contains("-r")) { int index = lst.IndexOf("-r"); if (index + 1 < lst.Count) { string strFile = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, lst[index + 1]); if (File.Exists(strFile)) { Process.Start(strFile, "-u"); } } } //删除自身 if (lst.Contains("-d")) { DeleteItself(); } } Application.Exit(); Process.GetCurrentProcess().Kill(); } private static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) { throw new NotImplementedException(); } private static void CopyFile(string strSource, string strTo, string strBasePath) { string[] files = Directory.GetFiles(strSource); foreach (var item in files) { string strFileName = Path.GetFileName(item).ToLower(); if (strFileName == "ver.xml ") { continue; } //如果是版本文件和文件配置xml则跳过,复制完成后再替换这2个文件 string strToPath = Path.Combine(strTo, item.Replace(strBasePath, "")); var strdir = Path.GetDirectoryName(strToPath); if (!Directory.Exists(strdir)) { Directory.CreateDirectory(strdir); } File.Copy(item, strToPath, true); } string[] dires = Directory.GetDirectories(strSource); foreach (var item in dires) { CopyFile(item, strTo, strBasePath); } } private static void DeleteItself() { ProcessStartInfo psi = new ProcessStartInfo("cmd.exe", "/C ping 1.1.1.1 -n 1 -w 1000 > Nul & Del " + Application.ExecutablePath); psi.WindowStyle = ProcessWindowStyle.Hidden; psi.CreateNoWindow = true; Process.Start(psi); } } }
更新程序界面
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; } } }
定义服务端接口,你可以用任意接口都行,我这里用webapi
获取文件列表
[HttpGet] public HttpResponseMessage GetUpdaterList(string key) { HttpResult httpResult = new HttpResult(); if (!CheckKey(key)) { httpResult.KeyValue = ""; httpResult.Result = false; httpResult.ErrorMessage = "无权限访问"; } else { //获取printupdate目录下update.exe的修改日期返回 string path = Path.Combine(HttpRuntime.AppDomainAppPath, "printupdate"); StringBuilder strXml = new StringBuilder(); strXml.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\" ?>"); strXml.AppendLine("<files>"); if (Directory.Exists(path)) { string[] fs = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories); var _p = path.ToLower().Trim().Length + 1; foreach (var item in fs) { var dt = File.GetLastAccessTime(item); strXml.AppendLine("<file time=\"" + dt.ToString("yyyy-MM-dd HH:mm:ss") + "\">" + item.Substring(_p) + "</file>"); } } strXml.AppendLine("</files>"); httpResult.KeyValue = strXml.ToString(); httpResult.Result = true; httpResult.ErrorMessage = ""; } return new HttpResponseMessage { Content = new StringContent(httpResult.ToJson(), Encoding.GetEncoding("UTF-8"), "application/json") }; }
定义服务端接口,你可以用任意接口都行,我这里用webapi
获取文件列表
[HttpGet] public HttpResponseMessage GetUpdaterList(string key) { HttpResult httpResult = new HttpResult(); if (!CheckKey(key)) { httpResult.KeyValue = ""; httpResult.Result = false; httpResult.ErrorMessage = "无权限访问"; } else { //获取printupdate目录下update.exe的修改日期返回 string path = Path.Combine(HttpRuntime.AppDomainAppPath, "printupdate"); StringBuilder strXml = new StringBuilder(); strXml.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\" ?>"); strXml.AppendLine("<files>"); if (Directory.Exists(path)) { string[] fs = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories); var _p = path.ToLower().Trim().Length + 1; foreach (var item in fs) { var dt = File.GetLastAccessTime(item); strXml.AppendLine("<file time=\"" + dt.ToString("yyyy-MM-dd HH:mm:ss") + "\">" + item.Substring(_p) + "</file>"); } } strXml.AppendLine("</files>"); httpResult.KeyValue = strXml.ToString(); httpResult.Result = true; httpResult.ErrorMessage = ""; } return new HttpResponseMessage { Content = new StringContent(httpResult.ToJson(), Encoding.GetEncoding("UTF-8"), "application/json") }; }
下载文件,我这里将文件序列号为base64字符串了,你可以直接返回文件流也行
[HttpGet] public HttpResponseMessage DownloadUpdaterFile(string key, string file) { HttpResult httpResult = new HttpResult(); if (!CheckKey(key)) { httpResult.KeyValue = ""; httpResult.Result = false; httpResult.ErrorMessage = "无权限访问"; } else { string path = Path.Combine(HttpRuntime.AppDomainAppPath + "printupdate", file); if (!File.Exists(path)) { httpResult.KeyValue = ""; httpResult.Result = false; httpResult.ErrorMessage = "文件不存在"; } else { httpResult = ConvertToBase64Type(path); } } return new HttpResponseMessage { Content = new StringContent(httpResult.ToJson(), Encoding.GetEncoding("UTF-8"), "application/json") }; }
HttpResult ConvertToBase64Type(string fileName) { HttpResult httpResult = new HttpResult(); var byts = File.ReadAllBytes(fileName); httpResult.KeyValue = Convert.ToBase64String(byts); return httpResult; }
bool CheckKey(string key) { return key == Encryption.Encrypt(m_strkey); }
private static string encryptKey = "111222333444"; //默认密钥向量 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 Convert.ToBase64String(encryptedData); }
需要注意的地方:
1、我这里用到了json,那么不能直接饮用json的dll文件,会出现更新时候占用的问题,可以使用fastjson的开源代码,放进来解决,你可以直接使用xml格式的返回内容,这样就不需要json了,这样更方便
2、如果你的下载接口是返回的文件流,那么你更新程序里面直接接收流保存文件就行了
3、Program.cs里面,停止服务的功能,其实是可以通过传递参数的形式来停止,我这里写死了,你们根据自己需求修改
效果
你可以根据自己的需求,修改下界面效果,这是最简单的示例界面而已。
以上就是用c# 自动更新程序的详细内容,更多关于c# 自动更新程序的资料请关注猪先飞其它相关文章!
相关文章
- 我们在使用C#做项目的时候,基本上都需要制作登录界面,那么今天我们就来一步步看看,如果简单的实现登录界面呢,本文给出2个例子,由简入难,希望大家能够喜欢。...2020-06-25
- 这篇文章主要介绍了C# 字段和属性的的相关资料,文中示例代码非常详细,供大家参考和学习,感兴趣的朋友可以了解下...2020-11-03
- 这篇文章主要介绍了C#中截取字符串的的基本方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-11-03
- 本文给大家分享C#连接SQL数据库和查询数据功能的操作技巧,本文通过图文并茂的形式给大家介绍的非常详细,需要的朋友参考下吧...2021-05-17
- 这篇文章主要介绍了C#实现简单的Http请求的方法,以实例形式较为详细的分析了C#实现Http请求的具体方法,需要的朋友可以参考下...2020-06-25
- 本文主要介绍了C#中new的几种用法,具有很好的参考价值,下面跟着小编一起来看下吧...2020-06-25
使用Visual Studio2019创建C#项目(窗体应用程序、控制台应用程序、Web应用程序)
这篇文章主要介绍了使用Visual Studio2019创建C#项目(窗体应用程序、控制台应用程序、Web应用程序),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-06-25- 这篇文章主要介绍了C#开发Windows窗体应用程序的简单操作步骤,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-04-12
- 这篇文章主要介绍了C#从数据库读取图片并保存的方法,帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下...2021-01-16
- 最近做一个小项目不可避免的需要前端脚本与后台进行交互。由于是在asp.net中实现,故问题演化成asp.net中jiavascript与后台c#如何进行交互。...2020-06-25
- 这篇文章主要用实例讲解C#递归算法的概念以及用法,文中代码非常详细,帮助大家更好的参考和学习,感兴趣的朋友可以了解下...2020-06-25
- 本文通过例子,讲述了C++调用C#的DLL程序的方法,作出了以下总结,下面就让我们一起来学习吧。...2020-06-25
- 轻松学习C#的基础入门,了解C#最基本的知识点,C#是一种简洁的,类型安全的一种完全面向对象的开发语言,是Microsoft专门基于.NET Framework平台开发的而量身定做的高级程序设计语言,需要的朋友可以参考下...2020-06-25
- 本文主要介绍了C#变量命名规则小结,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-09
- 这篇文章主要介绍了c#中(&&,||)与(&,|)的区别详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-25
- 本文主要介绍了C# 中取绝对值的函数。具有很好的参考价值。下面跟着小编一起来看下吧...2020-06-25
- 这篇文章主要介绍了C#绘制曲线图的方法,以完整实例形式较为详细的分析了C#进行曲线绘制的具体步骤与相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
- 这篇文章主要介绍了c#自带缓存使用方法,包括获取数据缓存、设置数据缓存、移除指定数据缓存等方法,需要的朋友可以参考下...2020-06-25
- 下面小编就为大家带来一篇C#学习笔记- 随机函数Random()的用法详解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-06-25
- 这篇文章主要介绍了C#中list用法,结合实例形式分析了C#中list排序、运算、转换等常见操作技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25