/// <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>
		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 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;
		}
Example #10
0
        //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);
        }
Example #11
0
        /// <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, "");
        }
Example #12
0
        /// <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);
            }
        }
Example #13
0
        //创建信息的具体操作函数
        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);
        }