一 实现程序更新思路
程序实现自我升级,一般有两种方式:
1. 独立的更新程序
开发一个独立的更新程序如Update.exe,用于检查主程序是否有新版本,并下载和安装新版本。
实现步骤:
- 主程序启动完后,调用一下更新程序。
- 更新程序检查版本不需要更新就退出否则执行更新。
- 更新程序检查主程序的版本号。
- 如果主程序的版本号低于服务器上的版本号,则下载新版本。
- 下载完成后,更新程序将新版本安装到主程序的目录中(一般要备份旧版的)。
- 更新程序重启主程序。
优点:
- 更新过程对用户透明,用户无需手动操作。
- 可以实现增量更新,只下载更新的文件,节省流量。
缺点:
- 更新程序需要访问服务器,如果服务器不可访问,则无法更新。
2. 主程序自带更新功能
将更新功能集成到主程序中,无需开发额外的更新程序。
实现步骤如下:
- 主程序启动时,向服务器发送请求,检查是否有新版本。
- 如果有新版本,则服务器返回新版本的版本号和下载地址。
- 主程序下载新版本。
- 下载完成后,主程序将新版本安装到自己的目录中。
- 主程序重启自身。
优点:
- 开发简单,在更新过程中无需考虑与主程序通讯。
缺点:
- 每次更新都需要下载整个程序,比较耗流量,在更新后不能很好实现自我重启,需要用脚本或者其它方式。
二 程序更新代码(独立的更新程序)
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;}
执行后的更新日记