[C.C++] C# WinForm实现自动更新程序的方法详解

1807 0
黑夜隐士 2022-11-5 08:09:08 | 显示全部楼层 |阅读模式
目录

    开发环境开发工具实现代码实现效果代码解析

这一篇就着重写一下客户端的代码,客户端主要实现的有:启动后检测本地的xml文件,然后发送到服务器获取需要更新的文件以及版本列表。循环下载。下载成功后,备份原始文件->复制到主目录(若失败进行回滚)->修改本地xml文件,更新完成后打开主程序。

开发环境

.NET Core 3.1

开发工具

Visual Studio 2019

实现代码
  1. /// <summary>
  2.         /// 更新自己
  3.         /// </summary>
  4.         private void CopyRun() {
  5.             string runPath = Process.GetCurrentProcess().MainModule.FileName;
  6.             string runName = Path.GetFileName(runPath);
  7.             if(!runName.StartsWith("_")) {
  8.                 string copyPath = runPath.Replace(runName, "_" + runName);
  9.                 byte[] bytes;
  10.                 using(FileStream fileStream = new FileStream(runPath, FileMode.Open, FileAccess.Read)) {
  11.                     bytes = new byte[fileStream.Length];
  12.                     fileStream.Read(bytes, 0, bytes.Length);
  13.                 }
  14.                 using(FileStream fileStream = new FileStream(copyPath, FileMode.Create, FileAccess.Write)) {
  15.                     fileStream.Write(bytes);
  16.                 }
  17.                 ProcessStartInfo info = new ProcessStartInfo(copyPath, _runApp);
  18.                 Process.Start(info);
  19.                 Environment.Exit(0);
  20.             }
  21.         }
  22.         /// <summary>
  23.         /// 更新UI
  24.         /// </summary>
  25.         /// <param name="actoin"></param>
  26.         private void UpdateUI(Action actoin) {
  27.             if(this.InvokeRequired) {
  28.                 this.BeginInvoke(actoin);
  29.             }
  30.             else {
  31.                 actoin();
  32.             }
  33.         }
  34.         /// <summary>
  35.         /// 获取本地更新地址
  36.         /// </summary>
  37.         /// <returns></returns>
  38.         private string GetUpdateUrl() {
  39.             XElement xele = XElement.Load(updateXml);
  40.             string url = xele.Element("url").Value;
  41.             return url;
  42.         }
  43.         /// <summary>
  44.         /// 获取本地更新文件
  45.         /// </summary>
  46.         /// <returns></returns>
  47.         private string GetUpdateFiles() {
  48.             XDocument xdoc = XDocument.Load(updateXml);
  49.             var files = from f in xdoc.Root.Element("files").Elements() select new { name = f.Attribute("name").Value, version = f.Attribute("version").Value };
  50.             return JsonConvert.SerializeObject(files);
  51.         }
  52.         /// <summary>
  53.         /// 更新完成后修改版本文件
  54.         /// </summary>
  55.         /// <param name="list"></param>
  56.         private void UpdateXml(List<UpdateModel> list) {
  57.             XDocument xdoc = XDocument.Load(updateXml);
  58.             foreach(var model in list) {
  59.                 var ele_files = xdoc.Root.Element("files");
  60.                 XElement xele = ele_files.Elements().FirstOrDefault(s => s.Attribute("name").Value == model.name);
  61.                 if(xele != null) {
  62.                     xele.SetAttributeValue("version", model.version);
  63.                 }
  64.                 else {
  65.                     XElement addXele = new XElement("file");
  66.                     addXele.SetAttributeValue("name", model.name);
  67.                     addXele.SetAttributeValue("version", model.version);
  68.                     ele_files.Add(addXele);
  69.                 }
  70.             }
  71.             xdoc.Save(updateXml);
  72.         }
复制代码
  1. readonly string _runApp;
  2.         public Form_update(string runApp) {
  3.             InitializeComponent();
  4.             _runApp = runApp;
  5.             //CopyRun();
  6.         }
  7.         readonly string updateXml = Application.StartupPath + "UpdateList.xml";
  8.         private void btn_update_Click(object sender, EventArgs e) {
  9.             #region 设置ui
  10.             btn_update.Enabled = false;
  11.             label_status.Text = "正在更新";
  12.             #endregion
  13.             #region 初始化路径
  14.             string savePath = Application.StartupPath + "temp_update\";
  15.             string backPath = Application.StartupPath + "temp_back\";
  16.             if(Directory.Exists(savePath)) {
  17.                 Directory.Delete(savePath, true);
  18.             }
  19.             Directory.CreateDirectory(savePath);
  20.             if(Directory.Exists(backPath)) {
  21.                 Directory.Delete(backPath, true);
  22.             }
  23.             Directory.CreateDirectory(backPath);
  24.             #endregion
  25.             #region 图标旋转
  26.             int angle = 0;
  27.             Image img = pictureBox1.BackgroundImage;
  28.             System.Threading.Timer timer = new System.Threading.Timer(s => {
  29.                 UpdateUI(() => {
  30.                     angle = angle == 360 ? 0 : angle + 10;
  31.                     pictureBox1.BackgroundImage = img.RotateImage(angle);
  32.                 });
  33.             }, null, 0, 100);
  34.             #endregion
  35.             #region 下载更新
  36.             string url = GetUpdateUrl();
  37.             bool isSuccess = false;
  38.             Task.Run(() => {
  39.                 try {
  40.                     //获取下载列表
  41.                     HttpResult httpResult = HttpUtil.HttpRequest(new HttpItem(url + "GetUpdateFiles", requestData: GetUpdateFiles()));
  42.                     if(httpResult.Status) {
  43.                         UpdateModel_Out output = JsonConvert.DeserializeObject<UpdateModel_Out>(httpResult.HttpStringData);
  44.                         if(output.updateList.Count == 0) {
  45.                             throw new Exception("当前已是最新版本");
  46.                         }
  47.                         UpdateUI(() => {
  48.                             progressBar1.Maximum = output.updateList.Count + 1;
  49.                         });
  50.                         //循环下载文件
  51.                         for(int i = 0; i < output.updateList.Count; i++) {
  52.                             UpdateModel updateModel = output.updateList[i];
  53.                             #region 进度条
  54.                             UpdateUI(() => {
  55.                                 label_status.Text = $"正在更新第 {i + 1}/{output.updateList.Count} 个文件,文件名:{updateModel.name}";
  56.                                 progressBar1.Value = i + 1;
  57.                             });
  58.                             #endregion
  59.                             #region 下载文件
  60.                             httpResult = HttpUtil.HttpRequest(new HttpItem(url + "DownloadFile", requestData: JsonConvert.SerializeObject(updateModel)));
  61.                             if(httpResult.Status) {
  62.                                 using(FileStream fileStream = new FileStream(savePath + updateModel.name, FileMode.Create)) {
  63.                                     fileStream.Write(httpResult.HttpByteData, 0, httpResult.HttpByteData.Length);
  64.                                 }
  65.                             }
  66.                             else {
  67.                                 throw new Exception(updateModel.name + "下载失败,请重试");
  68.                             }
  69.                             #endregion
  70.                             Task.Delay(1000).Wait();
  71.                         }
  72.                         #region 备份
  73.                         UpdateUI(() => {
  74.                             label_status.Text = "正在备份";
  75.                         });
  76.                         try {
  77.                             File.Copy(updateXml, backPath + "UpdateList.xml");
  78.                             foreach(var file in output.updateList) {
  79.                                 if(File.Exists(Application.StartupPath + file.name)) {
  80.                                     File.Copy(Application.StartupPath + file.name, backPath + file.name, true);
  81.                                 }
  82.                             }
  83.                         }
  84.                         catch { }
  85.                         #endregion
  86.                         #region 完成更新
  87.                         UpdateUI(() => {
  88.                             label_status.Text = "正在完成更新";
  89.                             progressBar1.Value = progressBar1.Maximum;
  90.                         });
  91.                         string[] files = Directory.GetFiles(savePath);
  92.                         try {
  93.                             #region 更新成功
  94.                             foreach(string file in files) {
  95.                                 File.Copy(file, Application.StartupPath + Path.GetFileName(file), true);
  96.                             }
  97.                             Directory.Delete(savePath, true);
  98.                             #region 保存最新版本
  99.                             UpdateXml(output.updateList);
  100.                             isSuccess = true;
  101.                             UpdateUI(() => {
  102.                                 label_status.Text = "更新完成";
  103.                             });
  104.                             #endregion
  105.                             #endregion
  106.                         }
  107.                         catch {
  108.                             #region 失败回滚
  109.                             UpdateUI(() => {
  110.                                 label_status.Text = "更新失败,正在回滚";
  111.                             });
  112.                             string[] files_back = Directory.GetFiles(backPath);
  113.                             foreach(string file in files_back) {
  114.                                 File.Copy(file, Application.StartupPath + Path.GetFileName(file), true);
  115.                             }
  116.                             File.Copy(backPath + "UpdateList.xml", updateXml, true);
  117.                             UpdateUI(() => {
  118.                                 label_status.Text = "回滚完成";
  119.                             });
  120.                             return;
  121.                             #endregion
  122.                         }
  123.                         #endregion
  124.                     }
  125.                     else {
  126.                         throw new Exception("获取更新列表失败");
  127.                     }
  128.                 }
  129.                 catch(Exception ex) {
  130.                     UpdateUI(() => {
  131.                         label_status.Text = "更新失败!" + ex.Message;
  132.                         btn_update.Enabled = true;
  133.                     });
  134.                 }
  135.                 finally {
  136.                     UpdateUI(() => {
  137.                         timer.Change(-1, -1);
  138.                         pictureBox1.BackgroundImage = img;
  139.                         if(isSuccess) {
  140.                             if(File.Exists(_runApp)) {
  141.                                 if(MessageBox.Show("更新完成,是否打开程序", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) {
  142.                                     Process.Start(_runApp);
  143.                                 }
  144.                                 Environment.Exit(0);
  145.                             }
  146.                         }
  147.                     });
  148.                 }
  149.             });
  150.             #endregion
  151.         }
  152.         private void btn_close_Click(object sender, EventArgs e) {
  153.             Close();
  154.         }
  155.         private void panel1_Paint(object sender, PaintEventArgs e) {
  156.             Pen pen = new Pen(Color.LightGray);
  157.             e.Graphics.DrawLine(pen, new Point(36, 36), new Point(panel1.Width - 36, 36));
  158.         }
复制代码
实现效果




代码解析

主要注释已经在代码中标注了,由于基本都是在线程中进行操作的,所以在更新UI的时候封装了UpdateUI方法,然后就是加了一个定时器实现图标的旋转。关于CopyRun(更新自己)方法,就是用来更新自动更新程序本身的,即运行之前复制一份本身,然后启动复制的程序,否则本身正在运行的时候是不能更新自己的。
以上就是C# WinForm实现自动更新程序的方法详解的详细内容,更多关于C# WinForm自动更新程序的资料请关注中国红客联盟其它相关文章!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2025 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行