作者:冰封一夏
出处:http://www.cnblogs.com/bfyx/
HZHControls官网:http://www.hzhcontrols.com
首先看获取和更新的接口
更新程序Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
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); } } } |
更新程序界面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
|
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
[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
获取文件列表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
[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字符串了,你可以直接返回文件流也行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
[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" ) }; } |
1
2
3
4
5
6
7
|
HttpResult ConvertToBase64Type( string fileName) { HttpResult httpResult = new HttpResult(); var byts = File.ReadAllBytes(fileName); httpResult.KeyValue = Convert.ToBase64String(byts); return httpResult; } |
1
2
3
4
|
bool CheckKey( string key) { return key == Encryption.Encrypt(m_strkey); } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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# 自动更新程序的资料请关注服务器之家其它相关文章!
原文链接:https://www.cnblogs.com/bfyx/p/13985825.html?utm_source=tuicool&utm_medium=referral