在Win应用程序中实现自动升级.doc_第1页
在Win应用程序中实现自动升级.doc_第2页
在Win应用程序中实现自动升级.doc_第3页
在Win应用程序中实现自动升级.doc_第4页
在Win应用程序中实现自动升级.doc_第5页
已阅读5页,还剩14页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

最近单位开发一个项目,其中需要用到自动升级功能。因为自动升级是一个比较常用的功能,可能会在很多程序中用到,于是,我就想写一个自动升级的组件,在应用程序中,只需要引用这个自动升级组件,并添加少量代码,即可实现自动升级功能。因为我们的程序中可能包含多个exe或者dll文件,所以要支持多文件的更新。首先,要确定程序应该去哪里下载需要升级的文件。我选择了到指定的网站上去下载,这样比较简单,也通用一些。在这个网站上,需要放置一个当前描述最新文件列表的文件,我们估且叫它服务器配置文件。这个文件保存了当前最新文件的版本号(lastver),大小(size),下载地址(url),本地文件的保存路径(path),还有当更新了这个文件后,程序是否需要重新启动(needRestart)。这个文件大致如下:updateservice.xml 同时,客户端也保存了一个需要升级的本地文件的列表,形式和服务器配置文件差不多,我们叫它本地配置文件。其中,节点表示是否启用自动升级功能,表示服务器配置文件的地址。update.config true/updateservice.xml使用自动各级组件的程序在启动时,会去检查这个配置文件。如果发现有配置文件中的文件版本和本地配置文件中描述的文件版本不一致,则提示用户下载。同时,如果本地配置文件中某些文件在服务器配置文件的文件列表中不存在,则说明这个文件已经不需要了,需要删除。最后,当升级完成后,会更新本地配置文件。我们先来看一下如何使用这个组件。在程序的Program.cs的Main函数中:STAThreadstaticvoid Main()Application.EnableVisualStyles();Application.SetCompatibleTextRenderingDefault(false);AutoUpdater au = new AutoUpdater();tryau.Update();catch (WebException exp)MessageBox.Show(String.Format(无法找到指定资源nn0, exp.Message), 自动升级, MessageBoxButtons.OK, MessageBoxIcon.Error);catch (XmlException exp)MessageBox.Show(String.Format(下载的升级文件有错误nn0, exp.Message), 自动升级, MessageBoxButtons.OK, MessageBoxIcon.Error);catch (NotSupportedException exp)MessageBox.Show(String.Format(升级地址配置错误nn0, exp.Message), 自动升级, MessageBoxButtons.OK, MessageBoxIcon.Error);catch (ArgumentException exp)MessageBox.Show(String.Format(下载的升级文件有错误nn0, exp.Message), 自动升级, MessageBoxButtons.OK, MessageBoxIcon.Error);catch (Exception exp)MessageBox.Show(String.Format(升级过程中发生错误nn0, exp.Message), 自动升级, MessageBoxButtons.OK, MessageBoxIcon.Error);Application.Run(new MainUI();如上所示,只需要简单的几行代码,就可以实现自动升级功能了。软件运行截图:下面,我们来详细说一下这个自动升级组件的实现。先看一下类图:AutoUpdater:自动升级的管理类,负责整体的自动升级功能的实现。Config:配置类,负责管理本地配置文件。DownloadConfirm:一个对话框,向用户显示需要升级的文件的列表,并允许用户选择是否马上升级。DownloadFileInfo:要下载的文件的信息DownloadProgress:一个对话框,显示下载进度。DownloadProgress.ExitCallBack,DownloadProgress.SetProcessBarCallBack,DownloadProgress.ShowCurrentDownloadFileNameCallBack:由于.NET2.0不允许在一个线程中访问另一个线程的对象,所以需要通过委托来实现。LocalFile:表示本地配置文件中的一个文件RemoteFile:表示服务器配置文件中的一个文件。UpdateFileList:一个集合,从List继承我们先整体看一下AutoUpdater.cs:publicclass AutoUpdaterconststring FILENAME = update.config;private Config config = null;privatebool bNeedRestart = false;public AutoUpdater()config = Config.LoadConfig(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, FILENAME);/*/ / 检查新版本/ / 无法找到指定资源/ 升级地址配置错误/ 下载的升级文件有错误/ 下载的升级文件有错误/ 未知错误/ publicvoid Update()if (!config.Enabled)return;/*/* 请求Web服务器,得到当前最新版本的文件列表,格式同本地的FileList.xml。* 与本地的FileList.xml比较,找到不同版本的文件* 生成一个更新文件列表,开始DownloadProgress* * * * path为相对于应用程序根目录的相对目录位置,包括文件名*/WebClient client = new WebClient();string strXml = client.DownloadString(config.ServerUrl);Dictionary listRemotFile = ParseRemoteXml(strXml);List downloadList = new List();/某些文件不再需要了,删除List preDeleteFile = new List();foreach (LocalFile file in config.UpdateFileList)if (listRemotFile.ContainsKey(file.Path)RemoteFile rf = listRemotFilefile.Path;if (rf.LastVer != file.LastVer)downloadList.Add(new DownloadFileInfo(rf.Url, file.Path, rf.LastVer, rf.Size);file.LastVer = rf.LastVer;file.Size = rf.Size;if (rf.NeedRestart)bNeedRestart = true;listRemotFile.Remove(file.Path);elsepreDeleteFile.Add(file);foreach (RemoteFile file in listRemotFile.Values)downloadList.Add(new DownloadFileInfo(file.Url, file.Path, file.LastVer, file.Size);config.UpdateFileList.Add(new LocalFile(file.Path, file.LastVer, file.Size);if (file.NeedRestart)bNeedRestart = true;if (downloadList.Count 0)DownloadConfirm dc = new DownloadConfirm(downloadList);if (this.OnShow != null)this.OnShow();if (DialogResult.OK = dc.ShowDialog()foreach (LocalFile file in preDeleteFile)string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, file.Path);if (File.Exists(filePath)File.Delete(filePath);config.UpdateFileList.Remove(file);StartDownload(downloadList);privatevoid StartDownload(List downloadList)DownloadProgress dp = new DownloadProgress(downloadList);if (dp.ShowDialog() = DialogResult.OK)/更新成功config.SaveConfig(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, FILENAME);if (bNeedRestart)MessageBox.Show(程序需要重新启动才能应用更新,请点击确定重新启动程序。, 自动更新, MessageBoxButtons.OK, MessageBoxIcon.Information);Process.Start(Application.ExecutablePath);Environment.Exit(0);private Dictionary ParseRemoteXml(string xml)XmlDocument document = new XmlDocument();document.LoadXml(xml);Dictionary list = new Dictionary();foreach (XmlNode node in document.DocumentElement.ChildNodes)list.Add(node.Attributespath.Value, new RemoteFile(node);return list;publicevent ShowHandler OnShow;在构造函数中,我们先要加载配置文件:public AutoUpdater()config = Config.LoadConfig(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, FILENAME);最主要的就是Update()这个函数了。当程序调用au.Update时,首先检查当前是否开户了自动更新: if (!config.Enabled)return;如果启用了自动更新,就需要去下载服务器配置文件了: WebClient client = new WebClient();string strXml = client.DownloadString(config.ServerUrl);然后,解析服务器配置文件到一个Dictionary中:Dictionary listRemotFile = ParseRemoteXml(strXml);接下来比较服务器配置文件和本地配置文件,找出需要下载的文件和本地需要删除的文件:List downloadList = new List();/某些文件不再需要了,删除List preDeleteFile = new List();foreach (LocalFile file in config.UpdateFileList)if (listRemotFile.ContainsKey(file.Path)RemoteFile rf = listRemotFilefile.Path;if (rf.LastVer != file.LastVer)downloadList.Add(new DownloadFileInfo(rf.Url, file.Path, rf.LastVer, rf.Size);file.LastVer = rf.LastVer;file.Size = rf.Size;if (rf.NeedRestart)bNeedRestart = true;listRemotFile.Remove(file.Path);elsepreDeleteFile.Add(file);foreach (RemoteFile file in listRemotFile.Values)downloadList.Add(new DownloadFileInfo(file.Url, file.Path, file.LastVer, file.Size);config.UpdateFileList.Add(new LocalFile(file.Path, file.LastVer, file.Size);if (file.NeedRestart)bNeedRestart = true;如果发现有需要下载的文件,则向用户显示这些文件,并提示其是否马上更新。如果用户选择了马上更新,则先删除本地不再需要的文件,然后开始下载更新文件。 if (downloadList.Count 0)DownloadConfirm dc = new DownloadConfirm(downloadList);if (this.OnShow != null)this.OnShow();if (DialogResult.OK = dc.ShowDialog()foreach (LocalFile file in preDeleteFile)string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, file.Path);if (File.Exists(filePath)File.Delete(filePath);config.UpdateFileList.Remove(file);StartDownload(downloadList);我们再来看一下StartDownload函数privatevoid StartDownload(List downloadList)DownloadProgress dp = new DownloadProgress(downloadList);if (dp.ShowDialog() = DialogResult.OK)/更新成功config.SaveConfig(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, FILENAME);if (bNeedRestart)MessageBox.Show(程序需要重新启动才能应用更新,请点击确定重新启动程序。, 自动更新, MessageBoxButtons.OK, MessageBoxIcon.Information);Process.Start(Application.ExecutablePath);Environment.Exit(0);在这个函数中,先调用DownloadProgress下载所有需要下载的文件,然后更新本地配置文件,最后,如果发现某些更新文件需要重新启动应用程序的话,会提示用户重新启动程序。至此,AutoUpdater这个类的使命就完成了,其实,整个的升级过程也就完成了。(废话)。最后,我们来看一下这个组件是如何下载更新文件的using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using System.Threading;using System.Net;using System.IO;using System.Diagnostics;namespace Iyond.Utilitypublic partial class DownloadProgress : Formprivatebool isFinished = false;private List downloadFileList = null;private ManualResetEvent evtDownload = null;private ManualResetEvent evtPerDonwload = null;private WebClient clientDownload = null;public DownloadProgress(List downloadFileList)InitializeComponent();this.downloadFileList = downloadFileList;privatevoid OnFormClosing(object sender, FormClosingEventArgs e)if (!isFinished & DialogResult.No = MessageBox.Show(当前正在更新,是否取消?, 自动升级, MessageBoxButtons.YesNo, MessageBoxIcon.Question)e.Cancel = true;return;elseif (clientDownload != null)clientDownload.CancelAsync();evtDownload.Set();evtPerDonwload.Set();privatevoid OnFormLoad(object sender, EventArgs e)evtDownload = new ManualResetEvent(true);evtDownload.Reset();Thread t = new Thread(new ThreadStart(ProcDownload);t.Name = download;t.Start();long total = 0;long nDownloadedTotal = 0;privatevoid ProcDownload()evtPerDonwload = new ManualResetEvent(false);foreach (DownloadFileInfo file inthis.downloadFileList)total += file.Size;while (!evtDownload.WaitOne(0, false)if (this.downloadFileList.Count = 0)break;DownloadFileInfo file = this.downloadFileList0;/Debug.WriteLine(String.Format(Start Download:0, file.FileName);this.ShowCurrentDownloadFileName(file.FileName);/下载clientDownload = new WebClient();clientDownload.DownloadProgressChanged += new DownloadProgressChangedEventHandler(OnDownloadProgressChanged);clientDownload.DownloadFileCompleted += new AsyncCompletedEventHandler(OnDownloadFileCompleted);evtPerDonwload.Reset();clientDownload.DownloadFileAsync(new Uri(file.DownloadUrl), Path.Combine(AppDomain.CurrentDomain.BaseDirectory, file.FileFullName + .tmp), file);/等待下载完成evtPerDonwload.WaitOne();clientDownload.Dispose();clientDownload = null;/移除已下载的文件this.downloadFileList.Remove(file);/Debug.WriteLine(All Downloaded);if (this.downloadFileList.Count = 0)Exit(true);elseExit(false);evtDownload.Set();void OnDownloadFileCompleted(object sender, AsyncCompletedEventArgs e)DownloadFileInfo file = e.UserState as DownloadFileInfo;nDownloadedTotal += file.Size;this.SetProcessBar(0, (int)(nDownloadedTotal * 100 / total);/Debug.WriteLine(String.Format(Finish Download:0, file.FileName);/替换现有文件string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, file.FileFullName);if (File.Exists(filePath)if (File.Exists(filePath + .old)File.Delete(filePath + .old);File.Move(filePath, filePath + .old);File.Move(filePath + .tmp, filePath);/继续下载其它文件evtPerDonwload.Set();void OnDownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)this.SetProcessBar(e.ProgressPercentage, (int)(nDownloadedTotal + e.BytesReceived) * 100 / total);delegatevoid ShowCurrentDownloadFileNameCallBack(string name);privatevoid ShowCurrentDownloadFileName(string name)if (this.labelCurrentItem.InvokeRequired)ShowCurrentDownloadFileNameCallBack cb = new ShowCurrentDownloadFileNameCallBack(ShowCurrentDownloadFileName);this.Invoke(cb, newobject name );elsethis.labelCurrentItem.Text = name;delegatevoid SetProcessBarCallBack(int current, int total);privatevoid SetProcessBar(int current, int total)if (gressBarCurrent.InvokeRequired)SetProcessBarCallBack cb = new SetProcessBarCallBack(SetProcessBar);this.Invoke(cb, newobject current, total );gressBarCurrent.Value = current;gressBarTotal.Value = total;delegatevoid ExitCallBack(bool success);privatevoid Exit(bool success)if (this.InvokeRequired)ExitCallBack cb = new ExitCallBack(Exit);this.Invoke(cb, newobject success );elsethis.isFinished = success;this.DialogResult = success ? DialogResult.OK : DialogResult.Cancel;this.Close();privatevoid OnCancel(object sender, EventArgs e)evtDownload.Set();evtPerDonwload.Set();在构造函数中,将要下载的文件列表传进来public DownloadProgress(List downloadFileList)InitializeComponent();this.downloadFileList = downloadFileList;在Form的Load事件中,启动下载线程,开始下载。privatevoid OnFormLoad(object sender, EventArgs e)evtDownload = new ManualResetEvent(true);evtDownload.Reset();Thread t = new Thread(new ThreadStart(ProcDownload);t.Name = download;t.Start();下载线程没什么特殊的,使用了WebClient的异步下载文件函数DownloadFileAsync,并且注册了两个事件,分别负责下载进度显示和下载完成后的处理: clientDownload.DownloadProgressChanged += new DownloadProgressChangedEventHandler(OnDownloadProgressChanged);clientDownload.DownloadFileCompleted += new AsyncCompletedEventHandler(OnDownloadFileCompleted);大家看一下就明白了。privatevoid ProcDow

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论