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

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

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

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

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

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:\A\A")</param>/// <param name="localSavePath">保存的目标目录(@"C:\B\B")</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 + @"Config\Custom.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 + @"Config\Custom.cfg")){File.Delete(i.FullName);      //删除指定文件
                        }}}}catch (Exception e){throw e;}}#endregion}

Fm19Update.cs

界面设计:

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

转载于:https://www.cnblogs.com/imes/p/9818232.html

C# Winform下一个热插拔的MIS/MRP/ERP框架14(自动更新)相关推荐

  1. C# Winform下一个热插拔的MIS/MRP/ERP框架(简介)

    Programmer普弱哥们都喜欢玩自己的框架,我也不例外. 理想中,这个框架要易于理解.易于扩展.易于维护:最重要的,易于CODING. 系统是1主体框架+N模组的多个EXE/DLL组成的,在主体框 ...

  2. MIS/MRP/ERP/OA/BPM/CMS等概念解析

    MIS(管理信息系统--Management Information System)系统 ,是一个由人.计算机及其他外围设备等组成的能进行信息的收集.传递.存贮.加工.维护和使用的系统.一个完整的MI ...

  3. 企业开发六大系统--MIS/MRP/ERP/OA/BPM/CMS

    MIS(管理信息系统--Management Information System)系统 , 是一个由人.计算机及其他外围设备等组成的能进行信息的收集.传递.存贮.加工.维护和使用的系统.一个完整的M ...

  4. 六大系统--MIS/MRP/ERP/OA/BPM/CMS

    MIS(管理信息系统--Management Information System)系统 ,是一个由人.计算机及其他外围设备等组成的能进行信息的收集.传递.存贮.加工.维护和使用的系统.一个完整的MI ...

  5. 最具体的历史centos下一个 postfix + extmail + dovecot + maildrop 安装注意事项2014更新...

    这篇文章原本是2008年发表的,近期几天照此笔记又安装了一遍系统.这里更新一下记录. 作者:wangdy 本文发表于  http://blog.csdn.net/aryang/article/deta ...

  6. Facebook发布Detectron2,下一个万星目标检测新框架

    作者 | CV君 来源 | 我爱计算机视觉(ID:aicvml) Detectron是Facebook于2018年发布的专注于目标检测的深度学习框架,基于Caffe2深度学习框架,实现了众多state ...

  7. Powershell 命令行泄漏下一个 Windows 10 更新内容

    Windows 10 下一个版本(称为Build 1903或19H1)更新内容,可以通过 PowerShell 的 Get-VMHostSupportedVersion 可以看到. Tero Alho ...

  8. 区块链、自动驾驶、人工智能鏖战开始 谁将成为下一个风口?

    近年来,区块链.自动驾驶以及人工智能的概念频繁爆红于科技界.有业者称,区块链的颠覆在于人们找到了一个低成本解决信任问题的方案:自动驾驶的出现方便了人们的交通出行:人工智能则为我们打开了新的世界.不论是 ...

  9. Winform窗体应用程序的自动更新功能

    本文将演示一种桌面程序自动更新方案,其步骤比较多,但原理非常简单,通用性尚可,对于小型应用来说,直接拿去就可以用了. 原理 服务器端的结构是这样的: 其工作原理如下: Update.asmx 仅提供一 ...

最新文章

  1. Openstack组件部署 — Nova overview
  2. 使用内部类隐藏实现细节
  3. EFCore+MSSS CodeFirst多对多设计初体验
  4. gradle 指定springcloud 版本_springcloud小技能:服务注册发现如何隔离
  5. 非刚性人脸跟踪 —— 人脸跟踪
  6. WebView跳转到底部
  7. hibernate课程 初探单表映射1-4 hibernate开发前准备
  8. python基础(part14)--异常处理
  9. lstm需要优化的参数_LSTM的物理结构和一些细节
  10. Error parsing HTTP request header Larger错误解决方法
  11. html 定位z_index,绝对定位、固定定位和z-index
  12. 灰度拉伸python_灰度变换之灰度线性拉伸(算法1)
  13. Java 中nextLine()方法没有执行直接跳过解决办法
  14. java连接redis集群
  15. 查看linux文件的日期格式,5个在Linux中管理文件类型和系统时间的有用命令
  16. 当前系统license已过期什么意思_Windows10为什么老是显示系统许可证已过期
  17. python这个怎么读-python怎么读(python怎么读中文)
  18. win10在电脑中添加新用户
  19. 微信公众号开发教程(四)自定义菜单
  20. 第二题:编写程序,将华氏度转换为摄氏度

热门文章

  1. python 程序流程控制结构-【笔记】《python语言程序设计》——程序的控制结构...
  2. 怎么把写好的python代码打包成exe-详解如何将python3.6软件的py文件打包成exe程序...
  3. python自动测试p-python网络爬虫之自动化测试工具selenium[二]
  4. 单独学python能干嘛-学 Python 都用来干嘛的?
  5. 我学会了python接下来学什么比较好-我,二本,学会Python后月入上万
  6. 全部python编程语言-可以用 Python 编程语言做哪些神奇好玩的事情?
  7. python绘制3d图-python3利用Axes3D库画3D模型图
  8. python学了有什么用处-Python主要用途是哪些,跟机器学习等有啥关系呢?
  9. 学python心得体会1000字-学习python cgi的一点心得体会
  10. python装饰器作用-Python装饰器用法实例总结