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

     界面设计:

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

  • 相关阅读:
    最大子数组问题(分治策略实现)
    Solving the Detached Many-to-Many Problem with the Entity Framework
    Working With Entity Framework Detached Objects
    Attaching detached POCO to EF DbContext
    如何获取qq空间最近访问人列表
    Health Monitoring in ASP.NET 2.0
    problem with displaying the markers on Google maps
    WebMatrix Database.Open… Close() and Dispose()
    Accessing and Updating Data in ASP.NET: Retrieving XML Data with XmlDataSource Control
    Create web setup project that has crystal reports and sql script run manually on client system
  • 原文地址:https://www.cnblogs.com/imes/p/9818232.html
Copyright © 2011-2022 走看看