最近做的一个项目中需要用到客户端自动更新功能,最初的想法是利用ClickOnce技术来完成,但在实践中发现根本行不能,原因如下:
1)项目应用到了DevExpress控件包,用ClickOnce发布的自动更新程序,客户在安装时报在GAC中找不到控件dll的错。
2)ClickOnce安装无法实现根据用户安装时录入的参数(比如数据库服务器名、数据库用户名和密码等)来动态修改配置文件的功能。
3)最后一下其实不重要了,就是ClickOnce无法实现用户自定义安装文件夹。
最后决定放弃使用ClickOnce,使用ftp方式进行,实现思路如下:用户启动程序时,先运行update.exe,该文件会自动比较本地配置文件和ftp服务器上配置文件的异同,会自动下载上次更新后变化的文件以及新加入的文件。(因为都是基本配置文件,所以开发了一个配置文件生成工具,用户只需要选择根目录后,就会自动生成配置文件。)文件下载结束后,再启动实际的客户端程序。
程序的主要代码如:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Code
1
using System;
2
using System.Collections.Generic;
3
using System.Diagnostics;
4
using System.IO;
5
using System.Net;
6
using System.Threading;
7
using System.Windows.Forms;
8![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
9
namespace Update
10![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
11![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
12
/// Description:
13
/// Author: ZhangRongHua
14
/// Create DateTime: 2009-6-21 12:25
15
/// UpdateHistory:
16
/// </summary>
17
public partial class frmUpdate : Form
18![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
19![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
Fields#region Fields
20![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
21
private const string CONFIGFILE = "update.xml";
22
private const string UPDATEDIR = "PMS";
23
private string appPath = Application.StartupPath;
24
private List<ErrorInfo> errorList = new List<ErrorInfo>();
25
private string locFile = String.Concat(Application.StartupPath, "\\", CONFIGFILE);
26
private string tmpUpdateFile = "TmpUpdate.xml";
27
private List<string> updateList;
28
private string updateTmpPath = string.Concat(Path.GetTempPath(), "\\", UPDATEDIR);
29
private string url = String.Empty;
30![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
31
private FTP ftp = null;
32![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
33
#endregion
34![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
35![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
Delegates#region Delegates
36![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
37
public delegate void AsycDownLoadFile(string srcFile, string destFile, int i);
38![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
39
public delegate void ExecuteUpdateFiles(string srcPath, string destPath);
40![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
41
public delegate void UpdateComplete();
42![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
43
public delegate void UpdateUI(int i, string message);
44![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
45
#endregion
46![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
47
public event UpdateComplete OnUpdateComplete;
48![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
49![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
Constructor#region Constructor
50![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
51
public frmUpdate()
52![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
53
InitializeComponent();
54
OnUpdateComplete += new UpdateComplete(frmUpdate_OnUpdateComplete);
55
}
56![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
57
#endregion
58![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
59![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
Event Handler#region Event Handler
60![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
61
private void frmUpdate_Load(object sender, EventArgs e)
62![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
63
if(Directory.Exists(updateTmpPath))
64![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
65
Directory.Delete(updateTmpPath, true);
66
}
67
68
// 如果有主程序启动,则关闭
69
Process[] ps = Process.GetProcesses();
70
foreach (Process p in ps)
71![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
72
//MessageBox.Show(p.ProcessName);
73
if (p.ProcessName.ToLower() == "wat.pms.winform")
74![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
75
p.Kill();
76
break;
77
}
78
}
79![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
80
GetUpdateFiles();
81
}
82![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
83
private void frmUpdate_OnUpdateComplete()
84![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
85
ExecuteUpdateFiles dExecuteUpdateFiles = new ExecuteUpdateFiles(ExecuteUpdate);
86![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
Invoke(dExecuteUpdateFiles, new object[]
{updateTmpPath, appPath});
87
}
88![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
89
private void frmUpdate_Shown(object sender, EventArgs e)
90![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
91
Thread updateThread = new Thread(new ThreadStart(DownLoadUpdateFiles));
92
updateThread.SetApartmentState(ApartmentState.STA);
93
updateThread.IsBackground = true;
94
Thread.Sleep(500);
95
updateThread.Start();
96![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
97
98
}
99![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
100
#endregion
101![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
102![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
Private Methods#region Private Methods
103![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
104![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
105
/// 将目标文件替换为本地文件
106
/// <remark>
107
/// Author:ZhangRongHua
108
/// Create DateTime: 2009-6-21 10:28
109
/// Update History:
110
/// </remark>
111
/// </summary>
112
/// <param name="srcFile">The SRC file.</param>
113
/// <param name="destFile">The dest file.</param>
114
private void DownLoadFile(string srcFile, string destFile)
115![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
116
if(ftp == null )
117![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
118
ftp = new FTP(Updater.URL, "", Updater.User, Updater.Password);
119
}
120![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
121
122![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
123
if(!ftp.Connected)
124![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
125
MessageBox.Show("无法连接远程服务器,无法更新程序", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
126
Process.Start(Updater.MainProgram);
127
Close();
128
129
}
130![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
131
// 得到服务器端的配置文件
132
ftp.Get(srcFile, updateTmpPath, destFile);
133![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
134
135
136
}
137![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
138![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
139
/// 得到需要更新的文件清单
140
/// <remark>
141
/// Author:ZhangRongHua
142
/// Create DateTime: 2009-6-21 10:29
143
/// Update History:
144
/// </remark>
145
/// </summary>
146
private void GetUpdateFiles()
147![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
148
Updater.GetBaseInfo(locFile);
149
url = Updater.URL;
150
string svrFile = String.Concat(url, CONFIGFILE);
151![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
152
if (String.IsNullOrEmpty(svrFile))
153![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
154
BroadCastOnUpdateComplete();
155
return;
156
}
157![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
158
Directory.CreateDirectory(updateTmpPath);
159
try
160![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
161
DownLoadFile(CONFIGFILE, tmpUpdateFile);
162
}
163
catch (Exception ex)
164![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
165
MessageBox.Show("无法连接远程服务器,无法更新程序", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
166
Process.Start(Updater.MainProgram);
167
Close();
168
}
169![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
170
updateList = Updater.GetUpdateFileList(locFile, tmpUpdateFile);
171
if (updateList == null || updateList.Count < 1)
172![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
173
BroadCastOnUpdateComplete();
174
return;
175
}
176![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
177
pbUpdate.Maximum = updateList.Count;
178
pbUpdate.Minimum = 0;
179
lblInfo.Text = String.Concat(updateList.Count, "个文件需要更新!");
180
lblInfo.BringToFront();
181
lblState.BringToFront();
182
lblInfo.Update();
183![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
184
pbUpdate.Maximum = updateList.Count;
185
pbUpdate.Minimum = 0;
186![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
187
for (int i = 0; i < updateList.Count; i++)
188![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
189
string file = updateList[i];
190
ListViewItem lvItem = new ListViewItem();
191
lvItem.Text = file;
192
lvItem.SubItems.Add(Updater.MainProgramVersion);
193
lvUpdateList.Items.Add(lvItem);
194
}
195
}
196![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
197
private void UpdateUIInfo(int i, string message)
198![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
199
pbUpdate.Value = i + 1;
200
lblState.Text = message;
201
lblState.Update();
202
}
203![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
204
private void BroadCastOnUpdateComplete()
205![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
206
if (OnUpdateComplete != null)
207![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
208
OnUpdateComplete();
209
}
210
}
211![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
212
private void DownLoadUpdateFiles()
213![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
214
if (updateList == null || updateList.Count < 1)
215![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
216
BroadCastOnUpdateComplete();
217
return;
218
}
219![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
220
try
221![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
222
UpdateUI dUpdateUI = new UpdateUI(UpdateUIInfo);
223
AsycDownLoadFile dAsycDownLoadFile = new AsycDownLoadFile(DownLoadFile);
224
for (int i = 0; i < updateList.Count; i++)
225![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
226
string file = updateList[i];
227
string destFile = String.Concat(updateTmpPath, "\\", file);
228
string destFileName = destFile.Substring(destFile.LastIndexOf("/") + 1);
229
string srcFile = String.Concat(url, file);
230
var srcFileName = file.Trim('/');
231
destFile = destFile.Replace("/", "\\");
232
Directory.CreateDirectory(destFile.Substring(0, destFile.LastIndexOf("\\")));
233
string curentFile = String.Concat("正在更新第", i + 1, "/", updateList.Count, "个", file);
234
235![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
Invoke(dAsycDownLoadFile, new object[]
{ srcFileName, srcFileName, i });
236
Thread.Sleep(50);
237![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
Invoke(dUpdateUI, new object[]
{i, curentFile});
238
}
239
}
240
catch (Exception ex)
241![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
242
Debug.WriteLine(ex.Message);
243
}
244![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
245
BroadCastOnUpdateComplete();
246
}
247![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
248
249![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
250
private void CopyUpdateFiles(string srcPath, string destPath)
251![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
252
string[] files = Directory.GetFiles(srcPath);
253
for (int i = 0; i < files.Length; i++)
254![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
255
string srcFile = files[i];
256
string destFile = string.Concat(destPath, "\\", Path.GetFileName(srcFile));
257
try
258![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
259
File.Copy(srcFile, destFile, true);
260
}
261
catch (System.IO.IOException ex)
262![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
263
264
265
}
266
267
}
268![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
269
string[] dirs = Directory.GetDirectories(srcPath);
270
for (int i = 0; i < dirs.Length; i++)
271![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
272
srcPath = dirs[i];
273
string tmpDestPath = String.Concat(destPath, "\\", Path.GetFileName(srcPath));
274
Directory.CreateDirectory(tmpDestPath);
275
CopyUpdateFiles(srcPath, tmpDestPath);
276
}
277
}
278![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
279![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
280![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
281![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
282
/// 更新完成后,要执行的动作(将下载的文件从临时目录复制到主目录,重启主程序)
283
/// <remark>
284
/// Author:ZhangRongHua
285
/// Create DateTime: 2009-6-21 12:25
286
/// Update History:
287
/// </remark>
288
/// </summary>
289
/// <param name="srcPath">The SRC path.</param>
290
/// <param name="destPath">The dest path.</param>
291
private void ExecuteUpdate(string srcPath, string destPath)
292![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
293
if (errorList != null && errorList.Count < 1)
294![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
295
lblInfo.Text = "正在执行更新";
296
lblInfo.Update();
297
CopyUpdateFiles(srcPath, destPath);
298
File.Copy(tmpUpdateFile, locFile, true);
299
}
300
Process.Start(Updater.MainProgram);
301![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
302
Close();
303
}
304![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
305
private void DownLoadFile(string srcFile, string destFile, ListViewItem lvItem)
306![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
307
try
308![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
309
DownLoadFile(srcFile, destFile);
310
lvItem.SubItems.Add("Ok");
311
}
312
catch (Exception ex)
313![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
314
Debug.WriteLine(ex.Message);
315
lvItem.SubItems.Add("fail");
316
ErrorInfo errorInfo = new ErrorInfo();
317
errorInfo.File = srcFile;
318
errorInfo.ErrorLevel = ErrorLevel.Serious;
319
errorInfo.Message = ex.Message;
320
errorList.Add(errorInfo);
321
}
322
}
323![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
324
private void DownLoadFile(string srcFile, string destFile, int i)
325![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
326
ListViewItem lvItem = lvUpdateList.Items[i];
327![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
328
lvUpdateList.Items[i].EnsureVisible();
329
try
330![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
331
DownLoadFile(srcFile, destFile);
332
lvItem.SubItems.Add("Ok");
333
}
334
catch (Exception ex)
335![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
336
Debug.WriteLine(ex.Message);
337
lvItem.SubItems.Add("fail");
338
ErrorInfo errorInfo = new ErrorInfo();
339
errorInfo.File = srcFile;
340
errorInfo.ErrorLevel = ErrorLevel.Serious;
341
errorInfo.Message = ex.Message;
342
errorList.Add(errorInfo);
343
MessageBox.Show(destFile);
344
}
345
}
346![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
347
#endregion
348
}
349
}