zoukankan      html  css  js  c++  java
  • C#做的在线升级小程序

    转自原文C#做的在线升级小程序

     

      日前收到一个小任务,要做一个通用的在线升级程序。更新的内容包括一些dll或exe或、配置文件。升级的大致流程是这样的,从服务器获取一个更新的配置文件,经过核对后如有新的更新,则会从服务器下载相应的文件更新到被升级的程序目录下。如果被升级的程序在升级之前已经启动,程序则会强制关闭它,待到升级完成之后重新启动相应的程序。在升级之前程序会自动备份一次,以防升级失败造成程序不能运行。

    定义数据实体

        public class FileENT
        {
            public string FileFullName { get; set; }
    
            public string Src { get; set; }
    
            public string Version { get; set; }
    
            public int Size { get; set; }
    
            public UpdateOption Option { get; set; }
        }

    下面这个类时程序的一些参数,包括了系统的配置参数,为了程序能通用一点,就加了配置上去。

        public class AppParameter
        {
            /// <summary>
            /// 备份路径
            /// </summary>
            public static string BackupPath = ConfigurationManager.AppSettings["backupPath"];
    
            /// <summary>
            /// 更新的URL
            /// </summary>
            public static string ServerURL = ConfigurationManager.AppSettings["serverURL"];
    
            /// <summary>
            /// 本地更新文件全名
            /// </summary>
            public static string LocalUPdateConfig = ConfigurationManager.AppSettings["localUPdateConfig"];
    
            /// <summary>
            /// 版本号
            /// </summary>
            public static string Version = ConfigurationManager.AppSettings["version"];
    
            /// <summary>
            /// 更新程序路径
            /// </summary>
            public static string LocalPath = AppDomain.CurrentDomain.BaseDirectory;
    
            /// <summary>
            /// 主程序路径
            /// </summary>
            public static string MainPath = ConfigurationManager.AppSettings["mainPath"];
    
            /// <summary>
            /// 有否启动主程序
            /// </summary>
            public static bool IsRunning = false;
    
            /// <summary>
            /// 主程序名
            /// </summary>
            public static List<string> AppNames = ConfigurationManager.AppSettings["appName"].Split(';').ToList();
        }
    AppParameter

    接着就介绍程序的代码

    程序是用窗体来实现的,下面三个是窗体新添加的三个字段

    private bool isDelete = true;    //是否要删除升级配置
    private bool runningLock = false;//是否正在升级
    private Thread thread;           //升级的线程

    载入窗体时需要检查更新,如果没有更新就提示”暂时无更新”;如果有更新的则先进行备份,备份失败的话提示错误退出更新。

    if (CheckUpdate())
    {
        if (!Backup())
        {
            MessageBox.Show("备份失败!");
            btnStart.Enabled = false;
            isDelete = true;
            return;
        }
    
    }
    else
    {
        MessageBox.Show("暂时无更新");
        this.btnFinish.Enabled = true;
        this.btnStart.Enabled = false;
        isDelete = false;
        this.Close();
    }

    在这些操作之前还要检测被更新程序有否启动,有则将其关闭。

                List<string> processNames = new List<string>();
                string mainPro = string.Empty;
                processNames.AddRange(AppParameter.AppNames);
                for (int i = 0; i < processNames.Count; i++)
                {
                    processNames[i] = processNames[i].Substring(processNames[i].LastIndexOf('\')).Trim('\').Replace(".exe", "");
                }
                mainPro = processNames.FirstOrDefault();
                AppParameter.IsRunning = ProcessHelper.IsRunningProcess(mainPro);
                if (AppParameter.IsRunning)
                {
                    MessageBox.Show("此操作需要关闭要更新的程序,请保存相关数据按确定继续", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    foreach (string item in processNames)
                        ProcessHelper.CloseProcess(item);
                }

    另外上面用到的CheckUpdate( )和Backup( )方法如下

            /// <summary>
            /// 检查更新 有则提示用户 确认后下载新的更新配置
            /// </summary>
            /// <returns>用户确认信息</returns>
            public static bool CheckUpdate()
            {
                bool result = false;
    
                HttpHelper.DownLoadFile(AppParameter.ServerURL, AppParameter.LocalPath + "temp_config.xml");
                if (!File.Exists(AppParameter.LocalUPdateConfig))
                    result = true;
                else
                {
                    long localSize = new FileInfo(AppParameter.LocalUPdateConfig).Length;
                    long tempSize = new FileInfo(AppParameter.LocalPath + "temp_config.xml").Length;
    
                    if (localSize >= tempSize) result = false;
    
                    else result = true;
                }
    
                if (result)
                {
                    if (File.Exists(AppParameter.LocalUPdateConfig)) File.Delete(AppParameter.LocalUPdateConfig);
                    File.Copy(AppParameter.LocalPath + "temp_config.xml", AppParameter.LocalUPdateConfig);
                }
                else
                    result = false;
    
                File.Delete(AppParameter.LocalPath + "temp_config.xml");
                return result;
            }
    
            /// <summary>
            /// 备份
            /// </summary>
            public static bool Backup()
            {
                string sourcePath = Path.Combine(AppParameter.BackupPath, DateTime.Now.ToString("yyyy-MM-dd HH_mm_ss")+"_v_"+AppParameter.Version + ".rar");
                return ZipHelper.Zip(AppParameter.MainPath.Trim() , sourcePath);
            }
    View Code

    下面则是更新部分的代码,使用了多线程。出于两方面的考虑,一是进度条需要;二是如果用单线程,万一更新文件下载时间过长或者更新内容过多,界面会卡死。

    /// <summary>
    /// 更新
    /// </summary>
    public void UpdateApp()
    {
        int successCount = 0;
        int failCount = 0;
        int itemIndex = 0;
        List<FileENT> list = ConfigHelper.GetUpdateList();
        if (list.Count == 0)
        {
            MessageBox.Show("版本已是最新", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
            this.btnFinish.Enabled = true;
            this.btnStart.Enabled = false;
            isDelete = false;
            this.Close();
            return;
        }
        thread = new Thread(new ThreadStart(delegate
        {
            #region thread method
    
            FileENT ent = null;
    
            while (true)
            {
                lock (this)
                {
                    if (itemIndex >= list.Count)
                        break;
                    ent = list[itemIndex];
    
    
                    string msg = string.Empty;
                    if (ExecUpdateItem(ent))
                    {
                        msg = ent.FileFullName + "更新成功";
                        successCount++;
                    }
                    else
                    {
                        msg = ent.FileFullName + "更新失败";
                        failCount++;
                    }
    
                    if (this.InvokeRequired)
                    {
                        this.Invoke((Action)delegate()
                        {
                            listBox1.Items.Add(msg);
                            int val = (int)Math.Ceiling(1f / list.Count * 100);
                            progressBar1.Value = progressBar1.Value + val > 100 ? 100 : progressBar1.Value + val;
                        });
                    }
    
    
                    itemIndex++;
                    if (successCount + failCount == list.Count && this.InvokeRequired)
                    {
                        string finishMessage = string.Empty;
                        if (this.InvokeRequired)
                        {
                            this.Invoke((Action)delegate()
                            {
                                btnFinish.Enabled = true;
                            });
                        }
                        isDelete = failCount != 0;
                        if (!isDelete)
                        {
                            AppParameter.Version = list.Last().Version;
                            ConfigHelper.UpdateAppConfig("version", AppParameter.Version);
                            finishMessage = "升级完成,程序已成功升级到" + AppParameter.Version;
                        }
                        else
                            finishMessage = "升级完成,但不成功";
                        MessageBox.Show(finishMessage, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        runningLock = false;
                    }
                }
            }
            #endregion
        }));
        runningLock = true;
        thread.Start();
    }
    
    /// <summary>
    /// 执行单个更新
    /// </summary>
    /// <param name="ent"></param>
    /// <returns></returns>
    public bool ExecUpdateItem(FileENT ent)
    {
        bool result = true;
    
        try
        {
    
            if (ent.Option == UpdateOption.del)
                File.Delete(ent.FileFullName);
            else
                HttpHelper.DownLoadFile(ent.Src, Path.Combine(AppParameter.MainPath, ent.FileFullName));
        }
        catch { result = false; }
        return result;
    }

    只开了一个子线程,原本是开了5个子线程的,但是考虑到多线程会导致下载文件的顺序不确定,还是用回单线程会比较安全。线程是用了窗体实例里的thread字段,在开启线程时还用到runningLock标识字段,表示当前正在更新。当正在更新程序时关闭窗口,则要提问用户是否结束更新,若用户选择了是则要结束那个更新进程thread了,下面则是窗口关闭的时间FormClosing事件的方法。

    if (runningLock )
    {
    if (MessageBox.Show("升级还在进行中,中断升级会导致程序不可用,是否中断",
    "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk) == DialogResult.Yes)
    {
    if (thread != null) thread.Abort();
    isDelete = true;
    AppParameter.IsRunning = false;
    }
        else 
        {
            e.Cancel = true;
            return;
        }
    }
    if (isDelete) File.Delete(AppParameter.LocalUPdateConfig);

    在这里还要做另一件事,就是把之前关了的程序重新启动

    try
    {
        if (AppParameter.IsRunning) ProcessHelper.StartProcess(AppParameter.AppNames.First());
    }
    catch (Exception ex)
    { 
        MessageBox.Show("程序无法启动!" + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }

    在这里展示一下更新的界面。挺丑的,别笑哈。

    更新程序的配置信息如下

    1   <appSettings>
    2     <add key="backupPath" value="C:UsersAdministratorDesktop	empackup"/>
    3     <add key="serverURL" value="http://localhost:8015/updateconfig.xml"/>
    4     <add key="localUPdateConfig" value="E:HopeGiCodeMyUpdateMyUpdateinDebugupdateconfig.xml"/>
    5     <add key="version" value="2"/>
    6     <add key="mainPath" value="C:UsersAdministratorDesktop	empmain"/>
    7     <add key="appName" value="D:	est.exe"/>
    8   </appSettings>

    完整文档下载:
    http://pan.baidu.com/share/link?shareid=443378&uk=85241834



    或者通过本博客百度网盘资源公开目录下载
    博客内的百度网盘资源公开目录下载




  • 相关阅读:
    ef mysql
    mvc RedirectToAction、mobile 重定向地址栏未改变
    避免复制引用程序集的XML文件
    端口扫描工具
    Python简单全双工聊天器
    Python半双工聊天程序
    Python简单服务器程序
    python+scrapy爬取亚马逊手机商品
    python+scrapy爬取知乎日报全站文章
    简单直接排序
  • 原文地址:https://www.cnblogs.com/arxive/p/6372710.html
Copyright © 2011-2022 走看看