zoukankan      html  css  js  c++  java
  • Winform在线更新

    引言

           2015年第一篇,Winform在线更新,算是重操旧业吧,09年刚到北京时一直做硬件联动编程,所以大多数时间都在搞Winform, 但是从来没做过在线更新这个功能,前几天参与部门另一个项目,上来就需要加一个在线更新。 该自动更新组件核心是圣殿骑士开发的,另外参考逆水寒龙使用情况,当我拿到这个组件源代码时并不知道如何去用,花了大半天时间也没调试通过,所以把我遇到的问题和解决方法记录下来,方便后续其他Coder使用时查看使用方法。

    在线更新思路

    1、请求远程站点Version.xml 或者请求Web服务器都可以,最主要是对比服务器端配置文件版本号和本地配置文件版本号。

    2、从远程站点下载文件。

    3、覆盖本地可执行文件及用到的Dll,当然覆盖之前需要关掉本地exe进程或者windows服务进程。

    4、文件覆盖后修改本地配置文件AutoUpdater.config.

    5、覆盖后重新启动可执行程序或者windows服务。

    该AutoUpdater缺点(使用过程中已完善)

    1、没看到圣殿骑士如何使用该组件,参考逆水寒龙Demo时,找到了主程序关闭的地方。

    2、在下载文件时没有考虑到远程服务器新增文件时处理本地AutoUpdater.config,也就是说更新程序处理时是基于本地配置文件config.UpdateFileList。

    3、没有针对windows服务处理进程(已完善windows服务处理类)。

    使用时遇到的问题

    1、不知道如何使用该组件?

         使用该组件时项目应该具备4部分:Web站点用于接受请求及下载需更新文件、AutoUpdater更新组件、MainApplication(也就是你的主程序)、UpdateApplication(更新程序入口,通过主程序启动,在这个程序内部调用AutoUpdater组件)。

    2、 不知道合适去关闭主程序和windows服务

          后在看逆水寒龙的Demo中看到他是在文件下载前,当你点击确认下载时关闭进程。

       

    if (bDownload)
                {
                    //关闭windows service
                    ServiceProcess serviceProcess = new ServiceProcess();
                    serviceProcess.StopService();
    
                    //关掉主程序
                    OperProcess oper=new OperProcess();
                    oper.InitUpdateEnvironment();
    
    
                    DownloadConfirm dc = new DownloadConfirm(downloadList);
                    if (this.OnShow != null)
                        this.OnShow();
                      
                    if (DialogResult.OK == dc.ShowDialog())
                    {
                        StartDownload(downloadList);
                    }
    }
    

    3、文件下载后临时目录和源程序主目录口径不一致

         这个根据自己需要调整文件Copy、Move代码。我们的程序可执行文件和主要Dll都是放在一个单独的文件里而不是默认的BinDebug下。所以我的做法就是把下载文件从TempFolder移动到可执行源文件根目录下。具体代码在DownloadProgress窗体的ProcDownload方法中处理。

    if (!string.IsNullOrEmpty(tempFolderPath))
                        {
                            oldPath = Path.Combine(CommonUnitity.SystemBinUrl, file.FileName);
                            newPath = Path.Combine(CommonUnitity.SystemBinUrl + ConstFile.TEMPFOLDERNAME + tempUrlPath, file.FileName);
                        }
    

    4、 文件下载移动复制后合适启动应用程序

          在更新程序里添加finally代码,启动windows服务、启动主程序、关闭更新程序(UpdateApplication)。

    void InitAndCheck()
            {
                bool bHasError = false;
                IAutoUpdater autoUpdater = new AutoUpdater();
    
                try
                {
                    autoUpdater.Update();
                }
                catch (WebException exp)
                {
                    MessageBox.Show("Can not find the specified resource");
                    bHasError = true;
                }
                catch (XmlException exp)
                {
                    bHasError = true;
                    MessageBox.Show("Download the upgrade file error");
                }
                catch (NotSupportedException exp)
                {
                    bHasError = true;
                    MessageBox.Show("Upgrade address configuration error");
                }
                catch (ArgumentException exp)
                {
                    bHasError = true;
                    MessageBox.Show("Download the upgrade file error");
                }
                catch (Exception exp)
                {
                    bHasError = true;
                    MessageBox.Show("An error occurred during the upgrade process");
                }
                finally
                {
                    if (bHasError == true)
                    {
                        try
                        {
                            autoUpdater.RollBack();
                        }
                        catch (Exception)
                        {
                            
                        }
                    }
                    ServiceProcess serviceProcess = new ServiceProcess();
                    serviceProcess.StartService();
    
                    OperProcess oper = new OperProcess();
                    oper.StartProcess();
                }
            }
    

    5、 当Web站点出现新增文件时没有同步到本地配置文件。

          看源代码是发现修改本地AutoUpdater.config是基于本地UpdateFileList,只需要把Web端新增文件信息添加到该List中,序列化本地config时就会同步。

    LocalFile tempFile = null;
                foreach (RemoteFile file in listRemotFile.Values)
                {
                    downloadList.Add(new DownloadFileInfo(file.Url, file.Path, file.LastVer, file.Size));
    
                    //把远程服务器新增文件加入config.UpdateFileList, 修改本地AutoUpdater.config时使用。
                    tempFile = new LocalFile(file.Path, file.LastVer, file.Size);
                    config.UpdateFileList.Add(tempFile);
    
                    if (file.NeedRestart)
                        bNeedRestart = true;
                }
    

    6、添加windows服务处理类

    public class ServiceProcess
        {
            #region 判断window服务是否启动
            /// <summary>  
            /// 判断某个Windows服务是否启动  
            /// </summary>  
            /// <returns></returns>  
            private bool IsServiceStart(string serviceName)
            {
                ServiceController psc = new ServiceController(serviceName);
                bool bStartStatus = false;
                try
                {
                    if (!psc.Status.Equals(ServiceControllerStatus.Stopped))
                    {
                        bStartStatus = true;
                    }
    
                    return bStartStatus;
                }
                catch (Exception ex)
                {
                    throw new Exception(ex.Message);
                }
            }
            #endregion
    
            #region 启动服务
            private bool StartService(string serviceName)
            {
                bool flag = true;
                if (ServiceIsExisted(serviceName))
                {
                    System.ServiceProcess.ServiceController service = new System.ServiceProcess.ServiceController(serviceName);
                    if (service.Status != System.ServiceProcess.ServiceControllerStatus.Running && service.Status != System.ServiceProcess.ServiceControllerStatus.StartPending)
                    {
                        service.Start();
                        for (int i = 0; i < 60; i++)
                        {
                            service.Refresh();
                            System.Threading.Thread.Sleep(1000);
                            if (service.Status == System.ServiceProcess.ServiceControllerStatus.Running)
                            {
                                break;
                            }
                            if (i == 59)
                            {
                                flag = false;
                            }
                        }
                    }
                }
                return flag;
            }
            #endregion
    
            #region 停止服务
            private bool StopService(string serviceName)
            {
                bool flag = true;
                if (ServiceIsExisted(serviceName))
                {
                    System.ServiceProcess.ServiceController service = new System.ServiceProcess.ServiceController(serviceName);
                    if (service.Status == System.ServiceProcess.ServiceControllerStatus.Running)
                    {
                        service.Stop();
                        for (int i = 0; i < 60; i++)
                        {
                            service.Refresh();
                            System.Threading.Thread.Sleep(1000);
                            if (service.Status == System.ServiceProcess.ServiceControllerStatus.Stopped)
                            {
                                break;
                            }
                            if (i == 59)
                            {
                                flag = false;
                            }
                        }
                    }
                }
                return flag;
            }
            #endregion
    
            #region 判断window服务是否存在
            private bool ServiceIsExisted(string serviceName)
            {
                ServiceController[] services = ServiceController.GetServices();
                foreach (ServiceController s in services)
                {
                    if (s.ServiceName == serviceName)
                    {
                        return true;
                    }
                }
                return false;
            }
            #endregion
    
            #region 安装服务
            private void InstallService(IDictionary stateSaver, string filepath)
            {
                try
                {
                    ServiceController service = new ServiceController("ServiceName");
                    if (!ServiceIsExisted("ServiceName"))
                    {
                        //Install Service  
                        AssemblyInstaller myAssemblyInstaller = new AssemblyInstaller();
                        myAssemblyInstaller.UseNewContext = true;
                        myAssemblyInstaller.Path = filepath;
                        myAssemblyInstaller.Install(stateSaver);
                        myAssemblyInstaller.Commit(stateSaver);
                        myAssemblyInstaller.Dispose();
                        //--Start Service  
                        service.Start();
                    }
                    else
                    {
                        if (service.Status != System.ServiceProcess.ServiceControllerStatus.Running && service.Status != System.ServiceProcess.ServiceControllerStatus.StartPending)
                        {
                            service.Start();
                        }
                    }
                }
                catch (Exception ex)
                {
                    
                }
            }
            #endregion
    
            #region 卸载windows服务
            private void UnInstallService(string filepath)
            {
                try
                {
                    if (ServiceIsExisted("ServiceName"))
                    {
                        //UnInstall Service  
                        AssemblyInstaller myAssemblyInstaller = new AssemblyInstaller();
                        myAssemblyInstaller.UseNewContext = true;
                        myAssemblyInstaller.Path = filepath;
                        myAssemblyInstaller.Uninstall(null);
                        myAssemblyInstaller.Dispose();
                    }
                }
                catch (Exception ex)
                {
                    
                }
            }
            #endregion
    
            public void StopService()
            {
                if (ServiceIsExisted("MyService"))
                {
                    if (IsServiceStart("MyService"))
                    {
                        this.StopService("MyService");
                    }
                }
                
            }
    
            public void StartService()
            {
    
                if (ServiceIsExisted("MyService"))
                {
                    if (!IsServiceStart("MyService"))
                    {
                        this.StartService("MyService");   
                    }
                }
              
            }
        }
    

     总结

          当有任何一个功能需要开发时先要弄懂其原理,并且能反复调试网上找来的源码,反复调试后能明白其中的原理才能更好的应用。初拿到这个功能时并不明白就想去集成,结果花了时间还没弄明白怎么使用。 再次感谢圣殿骑士和逆水寒龙的文章给我的启示。

          Demo下载 提取码99a9

  • 相关阅读:
    Codeforces Round #563 (Div. 2)B;Ehab Is an Odd Person
    Codeforces Round #563 (Div. 2)C. Ehab and a Special Coloring Problem
    Codeforces Round #567 (Div. 2) A.Chunga-Changa
    Codeforces Round #569 (Div. 2) B. Nick and Array
    Codeforces Round #570 (Div. 3) B. Equalize Prices
    2019年银联极客挑战赛第一题
    js点击保存图片
    vant地区三级联动
    input 输入金额正则判断
    git 实用命令
  • 原文地址:https://www.cnblogs.com/sword-successful/p/4213504.html
Copyright © 2011-2022 走看看