window平台C#实现软件升级功能(控制台)

 window平台C#实现软件升级功能

       之前用window窗体实现过一个升级功能,后来发现多个项目都需要升级功能,现改成可接收参数实现一种通用的exe.改用控制台方式实现这个升级功能,这样不仅实现了接收参数,升级程序体积也比原来的窗体形式更小。

一  Window窗体升级实现:

window平台C#实现软件升级功能(Window窗体应用)_开发电脑软件自动更新怎么实现-CSDN博客

 

二  控制台升级实现:

  1 关于升级细路,这里不再详细写,可参考上面Window窗体升级实现。

  2 完整C#控制台升级程序代码如下:

using System;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Runtime.InteropServices;
using System.Text.Json;
using System.Threading;

namespace ConsoleAppUpdate
{
    class Program
    {
        static String processName = "xxx应用";
        static String mainFilePath = "xxx应用.exe";
        static String infaceVersion = "";

       
        static String updateUrl = "https://xxx.xxx.xxx.xxx/pc/getLastApp";
        static String downloadUrlExe = "http://xxx.xxx.xxx.xx:89/common/downloadAppFile/2666c50a-6e1c-4a8a-b8f6-c1a5002d4ca0.exe";
        static String downloadFileName = "test.exe";

        // 导入 Windows API 函数
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern int MessageBox(IntPtr hWnd, String text, String caption, uint type);

        // 用visual studio 编译时 要配置
        static void Main(string[] args)
        {
            // 参数1 升级接口 url
            // 参数2 进程名称 用于关闭进程
            // 参数3 主文件名称 (不用指定目录,要求把升级文件放在主文件同一目录即可)
            if (args != null && args.Length > 1)
            {
                updateUrl = args[0];
                Log("rev update url = " + updateUrl);
            }
            else
            {
                Log("use default update url = " + updateUrl);
            }
            try
            {
                Update();
            }
            catch (Exception ee)
            {
                Log("update program Exception :" + ee.Message);

            }
            finally
            {
                Environment.Exit(0);
            }
        }



        //更新程序
        public static void Update()
        {
            Log("开始检测更新……");
            // 获取主程序的版本号
            String version = GetVersion(mainFilePath);

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

            if (newVersion != null)
            {

                if ("0.0.0.0".Equals(version))
                {
                    Log("原主程序,直接更新.");
                    Log("开始下载…");
                    if (DownloadNewVersion())
                    {


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


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

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


                }
                else
                {
                    // 如果有新版本,则下载新版本
                    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 static 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 static void InstallNewVersion()
        {

            Log("开始关闭主程序…");
            Process[] ppp = Process.GetProcessesByName(processName);
            if (ppp.Length > 0)
            {
                MessageBox(IntPtr.Zero, "正在执行升级,重启远程鉴定平台。", "升级提示", 0);
                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;

            if (File.Exists(mainFilePath))
            {
                File.Copy(mainFilePath, bakPath, true);
                Log("备份主程序完成。");

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

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

            if (downloadFileName.EndsWith(".zip",StringComparison.CurrentCultureIgnoreCase))
            {
                //如果升级包是zip 先解压
                try
                {
                    // 解压zip文件到当前目录
                    ZipFile.ExtractToDirectory(downloadFileName, "./");
                    Console.WriteLine("Zip文件解压成功!");
                    File.Delete(downloadFileName);
                    Log("删除下载文件OK。 ");
                }
                catch (Exception ex)
                {
                    Console.WriteLine("解压zip文件时出错:" + ex.Message);
                }

            }
            else
            {
                File.Copy(downloadFileName, mainFilePath);
                Log("更新主程序完成。");

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

          


        }


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

            String json = request( updateUrl);

            //{"msg":"操作成功","code":200,"data":{"versionName":"1.0.0.1","updateContent":"test","fileSize":"107KB","url":"http://192.168.22.144:8904/common/downloadAppFile/2666c50a-6e1c-4a8a-b8f6-c1a5002d4ca0.exe","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 static void Log(string v)
        {
    
            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 static String GetVersion(string path)
        {
            Log("获取本地版本号……:" + path + "\n");

            if (!File.Exists(path))
            {
                string currentDirectory = Directory.GetCurrentDirectory();
                Console.WriteLine("Current Directory: " + currentDirectory);
                path = currentDirectory + "\\" + path;

                if (!File.Exists(path))
                {
                    Log("检测不到主文件,直接返回原始版本号");
                    return "0.0.0.0";
                }
            }

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

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

            Log("获取本地版本号:" + 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;
        }
    }
}

     因为升级是后台进行的,所以编译代码时 不要显示控制台,改一下:

  1. 打开 Visual Studio 中的项目。
  2. 在解决方案资源管理器中,右键单击项目,然后选择“属性”。
  3. 在属性窗口中,选择“应用程序”选项卡。
  4. 在“输出类型”下拉菜单中选择“Windows 应用程序”。
  5. 保存更改并重新构建项目。

如下图:

代码编译后,发现引用了很多dll,原因是因为升级接口返回的是json数据所以使用了一个json解析用到几个dll,需要复制到需要用到升级功能的项目即可。

实现效果图如下:

 

查看更新日记 

 

测试完美实现更新。 

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

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

相关文章

如何让Ubuntu上的MySQL开发更便捷

前言 作为一款开源的数据库开发与数据库管理协同工具&#xff0c;&#xff08;OceanBase Developer Center&#xff0c;简称ODC&#xff09;&#xff0c;针对MySQL数据源&#xff0c;已提供了涵盖SQL开发、变更风险管控、数据安全合规等多个方面的功能&#xff0c;从而为MySQL…

Java集合框架-Collection-List-vector(遗留类)

目录 一、vector层次结构图二、概述三、底层数据结构四、常用方法五、和ArrayList的对比 一、vector层次结构图 二、概述 Vector类是单列集合List接口的一个实现类。与ArrayList类似&#xff0c;Vector也实现了一个可以动态修改的数组&#xff0c;两者最本质的区别在于——Vec…

# 使用 Hystrix 的线程池,idea 报错显示 HystrixThreadPoo1Properties.Setter 报红。

使用 Hystrix 的线程池&#xff0c;idea 报错显示 HystrixThreadPoo1Properties.Setter 报红。 一、可能的原因&#xff1a; 1、拼写错误&#xff1a; HystrixThreadPoo1Properties.Setter 中的 “Poo1” 可能是拼写错误&#xff0c;应为“Pool”。 2、类或方法不存在&#…

BGP配置和应用案例

策略路由的配置步骤 l 策略路由的配置步骤如下&#xff1a; 创建route-map 通过ACL匹配感兴趣的数据&#xff0c;定义策略动作 在指定接口下通过ip policy 命令应用route-map l 最终实现对通过该接口进入设备的数据进行检查&#xff0c;对匹配的数据执行规定的策略…

Selenium IDE 常见错误笔记

错误1&#xff1a;Failed:Exceeded waiting time for new window to appear 2000ms 这个错误通常出现在第一次运行时&#xff0c;有两个原因&#xff1a; Firefox阻止了弹出式窗口&#xff0c;在浏览器设置里允许这个操作即可。 有些网站设置了反扒机制&#xff0c;脚本运行…

【1569】jsp学生学籍管理系统Myeclipse开发sqlserver数据库web结构jsp编程计算机网页项目

一、源码特点 jsp 学生学籍管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为sqlserver2…

Cmake入门学习指南

Cmake入门学习指南 Cmake 官方教程 cmake 提供了一个很好的教程&#xff0c;里面的内容很简单&#xff0c;并且有简单的习题帮助你理解 cmake。 开始前需要的准备 这里默认你使用 windows 环境的电脑进行学习&#xff0c;如果是 Linux 系统就更简单了&#xff0c;直接各种 a…

企业微信hook接口协议,ipad协议http,发送大视频文件

发送大视频文件 参数名必选类型说明uuid是String每个实例的唯一标识&#xff0c;根据uuid操作具体企业微信send_userid是long要发送的人或群idisRoom是bool是否是群消息 请求示例 {"uuid":"1688853790xxx", //uuid 默认随机生成如果初始化传了id则用初始…

苍穹外卖学习

并不包含全部视频内容&#xff0c;大部分都按照操作文档来手搓代码&#xff0c;资料&#xff0c;代码都上传git。 〇、实际代码 0.1 Result封装 package com.sky.result;import lombok.Data;import java.io.Serializable;/*** 后端统一返回结果* param <T>*/ Data pub…

【iconv】Linux c++ 中文字符串转十六进制 GBK 编码/内码

文章目录 问题描述c 代码CMakeLists.txt参考链接 问题描述 Linux 系统默认使用的是 UTF-8 编码&#xff0c;并且 c 中没有标准库可以直接将中文字符转为 GBK 编码/内码。因此需要借助 iconv 库来实现。 在实现代码之前&#xff0c;可以在一下在线工具网站进行中文字符到各个编…

Docker 的数据管理 端口映射 容器互联 镜像的创建

目录 概念 概念 管理 Docker 容器中数据主要有两种方式&#xff1a;数据卷&#xff08;Data Volumes&#xff09;和数据卷容器&#xff08;DataVolumes Containers&#xff09;。总结&#xff1a;因为容器数据是临时保存的为了安全&#xff0c;就要让数据保持持久化。 1&#…

面试ssss

深拷贝和浅拷贝 深拷贝和浅拷贝是关于对象&#xff08;包括数组&#xff09;复制的两个概念。 浅拷贝在复制对象属性的时候&#xff0c;复制的是指针&#xff08;引用&#xff09;&#xff0c;所以&#xff0c;修改目标对象的属性值会影响到原对象的对应属性值 obj。assign …

互联网大厂ssp面经,数据结构part2

1. 什么是堆和优先队列&#xff1f;它们的特点和应用场景是什么&#xff1f; a. 堆是一种特殊的树形数据结构&#xff0c;具有以下特点&#xff1a;i. 堆是一个完全二叉树&#xff0c;即除了最后一层外&#xff0c;其他层都是满的&#xff0c;并且最后一层的节点都靠左对齐。i…

深入探索MySQL:成本模型解析与查询性能优化

码到三十五 &#xff1a; 个人主页 在数据库管理系统中&#xff0c;查询优化器是一个至关重要的组件&#xff0c;它负责将用户提交的SQL查询转换为高效的执行计划。在MySQL中&#xff0c;查询优化器使用了一个称为“成本模型”的机制来评估不同执行计划的优劣&#xff0c;并选择…

一般神经网络的微分与网络参数的初始化

(文章的主要内容来自电科的顾亦奇老师的 Mathematical Foundation of Deep Learning, 有部分个人理解) 一般深度神经网络的微分 上周讨论的前向和反向传播算法可以推广到任意深度神经网络的微分。 对于一般的网络来说&#xff0c;可能无法逐层分割&#xff0c;但仍然可以用流…

【HarmonyOS4学习笔记】《HarmonyOS4+NEXT星河版入门到企业级实战教程》课程学习笔记(三)

课程地址&#xff1a; 黑马程序员HarmonyOS4NEXT星河版入门到企业级实战教程&#xff0c;一套精通鸿蒙应用开发 &#xff08;本篇笔记对应课程第 4 - 6节&#xff09; P5《04.快速入门》 本节来实现一个 HelloWorld 效果&#xff1a; 1、打开编辑器&#xff0c;选择新建项目&…

洁盟超声波清洗机怎么样?希亦好用还是洁盟?超声波清洗机推荐

是不是还有很多朋友在选超声波清洗机方面还是觉得是越贵的就越好用&#xff01;或者说是不是还有很多小伙伴是不知道怎么选超声波清洗机&#xff1f;盲目跟风选超声波清洗机后才会知道真的很容易话冤枉钱&#xff0c;也并不是越贵的超声波清洗机就是越好的&#xff0c;在选超声…

Pandas 模块-操纵数据(11)-二元运算--超级add、sub、mul、div、mod、pow等等

目录 1. DataFrame.add 1.1 DataFrame.add 语法结构 1.2 DataFrame.add 参数说明 1.3 DataFrame.add 用法示例 1.3.1 正常的使用 1.3.2 需要注意类型相符合 2. DataFrame.sub 2.1 DataFrame.sub 语法结构 2.2 DataFrame.sub 参数说明 2.3 DataFrame.sub 用法示例 3.…

MySQL中什么情况下会出现索引失效?如何排查索引失效?

目录 1-引言&#xff1a;什么是MySQL的索引失效&#xff1f;(What、Why)1-1 索引失效定义1-2 为什么排查索引失效 2- 索引失效的原因及排查&#xff08;How&#xff09;2-1 索引失效的情况① 索引列参与计算② 对索引列进行函数操作③ 查询中使用了 OR 两边有范围查询 > 或 …

2.7设计模式——Proxy 代理模式(结构型)

意图 为其它对象提供一种代理以控制这个对象的访问。 结构 Proxy保存一个引用使得代理可以访问实体&#xff1b;提供一个与Subject的接口相同的接口&#xff0c;使代理可以用来替代实体&#xff1b;控制实体的存取&#xff0c;并可能负责创建和删除它&#xff1b;其他功能依赖…