window平台C#实现软件更新功能

 一 实现程序更新思路

    程序实现自我升级,一般有两种方式:

1. 独立的更新程序

开发一个独立的更新程序如Update.exe,用于检查主程序是否有新版本,并下载和安装新版本。

实现步骤:

  1. 主程序启动完后,调用一下更新程序。
  2. 更新程序检查版本不需要更新就退出否则执行更新。
  3. 更新程序检查主程序的版本号。
  4. 如果主程序的版本号低于服务器上的版本号,则下载新版本。
  5. 下载完成后,更新程序将新版本安装到主程序的目录中(一般要备份旧版的)。
  6. 更新程序重启主程序。

优点:

  • 更新过程对用户透明,用户无需手动操作。
  • 可以实现增量更新,只下载更新的文件,节省流量。

缺点:

  • 更新程序需要访问服务器,如果服务器不可访问,则无法更新。

2. 主程序自带更新功能

 将更新功能集成到主程序中,无需开发额外的更新程序。

实现步骤如下:

  1. 主程序启动时,向服务器发送请求,检查是否有新版本。
  2. 如果有新版本,则服务器返回新版本的版本号和下载地址。
  3. 主程序下载新版本。
  4. 下载完成后,主程序将新版本安装到自己的目录中。
  5. 主程序重启自身。

优点:

  • 开发简单,在更新过程中无需考虑与主程序通讯。

缺点:

  • 每次更新都需要下载整个程序,比较耗流量,在更新后不能很好实现自我重启,需要用脚本或者其它方式。

二  程序更新代码(独立的更新程序

 1 主程序增加调用更新程序代码:

  public void CheckForUpdates()
        {
            // 检查是否存在更新程序
            if (File.Exists("Update.exe"))
            {

                // 启动更新程序
                try
                {
                    Process.Start("Update.exe");
                }
                catch (Exception e)
                {
                    
                }
              
            }
  }

2 update.exe完整代码:

        //这部分用于隐藏窗体或控制台,一般静默更新,重启才提示。

        [DllImport("kernel32.dll")]
        static extern IntPtr GetConsoleWindow();

        [DllImport("user32.dll")]
        static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

        const int SW_HIDE = 0;
        String processName = "xxx平台";
        String mainFilePath = "xxx平台.exe";
        String infaceVersion = "";
        String updateUrl = "http://192.168.22.100:1888/pc/getVersionInfo";
        String downloadUrlExe = "http://192.168.22.144:8904/common/downloadAppFile/2666c50a-6e1c-4a8a-b8f6-c1a5002d4ca0.exe";
        String downloadFileName = "test.exe";
        public Form1()
        {

            InitializeComponent();

            // 获取控制台窗口句柄
            IntPtr hWnd = GetConsoleWindow();
            // 隐藏控制台窗口
            ShowWindow(hWnd, SW_HIDE);

        }

        private void Form1_Load(object sender, EventArgs e)
        {
            
            Update();
        }




        //更新程序
        public void Update()
        {
            // 获取主程序的版本号
            String version = GetVersion(mainFilePath);

            // 检查是否有新版本
            String newVersion = GetVersionFromWeb();

            if (newVersion != null)
            {
               
                // 如果有新版本,则下载新版本
                if (CompareVersion(newVersion, version) == 1)
                {
                    Log("本地版本:"+version);

                    Log("符合更新条件,开始更新…");

                    Log("开始下载…");
                    if (DownloadNewVersion())
                    {


                        // 安装新版本
                        Log("开始更新程序…");
                        InstallNewVersion();


                        Log("启动主程序…");
                        // 重启主程序
                        Process.Start(mainFilePath);
                        Log("启动主程序ok");

                    }
                    else
                    {
                        Log("因下载环节问题终止更新操作!");
                    }

          



                   

                }
                else
                {
                    Log("没有的新条件,退出");
                }


            }
            else
            {
                Log("获取服务器版本失败!");
            }

            Log("更新程序退出.");

            Environment.Exit(0);

        }

        /// <summary>
        /// 下载新版本并验证版本号
        /// </summary>
        /// <returns></returns>
        private Boolean DownloadNewVersion()
        {
            WebClient wcClient = new WebClient();


            // 下载文件并保存到指定位置
            WebClient client = new WebClient();
            Log("获取下载url: "+ downloadUrlExe);

            byte[] data = client.DownloadData(downloadUrlExe);

            Log("下载文件大小[" + data.Length/1024 + " kb]");

            String tempPath = "./" + downloadFileName;
            // 将字节数组保存到文件
            File.WriteAllBytes(tempPath, data);
            Log("保存位置 " + tempPath);


            //验证版本 是否与接口一致
            String version = GetVersion(tempPath);
            bool vaildVersion = version.Equals(infaceVersion);
            Log("验证已下载文件版本("+version+")与 接口版本("+infaceVersion+"): " + vaildVersion);
           
            return vaildVersion;

        }


        /// <summary>
        /// 安装
        /// </summary>
        private void InstallNewVersion()
        {

            Log("开始关闭主程序…");
            Process[] ppp= Process.GetProcessesByName(processName);
            if (ppp.Length > 0)
            {
                MessageBox.Show("正在执行升级,重启远程鉴定平台。");
                try
                {
                    for (int i = 0; i < ppp.Length; i++)
                    {
                        Log("结束进程:" + ppp[i].ProcessName);
                        ppp[i].Kill();

                    }
                }
                catch(Exception ex)
                {
                    Log("结束进程:" +ex.Message);
                }

               
            }

            Log("备份主程序…");
            if (!Directory.Exists("./bak"))
            {
                Directory.CreateDirectory("./bak");
            }

            DateTime currentDateAndTime = DateTime.Now;
            String time= currentDateAndTime.ToString("yyyyMMddHHmmss");
            String bakPath = "./bak/" + mainFilePath + "." + time;
            File.Copy(mainFilePath,bakPath,true);
            Log("备份主程序完成。");

            int waitTimeMilliseconds = 1000; // 5秒
            Thread.Sleep(waitTimeMilliseconds);

            File.Delete(mainFilePath);
            Log("删除旧版程序OK。 ");

            File.Copy(downloadFileName,mainFilePath);
            Log("更新文件OK。 ");

            File.Delete(downloadFileName);
            Log("删除下载文件OK。 ");


        }


        private String GetVersionFromWeb()
        {
            Log("准备获取服务器版本号…");

            String json =request(updateUrl);

            //{"msg":"操作成功","code":200,"data":{"id":589,"versionCode":3,"versionName":"1.0.0.1","updateContent":"test","fileName":"xxx平台.exe","saveName":"2666c50a-6e1c-4a8a-b8f6-c1a5002d4ca0.exe","fileSuffix":".exe","fileSize":"107KB","url":"http://192.168.22.144:8904/common/downloadAppFile/2666c50a-6e1c-4a8a-b8f6-c1a5002d4ca0.exe","type":2,"uploadTime":"2024-03-26 10:17:29"}}
  
            JsonElement element = JsonDocument.Parse(json).RootElement;

            infaceVersion = element.GetProperty("data").GetProperty("versionName").GetString();
            Log("获取服务器版本号:" + infaceVersion);

            downloadUrlExe = element.GetProperty("data").GetProperty("url").GetString();
            Log("获取服务器下载URL:" + downloadUrlExe);

            downloadFileName = element.GetProperty("data").GetProperty("saveName").GetString();
            Log("获取服务器下载文件名称:" + downloadFileName);

            return infaceVersion;
        }


        /// <summary>
        /// 日记记录
        /// </summary>
        /// <param name="v"></param>
        private void Log(string v)
        {
            //DateTime currentDateAndTime = DateTime.Now;
            //richTextBox1.AppendText(currentDateAndTime.ToString() +" - "+ v+"\n");

            String filePath = "./update.log";
            try
            {
                using (StreamWriter writer = new StreamWriter(filePath, true))
                {
                    string logEntry = $"{DateTime.Now} - {v}";
                    writer.WriteLine(logEntry);
                }
              
            }
            catch (Exception ex)
            {
                // 记录异常信息
                Console.WriteLine("日志记录失败:" + ex.Message);
            }

        }

        /// <summary>
        /// http请求
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public static string request(string url)
        {
            using (WebClient client = new WebClient())
            {
                return client.DownloadString(url);
            }
        }

        /// <summary>
        /// 获取文件版本号
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        private String GetVersion(string path)
        {
            richTextBox1.AppendText("准备获取本地版本号……:" + path+"\n");

            // 获取文件版本信息
            FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(path);

            // 获取文件版本号
            string fileVersion = fileVersionInfo.FileVersion;

            richTextBox1.AppendText("获取本地版本号:" + fileVersion + "\n");
            return fileVersion;
        }

        /// <summary>
        /// 比较软件的版本号
        /// </summary>
        /// <param name="version1"></param>
        /// <param name="version2"></param>
        /// <returns></returns>
        public static int CompareVersion(string version1, string version2)
        {
            string[] parts1 = version1.Split('.');
            string[] parts2 = version2.Split('.');

            for (int i = 0; i < parts1.Length && i < parts2.Length; i++)
            {
                int v1 = int.Parse(parts1[i]);
                int v2 = int.Parse(parts2[i]);

                if (v1 > v2)
                {
                    return 1;
                }
                else if (v1 < v2)
                {
                    return -1;
                }
            }

            return 0;
        }

执行后的更新日记 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/490764.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++引用学习day2

思维导图 定义一个矩形类&#xff08;Rectangle&#xff09;&#xff0c;包含私有成员&#xff1a;长(length)、宽&#xff08;width&#xff09;, 定义成员函数&#xff1a; 设置长度&#xff1a;void set_l(int l) 设置宽度&#xff1a;void set_w(int w) 获取长度&#…

Vue 2 组件发布到 npm 的常见问题解决

按照 Vue 2 组件打包并发布到 npm 的方法配置项目后&#xff0c;项目在实际开发过程中&#xff0c;随着代码写法的多样性增加而遇到的各种打包问题&#xff0c;本文将予以逐一解决&#xff1a; 本文目录 同时导出多个组件 样式表 import 问题解决 Json 文件 import 问题解决…

Java 面试宝典:什么是可见性?volatile 是如何保证可见性的?

大家好&#xff0c;我是大明哥&#xff0c;一个专注「死磕 Java」系列创作的硬核程序员。 本文已收录到我的技术网站&#xff1a;https://skjava.com。有全网最优质的系列文章、Java 全栈技术文档以及大厂完整面经 什么是可见性&#xff1f; 可见性是指一个线程对共享变量所作…

C语言例4-5:getchar()函数的调用格式和使用的例子

代码如下&#xff1a; //getchar()函数的调用格式和使用的例子 #include<stdio.h> //编译预处理命令&#xff0c;即文件包含命令 int main(void) {char ch1, ch2;int a;ch1 getchar(); //从键盘输入一个字符并赋予字符型变量ch1ch2 getchar(); //从键盘输入一个…

基于Java实验室预约管理系统设计与实现(源码+部署文档)

博主介绍&#xff1a; ✌至今服务客户已经1000、专注于Java技术领域、项目定制、技术答疑、开发工具、毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精彩专栏 推荐订阅 &#x1f447;&#x1f3fb; 不然下次找不到 Java项目精品实…

C语言例4-20:从键盘输入年和月,输出该月的天数。

代码如下&#xff1a; //从键盘输入年和月&#xff0c;输出该月的天数。 #include<stdio.h> int main(void) {int year, month, days;printf("输入年和月&#xff1f;\n");scanf("%d,%d",&year,&month); //从键盘输入年和月switch(month)…

本地大模型(免安装绿色版)

上一篇文章我们讨论了如何在本地运行大模型 。 安装本地大模型 大部分软件都需要安装&#xff0c;今天是免安装绿色版。 很多人下载不了原版&#xff0c;所以我放百度网盘了。 下载 下载&#xff1a;llava-1.5大模型(7b参数,流量警告:4G) 运行&#xff1a;.\llava-v1.5-7b-…

codeforces round.906 - E - Mirror Grid (数学,坐标变换)

You are given a square grid with n rows and n columns. Each cell contains either 0 0 0 or 1 1 1. In an operation, you can select a cell of the grid and flip it (from 0 → 1 0→1 0→1 or 1 → 0 1→0 1→0). Find the minimum number of operations you need…

TSINGSEE青犀智慧充电桩消防安全烟雾火焰AI算法识别预警方案

一、方案背景 随着AI人工智能、大数据、云计算等技术快速发展与落地&#xff0c;视频智能分析技术在智慧充电桩场景中的应用也越来越广泛。这种技术能够为充电桩站点提供全方位的监控和管理&#xff0c;提高运营效率&#xff0c;保障充电站设备的安全和稳定运行。 通过TSINGS…

第四百二十六回

文章目录 1. 概念介绍2. 实现方法2.1 原生方式2.1 插件方式 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何修改程序的桌面图标"相关的内容&#xff0c;本章回中将介绍如何处理ListView中的事件冲突.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介…

Web APIs知识点讲解(阶段三)

DOM- 节点操作 一.节点操作 1.DOM节点 目标&#xff1a;能说出DOM节点的类型 DOM节点 DOM树里每一个内容都称之为节点 节点类型 元素节点 所有的标签 比如 body、 div html 是根节点 属性节点 所有的属性 比如 href 文本节点 所有的文本 document树&#xff1a; 总结&…

你敢信?苹果iPhone 16将搭载百度AI文心一言

【行业焦点】苹果公司&#xff0c;这位全球消费电子舞台的常青树&#xff0c;近期传出一则震撼业界的消息&#xff1a;其将在新一代iPhone 16系列中国版产品中&#xff0c;深度融合百度的尖端生成式AI技术。这一重大决策不仅揭示了苹果对中国市场的深度耕耘与本地化创新战略&am…

Java Web-Maven

Maven是apache旗下的一个开源项目&#xff0c;是一款用于管理和构建java项目的工具 Maven的作用 1.依赖管理:方便快捷的管理项目依赖资源(jar包)&#xff0c;避免版本冲突问题 我们有的项目需要大量的jar包&#xff0c;采用手动导包的方式非常繁琐&#xff0c;并且版本升级也…

elasticsearch _cat/indices docs.count is different than <index>/_count

今天遇到一个问题&#xff0c;kibana中看到文档数与下面语句查询到的不同 GET /_cat/count/jiankunking_xxxxx_product_expand_test?v GET /jiankunking_xxxxx_product_expand_test/_search?track_total_hitstrue语句查询结果 epoch timestamp count 1711433785 06:16…

外贸企业如何访问外网?

在当今全球化的浪潮下&#xff0c;企业对于稳定、高效的网络连接需求日益迫切。无论是在境内还是境外&#xff0c;企业都需要依托可靠的网络基础设施&#xff0c;以确保业务的顺畅进行。在这样的背景下&#xff0c;我们提供的专业网络运营服务成为了众多企业的首选。 1. 网络建…

neo4j使用详解(三、cypher插入语法——最全参考)

1.插入语法 create, merge, set, delete, remove, create unique, load csv(import) 除插入语法外另外的语法详情请博主其他文章&#xff1a; 查询语法 其他语法 1.1.create语法 创建单个节点: create(n) # (ID:n) 创建带标签的节点: create (n:Person) # (ID:n, label:Perso…

垃圾回收:垃圾回收器

目录 垃圾回收器 评估GC的性能指标 7种典型的垃圾回收器 Serial回收器&#xff1a;串行回收 ParNew回收器&#xff1a;并行回收 Parallel回收器&#xff1a;吞吐量优先 CMS回收器&#xff1a;低延迟 G1回收器&#xff1a;区域化分代式 G1回收过程1-年轻代GC G1回收过程…

人、机中的幻觉和直觉

对于人类而言&#xff0c;幻觉和直觉是两种不同的心理现象。幻觉是一种错误的感知或体验&#xff0c;而直觉是一种在没有明显依据的情况下产生的直观认知。这两种概念在心理学和认知科学中具有不同的意义和研究对象。 人类幻觉是指个体在感知或体验上出现的错误&#xff0c;即看…

攻防世界-baby_web

题目信息 相关知识 使用bp进行抓包 解题过程 题目界面如下所示: 试图找index界面&#xff1a; 发现又跳转到http://61.147.171.105:51201/1.php页面&#xff0c;因此说明61.147.171.105:51201/index.php是存在的&#xff08;因为笔者试了&#xff0c;不存在的页面会直接报…

SHAP和LIME:Python机器学习模型解释

SHAP和LIME&#xff1a;Python机器学习模型解释 为了更好地展示&#xff0c;示例代码参见和鲸社区&#xff0c;一键运行 简介 机器学习模型在各个领域得到广泛应用&#xff0c;但其黑盒性质往往使人难以理解其决策过程&#xff0c;降低了模型的可信度和可靠性。为了解决这一…