• Winform自动更新程序


    本文采用自动更新策略为“访问Web站点获取最新版本,下载更新文件压缩包,并控制解压覆盖旧文件完成更新”。

    注意事项:

    因为是覆盖文件进行更新,故更新程序和主程序不能有关联

    • 不能引用相同的DLL文件(覆盖安装会告知文件占用无法覆盖)
    • 更新过程中主程序不能在启动状态(理由同上)

    思路:

    • 部署一个Web站点,用于判断更新信息和下载更新文件
    • 主程序和更新程序启动时,访问Web站点获取版本号并和主程序版本进行对比,不一致则提醒更新

     

    建立项目

    项目资源如下图:

    ps:主程序和更新程序不能共用更新处理类,故各放了1个。

    主程序-Main代码:

    using System;
    using System.Windows.Forms;
    
    namespace WinFormUpdaterDemo
    {
        public partial class Main : Form
        {
            public Main()
            {
                InitializeComponent();
            }
    
            private void Main_Load(object sender, EventArgs e)
            {
                label1.Text = "程序集版本:" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString() + "
    ";
                //label1.Text += "文件版本:" + Application.ProductVersion.ToString() + "
    ";
            }
        }
    }
    View Code

    主程序-更新处理类SoftUpdate.cs:

    using System;
    using System.IO;
    using System.Net;
    using System.Reflection;
    using System.Xml;
    
    namespace WinFormUpdaterDemo
    {
        /// <summary>  
        /// 更新完成触发的事件  
        /// </summary>  
        public delegate void UpdateState();
        /// <summary>  
        /// 程序更新  
        /// </summary> 
        public class SoftUpdate
        {
            private string download;
            private const string updateUrl = "http://127.0.0.1:7000/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);
                    //读取版本信息(直接使用Assembly.Load会导致资源占用,故使用如下方法读取文件,解决资源占用问题)
                    byte[] fileData = File.ReadAllBytes(loadFile);
                    Version verson = Assembly.Load(fileData).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;
            }
        }
    }
    View Code

    主程序入口Program.cs:

    using System;
    using System.Windows.Forms;
    
    namespace WinFormUpdaterDemo
    {
        static class Program
        {
            /// <summary>
            /// 应用程序的主入口点。
            /// </summary>
            [STAThread]
            static void Main()
            {
                //检查更新
                if (checkUpdateLoad())
                {
                    Application.Exit();
                    return;
                }
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Main());
            }
    
            public static bool checkUpdateLoad()
            {
                bool result = false;
                SoftUpdate app = new SoftUpdate(Application.ExecutablePath, "WinFormUpdaterDemo");
                try
                {
                    if (app.IsUpdate && MessageBox.Show("检查到新版本,是否更新?", "版本检查", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                    {
                        string path = Application.StartupPath;
                        System.Diagnostics.Process process = new System.Diagnostics.Process();
                        process.StartInfo.FileName = "AutoUpdater.exe";
                        process.StartInfo.WorkingDirectory = path;//要掉用得exe路径例如:"C:windows";               
                        process.StartInfo.CreateNoWindow = true;
                        process.Start();
    
                        result = true;
                    }
                    else
                    {
                        result = false;
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                    result = false;
                }
                return result;
            }
        }
    }
    View Code

    PS:更新程序的生成“输出位置”最好设置在主程序里,这样就省去了每次生成后都要把升级程序文件复制到主程序目录里。

     更新程序Updater代码:

    using ICSharpCode.SharpZipLib.Zip;
    using System;
    using System.IO;
    using System.Windows.Forms;
    
    namespace AutoUpdater
    {
        public partial class Updater : Form
        {
            public Updater()
            {
                InitializeComponent();
            }
    
            private void Updater_Load(object sender, EventArgs e)
            {
                richTextBox1.Text += DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " 清除历史遗留文件
    ";
                //清除之前下载来的rar文件
                if (File.Exists(Application.StartupPath + "\Update_NewVersion.zip"))
                {
                    try
                    {
                        File.Delete(Application.StartupPath + "\Update_NewVersion.zip");
                    }
                    catch (Exception) { }
                }
                if (Directory.Exists(Application.StartupPath + "\autoupload"))
                {
                    try
                    {
                        Directory.Delete(Application.StartupPath + "\autoupload", true);
                    }
                    catch (Exception) { }
                }
    
                timer1.Interval = 200;
                timer1.Enabled = true;
                timer1.Start();
                richTextBox1.Text += DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " 检查服务端是否有新版本程序
    ";
                //检查服务端是否有新版本程序
                checkUpdate();
            }
            SoftUpdate app = new SoftUpdate(Application.StartupPath, "WinFormUpdaterDemo");
            /// <summary>
            /// 检查更新
            /// </summary>
            public void checkUpdate()
            {
                app.UpdateFinish += new UpdateState(app_UpdateFinish);
                try
                {
                    if (app.IsUpdate)
                    {
                        richTextBox1.Text += DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " 开始下载更新文件
    ";
                        app.Update();
                    }
                    else
                    {
                        richTextBox1.Text += DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " 未检测到新版本
    ";
                        MessageBox.Show("未检测到新版本!");
                        Application.Exit();
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
    
            /// <summary>
            /// 下载更新文件完成后解压文件并覆盖旧文件完成更新
            /// </summary>
            void app_UpdateFinish()
            {
                //解压下载后的文件
                string path = app.FinalZipName;
                if (File.Exists(path))
                {
                    //后改的 先解压滤波zip植入ini然后再重新压缩
                    string dirEcgPath = Application.StartupPath + "\" + "autoupload\";
                    if (!Directory.Exists(dirEcgPath))
                    {
                        Directory.CreateDirectory(dirEcgPath);
                    }
                    richTextBox1.Text += DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " 解压下载后的文件:" + path + "
    "; ;
                    //开始解压压缩包
                    UnZIP(path, dirEcgPath);
                    richTextBox1.Text += DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " 解压成功
    "; ;
    
                    try
                    {
                        //复制新文件替换旧文件
                        richTextBox1.Text += DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " 更新新文件(替换旧文件)
    ";
                        DirectoryInfo TheFolder = new DirectoryInfo(dirEcgPath);
                        foreach (FileInfo NextFile in TheFolder.GetFiles())
                        {
                            File.Copy(NextFile.FullName, Application.StartupPath + "\" + NextFile.Name, true);
                        }
                        richTextBox1.Text += DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " 更新成功
    ";
                        richTextBox1.Text += DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " 删除残留文件
    ";
                        Directory.Delete(dirEcgPath, true);
                        File.Delete(path);
                        foreach (string delfilepath in app.deleteFiles)
                        {
                            string delfile = Application.StartupPath + "\" + delfilepath;
                            if (delfilepath.Contains("."))
                            {
                                //删除文件
                                if (File.Exists(delfile))
                                    File.Delete(delfile);
                            }
                            else
                            {
                                //删除目录
                                if (Directory.Exists(delfile))
                                    Directory.Delete(delfile,true);
                            }
                        }
                        richTextBox1.Text += DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " 删除成功
    ";
                        //覆盖完成 重新启动程序
                        richTextBox1.Text += DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " 启动更新后的新程序
    ";
                        path = Application.StartupPath;
                        System.Diagnostics.Process process = new System.Diagnostics.Process();
                        process.StartInfo.FileName = "WinFormUpdaterDemo.exe";
                        process.StartInfo.WorkingDirectory = path;//要掉用得exe路径例如:"C:windows";               
                        process.StartInfo.CreateNoWindow = true;
                        process.Start();
                        richTextBox1.Text += DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " 退出更新软件
    ";
                        //Application.Exit();
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("请关闭系统在执行更新操作!");
                        Application.Exit();
                    }
                }
            }
    
            /// <summary>
            /// 定时器(用来更新进度条)
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void timer1_Tick(object sender, EventArgs e)
            {
                label1.Text = "下载文件进度:" + CommonMethod.autostep.ToString() + "%";
                this.progressBar1.Value = CommonMethod.autostep;
                if (CommonMethod.autostep == 100)
                {
                    timer1.Stop();
                    timer1.Enabled = false;
                }
    
            }
    
            /// <summary>
            /// 解压文件
            /// </summary>
            /// <param name="zipFilePath">压缩文件路径</param>
            /// <param name="saveDirectory">解压路径</param>
            public static void UnZIP(string zipFilePath, string saveDirectory)
            {
                // Perform simple parameter checking.
                if (!File.Exists(zipFilePath))
                {
                    return;
                }
                if (!Directory.Exists(saveDirectory))
                {
                    //解压后存放的 文件夹路径
                    Directory.CreateDirectory(saveDirectory);
                }
    
                using (ZipInputStream s = new ZipInputStream(File.OpenRead(zipFilePath)))
                {
    
                    ZipEntry theEntry;
                    while ((theEntry = s.GetNextEntry()) != null)
                    {
                        string directoryName = Path.GetDirectoryName(theEntry.Name);
                        string fileName = Path.GetFileName(theEntry.Name);
    
                        // create directory
                        if (directoryName.Length > 0)
                        {
                            //创建目录
                            string saveDir = saveDirectory + directoryName;
                            Directory.CreateDirectory(saveDir);
                        }
    
                        if (fileName != String.Empty)
                        {
                            string saveFilePath = saveDirectory + theEntry.Name;
                            using (FileStream streamWriter = File.Create(saveFilePath))
                            {
                                int size = 2048;
                                byte[] data = new byte[2048];
                                while (true)
                                {
                                    size = s.Read(data, 0, data.Length);
                                    if (size > 0)
                                    {
                                        streamWriter.Write(data, 0, size);
                                    }
                                    else
                                    {
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
    
            }
        }
    }
    View Code

    更新程序-更新处理类SoftUpdate.cs:

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Net;
    using System.Reflection;
    using System.Xml;
    
    namespace AutoUpdater
    {
        /// <summary>  
        /// 更新完成触发的事件  
        /// </summary>  
        public delegate void UpdateState();
        /// <summary>  
        /// 程序更新  
        /// </summary> 
        public class SoftUpdate
        {
            private string download;
            public List<string> deleteFiles;
            private const string updateUrl = "http://127.0.0.1:7000/update.xml";//升级配置的XML文件地址  
    
            #region 构造函数
            public SoftUpdate() { }
    
            /// <summary>  
            /// 程序更新  
            /// </summary>  
            /// <param name="file">要更新的文件</param>  
            public SoftUpdate(string file, string softName)
            {
                this.LoadFile = file + "\" + softName + ".exe";
                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; }
            }
    
            private string _finalZipName = string.Empty;
    
            public string FinalZipName
            {
                get { return _finalZipName; }
                set { _finalZipName = value; }
            }
    
            #endregion
    
            /// <summary>  
            /// 更新完成时触发的事件  
            /// </summary>  
            public event UpdateState UpdateFinish;
            private void isFinish()
            {
                if (UpdateFinish != null)
                    UpdateFinish();
            }
    
            /// <summary>  
            /// 下载更新  
            /// </summary>  
            public void Update()
            {
                try
                {
                    if (!isUpdate)
                        return;
                    WebClient wc = new WebClient();
                    string filename = "Update_NewVersion.zip";
                    filename = Path.GetDirectoryName(loadFile) + "\" + filename;
    
                    FinalZipName = filename;
                    //wc.DownloadFile(download, filename);
                    wc.DownloadFileAsync(new Uri(download), filename);
                    wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
                    wc.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler(wc_DownloadFileCompleted);
                    //wc.Dispose();
                }
                catch
                {
                    throw new Exception("更新出现错误,网络连接失败!");
                }
            }
    
            void wc_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
            {
                (sender as WebClient).Dispose();
                if (e.Error != null)
                    throw e.Error;
                else
                    isFinish();
            }
    
            void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
            {
                CommonMethod.autostep = e.ProgressPercentage;
                //Thread.Sleep(100);
            }
    
            /// <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 if (xml.Name == "DownLoad")
                                    download = xml.InnerText;
                                else if (xml.Name == "Delete")
                                {
                                    deleteFiles = new List<string>();
                                    foreach (XmlNode delfile in xml)
                                    {
                                        if (delfile.Name == "file")
                                            deleteFiles.Add(delfile.InnerText);
                                    }
                                }
                            }
                        }
                    }
    
                    Version ver = new Version(newVerson);
                    //读取版本信息(直接使用Assembly.Load会导致资源占用,故使用如下方法读取文件,解决资源占用问题)
                    byte[] fileData = File.ReadAllBytes(loadFile);
                    Version verson = Assembly.Load(fileData).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;
            }
        }
    
        /// <summary>
        /// 全局进度条变量
        /// </summary>
        public static class CommonMethod
        {
            public static int autostep;
        }
    }
    View Code

    Web站点:

    update.xml代码:

    <?xml version="1.0" encoding="utf-8" ?>
    <Update>
      <Soft Name="WinFormUpdaterDemo">
        <Verson>1.0.0.1</Verson>
        <DownLoad>http://127.0.0.1:7000/Update_NewVersion.zip</DownLoad>
        <Delete>
          <file>test.txt</file>
          <file>test1.txt</file>
          <file>	est</file>
        </Delete>
      </Soft>
    </Update>
    View Code

    每次更新程序做以下操作即可:

    1. 修改主程序AssemblyInfo.cs中的版本号;
    2. 把最新的程序打包成“Update_autoUpdate.zip”,放入站点;(打包程序为覆盖安装,所以可以进行增量更新,减少更新成本)
    3. 修改站点xml文件版本号,使之和主程序AssemblyInfo.cs中的版本号一致。(XML中可配置要删除的文件,防止产生垃圾文件)

    好啦,这样自动更新程序就做好啦。

    效果演示:

     

     源码:https://download.csdn.net/download/u012322524/14141624

    懒得下源码的,照着上面自己弄一样的,说的应该很详细了。

     

  • 相关阅读:
    C++中的private/protected/public
    volatile关键字和mutable关键字
    vector容器使用和assert断言关键字
    静态变量static和extern外引用
    VS开发入门常识
    电子钱包的消费——java card开发第五篇
    电子钱包的圈存——java card开发第四篇
    PPT2010制作图片玻璃磨砂效果
    Word2010制作个人名片
    Word2010制作自动目录
  • 原文地址:https://www.cnblogs.com/BeInNight/p/14268129.html
Copyright © 2020-2023  润新知