自动更新程序

这里总结一下制作自动更新程序的一些思路。

首先制作一个自动更新程序,autoupdate.exe。其中包含的功能有2大部分,一个是制作自动更新部署包,一个是自动更新,通过读取远程配置文件,比对本地文件,完成本地文件的更新。

此程序可以通过启动参数,来实现程序更新检查、程序更新。来实现外部程序对它的调用。

一、配置文件格式


 
   
     
        nipay-t
        2023-03-16 13:52:52
        D:\nipay-t
        0
     

     
       
       
       
       
             
     

   

 


二、本地文件比对

使用certutil来查看本地文件与服务器文件差异,此方法的好处是没有程序被占用时无法获取md5的问题。

 public static string GetMD5HashFromFile(string fileName)
 {
     string md5Result = string.Empty;

     List certUtilResult = new List();

     try
     {
        
         Process startProcess = new Process();
         startProcess.StartInfo.FileName = "certutil";
         startProcess.StartInfo.Arguments = string.Format(" -hashfile {0} MD5", fileName);
         startProcess.StartInfo.UseShellExecute = false;
         startProcess.StartInfo.RedirectStandardInput = false;
         startProcess.StartInfo.RedirectStandardOutput = true;
         startProcess.StartInfo.CreateNoWindow = true;
         startProcess.OutputDataReceived += (sender, e) =>
         {
             if (!string.IsNullOrEmpty(e.Data))
             {
                 certUtilResult.Add(e.Data); 
             }
         };

         startProcess.Start();
         startProcess.BeginOutputReadLine();
         startProcess.WaitForExit();
     }
     catch (Exception ex)
     {
         throw new Exception("GetMD5HashFromFile() fail,error:" + ex.Message);
     }
     finally{

         if (certUtilResult != null && certUtilResult.Count > 0)
         {
             var regexMD5 = new System.Text.RegularExpressions.Regex(@"^(?:[a-f\d]{32}|[A-F\d]{32})", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
             var temp = certUtilResult.Where(t => regexMD5.IsMatch(t));
             if (temp != null && temp.Count() > 0)
             {
                 md5Result = temp.First().ToString() ;
             }                     
         }
     }

     return md5Result;
 }

三、文件占用的清理

文件需要更新前,关闭相应的文件夹中正在执行的应用程序。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
using System.Diagnostics; 

namespace Common.Utility
{
    public class HandleHelper
    {

        [DllImport("kernel32.dll")]
        public static extern IntPtr _lopen(string lpPathName, int iReadWrite);

        [DllImport("kernel32.dll")]
        public static extern bool CloseHandle(IntPtr hObject);

        public const int OF_READWRITE = 2;
        public const int OF_SHARE_DENY_NONE = 0x40;
        public readonly IntPtr HFILE_ERROR = new IntPtr(-1);


        private bool IsFileUsing(string filePath)
        {
            if (!File.Exists(filePath))
            {
                return false;
            }
            IntPtr vHandle = _lopen(filePath, OF_READWRITE | OF_SHARE_DENY_NONE);
            if (vHandle == HFILE_ERROR)
            {
                return true;
            }
            CloseHandle(vHandle);
            return false;
        }

        ///


        /// 获取指定文件或目录中存在的(关联的)运行进程信息,以便后面可以解除占用
        ///

        ///
        ///
        private Dictionary GetRunProcessInfos(string filePath)
        {

            Dictionary runProcInfos = new Dictionary();
            string fileName = Path.GetFileName(filePath);
            var fileRunProcs = Process.GetProcessesByName(fileName);
            if (fileRunProcs != null && fileRunProcs.Count() > 0)
            {
                runProcInfos = fileRunProcs.ToDictionary(p => p.Id, p => p.ProcessName);
                return runProcInfos;
            }

            string fileDirName = Path.GetDirectoryName(filePath); //查询指定路径下的运行的进程
            Process startProcess = new Process();
            startProcess.StartInfo.FileName = RelaseAndGetHandleExePath();
            startProcess.StartInfo.Arguments = string.Format("\"{0}\"", fileDirName);
            startProcess.StartInfo.UseShellExecute = false;
            startProcess.StartInfo.RedirectStandardInput = false;
            startProcess.StartInfo.RedirectStandardOutput = true;
            startProcess.StartInfo.CreateNoWindow = true;
            startProcess.StartInfo.StandardOutputEncoding = ASCIIEncoding.UTF8;
            startProcess.OutputDataReceived += (sender, e) =>
            {
                if (!string.IsNullOrEmpty(e.Data) && e.Data.IndexOf("pid:", StringComparison.OrdinalIgnoreCase) > 0)
                {
      
                    var regex = new System.Text.RegularExpressions.Regex(@"(^.+(?=pid:))\bpid:\s+(\d+)\s+", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                    if (regex.IsMatch(e.Data))
                    {
                        var mathedResult = regex.Match(e.Data);

                        int procId = int.Parse(mathedResult.Groups[2].Value);
                        string procFileName = mathedResult.Groups[1].Value.Trim();

                        if ("explorer.exe".Equals(procFileName, StringComparison.OrdinalIgnoreCase))
                        {
                            return;
                        }
                        
                        var regex2 = new System.Text.RegularExpressions.Regex(@"\b\w{1}:.+$", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                        string procFilePath = (regex2.Match(e.Data).Value ?? "").Trim();

                        if (filePath.Equals(procFilePath, StringComparison.OrdinalIgnoreCase) || filePath.Equals(PathJoin(procFilePath, procFileName), StringComparison.OrdinalIgnoreCase))
                        {
                            runProcInfos[procId] = procFileName;
                        }
                        else //如果乱码,则进行特殊的比对
                        {
                            if (procFilePath.Contains("?") || procFileName.Contains("?")) //?乱码比对逻辑
                            {
                                var regex3 = new System.Text.RegularExpressions.Regex(procFilePath.Replace(@"\", @"\\").Replace(".", @"\.").Replace("?", ".{1}"), System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                                if (regex3.IsMatch(filePath))
                                {
                                    runProcInfos[procId] = procFileName;
                                }
                                else
                                {
                                    string tempProcFilePath = PathJoin(procFilePath, procFileName);

                                    regex3 = new System.Text.RegularExpressions.Regex(tempProcFilePath.Replace(@"\", @"\\").Replace(".", @"\.").Replace("?", ".{1}"), System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                                    if (regex3.IsMatch(filePath))
                                    {
                                        runProcInfos[procId] = procFileName;
                                    }
                                }
                            }
                            else if (procFilePath.Length == filePath.Length || PathJoin(procFilePath, procFileName).Length == filePath.Length) 
                            {                              
                                {
                                    runProcInfos[procId] = procFileName;
                                }
                            }
                        }
                    }
                }
            };

            startProcess.Start();
            startProcess.BeginOutputReadLine();
            startProcess.WaitForExit();

            return runProcInfos;
        }


        private string RelaseAndGetHandleExePath()
        {
            string is32BiteSys = Environment.GetEnvironmentVariable("ProgramFiles(x86)");

            string _handleFilefullName = string.Empty;
            if (string.IsNullOrEmpty(is32BiteSys))
            { 
                 var handleInfo = new FileInfo(Path.Combine(Environment.CurrentDirectory, "handle.exe"));
                _handleFilefullName = handleInfo.FullName;
            }
            else  
            {

                var handleInfo = new FileInfo(Path.Combine(Environment.CurrentDirectory, "handle64.exe"));
                _handleFilefullName = handleInfo.FullName;

 
            }
           

            return _handleFilefullName;
        }

        private bool ExistHandleExeFile()
        {
            bool result = false;

            string is32BiteSys = Environment.GetEnvironmentVariable("ProgramFiles(x86)");

            string _handleFilefullName = string.Empty;
            if (string.IsNullOrEmpty(is32BiteSys))
            {
                var handleInfo = new FileInfo(Path.Combine(Environment.CurrentDirectory, "handle.exe"));
                _handleFilefullName = handleInfo.FullName;
            }
            else
            {

                var handleInfo = new FileInfo(Path.Combine(Environment.CurrentDirectory, "handle64.exe"));
                _handleFilefullName = handleInfo.FullName;


            }

            result = System.IO.File.Exists(_handleFilefullName);
            return result;
        }


        ///


        /// 拼接路径(不过滤殊字符)
        ///

        ///
        ///
        private string PathJoin(params string[] paths)
        {
            if (paths == null || paths.Length <= 0)
            {
                return string.Empty;
            }

            string newPath = paths[0];

            for (int i = 1; i < paths.Length; i++)
            {
                if (!newPath.EndsWith("\\"))
                {
                    newPath += "\\";
                }

                if (paths[i].StartsWith("\\"))
                {
                    paths[i] = paths[i].Substring(1);
                }

                newPath += paths[i];
            }

            return newPath;
        }


        public void CloseProcessWithFile(string filePath, out List killedFile)
        {
            killedFile = null;

            if (!IsFileUsing(filePath)) return;

            if (!ExistHandleExeFile()) return;

            var runProcInfos = GetRunProcessInfos(filePath); //获取被占用的进程

            System.IO.File.WriteAllText(Path.Combine(Environment.CurrentDirectory, "runProcInfos.txt"), string.Join("\r\n", runProcInfos.Select(p => string.Format("ProdId:{0},ProcName:{1}", p.Key, p.Value)).ToArray()));

            var currentProcessId = Process.GetCurrentProcess().Id;

            bool hasKilled = false;
            foreach (var item in runProcInfos)
            {
                if (item.Key != currentProcessId) //排除当前进程
                {                   
                    var runProcess = Process.GetProcessById(item.Key);
                    if (runProcess != null)
                    {
                        string killedFilaName = Path.Combine(System.IO.Path.GetDirectoryName(filePath), item.Value);
                        if (System.IO.File.Exists(killedFilaName))
                        {
                            if (killedFile == null)
                            {
                                killedFile = new List();
                            }
                            killedFile.Add(killedFilaName);
                        }


                        try
                        {
                            runProcess.Kill(); //强制关闭被占用的进程
                            hasKilled = true;
                        }
                        catch
                        { }
                    }
                }
            }

            if (hasKilled)
            {
                System.Threading.Thread.Sleep(500);
            }
        }
    }
}
 

你可能感兴趣的:(dreamweaver,windows,servlet)