Winform(C#.NET)自动更新组件的使用及部分功能实现_.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > Winform(C#.NET)自动更新组件的使用及部分功能实现

Winform(C#.NET)自动更新组件的使用及部分功能实现

 2013/11/28 15:33:25  逆水寒龙  博客园  我要评论(0)
  • 摘要:声明:核心功能的实现是由园子里圣殿骑士大哥写的,本人是基于他核心代码,按照自己需求进行修改的。而AutoUpdaterService.xml文件生成工具是基于评论#215楼ptangbao的代码而改写的。由于这个组件是在10年写的,.net也有更新有的方法已提示过时,更改如下://Addedthefunctiontosupportproxy//clientDownload.Proxy=System.Net.WebProxy.GetDefaultProxy();clientDownload
  • 标签:.net C# for 功能 实现 使用 net winform

声明:核心功能的实现是由园子里圣殿骑士大哥写的,本人是基于他核心代码,按照自己需求进行修改的。

     而AutoUpdaterService.xml文件生成工具是基于评论#215楼 ptangbao的代码而改写的。

由于这个组件是在10年写的,.net也有更新有的方法已提示过时,更改如下:

//Added the function to support proxy
//clientDownload.Proxy = System.Net.WebProxy.GetDefaultProxy();
clientDownload.Proxy = WebRequest.GetSystemWebProxy();

更改的主要功能如下:

  1》如果有更新将会直接更新,不再提供由用户点击确定后再更新。(强制更新)(这个暂时没有整理出来,后续会整理出来)

  2》更新前判断主程序进程是否开启

  如果有更新,主程序开启,关闭主程序,更新完成后自动启动主程序。

  如果没有更新,直接启动主程序。

  3》不再根据版本号不同进行更新。

  圣殿骑士大哥的是根据版本号,当然这也是最正规的,可是我们的程序有点特殊,所以不再根据版本号控制,而是根据GUID。

  这样就是有一点好处不管版本号一不一样,只要GUID不一样就是要更新。

  比如文件夹如下:

  

  使用CreateXmlTools.exe工具生成xml文件,增加的节点属性有version,值时GUID

<?xml version="1.0" encoding="utf-8"?>
<updateFiles>
  <file path="AutoUpdater.dll" url="http://172.30.100.55:8011/AutoUpdater.dll" lastver="5.0.0.0" size="26624" needRestart="false" version="1ef2b9dc-d14f-4fc4-a5ec-bdb07a6ba98c" />
  <file path="ReadMe.dll" url="http://172.30.100.55:8011/ReadMe.dll" lastver="" size="472" needRestart="false" version="3ddc1926-3088-468f-9088-92b07156c757" />
  <file path="aspnet_client/ReadMe.dll" url="http://172.30.100.55:8011/aspnet_client/ReadMe.dll" lastver="" size="472" needRestart="false" version="4aaa87e2-63bd-486a-9957-1c2df21607cb" />
</updateFiles>

  version就是用来替代lastver的,只要不一样就更新

  4》客户端更新主程序更改autoupdater.config文件的更新方式

  config里不必包含所有文件的配置,只要求配置成如下:  

<?xml version="1.0" encoding="utf-8" ?>
<Config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Enabled>true</Enabled>
  <ServerUrl>http://172.30.100.55:8011/AutoupdateService.xml</ServerUrl>
  <UpdateFileList>
    
  </UpdateFileList>
</Config>

  ServerUrl就是web服务器的地址加上面生成xml文件的地址。

  更新完成后客户端会自动更新autoupdater.config文件,将本地的guid保持与服务端一致,再次点击guid一致的不再更新

以上是大致改动的地方。

下面来说说代码吧:

由于增加了GUID这块,所以RemoteFile、LocalFile和DownloadFileInfo三个实体类都应该增加一个字段和一个属性

LocalFile.cs

class="code_img_closed" src="/Upload/Images/2013112815/0015B68B3C38AA5B.gif" alt="" />logs_code_hide('95e16e3b-2c48-43fc-bfff-588e27a768db',event)" src="/Upload/Images/2013112815/2B1B950FA3DF188F.gif" alt="" />
 1     public class LocalFile
 2     {
 3         #region The private fields
 4         private string path = "";
 5         private string lastver = "";
 6         private int size = 0;
 7         private string version = "";
 8         #endregion
 9 
10         #region The public property
11         [XmlAttribute("path")]
12         public string Path { get { return path; } set { path = value; } }
13         [XmlAttribute("lastver")]
14         public string LastVer { get { return lastver; } set { lastver = value; } }
15         [XmlAttribute("size")]
16         public int Size { get { return size; } set { size = value; } }
17         [XmlAttribute("version")]
18         public string Version { get { return version; } set { version = value; } }
19         #endregion
20 
21         #region The constructor of LocalFile
22         public LocalFile(string path, string ver, int size,string versionid)
23         {
24             this.path = path;
25             this.lastver = ver;
26             this.size = size;
27             this.version = versionid;
28         }
29 
30         public LocalFile()
31         {
32         }
33         #endregion
34 
35     }
View Code

RemoteFile.cs

 1     public class RemoteFile
 2     {
 3         #region The private fields
 4         private string path = "";
 5         private string url = "";
 6         private string lastver = "";
 7         private int size = 0;
 8         private bool needRestart = false;
 9         private string version = "";
10         #endregion
11 
12         #region The public property
13         public string Path { get { return path; } }
14         public string Url { get { return url; } }
15         public string LastVer { get { return lastver; } }
16         public int Size { get { return size; } }
17         public bool NeedRestart { get { return needRestart; } }
18         public string Verison { get { return version; } }
19         #endregion
20 
21         #region The constructor of AutoUpdater
22         public RemoteFile(XmlNode node)
23         {
24             this.path = node.Attributes["path"].Value;
25             this.url = node.Attributes["url"].Value;
26             this.lastver = node.Attributes["lastver"].Value;
27             this.size = Convert.ToInt32(node.Attributes["size"].Value);
28             this.needRestart = Convert.ToBoolean(node.Attributes["needRestart"].Value);
29             this.version = node.Attributes["version"].Value;
30         }
31         #endregion
32     }
View Code

DownloadFileInfo.cs

 1     public class DownloadFileInfo
 2     {
 3         #region The private fields
 4         string downloadUrl = string.Empty;
 5         string fileName = string.Empty;
 6         string lastver = string.Empty;
 7         int size = 0;
 8         string version = string.Empty;
 9         #endregion
10 
11         #region The public property
12         public string DownloadUrl { get { return downloadUrl; } }
13         public string FileFullName { get { return fileName; } }
14         public string FileName { get { return Path.GetFileName(FileFullName); } }
15         public string LastVer { get { return lastver; } set { lastver = value; } }
16         public int Size { get { return size; } }
17         public string Version { get { return version; } set { version = value; } }
18         #endregion
19 
20         #region The constructor of DownloadFileInfo
21         public DownloadFileInfo(string url, string name, string ver, int size,string versionid)
22         {
23             this.downloadUrl = url;
24             this.fileName = name;
25             this.lastver = ver;
26             this.size = size;
27             this.version = versionid;
28         }
29         #endregion
30     }
View Code

ConstFile.cs

一些常量配置文件

CommonUnitity.cs

//主要是更改获取多层目录文件夹路径
public
static string GetFolderUrl(DownloadFileInfo file) { string folderPathUrl = string.Empty; int folderPathPoint = file.DownloadUrl.IndexOf("/", 15) + 1; string filepathstring = file.DownloadUrl.Substring(folderPathPoint); //int folderPathPoint1 = filepathstring.IndexOf("/"); //string filepathstring1 = filepathstring.Substring(folderPathPoint1 + 1); //if(filepathstring1.IndexOf("/") != -1) if(filepathstring.IndexOf("/") != -1) { //string[] ExeGroup = filepathstring1.Split('/'); string[] ExeGroup = filepathstring.Split('/'); for (int i = 0; i < ExeGroup.Length - 1; i++) { folderPathUrl += "\\" + ExeGroup[i]; } if (!Directory.Exists(SystemBinUrl + ConstFile.TEMPFOLDERNAME + folderPathUrl)) { Directory.CreateDirectory(SystemBinUrl + ConstFile.TEMPFOLDERNAME + folderPathUrl); } } return folderPathUrl; }

autoupdater.cs

  1 public class AutoUpdater : IAutoUpdater
  2     {
  3         #region The private fields
  4         private Config config = null;
  5         private bool bNeedRestart = false;
  6         private bool bDownload = false;
  7         List<DownloadFileInfo> downloadFileListTemp = null;
  8         #endregion
  9 
 10         #region The public event
 11         public event ShowHandler OnShow;
 12         #endregion
 13 
 14         #region The constructor of AutoUpdater
 15         public AutoUpdater()
 16         {
 17             config = Config.LoadConfig(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConstFile.FILENAME));
 18         }
 19         #endregion
 20 
 21         #region The public method
 22         public void Update()
 23         {
 24             if (!config.Enabled)
 25                 return;
 26 
 27             Dictionary<string, RemoteFile> listRemotFile = ParseRemoteXml(config.ServerUrl);
 28             List<DownloadFileInfo> downloadList = new List<DownloadFileInfo>();
 29 
 30             foreach (LocalFile file in config.UpdateFileList)
 31             {
 32                 if (listRemotFile.ContainsKey(file.Path))
 33                 {
 34                     RemoteFile rf = listRemotFile[file.Path];
 35                     //Version v1 = new Version(rf.LastVer);
 36                     //Version v2 = new Version(file.LastVer);
 37                     //if (v1 > v2)
 38                     string v1 = rf.Verison;
 39                     string v2 = file.Version;
 40                     if (v1 != v2)
 41                     {
 42                         downloadList.Add(new DownloadFileInfo(rf.Url, rf.Path, rf.LastVer, rf.Size, rf.Verison));
 43                         file.Path = rf.Path;
 44                         file.LastVer = rf.LastVer;
 45                         file.Size = rf.Size;
 46                         file.Version = rf.Verison;
 47                         if (rf.NeedRestart)
 48                             bNeedRestart = true;
 49 
 50                         bDownload = true;
 51                     }
 52 
 53                     listRemotFile.Remove(file.Path);
 54                 }
 55             }
 56 
 57             foreach (RemoteFile file in listRemotFile.Values)
 58             {
 59                 downloadList.Add(new DownloadFileInfo(file.Url, file.Path, file.LastVer, file.Size, file.Verison));
 60                 bDownload = true;
 61                 config.UpdateFileList.Add(new LocalFile(file.Path, file.LastVer, file.Size, file.Verison));
 62                 if (file.NeedRestart)
 63                     bNeedRestart = true;
 64             }
 65 
 66             downloadFileListTemp = downloadList;
 67 
 68             if (bDownload)
 69             {
 70                 OperProcess op = new OperProcess();
 71                 op.InitUpdateEnvironment();
 72                 DownloadConfirm dc = new DownloadConfirm(downloadList);
 73 
 74                 if (this.OnShow != null)
 75                     this.OnShow();
 76                 StartDownload(downloadList);
 77             }
 78         }
 79 
 80         public void RollBack()
 81         {
 82             foreach (DownloadFileInfo file in downloadFileListTemp)
 83             {
 84                 string tempUrlPath = CommonUnitity.GetFolderUrl(file);
 85                 string oldPath = string.Empty;
 86                 try
 87                 {
 88                     if (!string.IsNullOrEmpty(tempUrlPath))
 89                     {
 90                         oldPath = Path.Combine(CommonUnitity.SystemBinUrl + tempUrlPath.Substring(1), file.FileName);
 91                     }
 92                     else
 93                     {
 94                         oldPath = Path.Combine(CommonUnitity.SystemBinUrl, file.FileName);
 95                     }
 96 
 97                     if (oldPath.EndsWith("_"))
 98                         oldPath = oldPath.Substring(0, oldPath.Length - 1);
 99 
100                     MoveFolderToOld(oldPath + ".old", oldPath);
101 
102                 }
103                 catch (Exception ex)
104                 {
105                     //log the error message,you can use the application's log code
106                 }
107             }
108         }
109 
110 
111         #endregion
112 
113         #region The private method
114         string newfilepath = string.Empty;
115         private void MoveFolderToOld(string oldPath, string newPath)
116         {
117             if (File.Exists(oldPath) && File.Exists(newPath))
118             {
119                 System.IO.File.Copy(oldPath, newPath, true);
120             }
121         }
122 
123         private void StartDownload(List<DownloadFileInfo> downloadList)
124         {
125             DownloadProgress dp = new DownloadProgress(downloadList);
126             if (dp.ShowDialog() == DialogResult.OK)
127             {
128                 //
129                 if (DialogResult.Cancel == dp.ShowDialog())
130                 {
131                     return;
132                 }
133                 //Update successfully
134                 config.SaveConfig(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConstFile.FILENAME));
135 
136                 if (bNeedRestart)
137                 {
138                     //Delete the temp folder
139                     Directory.Delete(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConstFile.TEMPFOLDERNAME), true);
140 
141                     MessageBox.Show(ConstFile.APPLYTHEUPDATE, ConstFile.MESSAGETITLE, MessageBoxButtons.OK, MessageBoxIcon.Information);
142                     CommonUnitity.RestartApplication();
143                 }
144             }
145         }
146 
147         private Dictionary<string, RemoteFile> ParseRemoteXml(string xml)
148         {
149             XmlDocument document = new XmlDocument();
150             document.Load(xml);
151 
152             Dictionary<string, RemoteFile> list = new Dictionary<string, RemoteFile>();
153             foreach (XmlNode node in document.DocumentElement.ChildNodes)
154             {
155                 list.Add(node.Attributes["path"].Value, new RemoteFile(node));
156             }
157 
158             return list;
159         }
160         #endregion
161 
162     }
View Code

OperProcess.cs

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Diagnostics;
 6 
 7 namespace AutoUpdater
 8 {
 9     /// <summary>
10     /// 启动进程、关闭进程操作
11     /// </summary>
12     public class OperProcess
13     {
14         #region init update env
15         public void InitUpdateEnvironment()
16         {
17             if (IfExist("MainProgram"))
18             {
19                 CloseExe("MainProgram");
20             }
21         }
22         #endregion init update env
23 
24         #region updated start process
25         public void StartProcess()
26         {
27             string path = System.Environment.CurrentDirectory;
28             if (!IfExist("MainProgram"))
29             {
30                 StartExe(path, "MainProgram.exe");
31             }
32             CloseExe("KnightsWarrior");
33         }
34 
35         #endregion
36 
37         #region 启动进程、关闭进程、判断进程是否存在
38         //启动exe绝对路径
39         private void StartExe(string filePath, string fileName)
40         {
41             Process proc = new Process();
42             proc.StartInfo.UseShellExecute = true;//是否使用操作系统外壳程序启动进程
43 
44             proc.StartInfo.WorkingDirectory = filePath;//启动进程的初始目录
45             proc.StartInfo.FileName = fileName;
46             proc.Start();
47         }
48 
49 
50         //exeName 关闭的exe进程名
51         private void CloseExe(string exeName)
52         {
53             Process[] arrPro = Process.GetProcessesByName(exeName);
54             foreach (Process pro in arrPro)
55                 pro.Kill();
56         }
57         //processName 进程名
58         private bool IfExist(string processName)
59         {
60             Process[] pro = Process.GetProcessesByName(processName);
61             return pro.Count() > 0;
62         }
63         #endregion 启动进程、关闭进程
64     }
65 }
View Code

以上就是整体的自动更新程序核心代码。

下面是创建xml的程序代码:

代码是根据评论修改的如下:

  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.Linq;
  7 using System.Text;
  8 using System.Windows.Forms;
  9 using System.Xml;
 10 using System.IO;
 11 using System.Diagnostics;
 12 
 13 namespace CreateXmlTools
 14 {
 15     public partial class FormMain : Form
 16     {
 17         public FormMain()
 18         {
 19             InitializeComponent();
 20             txtWebUrl.Text = "172.30.100.55:8011";
 21             txtWebUrl.ForeColor = Color.Gray;
 22         }
 23 
 24         //获取当前目录
 25         //string currentDirectory = AppDomain.CurrentDomain.BaseDirectory;
 26         string currentDirectory = System.Environment.CurrentDirectory;
 27         //服务端xml文件名
 28         string serverXmlName = "AutoupdateService.xml";
 29         //更新文件URL前缀
 30         string url = string.Empty;
 31 
 32         void CreateXml()
 33         {
 34             //创建文档对象
 35             XmlDocument doc = new XmlDocument();
 36             //创建根节点
 37             XmlElement root = doc.CreateElement("updateFiles");
 38             //头声明
 39             XmlDeclaration xmldecl = doc.CreateXmlDeclaration("1.0", "utf-8", null);
 40             doc.AppendChild(xmldecl);
 41             DirectoryInfo dicInfo = new DirectoryInfo(currentDirectory);
 42             
 43             //调用递归方法组装xml文件
 44             PopuAllDirectory(doc, root, dicInfo);
 45             //追加节点
 46             doc.AppendChild(root);
 47             //保存文档
 48             doc.Save(serverXmlName);
 49         }
 50 
 51         //递归组装xml文件方法
 52         private void PopuAllDirectory(XmlDocument doc, XmlElement root, DirectoryInfo dicInfo)
 53         {
 54             foreach (FileInfo f in dicInfo.GetFiles())
 55             {
 56                 //排除当前目录中生成xml文件的工具文件
 57                 if (f.Name != "CreateXmlTools.exe" && f.Name != "AutoupdateService.xml")
 58                 {
 59                     string path = dicInfo.FullName.Replace(currentDirectory, "").Replace("\\", "/");
 60                     string folderPath=string.Empty;
 61                     if (path != string.Empty)
 62                     {
 63                         folderPath = path.TrimStart('/') + "/";
 64                     }
 65                     XmlElement child = doc.CreateElement("file");
 66                     child.SetAttribute("path", folderPath + f.Name);
 67                     child.SetAttribute("url", url + path + "/" + f.Name);
 68                     child.SetAttribute("lastver", FileVersionInfo.GetVersionInfo(f.FullName).FileVersion);
 69                     child.SetAttribute("size", f.Length.ToString());
 70                     child.SetAttribute("needRestart", "false");
 71                     child.SetAttribute("version", Guid.NewGuid().ToString());
 72                     root.AppendChild(child);
 73                 }
 74             }
 75 
 76             foreach (DirectoryInfo di in dicInfo.GetDirectories())
 77                 PopuAllDirectory(doc, root, di);
 78         }
 79 
 80         private void btnCreate_Click(object sender, EventArgs e)
 81         {
 82             url = "http://" + txtWebUrl.Text.Trim();
 83             CreateXml();
 84             ReadXml();
 85         }
 86 
 87         private void ReadXml()
 88         {
 89             string path="AutoupdateService.xml";
 90             rtbXml.ReadOnly = true;
 91             if (File.Exists(path))
 92             {
 93                 rtbXml.Text = File.ReadAllText(path);
 94             }
 95         }
 96 
 97         private void txtWebUrl_Enter(object sender, EventArgs e)
 98         {
 99             txtWebUrl.ForeColor = Color.Black;
100             if (txtWebUrl.Text.Trim() == "172.30.100.55:8011")
101             {
102                 txtWebUrl.Text = string.Empty;
103             }
104         }
105         
106     }
107 }
View Code

由于我的主程序是被别人写死的(没有修改权限没有代码)所以我只能单独写更新程序,由用户打开我的更新程序调用exe的方式来处理

所以多了一个程序专门用来更新的

 1 using System;
 2 using System.Collections.Generic;
 3 using System.ComponentModel;
 4 using System.Data;
 5 using System.Drawing;
 6 using System.Linq;
 7 using System.Text;
 8 using System.Windows.Forms;
 9 using AutoUpdater;
10 using System.Net;
11 using System.Xml;
12 using KnightsWarriorAutoupdater;
13 
14 namespace KnightsWarrior
15 {
16     public partial class UpdateForm : Form
17     {
18         public UpdateForm()
19         {
20             InitializeComponent();
21         }
22         void InitCheckUpdate()
23         {
24             #region check and download new version program
25             bool bHasError = false;
26             IAutoUpdater autoUpdater = new KnightsWarriorAutoupdater.AutoUpdater();
27             try
28             {
29                 autoUpdater.Update();
30             }
31             catch (WebException exp)
32             {
33                 MessageBox.Show("服务器连接失败");
34                 bHasError = true;
35             }
36             catch (XmlException exp)
37             {
38                 bHasError = true;
39                 MessageBox.Show("下载更新文件错误");
40             }
41             catch (NotSupportedException exp)
42             {
43                 bHasError = true;
44                 MessageBox.Show("升级文件配置错误");
45             }
46             catch (ArgumentException exp)
47             {
48                 bHasError = true;
49                 MessageBox.Show("下载升级文件错误");
50             }
51             catch (Exception exp)
52             {
53                 bHasError = true;
54                 MessageBox.Show("更新过程中出现错误");
55             }
56             finally
57             {
58                 if (bHasError == true)
59                 {
60                     try
61                     {
62                         autoUpdater.RollBack();
63                     }
64                     catch (Exception)
65                     {
66                         //Log the message to your file or database
67                     }
68                 }
69                 OperProcess op = new OperProcess();
70                 //启动进程
71                 op.StartProcess();
72             }
73             #endregion
74         }
75     }
76 }
View Code

1、服务器端
  1、CreateXmlTools.exe给发布dll人员使用,用来生成要升级文件的列表,放在更新文件中的。
  2、webServer地址是web服务器的地址。
  3、点击生成之后会生成一个文件名为AutoupdateService.xml文件。
  4、将生成的xml文件放置在web服务器的根目录里。
2、客户端
  1、AutoUpdater.Config,该文件是保证客户端更新程序调用获取更新文件列表时使用的。
  2、KnightsWarrior.exe更新主程序,用户直接调用该文件
  3、AutoUpdater.dll更新程序的核心程序

本程序是要结合web服务器使用的,所有要更新的文件需要放在搭建的web服务器上,按照对应的目录存放,点CreateXmlTools.exe会生成一个xml文件的。

以上就是所有修改和增加部分的程序的代码及一些简要说明。建议先去看看组件源码,圣殿骑士大哥将其托管在托管地址。欢迎拍砖!

上一篇: JAVA图片验证码 下一篇: Hibernate继承映射
发表评论
用户名: 匿名