/// <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> /// <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; }
/// <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 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> 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> 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 (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; }
//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 e) { e.ReportProgress(0, 0, DME.Updater.SR.Updater_ExtractPackage); DME.Zip.Zip.FastZipEvents evt = new DME.Zip.Zip.FastZipEvents(); evt.ProcessFile += (s, f) => { e.ReportProgress(0, 0, "正在解压缩 " + System.IO.Path.GetFileName(f.Name)); }; DME.Zip.Zip.FastZip fz = new DME.Zip.Zip.FastZip(evt); if (!string.IsNullOrEmpty(UpdateInfo.PackagePassword)) fz.Password = UpdateInfo.PackagePassword; fz.ExtractZip(UpdatePackageFilePath, UpdateSourceDirectory, ""); }
/// <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); } }
//创建信息的具体操作函数 private void CreatePackage(object sender, RunworkEventArgs e) { var info = new UpdateInfo { AppName = txtAppName.Text, AppVersion = txtAppVersion.Text, Desc = txtDesc.Text, ExecuteArgumentAfter = txtAfterExecuteArgs.Text, ExecuteArgumentBefore = txtPreExecuteArgs.Text, PublishUrl = txtPublishUrl.Text, FileExecuteAfter = fileAfterExecute.SelectedFileName, FileExecuteBefore = filePreExecute.SelectedFileName, MD5 = "", Package = Path.GetFileName(txtPackagePath.Text), ExecuteTimeout = txtTimeout.Text.ToInt32(), PackageSize = 0, RequiredMinVersion = "" }; options.SaveSetting(info); var evt = new FastZipEvents(); evt.ProcessFile += (s, f) => e.ReportProgress(0, 0, "正在压缩文件 " + Path.GetFileName(f.Name)); var zip = new FastZip(evt); if (!info.PackagePassword.IsNullOrEmpty()) zip.Password = info.PackagePassword; //zip.CreateZip(this.txtPackagePath.Text, this.txtNewSoftDir.Text, true, ""); if (ckbModifyTime.Checked) { IScanFilter df = new DateTimeFilter(DateTime.Parse(dateTimePicker1.Text)); zip.CreateZip(File.Create(txtPackagePath.Text), txtNewSoftDir.Text, true, df, null); } else { zip.CreateZip(txtPackagePath.Text, txtNewSoftDir.Text, true, "", null); } //校验MD5 byte[] hash = null; int size = 0; using (var fs = new ExtendFileStream(SelectedPackagePath, FileMode.Open)) { e.ReportProgress((int) fs.Length, 0, ""); fs.ProgressChanged += (s, f) => { e.ReportProgress((int) fs.Position); }; MD5 md5 = MD5.Create(); hash = md5.ComputeHash(fs); size = (int) fs.Length; } info.MD5 = BitConverter.ToString(hash).Replace("-", "").ToUpper(); info.PackageSize = size; info.XmlSerilizeToFile(GetXmlPath(SelectedPackagePath)); e.ReportProgress(0, 0, "生成成功,MD5校验:" + info.MD5); }
/// <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> 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> 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); }