You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

499 lines
17 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AutoUpdater
{
public enum DownloadStatus
{
Downloading,
Completed,
Failed,
Canceled
}
public partial class Downloading : Form
{
/// <summary>
/// 下载器
/// </summary>
private FileDownloader downloader;
/// <summary>
/// 下载状态
/// </summary>
private DownloadStatus status = DownloadStatus.Downloading;
/// <summary>
/// 文件总大小
/// </summary>
private long totalSize = 0;
/// <summary>
/// 最后文件大小
/// </summary>
long lastSize = 0;
/// <summary>
/// 已经下载文件大小
/// </summary>
long completedSize = 0;
/// <summary>
/// 是否取消下载
/// </summary>
private bool canceled = false;
/// <summary>
/// 显示文本长度
/// </summary>
const int MAX_URL_LENGTH = 35;
/// <summary>
/// 是否更新成功
/// </summary>
private bool isUpdateSuccess = false;
/// <summary>
/// 执行数据下载
/// </summary>
delegate void DownloaderProgress(object sender);
public Downloading()
{
InitializeComponent();
//按钮切换
this.btnPause.Tag = "Pause";
//初始化文件下载
downloader = new FileDownloader();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
//删除下载目录信息
DeleteFolder(Global.Instance.DownloadPath);
//版本信息
this.lblVersion.Text = string.Format(this.lblVersion.Text , Global.Instance.NewVersion);
//remove limits from service point manager
//ServicePointManager.MaxServicePoints = 10000;
//ServicePointManager.DefaultConnectionLimit = 10000;
//ServicePointManager.CheckCertificateRevocationList = true;
//ServicePointManager.Expect100Continue = false;
//ServicePointManager.MaxServicePointIdleTime = 1000 * 30;
//ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
//ServicePointManager.UseNagleAlgorithm = false;
//ServicePointManager.DnsRefreshTimeout = 0;
////提升系统外联的最大并发web访问数
//ServicePointManager.DefaultConnectionLimit = 1024;
//ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
Task.Factory.StartNew(() => { this.DoStartDownload(this); });
}
private void DoStartDownload(object sender)
{
try
{
this.Invoke(new DownloaderProgress(this.downloaderProgress) , new object[] { sender });
Application.DoEvents();
}
catch (InvalidOperationException ex) //不建议使用该方法,目前尚未有效解决
{
ExceptionUtils.Current.Handle(ex);
}
}
private void downloaderProgress(object sender)
{
try
{
DownloadURLCollection urls = Global.Instance.Urls;
var tasks = new List<Task>();
foreach (DownloadURL url in urls)
{
tasks.Add(Task.Factory.StartNew<Tuple<bool , long>>(() =>
{
bool progressKnown = false;
long size = DownloadData.GetFileSize(url.URL , out progressKnown);
return new Tuple<bool , long>(progressKnown , size);
}).ContinueWith((data) =>
{
Tuple<bool , long> value = data.Result;
url.Size = value.Item2;
this.totalSize += value.Item2;
}));
}
Task.WaitAll(tasks.ToArray());
this.prgOverall.PositionMax = this.totalSize;
downloader.ProgressChanged += new DownloadProgressHandler(downloader_ProgressChanged);
long fileSizes = 0;
foreach (DownloadURL url in urls)
{
if (!canceled)
{
lastSize = 0;
Uri uri = new Uri(url.URL);
string fileName = uri.Segments[uri.Segments.Length - 1].ToString();
this.prgCurrent.PositionMax = url.Size;
if (url.Destination == string.Empty)
{
url.Destination = FileDownloader.DownloaderTempDirectory;
}
downloader.Download(url.URL , url.Destination);
if (canceled)
{
break;
}
fileSizes += url.Size;
this.Invoke(new MarshalProgress(MarshaledProgressChanged) , new object[] { null , new DownloadEventArgs(this.totalSize , url.Size) });
this.prgOverall.Position = fileSizes;
completedSize = fileSizes;
}
}
this.Invoke(new CompletedDelegate(this.MarshalDownloadComplete));
}
catch (Exception ex)
{
ExceptionUtils.Current.Handle(ex);
}
}
/// <summary>
/// 下载处理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
delegate void MarshalProgress(object sender , DownloadEventArgs e);
private void downloader_ProgressChanged(object sender , DownloadEventArgs e)
{
this.Invoke(new MarshalProgress(this.MarshaledProgressChanged) , new object[] { sender , e });
}
string lastPercent = string.Empty;
private void MarshaledProgressChanged(object sender , DownloadEventArgs e)
{
try
{
this.prgCurrent.Position = (int)e.CurrentFileSize;
if (e.CurrentFileSize == this.lastSize)
{
return;
}
this.prgOverall.Position += (e.CurrentFileSize - this.lastSize);
this.completedSize += (e.CurrentFileSize - this.lastSize);
this.lastSize = e.CurrentFileSize;
if (e.TotalFileSize > 1024)//以K为单位
{
this.lblCurrentComplete.Text = e.CurrentFileSize / 1024 + "K / " + e.TotalFileSize / 1024 + "K";
}
else//小于K
{
this.lblCurrentComplete.Text = e.CurrentFileSize + "B / " + e.TotalFileSize + "B";
}
this.prgCurrent.Text = ((int)((((double)e.CurrentFileSize) / e.TotalFileSize) * 100)).ToString() + "%";
this.prgOverall.Text = ((int)((((double)completedSize) / totalSize) * 100)).ToString() + "%";
if (this.prgOverall.Text != lastPercent)
{
int index = Text.IndexOf(" (");
if (index > -1)
{
this.Text = this.Text.Substring(0 , index);
}
this.Text += " (" + this.prgOverall.Text + ")";
lastPercent = this.prgOverall.Text;
}
Application.DoEvents();
}
catch (Exception ex)
{
ExceptionUtils.Current.Handle(ex);
}
}
private delegate void CompletedDelegate();
private void MarshalDownloadComplete()
{
if (this.totalSize == this.completedSize)
{
this.status = DownloadStatus.Completed;
//暂停功能无效
this.btnPause.Visible = false;
//窗体关闭功能无效
//关闭按钮无效
this.btnCancel.Enabled = false;
//判断主程序是否处于运行状态
if (this.IsAppInstanceExist(getProcessName()))
{
System.Diagnostics.Process[] startProcesses = System.Diagnostics.Process.GetProcessesByName(getProcessName());
foreach (System.Diagnostics.Process start in startProcesses)
{
start.Kill();
}
}
//程序延时2秒钟
System.Threading.Thread.Sleep(1000);
//将update目录下的 压缩文件 解压
UnZip(Global.Instance.DownloadPath);
this.canceled = true;
this.isUpdateSuccess = true;
if (chkAutoClose.Checked)
{
//升级完成后,启动主程序
this.StartApplication(Global.Instance.StartApplication);
this.Close();
}
else
{
//窗体关闭功能生效
//关闭按钮生效
this.btnCancel.Enabled = true;
this.btnCancel.Text = "关闭";
}
}
}
/// <summary>
/// 启动一个应用程序/进程
/// </summary>
/// <param name="appFilePath"></param>
private void StartApplication(string appFilePath)
{
string currentPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory , appFilePath);
if (File.Exists(currentPath))
{
Process downprocess = new Process();
downprocess.StartInfo.FileName = appFilePath;
downprocess.Start();
}
}
/// <summary>
/// 获取进程名称,根据主程序名称
/// </summary>
/// <returns></returns>
private string getProcessName()
{
int processIndex = Global.Instance.StartApplication.LastIndexOf(@".");
string processName = Global.Instance.StartApplication.Substring(0 , processIndex);
return processName;
}
/// <summary>
/// 监测目标应用程序是否启动
/// </summary>
/// <param name="instanceName"></param>
/// <returns></returns>
private bool IsAppInstanceExist(string instanceName)
{
System.Diagnostics.Process[] startProcesses = System.Diagnostics.Process.GetProcessesByName(instanceName);
if (startProcesses.Length >= 1)
{
return true;
}
return false;
}
private void btnPause_Click(object sender , System.EventArgs e)
{
if (this.btnPause.Tag.ToString() == "Pause")
{
downloader.Pause();
this.btnPause.Text = "继续";
this.btnPause.Tag = "Resume";
}
else if (this.btnPause.Tag.ToString() == "Resume")
{
downloader.Resume();
this.btnPause.Text = "暂停";
this.btnPause.Tag = "Pause";
}
}
private void btnCancel_Click(object sender , System.EventArgs e)
{
if (!canceled)
{
downloader.Cancel();
this.status = DownloadStatus.Canceled;
this.btnCancel.Text = "关闭";
this.btnPause.Visible = false;
//删除下载文件夹
DeleteFolder(Global.Instance.DownloadPath);
canceled = true;
}
else
{
if (isUpdateSuccess)
{
//升级完成后,启动主程序
this.StartApplication(Global.Instance.StartApplication);
}
this.Close();
}
}
/// <summary>
/// 删除文件夹
/// </summary>
/// <param name="dir"></param>
private void DeleteFolder(string dir)
{
if (Directory.Exists(dir))
{
foreach (string d in Directory.GetFileSystemEntries(dir))
{
if (File.Exists(d))
{
FileInfo fi = new FileInfo(d);
if (fi.Attributes.ToString().IndexOf("ReadOnly") != -1)
fi.Attributes = FileAttributes.Normal;
File.Delete(d);//直接删除其中的文件
}
else
DeleteFolder(d);//递归删除子文件夹
}
Directory.Delete(dir);//删除已空文件夹
}
}
////不推荐使用,可能影响其他
//private void KillProcess()
//{
// Process[] procList = Process.GetProcesses();
// for (int i = 0; i < procList.Length; i++)
// {
// switch (procList[i].ProcessName)
// {
// case "AutoUpdater":
// procList[i].Kill();
// procList[i].Close();
// break;
// }
// }
//}
private void Downloading_FormClosed(object sender , FormClosedEventArgs e)
{
downloader.Cancel();
this.status = DownloadStatus.Canceled;
//删除下载文件夹
DeleteFolder(Global.Instance.DownloadPath);
canceled = true;
System.Diagnostics.Process currentProcess = System.Diagnostics.Process.GetCurrentProcess();
currentProcess.Kill();
}
/// <summary>
/// 复制文件夹所有内容到目标文件夹
/// </summary>
/// <param name="srcPath"></param>
/// <param name="aimPath"></param>
private void CopyDirectory(string srcPath , string aimPath)
{
//检查目标目录是否以目录分割字符结束如果不是则添加之
if (aimPath[aimPath.Length - 1] != Path.DirectorySeparatorChar)
aimPath += Path.DirectorySeparatorChar;
//判断目标目录是否存在如果不存在则新建之
if (!Directory.Exists(aimPath)) Directory.CreateDirectory(aimPath);
//得到源目录的文件列表,该里面是包含文件以及目录路径的一个数组
//如果你指向copy目标文件下面的文件而不包含目录请使用下面的方法
//string[] fileList = Directory.GetFiles(srcPath);
string[] fileList = Directory.GetFileSystemEntries(srcPath);
//遍历所有的文件和目录
foreach (string file in fileList)
{
//先当作目录处理如果存在这个目录就递归Copy该目录下面的文件
if (Directory.Exists(file))
CopyDirectory(file , aimPath + Path.GetFileName(file));
//否则直接Copy文件
else
File.Copy(file , aimPath + Path.GetFileName(file) , true);
}
}
private void UnZip(string srcPath)
{
string[] fileList = Directory.GetFiles(srcPath);
foreach (string file in fileList)
{
FileInfo fileInfo = new FileInfo(file);
if (fileInfo.Extension.ToLower().Equals(".zip"))
{
ZipStorer zip = ZipStorer.Open(file , FileAccess.Read);
List<ZipStorer.ZipFileEntry> dir = zip.ReadCentralDir();
string path;
bool result;
foreach (ZipStorer.ZipFileEntry entry in dir)
{
path = Path.Combine(Application.StartupPath , entry.FilenameInZip);
result = zip.ExtractFile(entry , path);
}
zip.Close();
if (fileInfo.Attributes.ToString().IndexOf("ReadOnly") != -1)
fileInfo.Attributes = FileAttributes.Normal;
File.Delete(file);//直接删除其中的文件
}
}
}
}
}