using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Net;
using System.Globalization;
using System.Xml;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Xml.Linq;
using System.Security.Cryptography;
namespace AutoUpdateEx
{
public partial class FormUpdate : Form
{
private WebClient downWebClient = new WebClient();
///
/// 消息处理类申明
///
private static AutoUpdateEx.lib.ClassMessage classMsg = new AutoUpdateEx.lib.ClassMessage();
///
/// 进程检查类申明
///
private static AutoUpdateEx.lib.ClassCheckProIsRun classCPIR = new AutoUpdateEx.lib.ClassCheckProIsRun();
///
/// 日志类申明
///
private static AutoUpdateEx.lib.ClassLog classLog = new AutoUpdateEx.lib.ClassLog();
///
/// 是否有更新,默认没有更新
///
public bool boolUpdateFalg = false;
///
/// 更新服务器的URL
///
private static string strUpdateURL;
///
/// 所有文件大小
///
private static long SIZE;
///
/// 文件总数
///
private static int COUNT;
///
/// 文件名数组
///
private static string[] strArrayFileNames;
///
/// 已更新文件数
///
private static int NUM;
///
/// 已更新文件大小
///
private static long UPSIZE;
///
/// 当前更新文件名
///
private static string strCurFileName;
///
/// 当前更新的目录
///
private static string strCurPath;
///
/// 当前文件大小
///
private static long lngCurFileSize;
///
/// 本地update.xml的路径
///
private static string strUpdateXmlPath = Application.StartupPath + @"/update.xml";
///
/// 服务端updatelist.xml的URL地址
///
private static string strUpdateListXmlPath = "UpdateServer/UpdateList.xml";
///
/// 服务端更新文件的URL地址
///
private static string strUpdateFilesUrl = "UpdateServer/UpdateFiles";
///
/// 服务端updatelist.xml的更新日期
///
private static string strTheUpdateDate;
///
/// 更新文件临时保存的路径
///
private static string strUpdateFilesTmpPath = Application.StartupPath + @"\UpdateFiles\";
///
/// 主程序的文件名
///
private static string strMainProFileName = CommonHelper.strApplicationName;
///
/// 主程序目录
///
//private static string strMainProDir = new DirectoryInfo(Application.StartupPath).Parent.FullName;
private static string strMainProDir = new DirectoryInfo(Application.StartupPath).FullName;
///
/// 备份目录
///
private static string strBackupPath = strMainProDir + @"\backup\";
///
/// 主程序的路径
///
private static string strMainProPath = strMainProDir + "\\" + strMainProFileName;
///
/// 获取MD5
///
///
///
private static string GetMD5(string s)
{
try
{
FileStream file = new FileStream(s, FileMode.Open);
MD5 md5 = new MD5CryptoServiceProvider();
byte[] retval = md5.ComputeHash(file);
file.Close();
StringBuilder sc = new StringBuilder();
for (int i = 0; i < retval.Length; i++)
{
sc.Append(retval[i].ToString("x2"));
}
return sc.ToString();
}
catch (Exception ex)
{
return "";
}
}
public FormUpdate()
{
InitializeComponent();
this.ActiveControl = btnUpdate;
btnUpdate.Focus();
//430, 333
}
private void FormUpdate_Load(object sender, EventArgs e)
{
//提示关掉所有主程序
//if(classCPIR.checkProcessForProName(strMainProFileName))
//{
// classMsg.messageInfoBox("进程中检测到主程序正在运行,请先关闭才可更新。" + strMainProFileName);
// return;
//}
checkUpdate();
btnUpdate.Focus();
}
///
/// 检测是否有更新
///
private void checkUpdate()
{
strUpdateURL = getConfigValue(strUpdateXmlPath, "Url"); //读取本地xml中配置的更新服务器的URL
string strLastUpdateDate = getConfigValue(strUpdateXmlPath, "UpDate"); //读取本地xml中配置的最近一次更新日期
if (strUpdateURL.Substring(strUpdateURL.Length - 1) != "/") //如果配置的xml中URL没带最后一个反斜杠,则加一下,防止出错
strUpdateURL += "/";
strTheUpdateDate = getTheLastUpdateTime(strUpdateURL); //获得更新服务器端的此次更新日期
if (!String.IsNullOrEmpty(strTheUpdateDate) && !String.IsNullOrEmpty(strLastUpdateDate)) //日期都不为空
{
if (DateTime.Compare(
Convert.ToDateTime(strTheUpdateDate, CultureInfo.InvariantCulture),
Convert.ToDateTime(strLastUpdateDate, CultureInfo.InvariantCulture)) > 0) //字符转日期,并比较日期大小
{
boolUpdateFalg = true; //本次更新日期 大于 最近一次更新日期,有更新,修改更新标记
}
}
}
///
/// 开始更新
///
private void updaterStart()
{
float tempf;
//this.progressBarDownFile.Maximum = 808380;
//委托下载数据时事件
this.downWebClient.DownloadProgressChanged += delegate(object wcsender, DownloadProgressChangedEventArgs ex)
{
this.labelDownload.Text = String.Format(
CultureInfo.InvariantCulture,
"正在下载:{0} [ {1}/{2} ]",
strCurFileName,
convertSize(ex.BytesReceived),
convertSize(ex.TotalBytesToReceive));
lngCurFileSize = ex.TotalBytesToReceive;
tempf = ((float)(UPSIZE + ex.BytesReceived) / SIZE);
this.progressBarState.Value = Convert.ToInt32(tempf * 100);
this.progressBarDownFile.Value = ex.ProgressPercentage;
};
//委托下载完成时事件
this.downWebClient.DownloadFileCompleted += delegate(object wcsender, AsyncCompletedEventArgs ex)
{
if (ex.Error != null)
{
classMsg.messageInfoBox(ex.Error.Message);
//classLog.WriteLog(AutoUpdateEx.lib.ClassLog.LogType.Error, "Source:{" + ex.Error.Source + "}" + " StackTrace:{" + ex.Error.StackTrace + "}" + " Message:{" + ex.Error.Message + "}");
}
else
{
//创建备份日期+更新文件目录
if (!Directory.Exists(strBackupPath + strTheUpdateDate + strCurPath)) //路径是否存在
{
createMultipleFolders(strBackupPath, strTheUpdateDate + strCurPath); //创建多层目录
}
try
{
//备份
if (File.Exists(strMainProDir + strCurFileName))
{
if (File.Exists(strBackupPath + strTheUpdateDate + strCurFileName))
File.Delete(strBackupPath + strTheUpdateDate + strCurFileName);
File.Move(strMainProDir + strCurFileName, strBackupPath + strTheUpdateDate + strCurFileName);
if (File.Exists(strBackupPath + strTheUpdateDate + strCurFileName))
File.Delete(strMainProDir + strCurFileName);
}
//将更新文件从临时存放路径移动到正式路径中
File.Move(Application.StartupPath + @"\UpdateFiles\" + strCurFileName, strMainProDir + strCurFileName);
}
catch (IOException ioex)
{
classMsg.messageInfoBox(ioex.Message + strCurFileName); //已更新过,再更新报这个文件已存在;或者未备份成功的话更新会出故障
classLog.WriteLog(AutoUpdateEx.lib.ClassLog.LogType.Error, "Source:{" + ioex.Source + "}" + " StackTrace:{" + ioex.StackTrace + "}" + " Message:{" + ioex.Message + "}");
}
UPSIZE += lngCurFileSize;
if (strArrayFileNames.Length > NUM)
{
downloadFile(NUM);
}
else
{
setConfigValue(strUpdateXmlPath, "UpDate", strTheUpdateDate);
classMsg.messageInfoBox("更新完成!");
updaterClose();
}
}
};
SIZE = getUpdateSize(strUpdateURL + strUpdateListXmlPath);
if (SIZE == 0) //判断要更新的文件是否有大小,如果为0字节则结束更新
updaterClose();
NUM = 0;
UPSIZE = 0;
updateList();
if (strArrayFileNames != null)
downloadFile(0);
}
void downWebClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs ex)
{
float tempf;
this.labelDownload.Text = String.Format(
CultureInfo.InvariantCulture,
"正在下载:{0} [ {1}/{2} ]",
strCurFileName,
convertSize(ex.BytesReceived),
convertSize(ex.TotalBytesToReceive));
lngCurFileSize = ex.TotalBytesToReceive;
tempf = ((float)(UPSIZE + ex.BytesReceived) / SIZE);
this.progressBarState.Value = Convert.ToInt32(tempf * 100);
this.progressBarDownFile.Value = ex.ProgressPercentage;
}
///
/// 获取更新文件大小统计
///
/// 更新文件数据XML
/// 返回值
private static long getUpdateSize(string filePath)
{
long len = 0;
try
{
WebClient wc = new WebClient();
Stream sm = wc.OpenRead(filePath);
XmlTextReader xr = new XmlTextReader(sm);
while (xr.Read())
{
if (xr.Name == "UpdateSize")
{
len = Convert.ToInt64(xr.GetAttribute("Size"), CultureInfo.InvariantCulture);
break;
}
}
xr.Close();
sm.Close();
}
catch (WebException ex)
{
classMsg.messageInfoBox(ex.Message);
classLog.WriteLog(AutoUpdateEx.lib.ClassLog.LogType.Error, "Source:{" + ex.Source + "}" + " StackTrace:{" + ex.StackTrace + "}" + " Message:{" + ex.Message + "}");
}
return len;
}
///
/// 获取文件列表并赋给全局变量
///
private static void updateList()
{
string xmlPath = strUpdateURL + strUpdateListXmlPath;
WebClient wc = new WebClient();
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
try
{
StringBuilder sb = new StringBuilder();
Stream sm = wc.OpenRead(xmlPath);
XDocument oXDoc = XDocument.Load(xmlPath);
System.Xml.Linq.XElement xeRoot = oXDoc.Root;
System.Xml.Linq.XElement xele = xeRoot.Element("UpdateFileList");
foreach (var ele in xele.Elements())
{
if (sb.Length == 0)
{
sb.Append(ele.Value);
}
else
{
sb.Append("," + ele.Value);
}
}
strArrayFileNames = sb.ToString().Split(','); //赋给全局变量
//sm.Close();
}
catch (WebException ex)
{
classMsg.messageInfoBox(ex.Message);
classLog.WriteLog(AutoUpdateEx.lib.ClassLog.LogType.Error, "Source:{" + ex.Source + "}" + " StackTrace:{" + ex.StackTrace + "}" + " Message:{" + ex.Message + "}");
}
}
///
/// 下载文件
///
/// 下载序号
private void downloadFile(int arry)
{
try
{
NUM++; //全局变量来记录下载的文件序号
strCurFileName = strArrayFileNames[arry];
string strFileName = strCurFileName.Substring(strCurFileName.LastIndexOf("\\") + 1); //截取文件名
strCurPath = strCurFileName.Substring(0, strCurFileName.LastIndexOf("\\") + 1); //截取文件路径
if (!Directory.Exists(strUpdateFilesTmpPath + strCurPath)) //路径是否存在
{
createMultipleFolders(strUpdateFilesTmpPath, strCurPath); //创建多层目录
}
this.labelState.Text = String.Format(
CultureInfo.InvariantCulture,
"更新进度 {0}/{1} [ {2} ]",
NUM,
COUNT,
convertSize(SIZE));
//this.progressBarDownFile.Value = 0;
this.downWebClient.DownloadFileAsync(new Uri(strUpdateURL + strUpdateFilesUrl + strCurFileName.Replace('\\', '/')), strUpdateFilesTmpPath + strCurFileName);
}
catch (WebException ex)
{
classMsg.messageInfoBox(ex.Message);
classLog.WriteLog(AutoUpdateEx.lib.ClassLog.LogType.Error, "Source:{" + ex.Source + "}" + " StackTrace:{" + ex.StackTrace + "}" + " Message:{" + ex.Message + "}");
}
}
///
/// 创建多层文件夹
///
/// 弹出文件浏览窗口选中的符文件路径
/// 需要创建的多层文件夹路径
private void createMultipleFolders(string strParentPath, string strPath)
{
try
{
if (strParentPath != "")
{
Directory.CreateDirectory(strParentPath + @strPath);
}
}
catch (IOException ex)
{
classMsg.messageInfoBox("路径存在非法字符" + ex.Message);
classLog.WriteLog(AutoUpdateEx.lib.ClassLog.LogType.Error, "Source:{" + ex.Source + "}" + " StackTrace:{" + ex.StackTrace + "}" + " Message:{" + ex.Message + "}");
}
}
///
/// 转换字节大小
///
/// 输入字节数
/// 返回值
private static string convertSize(long byteSize)
{
string str = "";
float tempf = (float)byteSize;
if (tempf / 1024 > 1)
{
if ((tempf / 1024) / 1024 > 1)
{
str = ((tempf / 1024) / 1024).ToString("##0.00", CultureInfo.InvariantCulture) + "MB";
}
else
{
str = (tempf / 1024).ToString("##0.00", CultureInfo.InvariantCulture) + "KB";
}
}
else
{
str = tempf.ToString(CultureInfo.InvariantCulture) + "B";
}
return str;
}
///
/// 关闭程序
///
private static void updaterClose()
{
try
{
if (classCPIR.checkProcess(strMainProPath))
{
classMsg.messageInfoBox("更新程序" + strMainProFileName + "已打开!");
}
else
{
//启动程序
Process.Start(strMainProPath);
}
}
catch (Win32Exception ex)
{
classMsg.messageInfoBox(ex.Message); //主程序未更新成功或者被误删掉,再更新一遍
classLog.WriteLog(AutoUpdateEx.lib.ClassLog.LogType.Error, "Source:{" + ex.Source + "}" + " StackTrace:{" + ex.StackTrace + "}" + " Message:{" + ex.Message + "}");
}
Application.Exit(); //退出程序
}
///
/// 读取update.xml
///
/// update.xml文件的路径
/// "key"的值
/// 返回"value"的值
internal static string getConfigValue(string path, string appKey)
{
XmlDocument xDoc = new XmlDocument();
XmlNode xNode;
XmlElement xElem = null;
try
{
xDoc.Load(path);
xNode = xDoc.SelectSingleNode("//appSettings");
xElem = (XmlElement)xNode.SelectSingleNode("//add[@key=\"" + appKey + "\"]");
}
catch (XmlException ex)
{
classMsg.messageInfoBox(ex.Message);
classLog.WriteLog(AutoUpdateEx.lib.ClassLog.LogType.Error, "Source:{" + ex.Source + "}" + " StackTrace:{" + ex.StackTrace + "}" + " Message:{" + ex.Message + "}");
}
if (xElem != null)
return xElem.GetAttribute("value");
else
return "";
}
///
/// 程序更新完后,要更新update.xml
///
/// update.xml文件的路径
/// "key"的值
/// "value"的值
internal static void setConfigValue(string strXmlPath, string appKey, string appValue)
{
XmlDocument xDoc = new XmlDocument();
try
{
xDoc.Load(strXmlPath);
XmlNode xNode;
XmlElement xElem1;
XmlElement xElem2;
xNode = xDoc.SelectSingleNode("//appSettings");
xElem1 = (XmlElement)xNode.SelectSingleNode("//add[@key=\"" + appKey + "\"]");
if (xElem1 != null) xElem1.SetAttribute("value", appValue);
else
{
xElem2 = xDoc.CreateElement("add");
xElem2.SetAttribute("key", appKey);
xElem2.SetAttribute("value", appValue);
xNode.AppendChild(xElem2);
}
xDoc.Save(strXmlPath);
}
catch (XmlException ex)
{
classMsg.messageInfoBox(ex.Message);
classLog.WriteLog(AutoUpdateEx.lib.ClassLog.LogType.Error, "Source:{" + ex.Source + "}" + " StackTrace:{" + ex.StackTrace + "}" + " Message:{" + ex.Message + "}");
}
}
///
/// 获取服务器端软件的更新日期
///
/// 服务器地址
/// 返回日期
private static string getTheLastUpdateTime(string Dir)
{
string LastUpdateTime = "";
string AutoUpdaterFileName = Dir + strUpdateListXmlPath;
try
{
WebClient wc = new WebClient();
Stream sm = wc.OpenRead(AutoUpdaterFileName);
XmlTextReader xml = new XmlTextReader(sm);
while (xml.Read())
{
if (xml.Name == "UpdateTime")
{
LastUpdateTime = xml.GetAttribute("Date");
break;
}
}
xml.Close();
sm.Close();
}
catch (WebException ex)
{
classMsg.messageInfoBox(ex.Message);
classLog.WriteLog(AutoUpdateEx.lib.ClassLog.LogType.Error, "Source:{" + ex.Source + "}" + " StackTrace:{" + ex.StackTrace + "}" + " Message:{" + ex.Message + "}");
}
return LastUpdateTime;
}
private void btnCancel_Click(object sender, EventArgs e)
{
try
{
updaterClose();
}
catch
{
}
}
public void btnUpdate_Click(object sender, EventArgs e)
{
//提示关掉所有主程序
if (classCPIR.checkProcessForProName(strMainProFileName))
{
classMsg.messageInfoBox("进程中检测到主程序正在运行,请先关闭才可更新。" + strMainProFileName);
return;
}
if (boolUpdateFalg) //是否有更新
{
updaterStart(); //有更新
}
else
{
classMsg.messageInfoBox("已经是最新版本!");
updaterClose(); //默认无更新
}
}
private void FormUpdate_KeyDown(object sender, KeyEventArgs e)
{
}
private void FormUpdate_KeyPress(object sender, KeyPressEventArgs e)
{
}
private void FormUpdate_KeyUp(object sender, KeyEventArgs e)
{
//if (e.KeyCode == Keys.Enter)
//{
// btnUpdate_Click(null, null);
//}
//else if (e.KeyCode == Keys.Escape)
//{
// updaterClose();
//}
//else
//{
// MessageBox.Show("请按Enter确定更新,Esc取消更新!");
//}
}
}
}