- 功能展示
实现winform的在线更新,我这里主要实现了3部分的功能:
1.登录后检查更新
2.实现软件在运行中的实时更新提醒
3.在确认更新之后的在线更新功能
- 代码说明
1.实现登录时的检查更新
//检查版本更新 string version = Application.ProductVersion.ToString(); bool update = _client.TLoginCheckUpdate(version); if (update) { DialogResult dialogResult = MessageBox.Show("系统存在更新,是否现在升级?", "升级提示", MessageBoxButtons.YesNo, MessageBoxIcon.Information); if (dialogResult == DialogResult.Yes) { System.Diagnostics.Process.Start(Path.Combine(Application.StartupPath, "Update.exe"), "true"); Application.Exit(); return; } }
在登录完成之后,获取本地主程序的的版本级别,远程与服务器最新版本的客户端版本号进行比较,从而获取版本是否需要更新。
在选择更新的时候,关闭主程序进程,运行更新程序。
2.主程序的实时更新检查
检查版本线程
private void FormMain_Load(object sender, EventArgs e) { try { label1.Visible = true; backgroundWorker1.RunWorkerAsync(); tmTime.Start(); //开一个检测系统更新的线程 Thread thread = new Thread(new ParameterizedThreadStart(delegate { while (true) { //在线检查更新 bool result = _client.TLoginCheckUpdate(Application.ProductVersion.ToString()); if (result && OnCanBlinkChanged != null && _worned == false) { Action actionDelegate = () => { OnCanBlinkChanged(this, new OparateEventArgs(true)); }; this.Invoke(actionDelegate); _worned = true; } Thread.Sleep(10000); } })); thread.IsBackground = true; thread.Start(); } catch (Exception ex) { warningBox1.ShowMessage(ex.Message, MessageType.Error, 3000, Color.Red); } }
获取到版本更新之后,提醒用户,然后闪烁Notify图标
private static void main_OnCanBlinkChanged(object sender, OparateEventArgs e) { if (e.CanOparate) { _recivedMessage = true; _notify.ShowBalloonTip(3000, "更新提醒", "系统出现了新版本", ToolTipIcon.Info); _timer.Start(); } } private static void timer_Tick(object sender, EventArgs e) { if (!_blink) { _notify.Icon = Resources.main; } else { _notify.Icon = Resources.blank; } _blink = !_blink; }
3.在线更新的实现
远程获取需要新增、删除或者更新的文件列表
客户端代码
private void InitializeLstView() { string[] tempLst = null; //获取当前的系统版本号 string rootUrl = Application.StartupPath; Listconditions = new List (); string[] files = Directory.GetFiles(rootUrl); foreach (var item in files) { if (item.EndsWith("dll") || item.EndsWith("exe")) { FileVersionInfo version = FileVersionInfo.GetVersionInfo(item); conditions.Add(Path.GetFileName(item) + ',' + version.FileVersion); } else { conditions.Add(Path.GetFileName(item) + ','); //listView1.Items.Add(new ListViewItem(new string[] { Path.GetFileName(item), "", "" })); } } bool result = _client.TLoginUpdateSys(out tempLst, out _deleteLst, out _fileContent, conditions.ToArray()); if (result) { //添加删除列表 if (_deleteLst != null && _deleteLst.Length > 0) { lvUpdateList.Items.Add(new ListViewItem(new string[] { "文件删除个数:" + _deleteLst.Length, "", "0%" })); } //添加更新列表 List lstFile = new List (); foreach (string item in tempLst) { string[] arr = item.Split(';'); if (arr != null && arr.Length > 1) { string[] fileTemp = arr[0].Split('\\'); lvUpdateList.Items.Add(new ListViewItem(new string[] { fileTemp[fileTemp.Length - 1], arr[1], "0%" })); lstFile.Add(arr[0]); } } _fileLst = lstFile.ToArray(); } else { lbState.Text = "获取更新文件失败!"; } btnFinish.Enabled = !result; btnNext.Enabled = result; }
服务端代码
public bool Update(string[] currentFileVesion,out string[] uploadFileLst,out string[] deleteFileLst,out byte[][] fileContent) { bool result = true; try { uploadFileLst = null; fileContent = null; deleteFileLst = null; //记录原始版本,用于获取删除文件 DictionarysourceVesion = new Dictionary (); if (currentFileVesion == null) return false; Array.ForEach(currentFileVesion, t => { //fileName,Vesion string[] ff = t.Split(','); sourceVesion.Add(ff[0], ff[1]); }); List lstUpdate = new List (); List lstDelete = new List (); //获取最新版本的更新目录 string rootUrl = Path.Combine(HttpRuntime.AppDomainAppPath,"Sys"); string[] versions = Directory.GetDirectories(rootUrl); if (versions == null || versions.Length == 0) return false; Version lastestVersion = new Version("1.0"); string updateRoot = string.Empty; Array.ForEach(versions, t => { Version temp = new Version(Path.GetFileName(t)); if (temp > lastestVersion) { lastestVersion = temp; updateRoot = t; } }); //获取更新内容 string[] updateFilePaths = Directory.GetFiles(updateRoot); if (updateFilePaths == null || updateFilePaths.Length == 0) return false; Array.ForEach(updateFilePaths, t => { string tempFileName=Path.GetFileName(t); //判断目前版本是否存在该文件 bool exits = sourceVesion.ContainsKey(tempFileName); //判断是否需要更新 if (exits) { if (tempFileName.EndsWith("dll") || tempFileName.EndsWith("exe")) { Version oldVesion = new Version(sourceVesion[tempFileName]); FileVersionInfo versionTemp = FileVersionInfo.GetVersionInfo(t); Version newVesion = new Version(versionTemp.FileVersion); if (newVesion > oldVesion) { lstUpdate.Add(tempFileName); } } sourceVesion.Remove(tempFileName); } else { lstUpdate.Add(tempFileName); } }); //获取需要删除的文件 foreach (var item in sourceVesion) { lstDelete.Add(item.Key); } deleteFileLst = lstDelete.ToArray(); //返回更新的内容 List lst = new List (); List fileNames = new List (); foreach (string item in lstUpdate) { string path = Path.Combine(updateRoot, item); if (string.IsNullOrEmpty(item) || File.Exists(path) == false) continue; FileVersionInfo version = FileVersionInfo.GetVersionInfo(path); using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read)) { byte[] buffer = new byte[stream.Length]; stream.Read(buffer, 0, buffer.Length); lst.Add(buffer); fileNames.Add(item + ";" + version.FileVersion); } } uploadFileLst = fileNames.ToArray(); fileContent = lst.ToArray(); return result; } catch (Exception ex) { throw ex; } }
客户端后台更新类库
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { try { //循环删除文件 for (int deleteIndex = 0; deleteIndex < _deleteLst.Length; deleteIndex++) { string deleteTemp = Path.Combine(Application.StartupPath, _deleteLst[deleteIndex]); if (File.Exists(deleteTemp)) File.Delete(deleteTemp); backgroundWorker1.ReportProgress(1, new int[] { deleteIndex, (deleteIndex + 1) * 100 / _deleteLst.Length }); } //获取文件总大小 long totalSize = 0; Array.ForEach(_fileContent, t => { totalSize += t.Length; }); long currentSize = 0; //循环更新文件 for (int uploadIndex = 0; uploadIndex < _fileLst.Length; uploadIndex++) { string sourcePath = string.Empty; string[] tempFile = _fileLst[uploadIndex].Split('\\'); //遍历文件夹,判断是否存在-不存在需要删除 for (int folderDeep = 0; folderDeep < tempFile.Length - 1; folderDeep++) { if (string.IsNullOrEmpty(sourcePath)) sourcePath = Path.Combine(Application.StartupPath, tempFile[folderDeep]); else sourcePath = Path.Combine(sourcePath, tempFile[folderDeep]); if (Directory.Exists(sourcePath) == false) Directory.CreateDirectory(sourcePath); } sourcePath = Path.Combine(Application.StartupPath, _fileLst[uploadIndex]); if (File.Exists(sourcePath)) File.Delete(sourcePath);//删除要覆盖的文件 //开始写入新的文件 using (FileStream stream = new FileStream(sourcePath, FileMode.Append)) { byte[] total = _fileContent[uploadIndex]; byte[] buffer = new byte[10240]; //10KB long sCurrentSize = 0; int piz = total.Length / buffer.Length; for (int i = 0; i < piz; i++) { buffer = total.Skip(i * 10240).Take(buffer.Length).ToArray(); currentSize += buffer.Length; sCurrentSize += buffer.Length; stream.Write(buffer, 0, buffer.Length); backgroundWorker1.ReportProgress((int)(currentSize * 100 / totalSize), new int[] { uploadIndex + _deleteLst.Length, (int)(sCurrentSize * 100 / total.Length) }); } int left = total.Length % buffer.Length; if (left > 0) { buffer = total.Skip(piz * 10240).Take(left).ToArray(); currentSize += buffer.Length; stream.Write(buffer, 0, buffer.Length); backgroundWorker1.ReportProgress((int)(currentSize * 100 / totalSize), new int[] { uploadIndex + _deleteLst.Length, 100 }); } } } e.Result = null; } catch (Exception ex) { e.Result = ex.Message; } }
更新完成之后,将更新代码的程序关闭,开启客户端主线程
//关闭程序,开启主窗体 System.Diagnostics.Process.Start(Path.Combine(Application.StartupPath, "商户资料管理系统.exe")); Application.Exit();
- 源码
github
客户端安装程序 网盘提取码(meat)