winform版本自动更新
我们在使用软件的时候经常会遇到升级版本,这也是Winform程序的一个功能,今天就大概说下我是怎么实现的吧(代码有点不完美有小BUG,后面再说)
先说下我的思路:首先在打开程序的时候去拿到我之前在网站上写好的xml里边的版本号,判断是否要更新,之后要更新的话就调用更新的exe(ps:这个是单独出来的,因为更新肯定要覆盖当前的文件,文件运行的时候不能被覆盖),然后下载最新的压缩包到本地,调用7z解压覆盖即可
思路明确了之后就开始写代码(所以说思路很重要啊!!!):
<?xml version="1.0" encoding="utf-8" ?> <Update> <Soft Name="BlogWriter"> <Verson>1.0.1.2</Verson> <DownLoad>http://www.shitong666.cn/BlogWrite.zip</DownLoad> </Soft> </Update>
这是xml,先放到服务器上去
检查更新的代码(我把这个封装成了一个类):
using System; using System.Collections.Generic; using System.Text; using System.Reflection; using System.IO; using System.Net; using System.Xml; namespace UpdateDemo { /// <summary> /// 程序更新 /// </summary> public class SoftUpdate { private string download; private const string updateUrl = "http://www.shitong666.cn/update.xml";//升级配置的XML文件地址 #region 构造函数 public SoftUpdate() { } /// <summary> /// 程序更新 /// </summary> /// <param name="file">要更新的文件</param> public SoftUpdate(string file, string softName) { this.LoadFile = file; this.SoftName = softName; } #endregion #region 属性 private string loadFile; private string newVerson; private string softName; private bool isUpdate; /// <summary> /// 或取是否需要更新 /// </summary> public bool IsUpdate { get { checkUpdate(); return isUpdate; } } /// <summary> /// 要检查更新的文件 /// </summary> public string LoadFile { get { return loadFile; } set { loadFile = value; } } /// <summary> /// 程序集新版本 /// </summary> public string NewVerson { get { return newVerson; } } /// <summary> /// 升级的名称 /// </summary> public string SoftName { get { return softName; } set { softName = value; } } #endregion /// <summary> /// 检查是否需要更新 /// </summary> public void checkUpdate() { try { WebClient wc = new WebClient(); Stream stream = wc.OpenRead(updateUrl); XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load(stream); XmlNode list = xmlDoc.SelectSingleNode("Update"); foreach (XmlNode node in list) { if (node.Name == "Soft" && node.Attributes["Name"].Value.ToLower() == SoftName.ToLower()) { foreach (XmlNode xml in node) { if (xml.Name == "Verson") newVerson = xml.InnerText;//拿到最新版本号 else download = xml.InnerText;//拿到要更新的文件(这块不用拿的,懒得改了) } } } Version ver = new Version(newVerson); Version verson = Assembly.LoadFrom(loadFile).GetName().Version; int tm = verson.CompareTo(ver); //版本号比较 if (tm >= 0) isUpdate = false; else isUpdate = true; } catch (Exception ex) { throw new Exception("更新出现错误,请确认网络连接无误后重试!"); } } /// <summary> /// 获取要更新的文件 /// </summary> /// <returns></returns> public override string ToString() { return this.loadFile; } } }
然后在主程序里调用这个这检查更新:
public partial class Form1 : Form { public Form1() { InitializeComponent(); this.Text = "Hello(版本1.0)"; label1.Text = "Hello World 1.0"; checkUpdate();//检查更新 } public void checkUpdate() { SoftUpdate app = new SoftUpdate(Application.ExecutablePath, "BlogWriter"); try { if (app.IsUpdate && MessageBox.Show("检查到新版本,是否更新?", "Update", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { //更新(调用更新的exe,这个是单独的一个程序,下面再说怎么写) string fileName = Application.StartupPath+@"\Updata.exe"; Process p = new Process(); p.StartInfo.UseShellExecute = false; p.StartInfo.RedirectStandardOutput = true; p.StartInfo.FileName = fileName; p.StartInfo.CreateNoWindow = true; p.StartInfo.Arguments = "你好, 西安 欢迎你!";//参数以空格分隔,如果某个参数为空,可以传入”” p.Start();
System.Environment.Exit(System.Environment.ExitCode); //结束主线程
// p.WaitForExit(); //这里就不能等他结束了
// string output = p.StandardOutput.ReadToEnd(); //this.Dispose();//关闭主程序
} } catch (Exception ex) { MessageBox.Show(ex.Message); } } }
下来就是下载更新的压缩包了和解压的exe了:
先看界面
public partial class UpdateForm : Form { public UpdateForm() { InitializeComponent(); this.button1.Enabled = false; this.button1.Click += button1_Click; this.Text = "更新..."; UpdateDownLoad(); // Update(); } void button1_Click(object sender, EventArgs e) { this.Close(); } public delegate void ChangeBarDel(System.Net.DownloadProgressChangedEventArgs e); private void UpdateDownLoad() { WebClient wc = new WebClient(); wc.DownloadProgressChanged += wc_DownloadProgressChanged; wc.DownloadFileAsync(new Uri("http://www.shitong666.cn/BlogWriter.zip"), "Update.zip");//要下载文件的路径,下载之后的命名 } // int index = 0; void wc_DownloadProgressChanged(object sender, System.Net.DownloadProgressChangedEventArgs e) { Action act = () => { this.progressBar1.Value = e.ProgressPercentage; this.label1.Text = e.ProgressPercentage + "%"; }; this.Invoke(act); if (e.ProgressPercentage == 100) { //下载完成之后开始覆盖 ZipHelper.Unzip();//调用解压的类 this.button1.Enabled = true; } } }
解压的类:
public class ZipHelper { public static string zipFileFullName = "update.zip"; public static void Unzip() { string _appPath = new DirectoryInfo(Assembly.GetExecutingAssembly().ManifestModule.FullyQualifiedName).Parent.FullName; string s7z = _appPath + @"\7-Zip\7z.exe"; System.Diagnostics.Process pNew = new System.Diagnostics.Process(); pNew.StartInfo.FileName = s7z; pNew.StartInfo.Arguments = string.Format(" x \"{0}\\{1}\" -y -o\"{0}\"", _appPath, zipFileFullName); //x "1" -y -o"2" 这段7z命令的意思: x是解压的意思 "{0}"的位置写要解压文件路径"{1}"这个1的位置写要解压的文件名 -y是覆盖的意思 -o是要解压的位置 pNew.Start(); //等待完成 pNew.WaitForExit();
//删除压缩包
File.Delete(_appPath + @"\" + zipFileFullName); } }
最后说bug吧!这个bug真心多,首先我拿不到解压的进度,我的想法是让更新的进度条停在90%左右等待解压完成之后再走到100%,其余的再优化一下就应该可以用了,最后谢谢hover大神给我的指导