zoukankan      html  css  js  c++  java
  • C# Winform下一个热插拔的MIS/MRP/ERP框架14(自动更新)

    对于软件来说,启用自动更新是非常必要的。

    根据软件的应用场景,我们可以设计不同的更新模型。

    目前,IMES框架运行在.Net framework 4.0下面,使用的Win系统版本在Win7,域内管控,平时业务调整也不是很频繁。

    所以,我的更新很粗放,就是删除旧文件,拷贝新文件:

    1、更新文件放置在文件服务器一个公共目录下:\SV001PublicUpdate ;

    2、仅在用户登录时检测更新(或者在系统界面点击“更新”按钮手动更新);

    3、根据业务变更可以指定更新某一个文件、一个文件夹、或者所有文件;

    4、软件是否要更新,简单的由一个文本文件的最后修改时间来判断;

    5、可以保留某些本地生成和下载的配置/文件;

    完整代码:

        public partial class Fm19Update : Form
        {
            /// <summary>
            /// 这个程序会单独运行,因此不要引用其他DLL
            /// </summary>
            public Fm19Update()
            {
                InitializeComponent();
                FormBorderStyle = FormBorderStyle.None;
                StartPosition = FormStartPosition.CenterScreen;
            }
    
            #region 声明
            [DllImport("user32.dll")]
            public static extern bool ReleaseCapture();//拖动无窗体的控件
            [DllImport("user32.dll")]
            public static extern bool SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);
            public const int WM_SYSCOMMAND = 0x0112;
            public const int SC_MOVE = 0xF010;
            public const int HTCAPTION = 0x0002;
    
            /// <summary>
            /// 更新程序来源路径(更新文件一般放在所有客户端可访问的网络服务器上)
            /// </summary>
            private string UpdatePath = string.Empty;
    
            /// <summary>
            /// 更新内容(可使用\,*.*,0;dir1*.dll,0分割要更新的区块,所有文件全部更新使用[\,*.*,1]
            /// </summary>
            private string UpdateContent = string.Empty;
    
            /// <summary>
            /// 更新内容清单,由UpdateContent转换而来.
            /// </summary>
            private string[] UpdateList;
    
            /// <summary>
            /// 要更新的文件个数,由各更新区域加总
            /// </summary>
            private static int UpdateFilesCount = 0;
            #endregion
    
            /// <summary>
            /// 延时函数, 如使用Thread.Sleep()会停止响应
            /// </summary>
            /// <param name="delayTime"></param>
            /// <returns></returns>
            private static bool Delay(int delayTime)
            {
                DateTime now = DateTime.Now;
                int s;
                do
                {
                    TimeSpan spand = DateTime.Now - now;
                    s = spand.Seconds;
                    Application.DoEvents();
                }
                while (s < delayTime);
                return true;
            }
    
            /// <summary>
            /// 显示当前作业状态
            /// </summary>
            /// <param name="tStatus"></param>
            private void SetUpdateStatus(string tStatus)
            {
                LabCurStatus.Text = tStatus;
                Refresh();
            }
    
    
            private void CmdQuit_Click(object sender, EventArgs e)
            {
                Application.Exit();
    
            }
    
            private void Fm19Update_MouseDown(object sender, MouseEventArgs e)
            {
                ReleaseCapture();   //调用移动无窗体控件函数
                SendMessage(Handle, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);
            }
    
            private void Fm19Update_Shown(object sender, EventArgs e)
            {
                SetUpdateStatus("Checking progress status...");
                Refresh();
                Delay(2);   //这里的检测其实是一个假象,仅仅延时了2秒,以等待主程序结束运行。
                SetUpdateStatus("Checking progress status...Finished");
                Refresh();
                DoUpdate(); //开始进行更新
            }
            #region 更新作业区域
            /// <summary>
            /// 当本地更新文件的最后修改时间与更新路径下的更新文件不同,则认为需要更新。
            /// </summary>
            private void DoUpdate()
            {
                #region 判断来源与本地文件夹状态
                string localPath = AppDomain.CurrentDomain.BaseDirectory;
                localPath = localPath.Substring(0, localPath.Length - 1);
                //从本地更新历史文件读取远程更新路径
                string[] allLines = File.ReadAllLines(localPath + @"UpdateLog.txt");
                string remotePath = string.Empty;
                foreach (string line in allLines)
                {
                    if (line.IndexOf("UpdatePath=") >= 0)
                    {
                        remotePath = line.Substring(line.IndexOf("UpdatePath=") + 11).Trim();
                        break;
                    }
                }
                if (localPath.ToUpper() == remotePath.ToUpper())
                {
                    MessageBox.Show("更新路径不能与来源路径相同!", "警告...", MessageBoxButtons.OK, MessageBoxIcon.Stop);
                    return;
                }
                FileInfo fiUL = new FileInfo(localPath + @"UpdateLog.txt");
                FileInfo fiUR = new FileInfo(remotePath + @"UpdateLog.txt");
                if (fiUL.LastWriteTime == fiUR.LastWriteTime)
                {
                    SetUpdateStatus("系统没有更新,操作终止!");
                    return;
                }
                SetUpdateStatus("正在连接到目标文件夹......");
                if (!Directory.Exists(remotePath))
                {
                    SetUpdateStatus("目标文件夹:" + remotePath + " 不存在,请联络系统管理员!");
                    return;
                }
                SetUpdateStatus("正在连接到目标文件夹......成功!");
    
                //从远程读取本次更新内容
                string[] allLinesRmt = File.ReadAllLines(remotePath + @"UpdateLog.txt");
                foreach (string line in allLinesRmt)
                {
                    if (line.IndexOf("UpdateContent=") >= 0)
                    {
                        UpdateContent = line.Substring(line.IndexOf("UpdateContent=") + 14);
                        break;
                    }
                }
                #endregion
    
                #region 计算文件数量并设置百分比
                if (!string.IsNullOrEmpty(UpdateContent))
                {
                    UpdateList = UpdateContent.Split(';');
                }
                else
                {
                    UpdateList = (@"\,*.*,1").Split(';'); //更新内容设置不正确,则设置为更新所有文件.
                }
    
                UpdateFilesCount = 0;
                foreach (string ul in UpdateList)
                {
                    string[] updContent = ul.Split(',');
                    string updDirPath = string.Empty;
                    string updFilesPattern = "*.*";
                    int updWithSubDir = 0;
                    if (updContent.Length > 0)
                    {
                        updDirPath = updContent[0];
                        updDirPath = remotePath + @"" + updDirPath.Replace("\", "");
                    }
                    if (updContent.Length > 1)
                    {
                        updFilesPattern = updContent[1];
                    }
                    if (updContent.Length > 2)
                    {
                        updWithSubDir = Convert.ToInt16(updContent[2]);
                    }
                    bool withSubDir = updWithSubDir > 0;
    
                    if (!string.IsNullOrEmpty(updContent[0].Trim()))
                    {
                        UpdateFilesCount += CountAllFiles(updDirPath, updFilesPattern, withSubDir);
                    }
                }
    
                //所有更新进度根据更新区域切割百分比
                ProgMain.Value = 0;
                ProgMain.Step = 1;
                ProgMain.Maximum = UpdateFilesCount + 5;
                for (int i = 0; i < 6; i++)
                {
                    ProgMain.PerformStep();
                    LabProgStep.Text = (ProgMain.Value * 100 / ProgMain.Maximum).ToString() + "%";
                }
                #endregion
    
                #region 开始删除和复制文件(会删除目录下的所有文件,再重新复制,这样可以清除掉某些过期的文件)
    
                foreach (string ul in UpdateList)
                {
                    string[] updContent = ul.Split(',');
                    string localUpdDirPath = string.Empty;
                    string remoteUpdDirPath = string.Empty;
    
                    string updFilesPattern = "*.*";
                    int updWithSubDir = 0;
                    if (updContent.Length > 0)
                    {
                        localUpdDirPath = localPath + @"" + updContent[0].Replace("\", "");
                        remoteUpdDirPath = remotePath + @"" + updContent[0].Replace("\", "");
                    }
                    if (updContent.Length > 1)
                    {
                        updFilesPattern = updContent[1];
                    }
                    if (updContent.Length > 2)
                    {
                        updWithSubDir = Convert.ToInt16(updContent[2]);
                    }
                    bool withSubDir = updWithSubDir > 0;
    
                    SetUpdateStatus("正在更新" + (updContent[0] == @"\" ? "根目录" : updContent[0]) + "下的文件......");
                    if (!string.IsNullOrEmpty(updContent[0].Trim()))
                    {
                        CopyFilesTo(remoteUpdDirPath, updFilesPattern, localUpdDirPath, withSubDir);
                    }
                }
                #endregion
    
                //更新完成后重新启动主程序
                string mainEXE = AppDomain.CurrentDomain.BaseDirectory + @"B20.exe";
                Process.Start(mainEXE);
                Application.Exit();
            }
    
            /// <summary>
            /// 统计符合筛选条件的所有文件数量。(已排除A19.exe和LocalFile目录)
            /// </summary>
            /// <param name="fullPath">完整目录名称</param>
            /// <param name="sPattern">筛选条件(如*.xls)</param>
            /// <param name="withSubDir">是否包含子目录</param>
            /// <returns></returns>
            private int CountAllFiles(string fullPath, string sPattern, bool withSubDir = false)
            {
                SearchOption searchOption = withSubDir ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
    
                var files = Directory.EnumerateFiles(fullPath, sPattern, searchOption)
                .Where(s => !s.Contains("A19.exe") && !s.Contains("Custom.cfg"));
                return files.Count();
            }
    
            /// <summary>
            /// 从A文件夹拷贝文件到B文件夹下面
            /// </summary>
            /// <param name="remoteSourcePath">文件所在目录(@"C:AA")</param>
            /// <param name="localSavePath">保存的目标目录(@"C:BB")</param>
            /// <returns>返回:true-拷贝成功;false:拷贝失败</returns>
            public bool CopyFilesTo(string remoteSourcePath, string sPattern, string localSavePath, bool withSubDir = false)
            {
                try
                {
                    SearchOption searchOption = withSubDir ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
    
                    var files = Directory.EnumerateFiles(remoteSourcePath, sPattern, searchOption)
                    .Where(s => !s.Contains("A19.exe"));
    
                    if (withSubDir)
                    {
                        //包含子目录更新,先删除当前目录下的所有文件,再重新复制本目录,这样可以清除某些过期文件
                        SetUpdateStatus("正在清除旧文件......");
                        DelectDir(localSavePath, withSubDir);
    
                        //如果包含子目录 ,则先根据远端的目录结构全部检查/创建好.
                        var dirs = Directory.EnumerateDirectories(remoteSourcePath, "*.*", searchOption);
                        foreach (string dir in dirs)
                        {
                            string locTagDir = dir.Replace(remoteSourcePath, localSavePath);
                            if (!Directory.Exists(locTagDir))
                            {
                                Directory.CreateDirectory(locTagDir);
                            }
                        }
                    }
                    if (files.Count() > 0)
                    {
                        foreach (string fileName in files)
                        {
                            //采用覆盖模式,但要保留一些本地自定义文件
                            if (fileName == (remoteSourcePath + @"ConfigCustom.cfg"))
                            {
                                if (!File.Exists(fileName.Replace(remoteSourcePath, localSavePath)))
                                {
                                    File.Copy(fileName, fileName.Replace(remoteSourcePath, localSavePath), true);
                                }
                            }
                            else
                            {
                                File.Copy(fileName, fileName.Replace(remoteSourcePath, localSavePath), true);
                            }
                            ProgMain.PerformStep();
                            LabProgStep.Text = (ProgMain.Value * 100 / ProgMain.Maximum).ToString() + "%";
                        }
                    }
                    LabCurStatus.Text = "正在复制文件......完成!";
                    Refresh();
    
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                    return false;
                }
                return true;
            }
    
            /// <summary>
            /// 删除本目录下除更新程序及LocalFile目录(存储本地生成的文件)以外的所有文件
            /// </summary>
            /// <param name="tagPath"></param>
            public static void DelectDir(string tagPath, bool delSub = false)
            {
                try
                {
                    DirectoryInfo dir = new DirectoryInfo(tagPath);
                    FileSystemInfo[] fileinfo = dir.GetFileSystemInfos();  //返回目录中所有文件和子目录
                    foreach (FileSystemInfo i in fileinfo)
                    {
                        if (i is DirectoryInfo)            //判断是否文件夹
                        {
                            if (delSub)
                            {
                                if ((i.FullName != (tagPath + "LocalFiles")) && (i.FullName != (tagPath + "Config")))
                                {
                                    DirectoryInfo subdir = new DirectoryInfo(i.FullName);
                                    subdir.Delete(true);          //删除子目录和文件
                                }
                            }
                        }
                        else
                        {
                            if ((i.Name != "A19.exe") && (i.FullName != tagPath + @"ConfigCustom.cfg"))
                            {
                                File.Delete(i.FullName);      //删除指定文件
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    throw e;
                }
            }
    
            #endregion
        }
    Fm19Update.cs

     界面设计:

    当然,也可以扩展为从网站下载或者轮循新版本。

  • 相关阅读:
    C#接口入门学习
    消息队列接收时报错:对消息队列系统的访问被拒绝
    给某做测试的好友的建议
    在不同的Sql Server 数据库服务器(不同机器)导数据。
    如何让开发人员更好测试?
    存储过程初探
    语音报警.NET开发初探
    vs2010下Siverlight开发环境安装
    C# HttpWebRequest 从google服务器获取google的PageRank PR值
    创建进程API CreateProcess Demo
  • 原文地址:https://www.cnblogs.com/imes/p/9818232.html
Copyright © 2011-2022 走看看