四联光电智能照明论坛

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 20373|回复: 3
打印 上一主题 下一主题

C#[WinForm]实现自动更新(Auto Update)  

[复制链接]
  • TA的每日心情
    开心
    2022-6-10 09:59
  • 366

    主题

    741

    帖子

    9649

    积分

    超级版主

    Rank: 8Rank: 8

    积分
    9649
    跳转到指定楼层
    楼主
    发表于 2016-10-28 12:02:29 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    winform程序相对web程序而言,功能更强大,编程更方便,但软件更新却相当麻烦,要到客户端一台一台地升级,面对这个实际问题,在最近的一个小项目中,本人设计了一个通过软件实现自动升级技术方案,弥补了这一缺陷,有较好的参考价值

    实现原理:在WebServices中实现一个GetVer的WebMethod方法,其作用是获取当前的最新版本。 然后将现在版本与最新版本比较,如果有新版本,则进行升级。

    步骤:
        

    1、准备一个XML文件 (Update.xml)。
    <?xml version="1.0" encoding="utf-8" ?>
    <prod t>
    <version>1.0.1818.42821</version>
    <description>修正一些Bug</description>
    <filelist count="4" sourcepath="./update/">
    <item name="City.xml" size="">
    <val />
    </item>
    <item name="CustomerApplication.exe" size="">
    <val />
    </item>
    <item name="Interop.SHDocVw.dll" size="">
    <val />
    </item>
    <item name="Citys.xml" size="">
    <val />
    </item>
    </filelist>
    </prod t>


    作用是作为一个升级用的模板。
        

    2、WebServices的GetVer方法。

    [WebMethod(Description="取得更新版本")]
    p lic string GetVer()
    {
    XmlDocument doc = new XmlDocument();
    doc.Load(Server.MapPath("update.xml"));
    XmlElement root = doc.DocumentElement;
    return root.SelectSingleNode("version").InnerText;
    }
         

    3、WebServices的GetUpdateData方法。

    [WebMethod(Description="在线更新软件")]
    [SoapHeader("sHeader")]
    p lic System.Xml.XmlDocument GetUpdateData()
    {
    //验证用户是否登陆
    if(sHeader==null)
    return null;
    if(!DataProvider.GetInstance.CheckLogin(sHeader.Username,sHeader.Password))
    return null;
    //取得更新的xml模板内容
    XmlDocument doc = new XmlDocument();
    doc.Load(Server.MapPath("update.xml"));
    XmlElement root = doc.DocumentElement;
    //看看有几个文件需要更新
    XmlNode updateNode = root.SelectSingleNode("filelist");
    string path = updateNode.Attributes["sourcepath"].Val;
    int count = int.Parse(updateNode.Attributes["count"].Val);
    //将xml中的val用实际内容替换
    for(int i=0;i<count;i++)
    {
    XmlNode itemNode = updateNode.ChildNodes;
    string fileName = path + itemNode.Attributes["name"].Val;
    FileStream fs = File.OpenRead(Server.MapPath(fileName));
    itemNode.Attributes["size"].Val = fs.Length.ToString();
    BinaryReader br = new BinaryReader(fs);
    //这里是文件的实际内容,使用了Base64String编码
    itemNode.SelectSingleNode("val").InnerText = Convert.ToBase64String(br.ReadBytes((int)fs.Length),0,(int)fs.Length);
    br.Close();
    fs.Close();
    }
    return doc;
    }
       

    4、在客户端进行的工作。
    首先引用此WebServices,例如命名为:WebSvs,

    string nVer = Start.GetService.GetVer(); 
    if(Application.Prod tVersion.CompareTo(nVer)<=0)
    update();

    在本代码中 Start.GetService是WebSvs的一个Static 实例。首先检查版本,将结果与当前版本进行比较,如果为新版本则执行UpDate方法。

    void update()
    {
    this.statusBarPanel1.Text = "正在下载...";
    System.Xml.XmlDocument doc = ((System.Xml.XmlDocument)Start.GetService.GetUpdateData());
    doc.Save(Application.StartupPath + @"\update.xml");
    System.Diagnostics.Process.Start(Application.StartupPath + @"\update.exe");
    Close();
    Application.Exit();
    }

    这里为了简单起见,没有使用异步方法,当然使用异步方法能更好的提高客户体验,这个需要读者们自己去添加。:) update的作用是将升级的XML文件下载下来,保存为执行文件目录下的一个Update.xml文件。任务完成,退出程序,等待Update.Exe 来进行升级。     

    5、Update.Exe 的内容。

    private void Form1_Load(object sender, System.EventArgs e)
    {
    System.Diagnostics.Process[] ps = System.Diagnostics.Process.GetProcesses();
    foreach(System.Diagnostics.Process p in ps)
    {
    //MessageBox.Show(p.ProcessName);
    if(p.ProcessName.ToLower()=="customerapplication")
    {
    p.Kill();
    break;
    }
    }
    XmlDocument doc = new XmlDocument();
    doc.Load(Application.StartupPath + @"\update.xml");
    XmlElement root = doc.DocumentElement;
    XmlNode updateNode = root.SelectSingleNode("filelist");
    string path = updateNode.Attributes["sourcepath"].Val;
    int count = int.Parse(updateNode.Attributes["count"].Val);
    for(int i=0;i<count;i++)
    {
    XmlNode itemNode = updateNode.ChildNodes;
    string fileName = itemNode.Attributes["name"].Val;
    FileInfo fi = new FileInfo(fileName);
    fi.Delete();
    //File.Delete(Application.StartupPath + @"\" + fileName);
    this.label1.Text = "正在更新: " + fileName + " (" + itemNode.Attributes["size"].Val + ") ...";
    FileStream fs = File.Open(fileName,FileMode.Create,FileAccess.Write);
    fs.Write(System.Convert.FromBase64String(itemNode.SelectSingleNode("val").InnerText),0,int.Parse(itemNode.Attributes["size"].Val));
    fs.Close();
    }
    label1.Text = "更新完成";
    File.Delete(Application.StartupPath + @"\update.xml");
    label1.Text = "正在重新启动应用程序...";
    System.Diagnostics.Process.Start("CustomerApplication.exe");
    Close();
    Application.Exit();
    }

    这个代码也很容易懂,首先就是找到主进程,如果没有关闭,则用Process.Kill()来关闭主程序。然后则用一个XmlDocument来Load程序生成的update.xml文件。用xml文件里指定的路径和文件名来生成指定的文件,在这之前先前已经存在的文件删除。更新完毕后,则重新启动主应用程序。这样更新就完成了。

    原文地址:http://blog.163.com/lemon_wangju ... 380201131295653170/
  • TA的每日心情
    开心
    2018-12-28 16:25
  • 817

    主题

    1556

    帖子

    1万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    14941
    沙发
    发表于 2016-10-28 13:10:04 | 只看该作者
    http://blog.csdn.net/zhuweisky/article/details/50439386

    C#实现自动升级(附源码)
  • TA的每日心情
    开心
    2018-12-28 16:25
  • 817

    主题

    1556

    帖子

    1万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    14941
    板凳
    发表于 2016-10-28 13:39:06 | 只看该作者
    采用C#实现软件自动更新的方法
    1.问题概述:
    长期以来,广大程序员为到底是使用Client/Server,还是使用Browser/Server结构争论不休,在这些争论当中,C/S结构的程序可 维护性差,布置困难,升级不方便,维护成本高就是一个相当重要的因素。有很多企业用户就是因为这个原因而放弃使用C/S。然而当一个应用必须要使用C/S 结构才能很好的实现其功能的时候,我们该如何解决客户端的部署与自动升级问题?部署很简单,只要点击安装程序即可,难的在于每当有新版本发布时,能够实现 自动升级。现在好了,我们的目标很简单,我们希望开发一个与具体应用无关的能够复用的自动升级系统。下面我为大家提供了一套可复用的用C#编写的自 动升级系统。
    2.实现软件的自动升级存在的困难
     第一,为了查找远程服务器上的更新,应用程序必须有查询网络的途径,这需要网络编程、简单的应用程序与服务器通讯的协议。
     第二是下载。下载看起来不需要考虑联网的问题,但要考虑下载用户请求的文件,以及在没有用户同意时下载大文件。友好的自动更新应用程序将使用剩余的带宽下载更新。这听起来简单,但却是一个技术难题,幸运的是已经有了解决方法。
     第三个考虑因素是使用新版应用程序更换原应用程序的过程。这个问题比较有趣,因为它要求代码运行时将自己从系统删除,有多种办法可以实现该功能[5],本文程序主要通过比较新旧版本的日期号来实现替换新版本应用程序的功能。
    3.实现软件自动在线升级的原理
     写两个程序,一个是主程序;一个是升级程序;所有升级任务都由升级程序完成。
     ①.启动升级程序,升级程序连接到网站,下载新的主程序(当然还包括支持的库文件、XML配置文档等)到临时文件夹;
     ②.升级程序获取服务器端XML配置文件中新版本程序的更新日期或版本号或文件大小;
     ③.升级程序获取原有客户端应用程序的最近一次更新日期或版本号或文件大小,两者进行比较;如果发现升级程序的日期大于原有程序的最新日期,则提示用户 是否升级;或者是采用将现有版本与最新版本作比较,发现最新的则提示用户是否升级;也有人用其它属性如文件大小进行比较,发现升级程序的文件大小大于旧版 本的程序的大小则提示用户升级。本文主要采用比较新旧版本更新日期号来提示用户升级。
     ④.如果用户选择升级,则获取下载文件列表,开始进行批量下载文档;
     ⑤.升级程序检测旧的主程序是否活动,若活动则关闭旧的主程序;
     ⑥.删除旧的主程序,拷贝临时文件夹中的文件到相应的位置;
     ⑦.检查主程序的状态,若状态为活动的,则启动新的主程序;
     ⑧.关闭升级程序,升级完成。
    4.用C#实现在线升级的关键步骤
    这里我主要使用日期信息来检测是否需要下载升级版本。
    ①.准备一个XML配置文件
    名称为AutoUpdater.xml,作用是作为一个升级用的模板,显示需要升级的信息。
    <?xml version="1.0"?> //xml版本号
    <AutoUpdater>
    <URLAddres URL="http://192.168.198.113/vbroker/log/"/>//升级文件所在服务器端的网址
    <UpdateInfo>
    <UpdateTime Date = "2005-02-02"/> //升级文件的更新日期
    <Version Num = "1.0.0.1"/> //升级文件的版本号
    </UpdateInfo>
    <UpdateFileList> //升级文件列表
    <UpdateFile FileName = "aa.txt"/> //共有三个文件需升级
    <UpdateFile FileName = "VB40.rar"/>
    <UpdateFile FileName = "VB4-1.CAB"/>
    </UpdateFileList>
    <RestartApp>
    <ReStart Allow = "Yes"/> //允许重新启动应用程序
    <AppName Name = "TIMS.exe"/> //启动的应用程序名
    </RestartApp>
    </AutoUpdater>

    //xml版本号
    //升级文件所在服务器端的网址
    //升级文件的更新日期
    //升级文件的版本号
    //升级文件列表
    //共有三个文件需升级
    //允许重新启动应用程序
    //启动的应用程序名
     从以上XML文档中可以得知升级文档所在服务器端的地址、升级文档的更新日期、需要升级的文件列表,其中共有三个文件需升级:aa.txt、VB40.rar、VB4-1.CAB。以及是否允许重新启动应用程序和重新启动的应用程序名。
    ②.获取客户端应用程序及服务器端升级程序的最近一次更新日期
    可通过GetTheLastUpdateTime()函数来实现。

    private string GetTheLastUpdateTime(string Dir)
    {
    string LastUpdateTime = "";
    string AutoUpdaterFileName = Dir + @"\AutoUpdater.xml";
    if(!File.Exists(AutoUpdaterFileName))
    return LastUpdateTime;
    //打开xml文件
    FileStream myFile = new FileStream(AutoUpdaterFileName,FileMode.Open);
    //xml文件阅读器
    XmlTextReader xml = new XmlTextReader(myFile);
    while(xml.Read())
    {
    if(xml.Name == "UpdateTime")
    {
    //获取升级文档的最后一次更新日期
    LastUpdateTime = xml.GetAttribute("Date");
    break;
    }
    }
    xml.Close();
    myFile.Close();
    return LastUpdateTime;
    }
    通过XmlTextReader打开XML文档,读取更新时间从而获取Date对应的值,即服务器端升级文件的最近一次更新时间。
    函数调用实现:
    //获取客户端指定路径下的应用程序最近一次更新时间
    string thePreUpdateDate = GetTheLastUpdateTime(Application.StartupPath);
    Application.StartupPath指客户端应用程序所在的路径。
    //获得从服务器端已下载文档的最近一次更新日期
    string theLastsUpdateDate = GetTheLastUpdateTime(theFolder.FullName);
    theFolder.FullName指在升级文档下载到客户机上的临时文件夹所在的路径。
    ③.比较日期
    客户端应用程序最近一次更新日期与服务器端升级程序的最近一次更新日期进行比较。
    //获得已下载文档的最近一次更新日期
    string theLastsUpdateDate = GetTheLastUpdateTime(theFolder.FullName);
    if(thePreUpdateDate != "")
    {
    //如果客户端将升级的应用程序的更新日期大于服务器端升级的应用程序的更新日期
    if(Convert.ToDateTime(thePreUpdateDate)>=Convert.ToDateTime(theLastsUpdateDate))
    {
    MessageBox.Show("当前软件已经是最新的,无需更新!","系统提示",MessageBoxButtons.OK,MessageBoxIcon.Information);
    this.Close();
    }
    }
    this.labDownFile.Text = "下载更新文件";
    this.labFileName.Refresh();
    this.btnCancel.Enabled = true;
    this.progressBar.Position = 0;
    this.progressBarTotal.Position = 0;
    this.progressBarTotal.Refresh();
    this.progressBar.Refresh();

    //通过动态数组获取下载文件的列表
    ArrayList List = GetDownFileList(GetTheUpdateURL(),theFolder.FullName);
    string[] urls = new string[List.Count];
    List.CopyTo(urls, 0);

    将客户端升级的应用程序的日期与服务器端下载的应用程序日期进行比较,如果前者大于后者,则不更新;如果前者小于后者,则通过动态数组获取下载文件的列表,开始下载文件。
    通过BatchDownload()函数来实现。升级程序检测旧的主程序是否活动,若活动则关闭旧的主程序;删除旧的主程序,拷贝临时文件夹中的文件到相应的位置;检查主程序的状态,若状态为活动的,则启动新的主程序。

    private void BatchDownload(object data)
    {
    this.Invoke(this.activeStateChanger, new object[]{true, false});
    try
    {
    DownloadInstructions instructions = (DownloadInstructions) data;
    //批量下载
    using(BatchDownloader bDL = new BatchDownloader())
    {
    bDL.CurrentProgressChanged += new DownloadProgressHandler(this.SingleProgressChanged);
    bDL.StateChanged += new DownloadProgressHandler(this.StateChanged);
    bDL.FileChanged += new DownloadProgressHandler(bDL_FileChanged);
    bDL.TotalProgressChanged += new DownloadProgressHandler(bDL_TotalProgressChanged);
    bDL.Download(instructions.URLs, instructions.Destination, (ManualResetEvent) this.cancelEvent);
    }
    }
    catch(Exception ex)
    {
    ShowErrorMessage(ex);
    }
    this.Invoke(this.activeStateChanger, new object[]{false, false});
    this.labFileName.Text = "";
    //更新程序
    if(this._Update)
    {
    //关闭原有的应用程序
    this.labDownFile.Text = "正在关闭程序....";
    System.Diagnostics.Process[]proc=System.Diagnostics.Process.GetProcessesByName("TIMS");
    //关闭原有应用程序的所有进程
    foreach(System.Diagnostics.Process pro in proc)
    {
    pro.Kill();
    }
    DirectoryInfo theFolder=new DirectoryInfo(Path.GetTempPath()+"JurassicUpdate");
    if(theFolder.Exists)
    {
    foreach(FileInfo theFile in theFolder.GetFiles())
    {
    //如果临时文件夹下存在与应用程序所在目录下的文件同名的文件,则删除应用程序目录下的文件
    if(File.Exists(Application.StartupPath + \\"+Path.GetFileName(theFile.FullName)))
    File.Delete(Application.StartupPath + "\\"+Path.GetFileName(theFile.FullName));
    //将临时文件夹的文件移到应用程序所在的目录下
    File.Move(theFile.FullName,Application.StartupPath + \\"+Path.GetFileName(theFile.FullName));
    }
    }
    //启动安装程序
    this.labDownFile.Text = "正在启动程序....";
    System.Diagnostics.Process.Start(Application.StartupPath + "\\" + "TIMS.exe");
    this.Close();
    }
    }





  • TA的每日心情
    开心
    2018-12-28 16:25
  • 817

    主题

    1556

    帖子

    1万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    14941
    地板
    发表于 2016-10-28 14:38:00 | 只看该作者
    http://www.sufeinet.com/thread-2187-1-1.html

    C#Winform程序如何发布并自动升级(图解)
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|Archiver|手机版|小黑屋|Silian Lighting+ ( 蜀ICP备14004521号-1 )

    GMT+8, 2024-5-17 10:52 , Processed in 1.062500 second(s), 23 queries .

    Powered by Discuz! X3.2

    © 2001-2013 Comsenz Inc.

    快速回复 返回顶部 返回列表