/// <summary> 执行下载 </summary>
		bool DownloadPackages(Wrapper.RunworkEventArgs rt)
		{
			System.IO.Directory.CreateDirectory(Context.UpdatePackagePath);

			Trace.TraceInformation("开始下载网络更新包");

			var workerCount = Math.Max(1, Context.MultipleDownloadCount);
			var workers = new List<WebClient>(workerCount);
			var evt = new AutoResetEvent(false);
			var hasError = false;

			//download redirect
			if (!string.IsNullOrEmpty(Context.UpdateInfo.PackageUrlTemplate))
			{
				Trace.TraceInformation("已经重定向下载包地址到 {0}", Context.UpdateInfo.PackageUrlTemplate);
				Context.UpdateDownloadUrl = Context.UpdateInfo.PackageUrlTemplate;
			}

			//Ping
			if (!string.IsNullOrEmpty(Context.UpdateInfo.UpdatePingUrl))
			{
				try
				{
					Context.CreateWebClient().UploadData(new Uri(Context.UpdateInfo.UpdatePingUrl), new byte[0]);
				}
				catch (Exception)
				{
				}
			}

			//生成下载队列
			Trace.TraceInformation("正在初始化 {0} 个WebClient", workerCount);
			for (var i = 0; i < workerCount; i++)
			{
				var clnt = Context.CreateWebClient();
				clnt.DownloadFileCompleted += (s, e) =>
				{
					var pkg = e.UserState as PackageInfo;
					var cnt = s as WebClient;

					pkg.LastError = e.Error;
					if (e.Error != null)
					{
						Trace.TraceWarning("包【" + pkg.PackageName + "】下载失败:" + e.Error.Message);
						rt.PostEvent(PackageDownloadFailed, this, new PackageEventArgs(pkg));
					}
					else if (pkg.IsLocalFileValid != true)
					{
						Trace.TraceWarning("包【" + pkg.PackageName + "】MD5校验失败", "错误");
						pkg.LastError = new Exception("不文件哈希值不正确或文件不存在");
						rt.PostEvent(PackageHashMismatch, this, new PackageEventArgs(pkg));
					}

					if (pkg.LastError != null)
					{
						//如果出错,且重试次数在限制范围内,则重试
						pkg.IncreaseFailureCounter();
						if (pkg.RetryCount <= Context.MaxiumRetryDownloadCount)
						{
							Trace.TraceWarning("包【" + pkg.PackageName + "】未能成功下载,正在进行第 " + pkg.RetryCount + " 次重试,最大重试次数为 " + Context.MaxiumRetryDownloadCount, "错误");
							cnt.DownloadFileAsync(new Uri(pkg.SourceUri), pkg.LocalSavePath, pkg);
							rt.PostEvent(PackageDownloadRetried, this, new PackageEventArgs(pkg));
							return;
						}
						//标记出错
						hasError = true;
					}

					//包下载完成事件
					pkg.IsDownloading = false;
					pkg.IsDownloaded = pkg.LastError == null;
					rt.PostEvent(PackageDownloadFinished, this, new PackageEventArgs(e.UserState as PackageInfo));

					lock (PackagesToUpdate)
					{
						Trace.TraceInformation("包【" + pkg.PackageName + "】下载操作完成:" + (pkg.IsDownloaded ? "下载成功" : "下载失败"));
						evt.Set();
					}
				};
				clnt.DownloadProgressChanged += (s, e) =>
					{
						var pkg = e.UserState as PackageInfo;
						pkg.DownloadedSize = e.BytesReceived;
						pkg.PackageSize = e.TotalBytesToReceive > 0 ? e.TotalBytesToReceive : pkg.PackageSize;
						rt.PostEvent(DownloadProgressChanged, this,
									 new PackageDownloadProgressChangedEventArgs(pkg, pkg.PackageSize,
																				 pkg.DownloadedSize, e.ProgressPercentage));
					};
				workers.Add(clnt);
			}

			//开始处理事务
			while (!hasError)
			{
				var breakFlag = false;
				lock (PackagesToUpdate)
				{
					//没有错误,则分配下个任务
					WebClient client;
					while ((client = workers.Find(s => !s.IsBusy)) != null)
					{
						var nextPkg = PackagesToUpdate.Find(s => !s.IsDownloading && !s.IsDownloaded);
						if (nextPkg == null)
						{
							breakFlag = true;
							break;
						}

						nextPkg.IsDownloading = true;
						Trace.TraceInformation("包【" + nextPkg.PackageName + "】开始下载");
						rt.PostEvent(PackageDownload, this, new PackageEventArgs(nextPkg));
						client.DownloadFileAsync(new Uri(Context.RandomUrl(Context.GetUpdatePackageFullUrl(nextPkg.PackageName))), nextPkg.LocalSavePath, nextPkg);
					}
				}
				if (breakFlag) break;
				evt.WaitOne();
				Trace.TraceInformation("线程同步事件已收到");
			}
			//不管任何原因中止下载,到这里时都需要等待所有客户端中止
			while (true)
			{
				//出错了,那么对所有的客户端发出中止命令。这里不需要判断是否忙碌。
				if (hasError)
				{
					Trace.TraceWarning("出现错误,正在取消所有包的下载队列");
					workers.ForEach(s => s.CancelAsync());
				}
				lock (PackagesToUpdate)
				{
					Trace.TraceInformation("等待下载队列完成操作");
					if (workers.FindIndex(s => s.IsBusy) == -1) break;
				}
				evt.WaitOne();
			}
			Trace.TraceInformation("完成下载网络更新包");

			var errorPkgs = ExtensionMethod.ToList(ExtensionMethod.Where(PackagesToUpdate, s => s.LastError != null));
			if (errorPkgs.Count > 0) throw new PackageDownloadException(errorPkgs.ToArray());

			return !hasError;
		}