/// <summary> /// 删除原始安装文件 /// </summary> bool DeletePreviousFile(RunworkEventArgs e) { if (this.UpdateInfo.DeleteMethod == DeletePreviousProgramMethod.None) { return(true); } e.PostEvent(OnDeleteFileStart); var bakPath = RollbackPath; var rules = UpdateInfo.GetDeleteFileLimitRuleSet(); //找到所有文件 var allOldFiles = System.IO.Directory.GetFiles(ApplicationRoot, "*.*", System.IO.SearchOption.AllDirectories); //备份 var index = 0; foreach (var file in allOldFiles) { var rPath = file.Remove(0, ApplicationRoot.Length).TrimEnd('\\'); //保留的文件 if (PreservedFiles.ContainsKey(rPath)) { Trace.TraceInformation("文件 {0} 在保持文件列表中,跳过删除", file); continue; } var dPath = System.IO.Path.Combine(bakPath, rPath); if ((UpdateInfo.DeleteMethod == DeletePreviousProgramMethod.AllExceptSpecified && rules.FindIndex(s => s.IsMatch(rPath)) == -1) || (UpdateInfo.DeleteMethod == DeletePreviousProgramMethod.NoneButSpecified && rules.FindIndex(s => s.IsMatch(rPath)) != -1) ) { e.PostEvent(() => OnDeleteFile(new InstallFileEventArgs(file, dPath, allOldFiles.Length, ++index))); try { System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(dPath)); Trace.TraceInformation("备份并删除文件: {0} -> {1}", file, dPath); System.IO.File.Copy(file, dPath); System.IO.File.Delete(file); bakList.Add(rPath); } catch (Exception ex) { this.Exception = ex; Trace.TraceWarning("删除失败:" + ex.Message); return(false); } } } e.PostEvent(OnDeleteFileFinished); return(true); }
/// <summary> /// 安装文件 /// </summary> bool InstallFiles(RunworkEventArgs e) { e.PostEvent(OnInstallFileStart); string[] filelist = CreateNewFileList(); string OriginalPath, newVersionFile, backupPath; OriginalPath = newVersionFile = ""; try { var index = 0; foreach (var file in filelist) { OriginalPath = System.IO.Path.Combine(ApplicationRoot, file); newVersionFile = System.IO.Path.Combine(SourceFolder, file); backupPath = System.IO.Path.Combine(BackupPath, file); e.PostEvent(() => OnInstallFile(new InstallFileEventArgs(newVersionFile, OriginalPath, filelist.Length, ++index))); if (System.IO.File.Exists(OriginalPath)) { System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(backupPath)); System.IO.File.Move(OriginalPath, backupPath); Trace.TraceInformation("备份文件: " + OriginalPath + " -> " + backupPath); bakList.Add(file); } System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(OriginalPath)); System.IO.File.Move(newVersionFile, OriginalPath); installedFile.Add(file); Trace.TraceInformation("安装文件: " + newVersionFile + " -> " + OriginalPath); } } catch (Exception ex) { this.Exception = new Exception(string.Format(SR.Updater_InstallFileError, OriginalPath, newVersionFile, ex.Message)); Trace.Fail("安装文件时发生错误:" + ex.Message, ex.ToString()); return(false); } e.PostEvent(OnInstallFileFinished); return(true); }
/// <summary> /// 回滚备份的文件 /// </summary> void RollbackFiles(RunworkEventArgs e) { e.PostEvent(OnRollbackStart); var rootPath = RollbackPath; var index = 0; foreach (string file in bakList) { string newPath = System.IO.Path.Combine(ApplicationRoot, file); string oldPath = System.IO.Path.Combine(rootPath, file); OnRollbackFile(new InstallFileEventArgs(oldPath, newPath, bakList.Count, ++index)); Trace.TraceInformation("还原原始文件: " + oldPath + " -> " + newPath); System.IO.File.Move(oldPath, newPath); } e.PostEvent(OnRollbackFinished); }
/// <summary> /// 回滚备份的文件 /// </summary> void RollbackFiles(RunworkEventArgs e) { e.PostEvent(OnRollbackStart); var rootPath = RollbackPath; var index = 0; foreach (string file in _bakList) { e.ReportProgress(_bakList.Count, ++index, file); var newPath = Path.Combine(ApplicationRoot, file); var oldPath = Path.Combine(rootPath, file); OnRollbackFile(new InstallFileEventArgs(oldPath, newPath, _bakList.Count, index, file)); _logger.LogInformation("Restore original file: '" + oldPath + "' -> '" + newPath + "'"); File.Move(oldPath, newPath); } e.PostEvent(OnRollbackFinished); }
/// <summary> /// 回滚备份的文件 /// </summary> void RollbackFiles(RunworkEventArgs e) { e.PostEvent(OnRollbackStart); var rootPath = RollbackPath; var index = 0; foreach (string file in _bakList) { e.ReportProgress(_bakList.Count, ++index, file); var newPath = System.IO.Path.Combine(ApplicationRoot, file); var oldPath = System.IO.Path.Combine(rootPath, file); OnRollbackFile(new InstallFileEventArgs(oldPath, newPath, _bakList.Count, index)); Trace.TraceInformation("还原原始文件: " + oldPath + " -> " + newPath); System.IO.File.Move(oldPath, newPath); } e.PostEvent(OnRollbackFinished); }
/// <summary> /// 删除原始安装文件 /// </summary> bool DeletePreviousFile(RunworkEventArgs e) { if (this.UpdateInfo.DeleteMethod == DeletePreviousProgramMethod.None) return true; e.PostEvent(OnDeleteFileStart); var bakPath = RollbackPath; var rules = UpdateInfo.GetDeleteFileLimitRuleSet(); //找到所有文件 var allOldFiles = System.IO.Directory.GetFiles(ApplicationRoot, "*.*", System.IO.SearchOption.AllDirectories); //备份 foreach (var file in allOldFiles) { var rPath = file.Remove(0, ApplicationRoot.Length).TrimEnd('\\'); var dPath = System.IO.Path.Combine(bakPath, rPath); if ((UpdateInfo.DeleteMethod == DeletePreviousProgramMethod.AllExceptSpecified && rules.FindIndex(s => s.IsMatch(rPath)) == -1) || (UpdateInfo.DeleteMethod == DeletePreviousProgramMethod.NoneButSpecified && rules.FindIndex(s => s.IsMatch(rPath)) != -1) ) { e.PostEvent(new SendOrPostCallback(_arg => OnDeleteFile(new InstallFileEventArgs(file, dPath)))); try { System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(dPath)); Debug.WriteLine("Moving File: " + file + " -> " + dPath); System.IO.File.Move(file, dPath); installedFile.Add(rPath); } catch (Exception ex) { this.Exception = ex; return false; } } } e.PostEvent(OnDeleteFileFinished); return true; }
/// <summary> /// 关闭主程序进程 /// </summary> bool CloseApplication(RunworkEventArgs e) { Trace.TraceInformation("开始关闭进程"); e.ReportProgress(0, 0, "正在关闭进程...."); var closeApplication = new List<Process>(); foreach (var pid in Context.ExternalProcessID) { try { closeApplication.Add(Process.GetProcessById(pid)); Trace.TraceInformation("添加进程PID=" + pid + "到等待关闭列表"); } catch (Exception ex) { Trace.TraceInformation("添加进程PID=" + pid + "到等待关闭列表时出错:" + ex.Message); } } foreach (var pn in Context.ExternalProcessName) { closeApplication.AddRange(Process.GetProcessesByName(pn)); Trace.TraceInformation("添加进程名=" + pn + "到等待关闭列表"); } if (closeApplication.Count > 0) { //是否强制关闭进程? if (Context.AutoKillProcesses) { closeApplication.ForEach(s => s.Kill()); return true; } var evt = new QueryCloseApplicationEventArgs(closeApplication, NotifyUserToCloseApp); e.PostEvent(_ => OnQueryCloseApplication(evt)); while (!evt.IsCancelled.HasValue) { Thread.Sleep(100); } return !evt.IsCancelled.Value; } return true; }
/// <summary> /// 下载更新信息 /// </summary> /// <exception cref="System.ApplicationException">服务器返回了不正确的更新结果</exception> void DownloadUpdateInfoInternal(object sender, RunworkEventArgs e) { if (!Context.IsUpdateInfoDownloaded) { //下载更新信息 e.PostEvent(OnDownloadUpdateInfo); //下载信息时不直接下载到文件中.这样不会导致始终创建文件夹 Exception ex = null; byte[] data = null; var url = Context.RandomUrl(Context.UpdateInfoFileUrl); var client = Context.CreateWebClient(); client.DownloadProgressChanged += (x, y) => e.ReportProgress((int)y.TotalBytesToReceive, (int)y.BytesReceived); //远程下载。为了支持进度显示,这里必须使用异步下载 using (var wHandler = new AutoResetEvent(false)) { client.DownloadDataCompleted += (x, y) => { ex = y.Error; if (ex == null) { data = y.Result; } wHandler.Set(); }; Trace.TraceInformation("正在从 " + url + " 下载升级信息"); client.DownloadDataAsync(new Uri(url)); //等待下载完成 wHandler.WaitOne(); } Trace.TraceInformation("服务器返回数据----->" + (data == null ? "<null>" : data.Length.ToString() + "字节")); if (data != null && data.Length > 0x10) { //不是<xml标记,则执行解压缩 if (BitConverter.ToInt32(data, 0) != 0x6D783F3C) { Trace.TraceInformation("数据非正常数据, 正在执行解压缩"); data = ExtensionMethod.Decompress(data); } Context.UpdateInfoTextContent = Encoding.UTF8.GetString(data); } if (ex != null) throw ex; e.PostEvent(OnDownloadUpdateInfoFinished); //是否返回了正确的结果? if (string.IsNullOrEmpty(Context.UpdateInfoTextContent)) { throw new ApplicationException("服务器返回了不正确的更新结果"); } } if (Context.UpdateInfo == null) { if (string.IsNullOrEmpty(Context.UpdateInfoTextContent)) { Trace.TraceInformation("正在读取本地升级信息文件"); Context.UpdateInfoTextContent = System.IO.File.ReadAllText(Context.UpdateInfoFilePath, System.Text.Encoding.UTF8); } Context.UpdateInfo = XMLSerializeHelper.XmlDeserializeFromString<UpdateInfo>(Context.UpdateInfoTextContent); } if (Context.UpdateInfo == null) { throw new ApplicationException("未能成功加载升级信息"); } //设置必须的属性 if (Context.UpdateInfo.MustUpdate) { Context.AutoKillProcesses = true; Context.AutoEndProcessesWithinAppDir = true; Context.ForceUpdate = true; } //判断升级 if (!string.IsNullOrEmpty(Context.UpdateInfo.RequiredMinVersion) && Context.CurrentVersion < new Version(Context.UpdateInfo.RequiredMinVersion)) { Context.CurrentVersionTooLow = true; } else { Context.HasUpdate = new Version(Context.UpdateInfo.AppVersion) > Context.CurrentVersion; } if (Context.HasUpdate) { //判断要升级的包 if (PackagesToUpdate == null || PackagesToUpdate.Count == 0) { var pkgList = Context.UpdatePackageListPath; Trace.TraceInformation("外部升级包列表:{0}", pkgList); if (System.IO.File.Exists(pkgList)) { PackagesToUpdate = XMLSerializeHelper.XmlDeserializeFromString<List<PackageInfo>>(System.IO.File.ReadAllText(pkgList)); PackagesToUpdate.ForEach(s => s.Context = Context); } else { GatheringDownloadPackages(e); } var preserveFileList = Context.PreserveFileListPath; Trace.TraceInformation("外部文件保留列表:{0}", preserveFileList); if (System.IO.File.Exists(preserveFileList)) { var list = XMLSerializeHelper.XmlDeserializeFromString<List<string>>(System.IO.File.ReadAllText(preserveFileList)); list.ForEach(s => FileInstaller.PreservedFiles.Add(s, null)); } } } //如果没有要升级的包?虽然很奇怪,但依然当作不需要升级 Context.HasUpdate &= PackagesToUpdate.Count > 0; }
//BMK 更新主函数 (正式更新) /// <summary> /// 运行更新进程(主更新进程) /// </summary> /// <exception cref="System.InvalidProgramException"></exception> /// <exception cref="System.Exception"></exception> void UpdateInternal(object sender, RunworkEventArgs e) { DownloadUpdateInfoInternal(sender, e); //下载升级包。下载完成的时候校验也就完成了 if (!DownloadPackages(e)) return; //解压缩升级包 ExtractPackage(e); //关闭主程序 if (!CloseApplication(e)) throw new Exception(SR.Updater_UpdateCanceledByCloseApp); //运行安装前进程 e.PostEvent(OnExecuteExternalProcessBefore); RunExternalProgramBefore(e); //安装文件 e.PostEvent(OnInstallUpdates); FileInstaller.UpdateInfo = Context.UpdateInfo; FileInstaller.ApplicationRoot = Context.ApplicationDirectory; FileInstaller.WorkingRoot = Context.UpdateTempRoot; FileInstaller.SourceFolder = Context.UpdateNewFilePath; if (!FileInstaller.Install(e)) { throw FileInstaller.Exception; } //运行安装后进程 e.PostEvent(OnExecuteExternalProcessAfter); RunExternalProgramAfter(e); //完成更新 e.PostEvent(OnUpdateFinsihed); }
/// <summary> /// 关闭主程序进程 /// </summary> bool CloseApplication(RunworkEventArgs e) { string[] argus = Environment.GetCommandLineArgs(); List<Process> closeApplication = new List<Process>(); for (int i = 4; i < argus.Length; i++) { string tid = argus[i]; if (tid.StartsWith("*")) { //TID模式 int t = int.Parse(tid.Trim(new char[] { '*' })); try { Process p = Process.GetProcessById(t); if (p != null) closeApplication.Add(p); } catch (Exception ex) { Debug.WriteLine(ex.Message); } } else { Process[] plist = Process.GetProcessesByName(tid); if (plist.Length > 0) closeApplication.AddRange(plist); } } if (closeApplication.Count > 0) { var evt = new QueryCloseApplicationEventArgs(closeApplication, NotifyUserToCloseApp); e.PostEvent(new SendOrPostCallback(_ => OnQueryCloseApplication(evt))); while (!evt.IsCancelled.HasValue) { System.Threading.Thread.Sleep(100); } return !evt.IsCancelled.Value; } return true; }
/// <summary> /// 安装文件 /// </summary> bool InstallFiles(RunworkEventArgs e) { e.PostEvent(OnInstallFileStart); string[] filelist = CreateNewFileList(); string OriginalPath, newVersionFile, backupPath; OriginalPath = newVersionFile = ""; var tryCount = 0; try { var index = 0; foreach (var file in filelist) { e.ReportProgress(filelist.Length, ++index, file); OriginalPath = Path.Combine(ApplicationRoot, file); newVersionFile = Path.Combine(SourceFolder, file); backupPath = Path.Combine(RollbackPath, file); e.PostEvent(() => OnInstallFile(new InstallFileEventArgs(newVersionFile, OriginalPath, filelist.Length, index, file))); if (File.Exists(OriginalPath)) { Directory.CreateDirectory(Path.GetDirectoryName(backupPath)); tryCount = 0; while (true) { ++tryCount; try { if (File.Exists(OriginalPath)) { _logger.LogInformation("No." + tryCount + " attempt to backup file: '" + OriginalPath + "' -> '" + backupPath + "'"); File.Copy(OriginalPath, backupPath, true); _logger.LogInformation("No." + tryCount + "attempt to delete file: '" + OriginalPath); File.Delete(OriginalPath); _logger.LogInformation("Backup succeed."); } break; } catch (Exception ex) { _logger.LogError($"No.{tryCount} attempt failed:{ex.Message}", ex); if (tryCount < 20) { Thread.Sleep(1000); } else { throw; } } } _bakList.Add(file); } tryCount = 0; while (true) { ++tryCount; try { _logger.LogInformation("Copying new file: '" + newVersionFile + "' -> '" + OriginalPath + "'"); Directory.CreateDirectory(Path.GetDirectoryName(OriginalPath)); File.Copy(newVersionFile, OriginalPath); _logger.LogInformation("Installation succeed."); break; } catch (Exception ex) { _logger.LogWarning($"No.{tryCount}] attempt failed: {ex.Message}"); if (tryCount < 10) { Thread.Sleep(1000); } else { throw; } } } //尝试删除已安装文件 tryCount = 0; while (true) { ++tryCount; try { _logger.LogInformation("Trying removing file: " + newVersionFile); File.Delete(newVersionFile); _logger.LogInformation("Delete succeed."); break; } catch (Exception ex) { _logger.LogWarning("No." + tryCount + " attempt failed: " + ex.Message); if (tryCount < 10) { Thread.Sleep(1000); } else { break; } } } _installedFile.Add(file); _logger.LogInformation("Install file: '" + newVersionFile + "' -> '" + OriginalPath + "'"); } } catch (Exception ex) { Exception = new Exception(string.Format(SR.Updater_InstallFileError, OriginalPath, newVersionFile, ex.Message)); _logger.LogError("Install file failed: " + ex.Message, ex); return(false); } e.PostEvent(OnInstallFileFinished); return(true); }
/// <summary> /// 删除原始安装文件 /// </summary> bool DeletePreviousFile(RunworkEventArgs e) { if (UpdateInfo.DeleteMethod == DeletePreviousProgramMethod.None) { return(true); } e.PostEvent(OnDeleteFileStart); var bakPath = RollbackPath; var rules = UpdateInfo.GetDeleteFileLimitRuleSet(); //找到所有文件 var allOldFiles = Directory.GetFiles(ApplicationRoot, "*.*", SearchOption.AllDirectories); //备份 var index = 0; foreach (var file in allOldFiles) { e.ReportProgress(allOldFiles.Length, ++index, file); var rPath = file.Remove(0, ApplicationRoot.Length).TrimEnd('\\'); //保留的文件 if (PreservedFiles.ContainsKey(rPath)) { _logger.LogInformation($"File '{file}' not touched as it was in reserve list."); continue; } var dPath = Path.Combine(bakPath, rPath); if ((UpdateInfo.DeleteMethod == DeletePreviousProgramMethod.AllExceptSpecified && rules.FindIndex(s => s.IsMatch(rPath)) == -1) || (UpdateInfo.DeleteMethod == DeletePreviousProgramMethod.NoneButSpecified && rules.FindIndex(s => s.IsMatch(rPath)) != -1) ) { e.PostEvent(() => OnDeleteFile(new InstallFileEventArgs(file, dPath, allOldFiles.Length, index, rPath))); Directory.CreateDirectory(Path.GetDirectoryName(dPath)); _logger.LogInformation($"Backup and remove file: '{file}' -> '{dPath}'"); File.Copy(file, dPath); var tryCount = 0; while (true) { ++tryCount; try { File.Delete(file); break; } catch (Exception ex) { Exception = ex; _logger.LogError($"No.{tryCount} attempt to remove file failed: {ex.Message}", ex); } //如果删除失败,则等待1秒后重试 if (tryCount < 10) { Thread.Sleep(1000); } else { return(false); } } _bakList.Add(rPath); } } e.PostEvent(OnDeleteFileFinished); return(true); }
/// <summary> /// 回滚备份的文件 /// </summary> void RollbackFiles(RunworkEventArgs e) { e.PostEvent(OnRollbackStart); string rootPath = RollbackPath; foreach (string file in installedFile) { string newPath = System.IO.Path.Combine(ApplicationRoot, file); string oldPath = System.IO.Path.Combine(rootPath, file); OnRollbackFile(new InstallFileEventArgs(oldPath, newPath)); Debug.WriteLine("Rollback File: " + oldPath + " -> " + newPath); System.IO.File.Move(oldPath, newPath); } e.PostEvent(OnRollbackFinished); }
/// <summary> /// 安装文件 /// </summary> bool InstallFiles(RunworkEventArgs e) { e.PostEvent(OnInstallFileStart); string[] filelist = CreateNewFileList(); string OriginalPath, newVersionFile, backupPath; OriginalPath = newVersionFile = backupPath = ""; try { foreach (var file in filelist) { OriginalPath = System.IO.Path.Combine(ApplicationRoot, file); newVersionFile = System.IO.Path.Combine(SourceFolder, file); backupPath = System.IO.Path.Combine(BackupPath, file); e.PostEvent(new SendOrPostCallback(_ => OnInstallFile(new InstallFileEventArgs(newVersionFile, OriginalPath)))); if (System.IO.File.Exists(OriginalPath)) { System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(backupPath)); System.IO.File.Move(OriginalPath, backupPath); Debug.WriteLine("Backup File: " + OriginalPath + " -> " + backupPath); installedFile.Add(file); } System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(OriginalPath)); System.IO.File.Move(newVersionFile, OriginalPath); Debug.WriteLine("Install File: " + newVersionFile + " -> " + OriginalPath); } } catch (Exception ex) { this.Exception = new Exception(string.Format(DME.Updater.SR.Updater_InstallFileError, OriginalPath, newVersionFile, ex.Message)); return false; } e.PostEvent(OnInstallFileFinished); return true; }
/// <summary> /// 下载更新信息 /// </summary> void DownloadUpdateInfoInternal(object sender, RunworkEventArgs e) { if (!IsUpdateInfoDownloaded) { var client = new System.Net.WebClient(); client.DownloadProgressChanged += (x, y) => { e.ReportProgress((int)y.TotalBytesToReceive, (int)y.BytesReceived); }; //下载更新信息 e.PostEvent(OnDownloadUpdateInfo); //下载信息时不直接下载到文件中.这样不会导致始终创建文件夹 var finished = false; Exception ex = null; client.DownloadDataCompleted += (x, y) => { ex = y.Error; if (ex == null) UpdateContent = System.Text.Encoding.UTF8.GetString(y.Result); finished = true; }; client.DownloadDataAsync(new Uri(UpdateUrl)); while (!finished) { System.Threading.Thread.Sleep(50); } if (this.Exception != null) throw ex; e.PostEvent(OnDownloadUpdateInfoFinished); //是否返回了正确的结果? if (string.IsNullOrEmpty(UpdateContent)) { throw new ApplicationException("服务器返回了不正确的更新结果"); } } if (UpdateInfo == null) { if (string.IsNullOrEmpty(UpdateContent)) { UpdateContent = System.IO.File.ReadAllText(UpdateInfoFilePath, System.Text.Encoding.UTF8); } UpdateInfo = XMLSerializeHelper.XmlDeserializeFromString<UpdateInfo>(UpdateContent); } }
/// <summary> /// 安装文件 /// </summary> bool InstallFiles(RunworkEventArgs e) { e.PostEvent(OnInstallFileStart); string[] filelist = CreateNewFileList(); string OriginalPath, newVersionFile, backupPath; OriginalPath = newVersionFile = ""; var tryCount = 0; try { var index = 0; foreach (var file in filelist) { e.ReportProgress(filelist.Length, ++index, file); OriginalPath = System.IO.Path.Combine(ApplicationRoot, file); newVersionFile = System.IO.Path.Combine(SourceFolder, file); backupPath = System.IO.Path.Combine(RollbackPath, file); e.PostEvent(() => OnInstallFile(new InstallFileEventArgs(newVersionFile, OriginalPath, filelist.Length, index))); if (System.IO.File.Exists(OriginalPath)) { System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(backupPath)); tryCount = 0; while (true) { ++tryCount; try { if (File.Exists(OriginalPath)) { Trace.TraceInformation("第[" + tryCount + "]次尝试备份文件: " + OriginalPath + " -> " + backupPath); File.Copy(OriginalPath, backupPath, true); Trace.TraceInformation("第[" + tryCount + "]次尝试删除文件: " + OriginalPath); File.Delete(OriginalPath); Trace.TraceInformation("备份成功。"); } break; } catch (Exception ex) { Trace.TraceWarning("第[" + tryCount + "]次尝试失败: " + ex.Message); if (tryCount < 20) { Thread.Sleep(1000); } else { throw ex; } } } _bakList.Add(file); } tryCount = 0; while (true) { ++tryCount; try { Trace.TraceInformation("正在复制新版本文件: " + newVersionFile + " -> " + OriginalPath); System.IO.Directory.CreateDirectory(Path.GetDirectoryName(OriginalPath)); System.IO.File.Copy(newVersionFile, OriginalPath); Trace.TraceInformation("安装成功"); break; } catch (Exception ex) { Trace.TraceWarning("第[" + tryCount + "]次尝试失败: " + ex.Message); if (tryCount < 10) { Thread.Sleep(1000); } else { throw ex; } } } //尝试删除已安装文件 tryCount = 0; while (true) { ++tryCount; try { Trace.TraceInformation("正在尝试删除已安装文件: " + newVersionFile); System.IO.File.Delete(newVersionFile); Trace.TraceInformation("删除成功"); break; } catch (Exception ex) { Trace.TraceWarning("第[" + tryCount + "]次尝试失败: " + ex.Message); if (tryCount < 10) { Thread.Sleep(1000); } else { break; } } } _installedFile.Add(file); Trace.TraceInformation("安装文件: " + newVersionFile + " -> " + OriginalPath); } } catch (Exception ex) { this.Exception = new Exception(string.Format(SR.Updater_InstallFileError, OriginalPath, newVersionFile, ex.Message)); Trace.TraceWarning("安装文件时发生错误:" + ex.Message, ex.ToString()); return(false); } e.PostEvent(OnInstallFileFinished); return(true); }
//BMK 更新主函数 (正式更新) /// <summary> /// 运行更新进程(主更新进程) /// </summary> void UpdateInternal(object sender, RunworkEventArgs e) { Action<int, int> reportProgress = (x, y) => e.ReportProgress(x, y); DownloadUpdateInfoInternal(sender, e); //下载更新包 e.PostEvent(OnDownloadPackage); var packageDownloader = new Lib.PackageDownloader(AppInfoProvider.GetUpdatePackageUrl(UpdateUrl, UpdateInfo), UpdatePackageFilePath) { ProgressReportor = reportProgress }; if (!packageDownloader.Download()) { this.Exception = packageDownloader.Exception; return; } e.PostEvent(OnDownloadPackageFinished); //验证包 e.PostEvent(OnVerifyPackage); var packageValidator = new Lib.PackageValidator(UpdateInfo.MD5, UpdatePackageFilePath); if (!packageValidator.Validate((x, y) => e.ReportProgress(x, y))) throw new InvalidProgramException(DME.Updater.SR.Updater_MD5VerifyFailed); e.PostEvent(OnVerifyPackageFinished); //解压缩并安装包 ExtractPackage(e); //关闭主程序 if (!CloseApplication(e)) throw new Exception(DME.Updater.SR.Updater_UpdateCanceledByCloseApp); //运行安装前进程 RunExternalProgramBefore(); //安装文件 var installer = this.FileInstaller; installer.ProgressReportor = reportProgress; installer.UpdateInfo = this.UpdateInfo; if (!installer.Install(e)) { throw installer.Exception; } //运行安装后进程 RunExternalProgramAfter(); //完成更新 e.PostEvent(OnUpdateFinsihed); }
/// <summary> /// 解开安装包 /// </summary> void ExtractPackage(RunworkEventArgs rt) { Trace.TraceInformation("开始解压缩升级包"); rt.PostEvent(() => OnPackageExtractionBegin(new PackageEventArgs(null))); var fze = new ICCEmbedded.SharpZipLib.Zip.FastZipEvents(); fze.ProcessFile += (s, e) => rt.ReportProgress(0, 0, string.Format(SR.Updater_ExtractingFile, e.Name)); var fz = new ICCEmbedded.SharpZipLib.Zip.FastZip(fze); if (!string.IsNullOrEmpty(Context.UpdateInfo.PackagePassword)) { fz.Password = Context.UpdateInfo.PackagePassword; } foreach (var pkg in PackagesToUpdate) { Trace.TraceInformation("正在解压缩 " + pkg.PackageName); rt.PostEvent(() => OnPackageExtractionBegin(new PackageEventArgs(pkg))); fz.ExtractZip(pkg.LocalSavePath, Context.UpdateNewFilePath, null); rt.PostEvent(() => OnPackageExtractionEnd(new PackageEventArgs(pkg))); Trace.TraceInformation("完成解压缩 " + pkg.PackageName); } rt.PostEvent(() => OnPackageExtractionEnd(new PackageEventArgs(null))); Trace.TraceInformation("完成解压缩升级包"); }
/// <summary> /// 删除原始安装文件 /// </summary> bool DeletePreviousFile(RunworkEventArgs e) { if (this.UpdateInfo.DeleteMethod == DeletePreviousProgramMethod.None) return true; e.PostEvent(OnDeleteFileStart); var bakPath = RollbackPath; var rules = UpdateInfo.GetDeleteFileLimitRuleSet(); //找到所有文件 var allOldFiles = System.IO.Directory.GetFiles(ApplicationRoot, "*.*", System.IO.SearchOption.AllDirectories); //备份 var index = 0; foreach (var file in allOldFiles) { e.ReportProgress(allOldFiles.Length, ++index, file); var rPath = file.Remove(0, ApplicationRoot.Length).TrimEnd('\\'); //保留的文件 if (PreservedFiles.ContainsKey(rPath)) { Trace.TraceInformation("文件 {0} 在保持文件列表中,跳过删除", file); continue; } var dPath = System.IO.Path.Combine(bakPath, rPath); if ((UpdateInfo.DeleteMethod == DeletePreviousProgramMethod.AllExceptSpecified && rules.FindIndex(s => s.IsMatch(rPath)) == -1) || (UpdateInfo.DeleteMethod == DeletePreviousProgramMethod.NoneButSpecified && rules.FindIndex(s => s.IsMatch(rPath)) != -1) ) { e.PostEvent(() => OnDeleteFile(new InstallFileEventArgs(file, dPath, allOldFiles.Length, index))); System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(dPath)); Trace.TraceInformation("备份并删除文件: {0} -> {1}", file, dPath); System.IO.File.Copy(file, dPath); var tryCount = 0; while (true) { ++tryCount; try { System.IO.File.Delete(file); break; } catch (Exception ex) { this.Exception = ex; Trace.TraceWarning("第[" + tryCount + "]次删除失败:" + ex.Message); } //如果删除失败,则等待1秒后重试 if (tryCount < 10) Thread.Sleep(1000); else return false; } _bakList.Add(rPath); } } e.PostEvent(OnDeleteFileFinished); return true; }
/// <summary> 生成下载列表 </summary> void GatheringDownloadPackages(RunworkEventArgs rt) { if (PackagesToUpdate.Count > 0) return; Trace.TraceInformation("正在确定需要下载的升级包"); rt.PostEvent(OnGatheringPackages); if (!string.IsNullOrEmpty(Context.UpdateInfo.Package) && (Context.UpdateInfo.Packages == null || Context.UpdateInfo.Packages.Count == 0)) { //必须更新的包 Trace.TraceInformation("正在添加必须升级的主要安装包"); PackagesToUpdate.Add(new PackageInfo() { FilePath = "", FileSize = 0, PackageHash = Context.UpdateInfo.MD5, Method = UpdateMethod.Always, PackageName = Context.UpdateInfo.Package, PackageSize = Context.UpdateInfo.PackageSize, VerificationLevel = FileVerificationLevel.Hash, Version = "0.0.0.0", Context = Context }); } if (Context.UpdateInfo.Packages != null) { //判断增量升级包 var index = 0; foreach (var pkg in Context.UpdateInfo.Packages) { rt.ReportProgress(++index, Context.UpdateInfo.Packages.Count); var localPath = System.IO.Path.Combine(Context.ApplicationDirectory, pkg.FilePath); //对比本地路径 pkg.Context = Context; if (pkg.Method == UpdateMethod.Always) { Trace.TraceInformation("标记为始终更新,添加升级包 【" + pkg.PackageName + "】"); PackagesToUpdate.Add(pkg); continue; } //存在即跳过,或版本比较 if (!System.IO.File.Exists(localPath)) { PackagesToUpdate.Add(pkg); Trace.TraceInformation("本地路径【" + pkg.FilePath + "】不存在,添加升级包 【" + pkg.PackageName + "】"); continue; } //如果存在即跳过……那么你好去跳过了。 if (pkg.Method == UpdateMethod.SkipIfExists) { AddPackageToPreserveList(pkg); Trace.TraceInformation("本地路径【" + pkg.FilePath + "】已经存在,跳过升级包 【" + pkg.PackageName + "】"); continue; } var isNewer = false; if ((pkg.VerificationLevel & FileVerificationLevel.Version) == FileVerificationLevel.Version) { isNewer |= string.IsNullOrEmpty(pkg.Version) || ExtensionMethod.CompareVersion(localPath, pkg.Version); } if ((pkg.VerificationLevel & FileVerificationLevel.Hash) == FileVerificationLevel.Hash) { isNewer |= ExtensionMethod.GetFileHash(localPath) != pkg.FileHash; } if ((pkg.VerificationLevel & FileVerificationLevel.Size) == FileVerificationLevel.Size) { isNewer |= new System.IO.FileInfo(localPath).Length != pkg.FileSize; } if (isNewer) { Trace.TraceInformation("服务器版本更新,添加升级包 【" + pkg.PackageName + "】"); pkg.Context = Context; PackagesToUpdate.Add(pkg); } else { AddPackageToPreserveList(pkg); Trace.TraceInformation("服务器版本更旧或相同,跳过升级包 【" + pkg.PackageName + "】"); } } } rt.PostEvent(OnGatheredPackages); Trace.TraceInformation("完成确定需要下载的升级包"); }
/// <summary> /// 安装文件 /// </summary> bool InstallFiles(RunworkEventArgs e) { e.PostEvent(OnInstallFileStart); string[] filelist = CreateNewFileList(); string OriginalPath, newVersionFile, backupPath; OriginalPath = newVersionFile = ""; var tryCount = 0; try { var index = 0; foreach (var file in filelist) { e.ReportProgress(filelist.Length, ++index, file); OriginalPath = System.IO.Path.Combine(ApplicationRoot, file); newVersionFile = System.IO.Path.Combine(SourceFolder, file); backupPath = System.IO.Path.Combine(RollbackPath, file); e.PostEvent(() => OnInstallFile(new InstallFileEventArgs(newVersionFile, OriginalPath, filelist.Length, index))); if (System.IO.File.Exists(OriginalPath)) { System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(backupPath)); tryCount = 0; while (true) { ++tryCount; try { if (File.Exists(OriginalPath)) { Trace.TraceInformation("第[" + tryCount + "]次尝试备份文件: " + OriginalPath + " -> " + backupPath); File.Copy(OriginalPath, backupPath, true); Trace.TraceInformation("第[" + tryCount + "]次尝试删除文件: " + OriginalPath); File.Delete(OriginalPath); Trace.TraceInformation("备份成功。"); } break; } catch (Exception ex) { Trace.TraceWarning("第[" + tryCount + "]次尝试失败: " + ex.Message); if (tryCount < 20) Thread.Sleep(1000); else throw ex; } } _bakList.Add(file); } tryCount = 0; while (true) { ++tryCount; try { Trace.TraceInformation("正在复制新版本文件: " + newVersionFile + " -> " + OriginalPath); System.IO.Directory.CreateDirectory(Path.GetDirectoryName(OriginalPath)); System.IO.File.Copy(newVersionFile, OriginalPath); Trace.TraceInformation("安装成功"); break; } catch (Exception ex) { Trace.TraceWarning("第[" + tryCount + "]次尝试失败: " + ex.Message); if (tryCount < 10) Thread.Sleep(1000); else throw ex; } } //尝试删除已安装文件 tryCount = 0; while (true) { ++tryCount; try { Trace.TraceInformation("正在尝试删除已安装文件: " + newVersionFile); System.IO.File.Delete(newVersionFile); Trace.TraceInformation("删除成功"); break; } catch (Exception ex) { Trace.TraceWarning("第[" + tryCount + "]次尝试失败: " + ex.Message); if (tryCount < 10) Thread.Sleep(1000); else break; } } _installedFile.Add(file); Trace.TraceInformation("安装文件: " + newVersionFile + " -> " + OriginalPath); } } catch (Exception ex) { this.Exception = new Exception(string.Format(SR.Updater_InstallFileError, OriginalPath, newVersionFile, ex.Message)); Trace.TraceWarning("安装文件时发生错误:" + ex.Message, ex.ToString()); return false; } e.PostEvent(OnInstallFileFinished); return true; }
/// <summary> /// 执行外部进程 /// </summary> /// <param name="program"></param> /// <param name="arguments"></param> /// <param name="waitingForExit">是否等待进程退出</param> /// <param name="hide">是否隐藏进程执行的窗口</param> /// <returns></returns> bool RunExternalProgram(RunworkEventArgs e, string program, string arguments, bool waitingForExit, bool hide) { if (string.IsNullOrEmpty(program)) return true; var psi = new ProcessStartInfo(program, ReplaceEnvVar(arguments)) { WindowStyle = hide ? ProcessWindowStyle.Hidden : ProcessWindowStyle.Normal }; SetProcessEnvVar(psi); Trace.TraceInformation("正在执行外部进程,路径:{0},参数:{1}", psi.FileName, psi.Arguments); e.PostEvent(RunExternalProcess, this, new RunExternalProcessEventArgs(psi)); var p = Process.Start(psi); if (waitingForExit) { Trace.TraceInformation("等待外部进程执行完毕"); if (Context.UpdateInfo.ExecuteTimeout > 0) { p.WaitForExit(1000 * Context.UpdateInfo.ExecuteTimeout); } else p.WaitForExit(); Action<Process> actor = m => { var pet = new ProgramExecuteTimeout(); if (pet.ShowDialog() == DialogResult.OK) { if (!m.HasExited) m.Kill(); } }; while (!p.HasExited) { Application.OpenForms[0].Invoke(actor, p); if (!p.HasExited) p.WaitForExit(1000 * Context.UpdateInfo.ExecuteTimeout); } } Trace.TraceInformation("外部进程执行完毕"); return true; }
/// <summary> /// 安装文件 /// </summary> bool InstallFiles(RunworkEventArgs e) { e.PostEvent(OnInstallFileStart); string[] filelist = CreateNewFileList(); string OriginalPath, newVersionFile, backupPath; OriginalPath = newVersionFile = ""; try { var index = 0; foreach (var file in filelist) { OriginalPath = System.IO.Path.Combine(ApplicationRoot, file); newVersionFile = System.IO.Path.Combine(SourceFolder, file); backupPath = System.IO.Path.Combine(BackupPath, file); e.PostEvent(() => OnInstallFile(new InstallFileEventArgs(newVersionFile, OriginalPath, filelist.Length, ++index))); if (System.IO.File.Exists(OriginalPath)) { System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(backupPath)); System.IO.File.Move(OriginalPath, backupPath); Trace.TraceInformation("备份文件: " + OriginalPath + " -> " + backupPath); bakList.Add(file); } System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(OriginalPath)); System.IO.File.Move(newVersionFile, OriginalPath); installedFile.Add(file); Trace.TraceInformation("安装文件: " + newVersionFile + " -> " + OriginalPath); } } catch (Exception ex) { this.Exception = new Exception(string.Format(SR.Updater_InstallFileError, OriginalPath, newVersionFile, ex.Message)); Trace.Fail("安装文件时发生错误:" + ex.Message, ex.ToString()); return false; } e.PostEvent(OnInstallFileFinished); return true; }