Files
lserp_cs_6.0/插件库/Lskj.AutoUpdate/FrmProgress.cs
T
2026-07-02 10:11:39 +00:00

688 lines
26 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/******************************
* 说明:下载进度窗口
* 创建人:龚宇超
* 创建日期:2018-02-09
* 修改人:
* 修改日期:
* 修改备注:
* 版本:1.0.0.0
******************************/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Net;
namespace Lskj.AutoUpdate
{
/// <summary>
/// 下载进度窗口
/// </summary>
public partial class FrmProgress : Form
{
/// <summary>
/// 是否下载完成
/// </summary>
private bool isFinished = false;
/// <summary>
/// 下载总数
/// </summary>
private long total = 0;
/// <summary>
/// 当前下载的总数
/// </summary>
private long nDownloadedTotal = 0;
/// <summary>
/// 下载文件列表
/// </summary>
private List<DownloadFileInfo> downloadFileList = new List<DownloadFileInfo>();
/// <summary>
/// 所有文件列表
/// </summary>
private List<DownloadFileInfo> allFileList = null;
private ManualResetEvent evtDownload = null;
private ManualResetEvent evtPerDonwload = null;
private WebClient clientDownload = null;
private AutoUpdater autoUpdater = null;
private bool isUserCanceled = false;
private bool isClosingByCode = false;
private delegate void SetProcessBarCallBack(int current, int total);
private delegate void ExitCallBack(bool success);
private delegate void ShowCurrentDownloadFileNameCallBack(string name);
public bool IsUserCanceled
{
get { return isUserCanceled; }
}
public FrmProgress(List<DownloadFileInfo> downloadFileListTemp, AutoUpdater apd)
{
InitializeComponent();
this.autoUpdater = apd;
this.downloadFileList = downloadFileListTemp;
this.allFileList = downloadFileListTemp.Select(x => new DownloadFileInfo(x.DownloadUrl, x.FileName, x.Version, x.Size, x.LastVersion)).ToList();
//foreach (DownloadFileInfo item in downloadFileListTemp)
//{
// // 本地临时文件夹中不存在此文件则下载.
// string tempUrlPath = CommonUnitity.GetFolderUrl(item);
// tempUrlPath = Path.Combine(CommonUnitity.SystemBinUrl + ConstModel.TEMP_FOLDER_NAME + tempUrlPath, item.FileName);
// if (!File.Exists(tempUrlPath))
// {
// this.downloadFileList.Add(item);
// }
//}
this.lblAll.Text = string.Format("总进度(0/{0})", this.downloadFileList.Count);
}
/// <summary>
/// <para>说明:窗口加载</para>
/// <para>创建人:龚宇超</para>
/// <para>创建日期:2018-02-23 </para>
/// <para>修改人:</para>
/// <para>修改日期:</para>
/// <para>修改备注:</para>
/// <para>版本:1.0</para>
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
private void OnFormLoad(object sender, EventArgs e)
{
evtDownload = new ManualResetEvent(true);
evtDownload.Reset();
ThreadPool.QueueUserWorkItem(new WaitCallback(this.ProcDownload));
}
/// <summary>
/// <para>说明:</para>
/// <para>创建人:龚宇超</para>
/// <para>创建日期:2018-02-23 </para>
/// <para>修改人:</para>
/// <para>修改日期:</para>
/// <para>修改备注:</para>
/// <para>版本:1.0</para>
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="FormClosingEventArgs"/> instance containing the event data.</param>
private void OnFormClosing(object sender, FormClosingEventArgs e)
{
if (isClosingByCode)
{
ReleaseDownloadWait();
return;
}
if (!isFinished && !isUserCanceled)
{
if (DialogResult.Yes != MessageBox.Show(ConstModel.UPDATE_GIVING_UP, ConstModel.LS_TITLE_NAME, MessageBoxButtons.YesNo, MessageBoxIcon.Question))
{
e.Cancel = true;
return;
}
CancelUpdate(true);
}
ReleaseDownloadWait();
}
/// <summary>
/// <para>说明:下载文件</para>
/// <para>创建人:龚宇超</para>
/// <para>创建日期:2018-02-23 </para>
/// <para>修改人:</para>
/// <para>修改日期:</para>
/// <para>修改备注:</para>
/// <para>版本:1.0</para>
/// </summary>
/// <param name="o">The o.</param>
private void ProcDownload(object o)
{
string tempFolderPath = Path.Combine(CommonUnitity.SystemBinUrl, ConstModel.TEMP_FOLDER_NAME);
if (!Directory.Exists(tempFolderPath))
{
Directory.CreateDirectory(tempFolderPath);
}
evtPerDonwload = new ManualResetEvent(false);
foreach (DownloadFileInfo file in this.downloadFileList)
{
total += file.Size;
}
int count = this.downloadFileList.Count;
while (!evtDownload.WaitOne(0, false))
{
if (isUserCanceled)
return;
try
{
if (this.downloadFileList.Count == 0)
break;
this.lblAll.Text = string.Format("总进度({0}/{1})", count - this.downloadFileList.Count, count);
DownloadFileInfo file = this.downloadFileList[0];
//Debug.WriteLine(String.Format("Start Download:{0}", file.FileName));
this.ShowCurrentDownloadFileName(file.FileName);
//Download
clientDownload = new WebClient();
//Added the function to support proxy
//clientDownload.Proxy = System.Net.WebProxy.GetDefaultProxy();
clientDownload.Proxy = WebRequest.GetSystemWebProxy();
clientDownload.Proxy.Credentials = CredentialCache.DefaultCredentials;
clientDownload.Credentials = System.Net.CredentialCache.DefaultCredentials;
//End added
clientDownload.DownloadProgressChanged += (object sender, DownloadProgressChangedEventArgs e) =>
{
try
{
//this.Text = "接收:" + e.BytesReceived.ToString() + " 字节数:" + progressBarCurrent.Maximum.ToString();
progressBarCurrent.Value = (int)e.BytesReceived / progressBarCurrent.Maximum;
progressBarTotal.Value = (int)((nDownloadedTotal + e.BytesReceived) * 100 / total);
this.SetProcessBar(e.ProgressPercentage, (int)((nDownloadedTotal + e.BytesReceived) * 100 / total));
}
catch (Exception ex)
{
//MessageBox.Show(ex.Message);
//log the error message,you can use the application's log code
}
};
clientDownload.DownloadFileCompleted += (object sender, AsyncCompletedEventArgs e) =>
{
try
{
if (isUserCanceled || e.Cancelled)
{
evtPerDonwload.Set();
return;
}
if (e.Error != null)
throw e.Error;
DealWithDownloadErrors();
DownloadFileInfo dfile = e.UserState as DownloadFileInfo;
nDownloadedTotal += dfile.Size;
this.SetProcessBar(0, (int)(nDownloadedTotal * 100 / total));
evtPerDonwload.Set();
}
catch (Exception exp)
{
if (!isUserCanceled)
{
DownloadFileInfo dfile = e.UserState as DownloadFileInfo;
MessageBox.Show(BuildDownloadErrorMessage(dfile, exp), ConstModel.LS_TITLE_NAME, MessageBoxButtons.OK, MessageBoxIcon.Warning);
evtPerDonwload.Set();
ShowErrorAndRestartApplication();
}
//log the error message,you can use the application's log code
}
};
evtPerDonwload.Reset();
//Download the folder file
string tempFolderPath1 = CommonUnitity.GetFolderUrl(file);
if (!string.IsNullOrEmpty(tempFolderPath1))
{
tempFolderPath = Path.Combine(CommonUnitity.SystemBinUrl, ConstModel.TEMP_FOLDER_NAME);
tempFolderPath += tempFolderPath1;
}
else
{
tempFolderPath = Path.Combine(CommonUnitity.SystemBinUrl, ConstModel.TEMP_FOLDER_NAME);
}
clientDownload.DownloadFileAsync(new Uri(file.DownloadUrl), Path.Combine(tempFolderPath, file.FileName), file);
//Wait for the download complete
evtPerDonwload.WaitOne();
if (isUserCanceled)
return;
clientDownload.Dispose();
clientDownload = null;
//Remove the downloaded files
this.downloadFileList.Remove(file);
}
catch (Exception e)
{
if (!isUserCanceled)
{
DownloadFileInfo file = this.downloadFileList.Count > 0 ? this.downloadFileList[0] : null;
MessageBox.Show(BuildDownloadErrorMessage(file, e), ConstModel.LS_TITLE_NAME, MessageBoxButtons.OK, MessageBoxIcon.Warning);
ShowErrorAndRestartApplication();
}
//throw;
}
}
if (isUserCanceled)
return;
//When the files have not downloaded,return.
if (downloadFileList.Count > 0)
{
return;
}
//Test network and deal with errors if there have
DealWithDownloadErrors();
//Debug.WriteLine("All Downloaded");
bool replaceSuccess = true;
foreach (DownloadFileInfo file in this.allFileList)
{
string tempUrlPath = CommonUnitity.GetFolderUrl(file);
string oldPath = string.Empty;
string newPath = string.Empty;
try
{
if (!string.IsNullOrEmpty(tempUrlPath))
{
oldPath = Path.Combine(CommonUnitity.SystemBinUrl + tempUrlPath.Substring(1), file.FileName);
newPath = Path.Combine(CommonUnitity.SystemBinUrl + ConstModel.TEMP_FOLDER_NAME + tempUrlPath, file.FileName);
}
else
{
oldPath = Path.Combine(CommonUnitity.SystemBinUrl, file.FileName);
newPath = Path.Combine(CommonUnitity.SystemBinUrl + ConstModel.TEMP_FOLDER_NAME, file.FileName);
}
//just deal with the problem which the files EndsWith xml can not download
System.IO.FileInfo f = new FileInfo(newPath);
if (!file.Size.ToString().Equals(f.Length.ToString()) && !file.FileName.ToString().EndsWith(".xml"))
{
MessageBox.Show($"文件大小与服务器不匹配 "+ file.FileName);
ShowErrorAndRestartApplication();
}
//Added for dealing with the config file download errors
string newfilepath = string.Empty;
if (newPath.Substring(newPath.LastIndexOf(".") + 1).Equals(ConstModel.CONFIG_FILE_KEY))
{
if (System.IO.File.Exists(newPath))
{
if (newPath.EndsWith("_"))
{
newfilepath = newPath;
newPath = newPath.Substring(0, newPath.Length - 1);
oldPath = oldPath.Substring(0, oldPath.Length - 1);
}
File.Move(newfilepath, newPath);
}
}
//End added
if (File.Exists(oldPath))
{
MoveFolderToOld(oldPath, newPath);
}
else
{
//Edit for config_ file
if (!string.IsNullOrEmpty(tempUrlPath))
{
if (!Directory.Exists(CommonUnitity.SystemBinUrl + tempUrlPath.Substring(1)))
{
Directory.CreateDirectory(CommonUnitity.SystemBinUrl + tempUrlPath.Substring(1));
MoveFolderToOld(oldPath, newPath);
}
else
{
MoveFolderToOld(oldPath, newPath);
}
}
else
{
MoveFolderToOld(oldPath, newPath);
}
}
}
catch (Exception exp)
{
replaceSuccess = false;
MessageBox.Show("oldPath" + oldPath + "\r\n" + "newPath" + newPath + "\r\n" + exp.Message);
break;
//log the error message,you can use the application's log code
}
}
//After dealed with all files, clear the data
this.allFileList.Clear();
if (this.downloadFileList.Count == 0 && replaceSuccess)
Exit(true);
else
Exit(false);
evtDownload.Set();
}
/// <summary>
/// <para>说明:移动文件</para>
/// <para>创建人:龚宇超</para>
/// <para>创建日期:2018-02-23 </para>
/// <para>修改人:</para>
/// <para>修改日期:</para>
/// <para>修改备注:</para>
/// <para>版本:1.0</para>
/// </summary>
/// <param name="oldPath">The old path.</param>
/// <param name="newPath">The new path.</param>
private void MoveFolderToOld(string oldPath, string newPath)
{
Exception lastException = null;
for (int i = 0; i < 10; i++)
{
try
{
if (File.Exists(oldPath + ".old"))
System.IO.File.SetAttributes(oldPath + ".old", System.IO.FileAttributes.Normal);
if (File.Exists(oldPath))
System.IO.File.SetAttributes(oldPath, System.IO.FileAttributes.Normal);
if (File.Exists(oldPath + ".old"))
File.Delete(oldPath + ".old");
if (File.Exists(oldPath))
File.Move(oldPath, oldPath + ".old");
File.Move(newPath, oldPath);
return;
}
catch (IOException ex)
{
lastException = ex;
Thread.Sleep(500);
}
catch (UnauthorizedAccessException ex)
{
lastException = ex;
Thread.Sleep(500);
}
}
throw new IOException("文件可能仍被其他进程占用,重试后仍无法替换:" + oldPath, lastException);
}
/// <summary>
/// <para>说明:显示当前下载文件</para>
/// <para>创建人:龚宇超</para>
/// <para>创建日期:2018-02-23 </para>
/// <para>修改人:</para>
/// <para>修改日期:</para>
/// <para>修改备注:</para>
/// <para>版本:1.0</para>
/// </summary>
/// <param name="name">The name.</param>
private void ShowCurrentDownloadFileName(string name)
{
if (this.labelCurrentItem.InvokeRequired)
{
ShowCurrentDownloadFileNameCallBack cb = new ShowCurrentDownloadFileNameCallBack(ShowCurrentDownloadFileName);
this.Invoke(cb, new object[] { name });
this.labelCurrentItem.Text = "正在更新:" + name;
}
else
{
this.labelCurrentItem.Text = "正在更新:" + name;
}
}
/// <summary>
/// <para>说明:显示当前进度</para>
/// <para>创建人:龚宇超</para>
/// <para>创建日期:2018-02-23 </para>
/// <para>修改人:</para>
/// <para>修改日期:</para>
/// <para>修改备注:</para>
/// <para>版本:1.0</para>
/// </summary>
/// <param name="current">The current.</param>
/// <param name="total">The total.</param>
private void SetProcessBar(int current, int total)
{
if (this.progressBarCurrent.InvokeRequired)
{
SetProcessBarCallBack cb = new SetProcessBarCallBack(SetProcessBar);
this.Invoke(cb, new object[] { current, total });
}
else
{
this.progressBarCurrent.Value = current;
this.progressBarTotal.Value = total;
}
}
/// <summary>
/// <para>说明:退出升级程序</para>
/// <para>创建人:龚宇超</para>
/// <para>创建日期:2018-02-23 </para>
/// <para>修改人:</para>
/// <para>修改日期:</para>
/// <para>修改备注:</para>
/// <para>版本:1.0</para>
/// </summary>
/// <param name="success">if set to <c>true</c> [success].</param>
private void Exit(bool success)
{
if (this.InvokeRequired)
{
ExitCallBack cb = new ExitCallBack(Exit);
this.Invoke(cb, new object[] { success });
}
else
{
this.isClosingByCode = true;
this.isFinished = success;
this.DialogResult = success ? DialogResult.OK : DialogResult.Cancel;
this.Close();
}
}
/// <summary>
/// <para>说明:取消</para>
/// <para>创建人:龚宇超</para>
/// <para>创建日期:2018-02-23 </para>
/// <para>修改人:</para>
/// <para>修改日期:</para>
/// <para>修改备注:</para>
/// <para>版本:1.0</para>
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
private void OnCancel(object sender, EventArgs e)
{
if (isUserCanceled)
return;
if (!isFinished && DialogResult.Yes == MessageBox.Show(ConstModel.UPDATE_GIVING_UP, ConstModel.LS_TITLE_NAME, MessageBoxButtons.YesNo, MessageBoxIcon.Question))
{
CancelUpdate(true);
Exit(false);
}
}
/// <summary>
/// <para>说明:下载失败</para>
/// <para>创建人:龚宇超</para>
/// <para>创建日期:2018-02-23 </para>
/// <para>修改人:</para>
/// <para>修改日期:</para>
/// <para>修改备注:</para>
/// <para>版本:1.0</para>
/// </summary>
private void DealWithDownloadErrors()
{
try
{
//Test Network is OK or not.
Config config = new Config().LoadConfig(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConstModel.AUTOUPDATE_CONFIG));
WebClient client = new WebClient();
client.DownloadString(config.ServerUrl);
}
catch (Exception e)
{
//MessageBox.Show(e.Message);
//log the error message,you can use the application's log code
ShowErrorAndRestartApplication();
}
}
/// <summary>
/// 将WebClient下载异常转换为用户可理解的提示。
/// </summary>
/// <param name="file">下载文件信息。</param>
/// <param name="ex">下载异常。</param>
/// <returns>友好的错误提示。</returns>
private string BuildDownloadErrorMessage(DownloadFileInfo file, Exception ex)
{
StringBuilder message = new StringBuilder();
message.AppendLine("更新文件下载失败。");
if (file != null)
{
message.AppendLine("文件:" + file.FileName);
message.AppendLine("地址:" + file.DownloadUrl);
}
message.AppendLine("原因:" + GetFriendlyDownloadExceptionMessage(ex));
message.AppendLine();
message.AppendLine("请检查网络是否正常、更新服务器是否可访问,或关闭防火墙/杀毒软件拦截后重试。");
return message.ToString();
}
/// <summary>
/// 获取下载异常的具体原因。
/// </summary>
/// <param name="ex">异常对象。</param>
/// <returns>异常原因说明。</returns>
private string GetFriendlyDownloadExceptionMessage(Exception ex)
{
WebException webException = ex as WebException;
if (webException == null && ex != null)
{
webException = ex.InnerException as WebException;
}
if (webException != null)
{
HttpWebResponse response = webException.Response as HttpWebResponse;
if (response != null)
{
if (response.StatusCode == HttpStatusCode.ProxyAuthenticationRequired)
{
return "代理服务器需要认证,请检查系统代理账号或网络代理设置。";
}
if (response.StatusCode == HttpStatusCode.NotFound)
{
return "服务器上找不到该更新文件,请确认更新包是否已上传完整。";
}
if (response.StatusCode == HttpStatusCode.Forbidden || response.StatusCode == HttpStatusCode.Unauthorized)
{
return "服务器拒绝访问该更新文件,请检查文件权限或更新地址配置。";
}
return string.Format("服务器返回 {0} {1},请确认更新文件是否存在或服务器权限是否正确。", (int)response.StatusCode, response.StatusDescription);
}
switch (webException.Status)
{
case WebExceptionStatus.NameResolutionFailure:
return "无法解析更新服务器地址,请检查DNS、网络连接或服务器地址配置。";
case WebExceptionStatus.ConnectFailure:
return "无法连接更新服务器,请检查网络、服务器端口或防火墙设置。";
case WebExceptionStatus.Timeout:
return "连接更新服务器超时,可能是网络不稳定或服务器响应过慢。";
case WebExceptionStatus.ProxyNameResolutionFailure:
return "代理服务器地址解析失败,请检查系统代理设置。";
case WebExceptionStatus.TrustFailure:
case WebExceptionStatus.SecureChannelFailure:
return "安全连接失败,请检查服务器证书或客户端系统时间。";
case WebExceptionStatus.ConnectionClosed:
return "下载过程中连接被关闭,可能是网络中断或服务器主动断开。";
case WebExceptionStatus.ProtocolError:
return "服务器返回了错误响应,请确认更新地址和文件权限。";
default:
return webException.Message;
}
}
if (ex is UriFormatException)
{
return "更新文件地址格式不正确。";
}
if (ex is UnauthorizedAccessException)
{
return "没有写入更新文件的权限,请以管理员身份运行或检查目录权限。";
}
if (ex is IOException)
{
return "写入更新文件失败,可能是文件被占用或磁盘空间不足。";
}
return ex != null ? ex.Message : "未知错误。";
}
/// <summary>
/// <para>说明:重新下载</para>
/// <para>创建人:龚宇超</para>
/// <para>创建日期:2018-02-23 </para>
/// <para>修改人:</para>
/// <para>修改日期:</para>
/// <para>修改备注:</para>
/// <para>版本:1.0</para>
/// </summary>
private void ShowErrorAndRestartApplication()
{
DialogResult dlg = MessageBox.Show(ConstModel.UPDATE_CONTINUE, ConstModel.LS_TITLE_NAME, MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (dlg == DialogResult.Yes)
CommonUnitity.RestartApplication();
else
{
if (clientDownload != null)
clientDownload.CancelAsync();
ReleaseDownloadWait();
autoUpdater.RollBack();
Exit(false);
}
}
private void CancelUpdate(bool rollback)
{
isUserCanceled = true;
if (clientDownload != null)
clientDownload.CancelAsync();
ReleaseDownloadWait();
if (rollback)
autoUpdater.RollBack(true);
}
private void ReleaseDownloadWait()
{
if (evtDownload != null)
evtDownload.Set();
if (evtPerDonwload != null)
evtPerDonwload.Set();
}
}
}