软件编程
位置:首页>> 软件编程>> C#编程>> 用c# 自动更新程序

用c# 自动更新程序

作者:冰封一夏  发布时间:2023-04-03 09:03:46 

标签:c#,自动,更新,程序

作者:冰封一夏
出处:http://www.cnblogs.com/bfyx/
HZHControls官网:http://www.hzhcontrols.com

首先看获取和更新的接口

更新程序Program.cs


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Update
{
 static class Program
 {
   /// <summary>
   /// 更新程序启动后复制自身,使用副本进行更新
   /// -h 不显示界面
   /// -c 不使用copy更新程序
   /// -d 更新完成删除自身,通常用在copy的更新程序
   /// -b 更新下载到备份文件,不替换原文件
   /// -r 更新完成运行的文件,下一个参数为文件路径
   /// -k 如果系统正在运行则干掉
   /// </summary>
   [STAThread]
   static void Main(string[] args)
   {
     Application.EnableVisualStyles();
     Application.SetCompatibleTextRenderingDefault(false);
     Application.ThreadException += Application_ThreadException;

List<string> lst = args.ToList();
     if (!lst.Contains("-b") && !lst.Contains("-k"))
     {
       //这里判断成程序是否退出
       if (Process.GetProcessesByName("serviceclient").Length > 0)
       {
         MessageBox.Show("服务正在运行,请退出后重试。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
         return;
       }
     }

if (lst.Contains("-k"))
     {
       var ps = Process.GetProcessesByName("serviceclient");
       if (ps.Length > 0)
       {
         ps[0].Kill();
       }
     }

//副本更新程序运行
     if (!lst.Contains("-c"))//不存在-c 则进行复制运行
     {
       string strFile = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), Guid.NewGuid().ToString() + ".exe");
       File.Copy(Application.ExecutablePath, strFile);
       lst.Add("-c");
       lst.Add("-d");
       Process.Start(strFile, string.Join(" ", lst));
     }
     else
     {
       Action actionAfter = null;
       //将更新文件替换到当前目录
       if (!lst.Contains("-b"))
       {
         actionAfter = () =>
         {
           string strUpdatePath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "UpdateCache\\");
           if (Directory.Exists(strUpdatePath) && Directory.GetFiles(strUpdatePath).Length > 0)
           {
             CopyFile(strUpdatePath, System.AppDomain.CurrentDomain.BaseDirectory, strUpdatePath);
             if (File.Exists(Path.Combine(strUpdatePath, "ver.xml")))
               File.Copy(Path.Combine(strUpdatePath, "ver.xml"), Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "ver.xml"), true);
             Directory.Delete(strUpdatePath, true);
           }
         };
       }
       try
       {
         //隐藏运行
         if (!lst.Contains("-h"))
         {
           Application.Run(new FrmUpdate(actionAfter, true));
         }
         else
         {
           FrmUpdate frm = new FrmUpdate(actionAfter);
           frm.Down();
         }
       }
       catch (Exception ex)
       { }
       //运行更新后的文件
       if (lst.Contains("-r"))
       {
         int index = lst.IndexOf("-r");
         if (index + 1 < lst.Count)
         {
           string strFile = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, lst[index + 1]);
           if (File.Exists(strFile))
           {
             Process.Start(strFile, "-u");
           }
         }
       }
       //删除自身
       if (lst.Contains("-d"))
       {
         DeleteItself();
       }
     }
     Application.Exit();
     Process.GetCurrentProcess().Kill();
   }

private static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
   {
     throw new NotImplementedException();
   }
   private static void CopyFile(string strSource, string strTo, string strBasePath)
   {
     string[] files = Directory.GetFiles(strSource);
     foreach (var item in files)
     {
       string strFileName = Path.GetFileName(item).ToLower();

if (strFileName == "ver.xml ")
       {
         continue;
       }
       //如果是版本文件和文件配置xml则跳过,复制完成后再替换这2个文件
       string strToPath = Path.Combine(strTo, item.Replace(strBasePath, ""));
       var strdir = Path.GetDirectoryName(strToPath);
       if (!Directory.Exists(strdir))
       {
         Directory.CreateDirectory(strdir);
       }
       File.Copy(item, strToPath, true);
     }
     string[] dires = Directory.GetDirectories(strSource);
     foreach (var item in dires)
     {
       CopyFile(item, strTo, strBasePath);
     }
   }

private static void DeleteItself()
   {
     ProcessStartInfo psi = new ProcessStartInfo("cmd.exe", "/C ping 1.1.1.1 -n 1 -w 1000 > Nul & Del " + Application.ExecutablePath);
     psi.WindowStyle = ProcessWindowStyle.Hidden;
     psi.CreateNoWindow = true;
     Process.Start(psi);
   }
 }
}

更新程序界面


using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml;

namespace HW.Print.ServiceClient.Update
{
 public partial class FrmUpdate : Form
 {
   private static string m_strkey = "sdfadsfdsfasdf";//定义一个密钥用以验证权限,不适用ticket
   Random r = new Random();
   Action m_actionAfter = null;
   bool m_blnShow = false;
   public FrmUpdate(Action actionAfter, bool blnShow = false)
   {
     m_blnShow = blnShow;
     m_actionAfter = actionAfter;
     InitializeComponent();
   }

private void Form1_VisibleChanged(object sender, EventArgs e)
   {
     if (Visible)
     {
       var rect = Screen.PrimaryScreen.WorkingArea;
       this.Location = new Point(rect.Right - this.Width, rect.Bottom - this.Height);
     }
   }

private void FrmUpdate_Load(object sender, EventArgs e)
   {
     Thread th = new Thread(() =>
     {
       Down();
       this.BeginInvoke(new MethodInvoker(delegate ()
       {
         this.Close();
       }));
     });
     th.IsBackground = true;
     th.Start();
   }
   private string CheckIsXP(string strUrl)
   {
     bool blnXp = false;
     if (Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor == 1)
     {
       blnXp = true;
     }
     if (blnXp && strUrl.StartsWith("https"))
     {
       strUrl = "http" + strUrl.Substring(5);
     }
     return strUrl;
   }

private void SetProcess(string strTitle, int? value, int? maxValue = null)
   {
     this.lblMsg.BeginInvoke(new MethodInvoker(delegate ()
     {
       if (maxValue.HasValue)
       {
         this.progressBar1.Maximum = maxValue.Value;
       }
       if (value.HasValue)
       {
         this.progressBar1.Value = value.Value;
       }
       if (!string.IsNullOrEmpty(strTitle))
       {
         this.lblMsg.Text = strTitle;
       }
       lblValue.Text = this.progressBar1.Value + "/" + this.progressBar1.Maximum;
     }));
   }

public void Down()
   {
     if (m_blnShow)
       SetProcess("正在检查版本", null);
     try
     {
       //先清理掉旧文件
       try
       {
         if (Directory.Exists(System.AppDomain.CurrentDomain.BaseDirectory + "UpdateCache"))
         {
           Directory.Delete(System.AppDomain.CurrentDomain.BaseDirectory + "UpdateCache", true);
         }
       }
       catch { }
       if (!File.Exists(System.AppDomain.CurrentDomain.BaseDirectory + "setting.dat"))
       {
         Log.WriteLog("配置文件setting.dat不存在!");
         return;
       }
       string strFileUrl = File.ReadAllText(System.AppDomain.CurrentDomain.BaseDirectory + "setting.dat");

strFileUrl = CheckIsXP(strFileUrl);
       //获取列表文件
       string json = HttpGet(strFileUrl.Trim('/') + "/getUpdaterList?key=" + Encrypt(m_strkey), Encoding.UTF8);
       ResponseMessage rm = fastJSON.JSON.ToObject<ResponseMessage>(json);
       if (rm == null)
       {
         Log.WriteLog("获取更新文件错误");
         return;
       }
       if (!rm.Result)
       {
         Log.WriteLog("获取更新文件错误:" + rm.ErrorMessage);
         return;
       }
       //云列表
       Dictionary<string, DateTime> lstNewFiles = new Dictionary<string, DateTime>();
       XmlDocument doc = new XmlDocument();
       doc.LoadXml(rm.KeyValue);
       var documentElement = doc.DocumentElement;
       var nodes = documentElement.SelectNodes("//files/file");
       foreach (XmlNode item in nodes)
       {
         lstNewFiles[item.InnerText] = DateTime.Parse(item.Attributes["time"].Value);
       }

List<string> lstUpdateFile = new List<string>();
       string locationXml = System.AppDomain.CurrentDomain.BaseDirectory + "ver.xml";
       if (!File.Exists(locationXml))
       {
         lstUpdateFile = lstNewFiles.Keys.ToList();
       }
       else
       {
         XmlDocument docLocation = new XmlDocument();
         docLocation.Load(locationXml);
         var documentElementLocation = docLocation.DocumentElement;
         var nodesLocation = documentElementLocation.SelectNodes("//files/file");
         foreach (XmlNode item in nodesLocation)
         {
           if (!lstNewFiles.ContainsKey(item.InnerText))
           {
             lstUpdateFile.Add(item.InnerText);
           }
           else if (lstNewFiles[item.InnerText] < DateTime.Parse(item.Attributes["time"].Value))
           {
             lstUpdateFile.Add(item.InnerText);
           }
         }
       }
       if (lstUpdateFile.Count > 0)
       {
         string strRootPath = System.AppDomain.CurrentDomain.BaseDirectory + "UpdateCache";
         if (!System.IO.Directory.Exists(strRootPath))
         {
           System.IO.Directory.CreateDirectory(strRootPath);
         }
         SetProcess("", null, lstUpdateFile.Count);
         for (int i = 0; i < lstUpdateFile.Count; i++)
         {
           if (m_blnShow)
             SetProcess("正在下载:" + lstUpdateFile[i], i + 1);

string filejson = HttpGet(strFileUrl.Trim('/') + "/downloadUpdaterFile?key=" + Encrypt(m_strkey) + "&file=" + System.Web.HttpUtility.UrlEncode(lstUpdateFile[i]), Encoding.UTF8);
           ResponseMessage filerm = fastJSON.JSON.ToObject<ResponseMessage>(filejson);
           if (rm == null)
           {
             Log.WriteLog("下载更新文件错误");
             return;
           }
           if (!rm.Result)
           {
             Log.WriteLog("下载更新文件错误:" + rm.ErrorMessage);
             return;
           }

string saveFile = Path.Combine(strRootPath, lstUpdateFile[i]);
           if (!Directory.Exists(Path.GetDirectoryName(saveFile)))
           {
             System.IO.Directory.CreateDirectory(Path.GetDirectoryName(saveFile));
           }
           string strbase64 = filerm.KeyValue;  
           MemoryStream stream = new MemoryStream(Convert.FromBase64String(strbase64));
           FileStream fs = new FileStream(strRootPath + "\\" + lstUpdateFile[i], FileMode.OpenOrCreate, FileAccess.Write);
           byte[] b = stream.ToArray();
           fs.Write(b, 0, b.Length);
           fs.Close();

}

doc.Save(System.AppDomain.CurrentDomain.BaseDirectory + "UpdateCache//ver.xml");

if (m_actionAfter != null)
         {
           if (m_blnShow)
             SetProcess("替换文件", null);
           m_actionAfter();
         }

if (m_blnShow)
           SetProcess("更新完成。", null);
       }
       else
       {
         if (m_blnShow)
           SetProcess("没有需要更新的文件。", null);
       }
     }
     catch (Exception ex)
     {
       if (m_blnShow)
         SetProcess("获取更新列表失败:" + ex.Message, null);
       Log.WriteLog(ex.ToString());
     }
     finally
     {
       if (m_blnShow)
         Thread.Sleep(3000);
     }
   }

private static string encryptKey = "111222333444555666";

//默认密钥向量
   private static byte[] Keys = { 0x41, 0x72, 0x65, 0x79, 0x6F, 0x75, 0x6D, 0x79, 0x53, 0x6E, 0x6F, 0x77, 0x6D, 0x61, 0x6E, 0x3F };
   /// <summary>
   /// 加密
   /// </summary>
   /// <param name="encryptString"></param>
   /// <returns></returns>
   public static string Encrypt(string encryptString)
   {
     if (string.IsNullOrEmpty(encryptString))
       return string.Empty;
     RijndaelManaged rijndaelProvider = new RijndaelManaged();
     rijndaelProvider.Key = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 32));
     rijndaelProvider.IV = Keys;
     ICryptoTransform rijndaelEncrypt = rijndaelProvider.CreateEncryptor();

byte[] inputData = Encoding.UTF8.GetBytes(encryptString);
     byte[] encryptedData = rijndaelEncrypt.TransformFinalBlock(inputData, 0, inputData.Length);

return System.Web.HttpUtility.UrlEncode(Convert.ToBase64String(encryptedData));
   }
   public static string HttpGet(string url, Encoding encodeing, Hashtable headht = null)
   {
     HttpWebRequest request;

//如果是发送HTTPS请求
     //if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
     //{
     //ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
     request = WebRequest.Create(url) as HttpWebRequest;
     request.ServicePoint.Expect100Continue = false;
     request.ProtocolVersion = HttpVersion.Version11;
     request.KeepAlive = true;
     //}
     //else
     //{
     //  request = WebRequest.Create(url) as HttpWebRequest;
     //}
     request.Method = "GET";
     //request.ContentType = "application/x-www-form-urlencoded";
     request.Accept = "*/*";
     request.Timeout = 30000;
     request.AllowAutoRedirect = false;
     WebResponse response = null;
     string responseStr = null;
     if (headht != null)
     {
       foreach (DictionaryEntry item in headht)
       {
         request.Headers.Add(item.Key.ToString(), item.Value.ToString());
       }
     }

try
     {
       response = request.GetResponse();

if (response != null)
       {
         StreamReader reader = new StreamReader(response.GetResponseStream(), encodeing);
         responseStr = reader.ReadToEnd();
         reader.Close();
       }
     }
     catch (Exception)
     {
       throw;
     }
     return responseStr;
   }
 }
}

定义服务端接口,你可以用任意接口都行,我这里用webapi

获取文件列表


[HttpGet]
   public HttpResponseMessage GetUpdaterList(string key)
   {
     HttpResult httpResult = new HttpResult();
     if (!CheckKey(key))
     {
       httpResult.KeyValue = "";
       httpResult.Result = false;
       httpResult.ErrorMessage = "无权限访问";
     }
     else
     {
       //获取printupdate目录下update.exe的修改日期返回
       string path = Path.Combine(HttpRuntime.AppDomainAppPath, "printupdate");
       StringBuilder strXml = new StringBuilder();
       strXml.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
       strXml.AppendLine("<files>");
       if (Directory.Exists(path))
       {
         string[] fs = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
         var _p = path.ToLower().Trim().Length + 1;
         foreach (var item in fs)
         {
           var dt = File.GetLastAccessTime(item);
           strXml.AppendLine("<file time=\"" + dt.ToString("yyyy-MM-dd HH:mm:ss") + "\">" + item.Substring(_p) + "</file>");
         }
       }
       strXml.AppendLine("</files>");

httpResult.KeyValue = strXml.ToString();
       httpResult.Result = true;
       httpResult.ErrorMessage = "";
     }
     return new HttpResponseMessage { Content = new StringContent(httpResult.ToJson(), Encoding.GetEncoding("UTF-8"), "application/json") };
   }

定义服务端接口,你可以用任意接口都行,我这里用webapi

获取文件列表


[HttpGet]
   public HttpResponseMessage GetUpdaterList(string key)
   {
     HttpResult httpResult = new HttpResult();
     if (!CheckKey(key))
     {
       httpResult.KeyValue = "";
       httpResult.Result = false;
       httpResult.ErrorMessage = "无权限访问";
     }
     else
     {
       //获取printupdate目录下update.exe的修改日期返回
       string path = Path.Combine(HttpRuntime.AppDomainAppPath, "printupdate");
       StringBuilder strXml = new StringBuilder();
       strXml.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\" ?>");
       strXml.AppendLine("<files>");
       if (Directory.Exists(path))
       {
         string[] fs = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
         var _p = path.ToLower().Trim().Length + 1;
         foreach (var item in fs)
         {
           var dt = File.GetLastAccessTime(item);
           strXml.AppendLine("<file time=\"" + dt.ToString("yyyy-MM-dd HH:mm:ss") + "\">" + item.Substring(_p) + "</file>");
         }
       }
       strXml.AppendLine("</files>");

httpResult.KeyValue = strXml.ToString();
       httpResult.Result = true;
       httpResult.ErrorMessage = "";
     }
     return new HttpResponseMessage { Content = new StringContent(httpResult.ToJson(), Encoding.GetEncoding("UTF-8"), "application/json") };
   }

下载文件,我这里将文件序列号为base64字符串了,你可以直接返回文件流也行


[HttpGet]
   public HttpResponseMessage DownloadUpdaterFile(string key, string file)
   {
     HttpResult httpResult = new HttpResult();
     if (!CheckKey(key))
     {
       httpResult.KeyValue = "";
       httpResult.Result = false;
       httpResult.ErrorMessage = "无权限访问";
     }
     else
     {
       string path = Path.Combine(HttpRuntime.AppDomainAppPath + "printupdate", file);
       if (!File.Exists(path))
       {
         httpResult.KeyValue = "";
         httpResult.Result = false;
         httpResult.ErrorMessage = "文件不存在";
       }
       else
       {
         httpResult = ConvertToBase64Type(path);
       }
     }
     return new HttpResponseMessage { Content = new StringContent(httpResult.ToJson(), Encoding.GetEncoding("UTF-8"), "application/json") };

}

HttpResult ConvertToBase64Type(string fileName)
   {
     HttpResult httpResult = new HttpResult();
     var byts = File.ReadAllBytes(fileName);
     httpResult.KeyValue = Convert.ToBase64String(byts);
     return httpResult;
   }

bool CheckKey(string key)
    {
      return key == Encryption.Encrypt(m_strkey);
    }

private static string encryptKey = "111222333444";

//默认密钥向量
   private static byte[] Keys = { 0x41, 0x72, 0x65, 0x79, 0x6F, 0x75, 0x6D, 0x79, 0x53, 0x6E, 0x6F, 0x77, 0x6D, 0x61, 0x6E, 0x3F };
   /// <summary>
   /// 加密
   /// </summary>
   /// <param name="encryptString"></param>
   /// <returns></returns>
   public static string Encrypt(string encryptString)
   {
     if (string.IsNullOrEmpty(encryptString))
       return string.Empty;
     RijndaelManaged rijndaelProvider = new RijndaelManaged();
     rijndaelProvider.Key = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 32));
     rijndaelProvider.IV = Keys;
     ICryptoTransform rijndaelEncrypt = rijndaelProvider.CreateEncryptor();

byte[] inputData = Encoding.UTF8.GetBytes(encryptString);
     byte[] encryptedData = rijndaelEncrypt.TransformFinalBlock(inputData, 0, inputData.Length);

return Convert.ToBase64String(encryptedData);
   }

需要注意的地方:

1、我这里用到了json,那么不能直接饮用json的dll文件,会出现更新时候占用的问题,可以使用fastjson的开源代码,放进来解决,你可以直接使用xml格式的返回内容,这样就不需要json了,这样更方便

2、如果你的下载接口是返回的文件流,那么你更新程序里面直接接收流保存文件就行了

3、Program.cs里面,停止服务的功能,其实是可以通过传递参数的形式来停止,我这里写死了,你们根据自己需求修改

效果

用c# 自动更新程序

 你可以根据自己的需求,修改下界面效果,这是最简单的示例界面而已。

来源:https://www.cnblogs.com/bfyx/p/13985825.html?utm_source=tuicool&utm_medium=referral

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com