using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Threading; using System.IO; using EAS.Distributed; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using EAS.Security; namespace EAS.Distributed { public partial class UpdateUI : System.Windows.Forms.Form { Thread updateThread = null; Thread killThread = null; DateTime lastTime = DateTime.MinValue; DateTime sTime = DateTime.MinValue; SmartConfig sc1 = null; //原有配置 SmartConfig sc2 = null; //新配置 IList updateList = new List(); IList deleteList = new List(); bool bComplete = false; bool m_Kill = true; public UpdateUI() { InitializeComponent(); } protected override void OnLoad(EventArgs e) { base.OnLoad (e); if(XUpdate.Instance.Title.Length > 0) this.Text = XUpdate.Instance.Title; this.progressBar.Maximum = 0; this.progressBar.Minimum = 0; this.statusErrors.Text = "0个错误"; this.statusTasks.Text = "0个任务"; //1.开启升级线程。 this.updateThread = new Thread(new ThreadStart(this.AutoUpdate)); this.updateThread.Start(); #if DEBUG using (TextLogger loggger = new TextLogger()) { loggger.Debug(XUpdate.Instance.GetBaseDirectory()); } #endif //2.启动一线程,杀掉相关的应用进程。 this.killThread = new Thread(new ThreadStart(() => { while (m_Kill) { string baseDirectory = XUpdate.Instance.GetBaseDirectory(); Process[] process = System.Diagnostics.Process.GetProcesses(); foreach (var item in process) { //A.本进程,跳过。 if (item.Id == Process.GetCurrentProcess().Id) //自已 { continue; } bool exists = false; #region //A2.进程名如果同引导程序,关闭之。 string pName = item.ProcessName; if (pName.EndsWith("*32")) { pName = pName.Substring(0, pName.Length - 3).Trim(); } #if DEBUG using (TextLogger loggger = new TextLogger { Path = Path.Combine(baseDirectory, "logs"), FileName = "kill.log" }) { loggger.Info(pName); } #endif exists = string.Compare(Path.GetFileNameWithoutExtension(XUpdate.Instance.Application), item.ProcessName, true) == 0; if (!exists) { exists = string.Compare(Path.GetFileName(XUpdate.Instance.Application), item.ProcessName, true) == 0; } #endregion if (!exists) { #region 求进程之中是否引用了本目录的dll //B.求模块清单,进程是否64位。 ProcessModuleCollection ProcessModule = null; try { ProcessModule = item.Modules; } catch { } if (ProcessModule != null) { List vList = new List(); foreach (ProcessModule pModule in ProcessModule) { vList.Add(pModule); } try { vList.Add(item.MainModule); } catch { } #region 32位程序是否Kill。 //2.判断需要Kill? //凡加载了工作目录之中的文件的进程就强制中止。 foreach (ProcessModule pModule in vList) //循环扫描模块。 { #region 循环检测模块 string modueFile = string.Empty; try { modueFile = pModule.FileName; } catch { } #if DEBUG //using (TextLogger loggger = new TextLogger { Path = Path.Combine(baseDirectory, "logs"), FileName = "kill.log" }) //{ // loggger.Info(modueFile); //} #endif if (string.Compare(Path.GetDirectoryName(modueFile), baseDirectory, true) == 0) { exists = true; break; } #endregion } #endregion } #endregion } if (exists) //执行Kill。 { #region 执行Kill try { item.Kill(); } catch (System.Exception exc) { #if DEBUG using (TextLogger loggger = new TextLogger { Path = Path.Combine(baseDirectory, "logs"),FileName ="kill.log" }) { loggger.Error(exc); } #endif } #endregion } } //暂停100毫秒继续。 System.Threading.Thread.Sleep(50); } })); killThread.Start(); } bool CloseComplete { get { return this.checkCloseComplete.Checked; } set { this.checkCloseComplete.Checked = value; } } #region UI通知 int progressMax = 0; int progressPos = 0; string _message = string.Empty; bool _error = false; void UpdateMessage(string message,bool error) { _message = message; _error = error; ChangeMessage(); } void ChangeMessage() { try { if (this.InvokeRequired) { this.Invoke(new MethodInvoker(this.ChangeMessage)); return; } this.statusMessage.Text = _message.Trim() + "..."; this.labelMessage.Text = _message.Trim() + "..."; ListViewItem item = null; if (!_error) { item = this.listTasks.Items.Add(_message, 1); this.statusTasks.Text = this.listTasks.Items.Count.ToString() + "个任务"; this.listTasks.Update(); } else { string msg = _message.Replace("\n", ""); item = this.listErrors.Items.Add(_message, 0); this.statusErrors.Text = this.listErrors.Items.Count.ToString() + "个错误"; this.listErrors.Update(); } } catch { } } void UpdateProgress(int pos,int total) { progressMax = total; progressPos = pos; ChangeProgress(); } void ChangeProgress() { try { if (this.InvokeRequired) { this.Invoke(new MethodInvoker(this.ChangeProgress)); return; } this.progressBar.Maximum = progressMax; this.progressBar.Value = progressPos; } catch { } } void ShowClose() { try { if (this.InvokeRequired) { this.Invoke(new MethodInvoker(this.ShowClose)); return; } this.btnCancel.Visible = false; this.btnClose.Visible = true; } catch { } } #endregion /// /// 检测是否需要更新。 /// /// bool CheckUpdate() { updateList.Clear(); //判断 if (!XUpdate.Instance.AllowUpdate) { this.UpdateMessage("系统不需要升级", true); this.UpdateProgress(500,500); this.bComplete = false; return false; } if (XUpdate.Instance.Service == null) { try { XUpdate.GetService(); } catch(System.Exception exc) { this.UpdateMessage("初始化服务参数出错,错误:" + exc.Message, false); this.UpdateProgress(500,500); this.bComplete = false; return false; } } if (XUpdate.Instance.Service == null) { this.bComplete = false; return false; } //读本地文件。 string file = Path.Combine(XUpdate.Instance.GetBaseDirectory(), SmartConfig.DefaultConfgiFile); if (File.Exists(file)) { try { sc1 = XUpdate.LoadSmartAssemblyList(); lastTime = sc1.Time; } catch { this.UpdateProgress(500, 500); this.bComplete = false; return false; } } //生成升级清单。 this.GenUpdateList(); bool update = this.updateList.Count>0; if (!update) { this.UpdateMessage("系统已是最新版本", false); string buffer = XUpdate.Instance.Service.GetSmartUpdateConfig(); sc2 = SmartConfig.LoadXML(buffer); string configFile = Path.Combine(XUpdate.Instance.GetBaseDirectory(), SmartConfig.DefaultConfgiFile); SmartConfig.Save(this.sc2, configFile); this.UpdateProgress(500,500); this.bComplete = true; } return update; } /// /// 生成更新清单。 /// /// void GenUpdateList() { updateList = new List(); //A1.原有配置。 if (sc1 == null) { sc1 = new SmartConfig(); } //B.下载新配置 try { string buffer = XUpdate.Instance.Service.GetSmartUpdateConfig(); sc2 = SmartConfig.LoadXML(buffer); } catch (System.Exception exc) { this.UpdateMessage("下载程序集清单出错,错误:" + exc.Message, true); this.UpdateProgress(500,500); return; } if (sc2 == null) sc2 = new SmartConfig(); //X1.在远程之中循环,排除在本地清单之中并且时间没有变更的记录。 foreach (SmartFile item in sc2.Files) { var sFile = sc1.Files .Where(p => string.Compare(p.FileName, item.FileName, true) == 0) .FirstOrDefault(); if (sFile == null) { updateList.Add(item); } else if(sFile.Time!=item.Time) { updateList.Add(item); } } //X2.在远程清单之中但是本地没有文件。 string baseDirectory = XUpdate.Instance.GetBaseDirectory(); foreach (SmartFile item in sc2.Files) { string descFile = Path.Combine(baseDirectory, item.FileName); if (!File.Exists(descFile)) { int count = updateList .Where(p => string.Compare(p.FileName, item.FileName, true) == 0) .Count(); if (count == 0) { updateList.Add(item); } } } } /// /// 生成删除清单。 /// /// /// 删除不必要的文件,即如果服务端删除了某些文件客户段如何处理。 /// /// void GenDeleteList() { //添加服务程序集到一个Key-Value之中 Dictionary smartFiles = new Dictionary(); foreach (SmartFile item in sc2.Files) { if (!smartFiles.ContainsKey(item.FileName)) { smartFiles.Add(item.FileName, item); } } //求在本地清单之中,不在服务器清单之中的。 foreach (SmartFile item in sc1.Files) { if (!smartFiles.ContainsKey(item.FileName)) { deleteList.Add(item); } } } /// /// 下载文件。 /// /// void DownFile(SmartFile sf) { string downDirectory = XUpdate.Instance.GetDownDirectory(); if (!Directory.Exists(downDirectory)) Directory.CreateDirectory(downDirectory); try { XUpdate.GetService(); byte[] buffer = XUpdate.Instance.Service.DownloadSmartFile(sf.FileName); buffer = Compressor.Decompress(buffer); string fileName = Path.Combine(downDirectory, sf.FileName); //子文件夹的创建。 string xPath = Path.GetDirectoryName(fileName); if (!Directory.Exists(xPath)) { try { Directory.CreateDirectory(xPath); } catch { } } //写文件。 File.WriteAllBytes(fileName, buffer); } catch (System.Exception exc) { this.UpdateMessage("下载组件"+Path.GetFileName(sf.FileName)+"出错,错误:" + exc.Message, true); return; } } /// /// 移动文件。 /// void MoveFiles() { string downDirectory = XUpdate.Instance.GetDownDirectory(); string baseDirectory = XUpdate.Instance.GetBaseDirectory(); if (!Directory.Exists(downDirectory)) return; //1.移动文件 foreach (SmartFile sf in this.updateList) { string sourceFile = Path.Combine(downDirectory, sf.FileName); string descFile = Path.Combine(baseDirectory, sf.FileName); //子文件夹的创建。 string xPath = Path.GetDirectoryName(descFile); if (!Directory.Exists(xPath)) { try { Directory.CreateDirectory(xPath); } catch { } } if (File.Exists(sourceFile) && File.Exists(descFile)) { try { File.Delete(descFile); } catch { } } if (File.Exists(sourceFile)) { string dt = Path.GetDirectoryName(descFile); if (!Directory.Exists(dt)) try { Directory.CreateDirectory(dt); } catch { } try { File.Move(sourceFile, descFile); } catch { } } } //2.删除目录 string[] files = Directory.GetFiles(downDirectory, "*.*", SearchOption.AllDirectories); foreach (string file in files) { try { File.Delete(file); } catch { } } files = Directory.GetDirectories(downDirectory, "*.*", SearchOption.AllDirectories); foreach (string file in files) { try { Directory.Delete(file); } catch { } } if (Directory.Exists(downDirectory)) try { Directory.Delete(downDirectory); } catch { } //3.删除文件 foreach (SmartFile sf in this.deleteList) { string descFile = Path.Combine(baseDirectory, sf.FileName); if (File.Exists(descFile) && !sf.FileName.EndsWith("EAS.SmartUpdater.exe", StringComparison.CurrentCultureIgnoreCase) && !sf.FileName.EndsWith("update.ini", StringComparison.CurrentCultureIgnoreCase)) { try { File.Delete(descFile); } catch { } } } //写配置 string configFile = Path.Combine(XUpdate.Instance.GetBaseDirectory(), SmartConfig.DefaultConfgiFile); SmartConfig.Save(this.sc2, configFile); } void OnDataTransmit(System.EventArgs e) { UpdateMessage("判断系统是否需要更新", false); this.UpdateProgress(1, 500); bool update = this.CheckUpdate(); if (!update) { return; } //检查需要更新的程序集 this.UpdateMessage("下载升级清单", false); this.UpdateProgress(2, 500); this.GenUpdateList(); this.GenDeleteList(); if (this.updateList.Count == 0 && this.deleteList.Count == 0) { this.UpdateMessage("没有需要更新的组件", false); this.UpdateProgress(500, 500); //写配置 string configFile = Path.Combine(XUpdate.Instance.GetBaseDirectory(), SmartConfig.DefaultConfgiFile); SmartConfig.Save(this.sc2, configFile); this.bComplete = true; //终止Kill纯程 this.m_Kill = false; System.Threading.Thread.Sleep(100); //关闭 btnClose_Click(this.btnClose, e); return; } #region //删除待升级文件。 foreach (var sf in this.updateList) { string vDirectory = XUpdate.Instance.GetBaseDirectory(); string vFile = Path.Combine(vDirectory, sf.FileName); if (File.Exists(vFile) && !sf.FileName.EndsWith("EAS.SmartUpdater.exe", StringComparison.CurrentCultureIgnoreCase) && !sf.FileName.EndsWith("update.ini", StringComparison.CurrentCultureIgnoreCase)) { try { File.Delete(vFile); } catch { } } } #endregion //检查需要更新的程序集 this.UpdateMessage("准备下载文件", false); this.UpdateProgress(3, 500); int xProgress = 5 * this.updateList.Count + 10; int index = 1; foreach (SmartFile sf in this.updateList) { this.UpdateMessage("准备下载" + Path.GetFileName(sf.FileName) + "", false); this.DownFile(sf); this.UpdateMessage(Path.GetFileName(sf.FileName) + "完成下载", false); this.UpdateProgress(5 * index, xProgress); index++; } // this.UpdateMessage("准备更新系统", false); this.MoveFiles(); this.UpdateProgress(xProgress - 5, xProgress); if (sc2.StartEx.Length > 0) { string cmd = XUpdate.Instance.GetBaseDirectory() + " " + sc2.StartEx; System.Diagnostics.Process.Start(cmd); } //终止Kill纯程 this.m_Kill = false; System.Threading.Thread.Sleep(100); this.UpdateMessage("升级完成", false); this.UpdateProgress(xProgress, xProgress); this.bComplete = true; } void AutoUpdate() { bComplete = false; try { this.OnDataTransmit(new System.EventArgs()); if (this.checkCloseComplete.Checked) { //this.Close(); System.Windows.Forms.Application.Exit(); } } catch (System.Threading.ThreadAbortException abortExc) { this.UpdateMessage(abortExc.Message, true); } catch (System.Exception exc) { this.UpdateMessage(exc.Message, true); } finally { this.ShowClose(); } } private void btnDetails_Click(object sender, System.EventArgs e) { if(this.buttonDetails.Text == "<< 详细") { this.buttonDetails.Text = "详细 >>"; this.tabControl.Visible = false; this.Height = this.Height - this.tabControl.Height; } else { this.buttonDetails.Text = "<< 详细"; tabControl.Visible = true; this.Height = this.Height + this.tabControl.Height; } } private void btnCancel_Click(object sender, System.EventArgs e) { this.btnCancel.Enabled = false; Cursor = Cursors.WaitCursor; try { this.updateThread.Abort(); } catch { } this.m_Kill = false; System.Threading.Thread.Sleep(100); Cursor = Cursors.Default; this.UpdateMessage("操作被取消", true); this.btnClose.Visible = true; tabControl.SelectedIndex = 1; } private void btnClose_Click(object sender, System.EventArgs e) { this.m_Kill = false; System.Threading.Thread.Sleep(100); if (this.bComplete) { if (this.updateList.Count >= 1) { MessageBox.Show(this, "系统升级完成,共升级了" + this.updateList.Count + "个应用程序模块,应用程序将重新启动!", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } Thread m_StartThread = new Thread(new ThreadStart(() => { try { System.Diagnostics.Process.Start(XUpdate.Instance.Application); } catch { } })); m_StartThread.Start(); } //this.Close(); System.Windows.Forms.Application.Exit(); } private void listErrors_SelectedIndexChanged(object sender, System.EventArgs e) { if(this.listErrors.SelectedItems.Count > 0) { this.textError.Text = this.listErrors.SelectedItems[0].Text; } else { this.textError.Text = string.Empty; } } private void UpdateUI_Load(object sender, EventArgs e) { } } }