博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C#软件自动更新程序
阅读量:5984 次
发布时间:2019-06-20

本文共 13440 字,大约阅读时间需要 44 分钟。

hot3.png

 基于C#实现的软件自动更新程序,之前在网上搜集了两款软件自动更新程序,在实际应用中,对部分BUG进行修复,添加+完善一些功能。这里,推荐给大家。代码完全开放,可以根据实际应用场景,作调整。

先来看看第一款软件自动更新程序的效果图吧:

软件自动更新程序1

它的原理非常简单,它是根据文件的日期,进行比较,然后在服务端修改生成一个XML文件,软件在启动的时候,验证是否更新,如果需要更新,则终止主程序,启动自动更新程序,更新成功后,再启动主程序。

它的大体结构是这样的:

1、需要一个网站,把需要更新的文件都存放在这个网站下的UpdateServer文件夹,它自身提供了一个生成更新配置文件的UpdateListBuilder.exe工具,只需点击执行exe,便可在服务端生成更新所需的xml配置文件。格式如下:

\K3SP.exe
\conf\menu.xml

这里的K3SP.exe是主程序exe。

2、主程序添加如下代码:

///         /// 检测更新        ///         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)     //字符转日期,并比较日期大小                {                    //本次更新日期 大于 最近一次更新日期,开始更新                    try                    {                        if (new K3SP.lib.ClassCheckProIsRun().checkProcess(strUpdaterProFileName, strUpdaterProPath))                        {                            classMsg.messageInfoBox("更新程序" + strUpdaterProFileName + "已打开!");                        }                        else                        {                            Process.Start(strUpdaterProPath);                        }                    }                    catch (Win32Exception ex)                    {                        classMsg.messageInfoBox(ex.Message);      //主程序未更新成功或者被误删掉,再更新一遍                    }                    Application.Exit();         //退出主程序                }            }        }

在窗体加载事件,调用checkUpdate方法进行检测更新。

再来看看第二种自动更新的效果吧:

自动更新程序

自动更新程序

     该工具自身是英文的,在此基础上,进行了部分汉化,又增加了AutoUpdateBuilder自动生成更新配置文件的程序,方便我们在服务端维护。

自动更新程序

这里,我做了个简单的demo程序。为使用改程序,我还新加了一个AutoUpdaterTool的工具,来进行软件的升级更新。

先来,看看AutoUpdaterTool都做了些什么?

///         /// 应用程序的主入口点。        ///         [STAThread]        static void Main()        {            Application.EnableVisualStyles();            Application.SetCompatibleTextRenderingDefault(false);            //Application.Run(new Form1());            #region check and download new version program            bool bHasError = false;            IAutoUpdater autoUpdater = new KnightsWarriorAutoupdater.AutoUpdater();            //主程序执行路径            string strExePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "AutoUpdaterDemo.exe");            try            {                if (new ClassCheckProIsRun().checkProcessForProName(strExePath))//检测主程序是否执行                {                    MessageBox.Show(@"进程中检测到主程序正在运行,请先关闭才可更新。");                    return;                }                autoUpdater.Update();            }            catch (WebException exp)            {                MessageBox.Show(@"不能够找到指定的资源!");                bHasError = true;            }            catch (XmlException exp)            {                bHasError = true;                MessageBox.Show(@"下载升级文件时发生错误!");            }            catch (NotSupportedException exp)            {                bHasError = true;                MessageBox.Show(@"更新地址配置错误");            }            catch (ArgumentException exp)            {                bHasError = true;                MessageBox.Show(@"下载升级文件时发生错误");            }            catch (Exception exp)            {                bHasError = true;                MessageBox.Show(@"升级过程中发生错误!");            }            finally            {                if (bHasError == true)                {                    try                    {                        autoUpdater.RollBack();                    }                    catch (Exception)                    {                        //Log the message to your file or database                    }                }            }            #endregion            System.Diagnostics.Process.Start(strExePath, ((KnightsWarriorAutoupdater.AutoUpdater)autoUpdater).isCancel.ToString());            Application.Exit();        }

 

我建了一个Winform程序,不要窗口,检测更新程序,都写在了Main函数里。

接下来,在看看AutoUpdaterDemo示例程序的检测方法:

///         ///         ///         public bool IsCancelUpdate { get; set; }        ///         /// 检测更新        ///         ///         ///         private void Form1_Load(object sender, EventArgs e)        {            if (!IsCancelUpdate) CheckUpdate();        }        ///         /// 自动更新程序路径        ///         private readonly string autoUpdaterPath = AppDomain.CurrentDomain.BaseDirectory + "AutoUpdaterTool.exe";        ///         /// 检测更新程序        ///         void CheckUpdate()        {            try            {                IAutoUpdater autoUpdater = new KnightsWarriorAutoupdater.AutoUpdater();                if (autoUpdater.CheckUpdate())                {                    if (new lib.ClassCheckProIsRun().checkProcess(autoUpdaterPath))                    {                        MessageBox.Show(@"更新程序已经运行!");                        return;                    }                    System.Diagnostics.Process.Start(autoUpdaterPath);                    Application.Exit();                }            }            catch (Exception exception)            {                MessageBox.Show(exception.Message);            }        }

注意:在这里,我给窗体新加了一个IsCancelUpdate的属性,这个为下面的取消更新做了铺垫。

这个AutoUpdaterDemo的入口函数,我添加了参数,来实现取消更新的功能。

///         /// 应用程序的主入口点。        ///         [STAThread]        static void Main(string[] args)        {            Application.EnableVisualStyles();            Application.SetCompatibleTextRenderingDefault(false);            var mainForm = new Form1();            if (args != null && args.Length > 0) mainForm.IsCancelUpdate = Convert.ToBoolean(args[0]);            Application.Run(mainForm);        }

妙处就在这里。为什么要这么做?因为自动更新程序和主程序,是两个进程,我们在主程序里检测更新,如果客户端取消更新,又会启动主程序,主程序又会检测更新,这样形成了一个死循环。

这个参数,是通过自动更新工具AutoUpdaterTool.exe来传递的,代码如下:

///         /// 应用程序的主入口点。        ///         [STAThread]        static void Main()        {            Application.EnableVisualStyles();            Application.SetCompatibleTextRenderingDefault(false);            //Application.Run(new Form1());            #region check and download new version program            bool bHasError = false;            IAutoUpdater autoUpdater = new KnightsWarriorAutoupdater.AutoUpdater();            //主程序执行路径            string strExePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "AutoUpdaterDemo.exe");            try            {                if (new ClassCheckProIsRun().checkProcessForProName(strExePath))//检测主程序是否执行                {                    MessageBox.Show(@"进程中检测到主程序正在运行,请先关闭才可更新。");                    return;                }                autoUpdater.Update();            }            catch (WebException exp)            {                MessageBox.Show(@"不能够找到指定的资源!");                bHasError = true;            }            catch (XmlException exp)            {                bHasError = true;                MessageBox.Show(@"下载升级文件时发生错误!");            }            catch (NotSupportedException exp)            {                bHasError = true;                MessageBox.Show(@"更新地址配置错误");            }            catch (ArgumentException exp)            {                bHasError = true;                MessageBox.Show(@"下载升级文件时发生错误");            }            catch (Exception exp)            {                bHasError = true;                MessageBox.Show(@"升级过程中发生错误!");            }            finally            {                if (bHasError == true)                {                    try                    {                        autoUpdater.RollBack();                    }                    catch (Exception)                    {                        //Log the message to your file or database                    }                }            }            #endregion            System.Diagnostics.Process.Start(strExePath, ((KnightsWarriorAutoupdater.AutoUpdater)autoUpdater).isCancel.ToString());            Application.Exit();

就在这段代码的最后,启动这个进程的时候,我把取消isCancel这个属性传递给主程序。

isCancel是我为AutoUpdater对象添加的一个属性。

另外,我还为IAutoUpdater接口,公开了CheckUpdate方法,用来在AutoUpdaterDemo中,调用该方法,检测是否需要更新。

再来看看,为自动生成更新配置文件的程序。注意:要想支持文件夹的更新,需要简单的修改下代码即可。

using System;using System.Collections.Generic;using System.Configuration;using System.IO;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Xml;/****************************************************************************************************************** *  *  * 说 明: 生成自动更新配置文件(版本:Version1.0.0) * 作 者:李朝强 * 日 期:2015/05/19 * 修 改: * 参 考:http://my.oschina.net/lichaoqiang/ * 备 注:暂无... *  *  * ***************************************************************************************************************/namespace AutoUpdaterBuilder{    class Program    {        ///         ///         ///         ///         static void Main(string[] args)        {            Console.Title = "更新文档生成工具!";            try            {                //远程服务器URL                string strServerUrl = System.Configuration.ConfigurationManager.AppSettings["ServerUrl"];                //创建Xml文档                XmlDocument xml = new XmlDocument();                var declaration = xml.CreateXmlDeclaration("1.0", "utf-8", null);                xml.AppendChild(declaration);                var root = xml.CreateElement("UpdateFileList");//根节点                string strBaseDirectory = AppDomain.CurrentDomain.BaseDirectory;//应用程序根目录                string[] strFiles = Directory.GetFiles(strBaseDirectory);//获取目录下所有文件                //版本信息                Version v = new Version(System.Configuration.ConfigurationManager.AppSettings["Version"]);                Version theNewVersion = new Version(v.Major, v.Minor, v.Build, v.Revision + 1);//生成新的版本号                List
updataFileInfos = new List
();//更新文件列表 //循环更新文件 foreach (string strfile in strFiles) { if (strfile.Contains("AutoUpdaterBuilder.exe") || strfile.EndsWith(".xml") || strfile.EndsWith(".config")) continue; //文件名 FileInfo file = new FileInfo(strfile); var localFile = xml.CreateElement("LocalFile"); localFile.SetAttribute("path", file.Name); localFile.SetAttribute("url", string.Format("{0}/{1}", strServerUrl, file.Name)); localFile.SetAttribute("lastver", theNewVersion.ToString()); localFile.SetAttribute("size", file.Length.ToString()); localFile.SetAttribute("needRestart", "false"); root.AppendChild(localFile); updataFileInfos.Add(file); ShowMessge("正在创建文件“{0}”的更新配置", file.Name); } xml.AppendChild(root); string strSaveToPath = System.IO.Path.Combine(strBaseDirectory, "AutoupdateService.xml");//配置文件保存路径 xml.Save(strSaveToPath); //更新日志 string[] strUpdateLogs = Array.ConvertAll(updataFileInfos.ToArray(), (t) => string.Format("[{0}] {1}", t.LastWriteTime.ToString("yyyy/MM/dd HH:mm:ss"), t.Name)); File.WriteAllLines(Path.Combine(strBaseDirectory, "UpdateLog.txt"), strUpdateLogs); //修改配置文件 ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap(); fileMap.ExeConfigFilename = System.IO.Path.Combine(strBaseDirectory, "AutoUpdaterBuilder.exe.config"); System.Configuration.Configuration configuration = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); configuration.AppSettings.Settings["Version"].Value = theNewVersion.ToString(); configuration.Save(ConfigurationSaveMode.Modified); Console.WriteLine("更新文件生成成功,2s后退出!"); System.Threading.Thread.Sleep(2000);//线程休眠2s } catch (Exception exception) { Console.WriteLine(exception.Message); Console.ReadLine(); } } ///
/// /// ///
///
static void ShowMessge(string format, params object[] args) { Console.WriteLine(format, arg: args); } ///
/// /// ///
///
static void Log(string format, params object[] args) { } }}

生成后的xml文件

怎样部署?

很简单,首先,我们只需要建一个网站,把AutoUpdaterBuilder.exe和AutoUpdaterBuilder.exe.config文件放进去,然后再把需要更新的文件,放入改文件夹下。

以上是AutoUpdaterBuilder.exe.config配置文件。

其次,在主程序上添加对AutoUpdater.dll的引用,主要是为了调用它的检测更新方法。

今天就写到这吧,感兴趣的朋友,可以亲手尝试下。

转载于:https://my.oschina.net/lichaoqiang/blog/866525

你可能感兴趣的文章
sencha touch学习心得之FormPanel
查看>>
1.扩展方法2.接口的隐式实现和显式实现
查看>>
HDU题目分类
查看>>
HDU - 3085 Nightmare Ⅱ
查看>>
kafka java api消费者
查看>>
zabbix 获取不到自定义脚本的值解决
查看>>
在StackPanel中加入新的stackpanel,包含图片和文字
查看>>
MySQL监控内容
查看>>
Windows保护模式 - 基础篇05|解密系列
查看>>
合并链表 【微软面试100题 第四十二题】
查看>>
Poj OpenJudge 1068 Parencodings
查看>>
RenderSection
查看>>
CocoaPods详解之----进阶篇
查看>>
linux python升级和ipython的安装
查看>>
0512操作系统 实验三 进度调度模拟程序
查看>>
nginx 负载均衡
查看>>
Entity Framework Core 修改映射主键名称
查看>>
SQL 经典面试题
查看>>
为知笔记发布博客地址
查看>>
java - Math、system、BigDecimal、Date、SimpleDateFormat、Calendar类概述和方法使用
查看>>