c# 自动更新程序
首先看获取和更新的接口
更新程序Program.cs
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 }
更新程序界面
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
获取文件列表
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 }
下载文件,我这里将文件序列号为base64字符串了,你可以直接返回文件流也行
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 }
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 }
1 bool CheckKey(string key)
2 {
3 return key == Encryption.Encrypt(m_strkey);
4 }
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 }
需要注意的地方:
1、我这里用到了json,那么不能直接饮用json的dll文件,会出现更新时候占用的问题,可以使用fastjson的开源代码,放进来解决,你可以直接使用xml格式的返回内容,这样就不需要json了,这样更方便
2、如果你的下载接口是返回的文件流,那么你更新程序里面直接接收流保存文件就行了
3、Program.cs里面,停止服务的功能,其实是可以通过传递参数的形式来停止,我这里写死了,你们根据自己需求修改
效果
你可以根据自己的需求,修改下界面效果,这是最简单的示例界面而已。
c# 自动更新程序的更多相关文章
- C#之tcp自动更新程序
.NETTCP自动更新程序有如下几步骤: 第一步:服务端开启监听 ServiceHost host; private void button1_Click(object sender, EventAr ...
- ASP.NET网站版本自动更新程序及代码[转]
1.自动更新程序主要负责从服务器中获取相应的更新文件,并且把这些文件下载到本地,替换现有的文件.达到修复Bug,更新功能的目的.用户手工点击更新按钮启动更新程序.已测试.2.环境VS2008,采用C# ...
- WPF自动更新程序
WPF AutoUpdater 描述: WPF+MVVM实现的自动更新程序 支持更新包文件验证(比较文件MD5码) 支持区分x86与x64程序的更新 支持更新程序的版本号 支持执行更新策略 截图: 使 ...
- winform自动更新程序实现
一.问题背景 本地程序在实际项目使用过程中,因为可以操作电脑本地的一些信息,并且对于串口.OPC.并口等数据可以方便的进行收发,虽然现在软件行业看着动不动都是互联网啊啥的,大有Web服务就是高大上的感 ...
- C# WINFORM的自动更新程序
自动更新程序AutoUpdate.exe https://git.oschina.net/victor596jm/AutoUpdate.git 1.获取源码 http://git.oschina.ne ...
- C#.Net版本自动更新程序及3种策略实现
C#.Net版本自动更新程序及3种策略实现 C/S程序是基于客户端和服务器的,在客户机编译新版本后将文件发布在更新服务器上,然后建立一个XML文件,该文件列举最新程序文件的版本号及最后修改日期.如程序 ...
- winform 通用自动更新程序
通用自动更新程序 主要功能: 1. 可用于 C/S 程序的更新,集成到宿主主程序非常简单和配置非常简单,或不集成到主程序独立运行. 2. 支持 HTTP.FTP.WebService等多种更新下载方式 ...
- .Net自动更新程序GeneralUpdate,适用于wpf,winfrom,控制台应用
什么是GeneralUpdate: GeneralUpdate是基于.net framwork4.5.2开发的一款(c/s应用)自动升级程序. 第一个版本叫Autoupdate(原博客: WPF自动更 ...
- android自动更新程序,安装完以后就什么都没有了,没有出现安装成功的界面的问题
转载自: http://blog.csdn.net/lovexieyuan520/article/details/9250099 在android软件开发中,总是需要更新版本,所以当有新版本开发的时候 ...
- Winfrom强大的自动更新程序
推荐一:.Net 小型软件自动更新库(SimpAutoUpdater) http://www.fishlee.net/soft/simple_autoupdater/usage.html 下载地址:h ...
随机推荐
- DM9000时序设置
想了解一下DM9000的移植修改原理,所以分析了一下时序图和引脚连接 首先看一下DM9000的引脚和MINI2440的引脚连接 DM9000 MINI2440 功能描述 SD0 DA ...
- 多测师讲解RF自动化测试实现流程_高级讲师肖sir
1.环境搭建过程?整套环境需要哪些工具包,以及工具包的作用?因为我搭建的RF框架是基于Python的,所以肯定要先安装Python,python安装完之后,开始安装自动化测试框架rf3.0-在do ...
- JSON,数组根据字段分组
function GroupbyName(data, Name) { //data数据源,Name 根据什么字段分组 var map = {}, dest = []; for (var i = 0; ...
- xuexi0.2
1.数据结构就是研究数据如何排布和如何加工. 2.数组的目的是为了管理程序中类型相同,意义相关的变量. 3.数组的优势是比较简单,可以通过访问下标来进行随机访问.数组的限制:元素类型必须相同,数组的大 ...
- windows 快速安装Python3.7.2
1.官方下载地址:https://www.python.org/downloads/release/python-372/ 其他地址:http://www.uzzf.com/soft/449550.h ...
- centos 7.8 添加磁盘后查看、分区、格式化、挂载
基础环境 公有云 由于磁盘空间快用完了,现在决定多加一个40G磁盘 第一步 分区 fdisk -l #查看当前磁盘信息 fdisk /dev/vdb #对指定磁盘进行操作 如上图一般磁盘的第一个分区都 ...
- List<String>转换为实体类的属性【转】
package model; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arr ...
- Python初识和变量基础
Python是面向对象,动态解释型和强类型的语言 编译型: 将代码一次性全部编译成二进制,然后再执行 优点:执行效率高. 缺点:开发效率低. 代表语言:C 解释型: 逐行解释成二进制,逐行运行 优点: ...
- C++学习---队列的构建及操作
一.循环队列 #include <iostream> using namespace std; #define MAXQSIZE 100 typedef struct { int* bas ...
- revel run报错 undefined: sys call.SIGUSR2"
revel run报错,报错信息为 o Compilation Error (in ..\\..\\revel\\server_adapter_go.go:135): undefined: sysca ...