UpdateWork.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Net;
  5. using System.IO;
  6. using System.Diagnostics;
  7. using System.Windows.Forms;
  8. using System.Threading;
  9. using System.Runtime.InteropServices;
  10. using Microsoft.Win32;
  11. using System.Xml;
  12. using Ionic.Zip;
  13. using System.Net.Security;
  14. using System.Security.Cryptography.X509Certificates;
  15. using System.Collections;
  16. using System.Configuration;
  17. namespace MAutoUpdate
  18. {
  19. public class UpdateWork
  20. {
  21. public delegate void UpdateProgess(double data);
  22. public UpdateProgess OnUpdateProgess;
  23. string mainName;
  24. //临时目录(WIN7以及以上在C盘只有对于temp目录有操作权限)
  25. //string tempPath = Path.Combine(Environment.GetEnvironmentVariable("TEMP"), @"MAutoUpdate\temp\");
  26. //string bakPath = Path.Combine(Environment.GetEnvironmentVariable("TEMP"), @"MAutoUpdate\bak\");
  27. string tempPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"MAutoUpdate\temp\");
  28. string bakPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"MAutoUpdate\bak\");
  29. string appPath = AppDomain.CurrentDomain.BaseDirectory + "/";
  30. LocalInfo localInfo;
  31. Hashtable hashTable;
  32. public List<RemoteInfo> UpdateVerList { get; set; }
  33. public string programName { get; set; }
  34. public string subKey { get; set; }
  35. public int Type { get; set; }
  36. /// <summary>
  37. /// 初始化配置目录信息
  38. /// </summary>
  39. public UpdateWork(string _programName, string localAddress, string isClickUpdate, int _type, Hashtable ht)
  40. {
  41. hashTable = ht;
  42. Type = _type;
  43. //localInfo = new LocalInfo(localAddress);
  44. //Process cur = Process.GetCurrentProcess();
  45. //mainName = Path.GetFileName(cur.MainModule.FileName);
  46. programName = _programName;
  47. //创建备份目录信息
  48. //DirectoryInfo bakinfo = new DirectoryInfo(bakPath);
  49. //if (bakinfo.Exists == false)
  50. //{
  51. // bakinfo.Create();
  52. //}
  53. ////创建临时目录信息
  54. //DirectoryInfo tempinfo = new DirectoryInfo(tempPath);
  55. //if (tempinfo.Exists == false)
  56. //{
  57. // tempinfo.Create();
  58. //}
  59. //localInfo.LoadXml(_type);
  60. //UpdateVerList = GetServer(localInfo.ServerUpdateUrl);
  61. //CheckVer(localInfo.LocalVersion, localInfo.LocalIgnoreVersion, isClickUpdate);
  62. }
  63. //public bool Do()
  64. //{
  65. // KillProcessExist();
  66. // Thread.Sleep(400);
  67. // //更新之前先备份
  68. // Bak();
  69. // Thread.Sleep(400);
  70. // //备份结束开始下载东西
  71. // DownLoad();//下载更新包文件信息
  72. // Thread.Sleep(400);
  73. // //3、开始更新
  74. // Update();
  75. // Thread.Sleep(400);
  76. // Start();
  77. // Thread.Sleep(400);
  78. // return true;
  79. //}
  80. public bool Do()
  81. {
  82. KillProcessExist();
  83. Thread.Sleep(1000);
  84. //更新之前先备份
  85. //备份结束开始下载东西
  86. //DownLoad();//下载更新包文件信息
  87. DownLoadInfo();
  88. Thread.Sleep(400);
  89. Start();
  90. Thread.Sleep(400);
  91. return true;
  92. }
  93. public void DownLoadInfo()
  94. {
  95. var url = appPath;
  96. if (!Directory.Exists(url))
  97. {
  98. Directory.CreateDirectory(url);
  99. }
  100. foreach (var item in hashTable.Keys)
  101. {
  102. if (item.ToString() == "MAutoUpdate.exe")
  103. {
  104. continue;
  105. }
  106. Stream stream = new MemoryStream();
  107. try
  108. {
  109. LogTool.AddLog("更新程序:下载更新包文件" + item);
  110. byte[] bs = Convert.FromBase64String(hashTable[item].ToString());
  111. stream.Read(bs, 0, bs.Length);
  112. using (FileStream fs = new FileStream(appPath + item.ToString(), FileMode.Create))
  113. {
  114. fs.Write(bs, 0, bs.Length);
  115. }
  116. //web.DownloadFile(hashTable[item].ToString(), AppDomain.CurrentDomain.BaseDirectory + @"Debug/" + item.ToString());
  117. //OnUpdateProgess?.Invoke(60 / UpdateVerList.Count);
  118. }
  119. catch (Exception ex)
  120. {
  121. LogTool.AddLog("更新程序:更新包文件" + item + "下载失败,本次停止更新,异常信息:" + ex.Message);
  122. throw ex;
  123. }
  124. finally
  125. {
  126. stream.Close();
  127. stream.Dispose();
  128. }
  129. }
  130. //using (WebClient web = new WebClient())
  131. //{
  132. // foreach (var item in hashTable.Keys)
  133. // {
  134. // try
  135. // {
  136. // LogTool.AddLog("更新程序:下载更新包文件" + item);
  137. // web.DownloadFile(hashTable[item].ToString(), AppDomain.CurrentDomain.BaseDirectory + @"Debug/" + item.ToString());
  138. // //OnUpdateProgess?.Invoke(60 / UpdateVerList.Count);
  139. // }
  140. // catch (Exception ex)
  141. // {
  142. // LogTool.AddLog("更新程序:更新包文件" + item + "下载失败,本次停止更新,异常信息:" + ex.Message);
  143. // throw ex;
  144. // }
  145. // }
  146. //}
  147. }
  148. public static byte[] HexStrTobyte(string hexString)
  149. {
  150. hexString = hexString.Replace(" ", "");
  151. if ((hexString.Length % 2) != 0)
  152. hexString += " ";
  153. byte[] returnBytes = new byte[hexString.Length / 2];
  154. for (int i = 0; i < returnBytes.Length; i++)
  155. returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2).Trim(), 16);
  156. return returnBytes;
  157. }
  158. public void IgnoreThisVersion()
  159. {
  160. var item = UpdateVerList[UpdateVerList.Count - 1];
  161. localInfo.LocalIgnoreVersion = item.ReleaseVersion;
  162. localInfo.SaveXml();
  163. }
  164. /// <summary>
  165. /// 获取更新的服务器端的数据信息
  166. /// </summary>
  167. /// <param name="url">自动更新的URL信息</param>
  168. /// <returns></returns>
  169. private static List<RemoteInfo> GetServer(string url)
  170. {
  171. ServicePointManager.ServerCertificateValidationCallback += RemoteCertificateValidate;
  172. List<RemoteInfo> list = new List<RemoteInfo>();
  173. XmlReader xml = XmlReader.Create(url);
  174. XmlDocument xdoc = new XmlDocument();
  175. xdoc.Load(url);
  176. var root = xdoc.DocumentElement;
  177. var listNodes = root.SelectNodes("/ServerUpdate/item");
  178. foreach (XmlNode item in listNodes)
  179. {
  180. RemoteInfo remote = new RemoteInfo();
  181. foreach (XmlNode pItem in item.ChildNodes)
  182. {
  183. remote.GetType().GetProperty(pItem.Name).SetValue(remote, pItem.InnerText, null);
  184. }
  185. list.Add(remote);
  186. }
  187. return list;
  188. }
  189. private static bool RemoteCertificateValidate(
  190. object sender, X509Certificate cert,
  191. X509Chain chain, SslPolicyErrors error)
  192. {
  193. System.Console.WriteLine("Warning, trust any certificate");
  194. return true;
  195. }
  196. /// <summary>
  197. /// 下载方法
  198. /// </summary>
  199. private UpdateWork DownLoad()
  200. {
  201. //比如uri=http://localhost/Rabom/1.rar;iis就需要自己配置了。
  202. //截取文件名
  203. //构造文件完全限定名,准备将网络流下载为本地文件
  204. using (WebClient web = new WebClient())
  205. {
  206. foreach (var item in UpdateVerList)
  207. {
  208. try
  209. {
  210. LogTool.AddLog("更新程序:下载更新包文件" + item.ReleaseVersion);
  211. web.DownloadFile(item.ReleaseUrl, tempPath + item.ReleaseVersion + ".zip");
  212. OnUpdateProgess?.Invoke(60 / UpdateVerList.Count);
  213. }
  214. catch (Exception ex)
  215. {
  216. LogTool.AddLog("更新程序:更新包文件" + item.ReleaseVersion + "下载失败,本次停止更新,异常信息:" + ex.Message);
  217. throw ex;
  218. }
  219. }
  220. return this;
  221. }
  222. }
  223. /// <summary>
  224. /// 备份当前的程序目录信息
  225. /// </summary>
  226. private UpdateWork Bak()
  227. {
  228. try
  229. {
  230. LogTool.AddLog("更新程序:准备执行备份操作");
  231. DirectoryInfo di = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);
  232. foreach (var item in di.GetFiles())
  233. {
  234. if (item.Name != mainName)//当前文件不需要备份
  235. {
  236. File.Copy(item.FullName, bakPath + item.Name, true);
  237. }
  238. }
  239. //文件夹复制
  240. foreach (var item in di.GetDirectories())
  241. {
  242. if (item.Name != "bak" && item.Name != "temp")
  243. {
  244. CopyDirectory(item.FullName, bakPath);
  245. }
  246. }
  247. LogTool.AddLog("更新程序:备份操作执行完成,开始关闭应用程序");
  248. OnUpdateProgess?.Invoke(20);
  249. return this;
  250. }
  251. catch (Exception EX)
  252. {
  253. throw EX;
  254. }
  255. }
  256. private UpdateWork Update()
  257. {
  258. foreach (var item in UpdateVerList)
  259. {
  260. try
  261. {
  262. //如果是覆盖安装的话,先删除原先的所有程序
  263. if (item.UpdateMode == "Cover")
  264. {
  265. DelLocal();
  266. }
  267. string path = tempPath + item.ReleaseVersion + ".zip";
  268. using (ZipFile zip = new ZipFile(path))
  269. {
  270. LogTool.AddLog("更新程序:解压" + item.ReleaseVersion + ".zip");
  271. zip.ExtractAll(AppDomain.CurrentDomain.BaseDirectory, ExtractExistingFileAction.OverwriteSilently);
  272. LogTool.AddLog("更新程序:" + item.ReleaseVersion + ".zip" + "解压完成");
  273. ExecuteINI();//执行注册表等更新以及删除文件
  274. }
  275. localInfo.LastUdpate = item.ReleaseDate;
  276. localInfo.LocalVersion = item.ReleaseVersion;
  277. localInfo.SaveXml();
  278. }
  279. catch (Exception ex)
  280. {
  281. LogTool.AddLog("更新程序出现异常:异常信息:" + ex.Message);
  282. LogTool.AddLog("更新程序:更新失败,进行回滚操作");
  283. Restore();
  284. break;
  285. }
  286. finally
  287. {
  288. //删除下载的临时文件
  289. LogTool.AddLog("更新程序:删除临时文件" + item.ReleaseVersion);
  290. DelTempFile(item.ReleaseVersion + ".zip");//删除更新包
  291. LogTool.AddLog("更新程序:临时文件删除完成" + item.ReleaseVersion);
  292. }
  293. }
  294. OnUpdateProgess?.Invoke(98);
  295. return this;
  296. }
  297. private UpdateWork Start()
  298. {
  299. try
  300. {
  301. var processPath = appPath + "EapForIdle.exe";
  302. Process.Start(processPath);
  303. //CopyFile();
  304. //String[] StartInfo = UpdateVerList[UpdateVerList.Count - 1].ApplicationStart.Split(',');
  305. //if (StartInfo.Length > 0)
  306. //{
  307. // foreach (var item in StartInfo)
  308. // {
  309. // LogTool.AddLog("更新程序:启动" + item);
  310. // Process.Start(Path.Combine(AppDomain.CurrentDomain.BaseDirectory + @"Debug\", item));
  311. // }
  312. //}
  313. //OnUpdateProgess?.Invoke(100);
  314. return this;
  315. }
  316. catch (Exception ex)
  317. {
  318. LogTool.AddLog(ex.ToString());
  319. return this;
  320. }
  321. }
  322. public void CopyFile()
  323. {
  324. try
  325. {
  326. string sourceName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Local.xml");
  327. string folderPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Debug");
  328. if (!Directory.Exists(folderPath))
  329. {
  330. Directory.CreateDirectory(folderPath);
  331. }
  332. string fileName = Path.GetFileName(sourceName);
  333. string targetPath = Path.Combine(folderPath, fileName);
  334. FileInfo file = new FileInfo(sourceName);
  335. if (file.Exists)
  336. {
  337. file.CopyTo(targetPath, true);
  338. }
  339. }
  340. catch (Exception ex)
  341. {
  342. LogTool.AddLog(ex.ToString());
  343. }
  344. }
  345. /// <summary>
  346. /// 文件拷贝
  347. /// </summary>
  348. /// <param name="srcdir">源目录</param>
  349. /// <param name="desdir">目标目录</param>
  350. private UpdateWork CopyDirectory(string srcdir, string desdir)
  351. {
  352. string folderName = srcdir.Substring(srcdir.LastIndexOf("\\") + 1);
  353. string desfolderdir = desdir + "\\" + folderName;
  354. if (desdir.LastIndexOf("\\") == (desdir.Length - 1))
  355. {
  356. desfolderdir = desdir + folderName;
  357. }
  358. string[] filenames = Directory.GetFileSystemEntries(srcdir);
  359. foreach (string file in filenames)// 遍历所有的文件和目录
  360. {
  361. if (Directory.Exists(file))// 先当作目录处理如果存在这个目录就递归Copy该目录下面的文件
  362. {
  363. string currentdir = desfolderdir + "\\" + file.Substring(file.LastIndexOf("\\") + 1);
  364. if (!Directory.Exists(currentdir))
  365. {
  366. Directory.CreateDirectory(currentdir);
  367. }
  368. CopyDirectory(file, desfolderdir);
  369. }
  370. else // 否则直接copy文件
  371. {
  372. string srcfileName = file.Substring(file.LastIndexOf("\\") + 1);
  373. srcfileName = desfolderdir + "\\" + srcfileName;
  374. if (!Directory.Exists(desfolderdir))
  375. {
  376. Directory.CreateDirectory(desfolderdir);
  377. }
  378. File.Copy(file, srcfileName, true);
  379. }
  380. }
  381. return this;
  382. }
  383. /// <summary>
  384. /// 删除临时文件
  385. /// </summary>
  386. private UpdateWork DelTempFile(String name)
  387. {
  388. FileInfo file = new FileInfo(tempPath + name);
  389. file.Delete();
  390. return this;
  391. }
  392. /// <summary>
  393. /// 更新失败的情况下,回滚当前更新
  394. /// </summary>
  395. private UpdateWork Restore()
  396. {
  397. DelLocal();
  398. CopyDirectory(bakPath, appPath);
  399. return this;
  400. }
  401. /// <summary>
  402. /// 删除本地文件夹的文件
  403. /// </summary>
  404. private UpdateWork DelLocal()
  405. {
  406. DirectoryInfo di = new DirectoryInfo(appPath);
  407. foreach (var item in di.GetFiles())
  408. {
  409. if (item.Name != mainName)
  410. {
  411. if (item.Name == "Local.xml")
  412. {
  413. }
  414. else
  415. {
  416. File.Delete(item.FullName);
  417. }
  418. }
  419. }
  420. foreach (var item in di.GetDirectories())
  421. {
  422. if (item.Name != "bak" && item.Name != "temp")
  423. {
  424. item.Delete(true);
  425. }
  426. }
  427. return this;
  428. }
  429. /// <summary>
  430. /// 校验程序版本号
  431. /// </summary>
  432. /// <param name="LocalVer">当前本地版本信息</param>
  433. /// <returns></returns>
  434. private UpdateWork CheckVer(string LocalVer, string localIgnoreVer, string isClickUpdate)
  435. {
  436. string[] Local = LocalVer.Split('.');
  437. string[] LocalIgnore = localIgnoreVer.Split('.');
  438. List<RemoteInfo> list = new List<RemoteInfo>();
  439. List<RemoteInfo> listReal = new List<RemoteInfo>();
  440. foreach (var item in UpdateVerList)
  441. {
  442. string[] Remote = item.ReleaseVersion.Split('.');
  443. for (int i = 0; i < Local.Length; i++)
  444. {
  445. if (int.Parse(Local[i]) < int.Parse(Remote[i]))
  446. {
  447. list.Add(item);
  448. break;
  449. }
  450. else if (int.Parse(Local[i]) == int.Parse(Remote[i]))
  451. {
  452. continue;
  453. }
  454. else
  455. {
  456. break;
  457. }
  458. }
  459. }
  460. if (isClickUpdate == "0")
  461. {
  462. foreach (var item in list)
  463. {
  464. string[] Remote = item.ReleaseVersion.Split('.');
  465. for (int i = 0; i < LocalIgnore.Length; i++)
  466. {
  467. if (int.Parse(LocalIgnore[i]) < int.Parse(Remote[i]))
  468. {
  469. listReal.Add(item);
  470. break;
  471. }
  472. else if (int.Parse(LocalIgnore[i]) == int.Parse(Remote[i]))
  473. {
  474. continue;
  475. }
  476. else
  477. {
  478. break;
  479. }
  480. }
  481. }
  482. }
  483. else
  484. {
  485. listReal = list;
  486. }
  487. UpdateVerList = listReal;
  488. return this;
  489. }
  490. /// <summary>
  491. /// 更新配置信息
  492. /// </summary>
  493. private UpdateWork ExecuteINI()
  494. {
  495. DirectoryInfo TheFolder = new DirectoryInfo(appPath);
  496. if (File.Exists(Path.Combine(TheFolder.FullName, "config.update")))
  497. {
  498. string[] ss = File.ReadAllLines(Path.Combine(TheFolder.FullName, "config.update"));
  499. Int32 i = -1;//0[regedit_del] 表示注册表删除‘1[regedit_add]表示注册表新增 2[file_del] 表示删除文件
  500. foreach (var s in ss)
  501. {
  502. String s1 = s.Trim();
  503. if (s1 == "[regedit_del]")
  504. {
  505. i = 0;
  506. }
  507. else if (s1 == "[regedit_add]")
  508. {
  509. i = 1;
  510. }
  511. else if (s1 == "[file_del]")
  512. {
  513. i = 2;
  514. }
  515. else
  516. {
  517. if (i == 0)
  518. {
  519. string[] tempKeys = s1.Split(',');
  520. DelRegistryKey(tempKeys[0], tempKeys[1]);
  521. }
  522. else if (i == 1)
  523. {
  524. string[] values = s1.Split('=');
  525. string[] tempKeys = values[0].Split(',');
  526. SetRegistryKey(tempKeys[0], tempKeys[1], values[1]);
  527. }
  528. else if (i == 2)
  529. {
  530. DelFile(Path.Combine(appPath, s1));
  531. }
  532. }
  533. }
  534. DelFile(Path.Combine(TheFolder.FullName, "config.update"));
  535. }
  536. return this;
  537. }
  538. /// <summary>
  539. /// 删除文件
  540. /// </summary>
  541. private UpdateWork DelFile(string name)
  542. {
  543. if (File.Exists(Path.Combine(appPath, name)))
  544. {
  545. FileInfo file = new FileInfo(Path.Combine(appPath, name));
  546. file.Delete();
  547. }
  548. return this;
  549. }
  550. /// <summary>
  551. /// 校验当前程序是否在运行
  552. /// </summary>
  553. /// <param name="programName"></param>
  554. /// <returns></returns>
  555. public bool CheckProcessExist()
  556. {
  557. return Process.GetProcessesByName(programName).Length > 0 ? true : false;
  558. }
  559. /// <summary>
  560. /// 杀掉当前运行的程序进程
  561. /// </summary>
  562. /// <param name="programName">程序名称</param>
  563. public void KillProcessExist()
  564. {
  565. Process[] processes = Process.GetProcessesByName(programName);
  566. foreach (Process p in processes)
  567. {
  568. p.Kill();
  569. p.Close();
  570. p.Dispose();
  571. }
  572. }
  573. #region 暂时没用,如果需要将本地版本放注册表的话 那是有用的
  574. /// <summary>
  575. /// 设置注册表值
  576. /// </summary>
  577. /// <param name="subKey"></param>
  578. /// <param name="key"></param>
  579. /// <param name="value"></param>
  580. private void SetRegistryKey(String subKey, String key, String value)
  581. {
  582. RegistryKey reg;
  583. RegistryKey reglocal = Registry.CurrentUser;
  584. reg = reglocal.OpenSubKey(subKey, true);
  585. if (reg == null)
  586. reg = reglocal.CreateSubKey(subKey);
  587. reg.SetValue(key, value, RegistryValueKind.String);
  588. if (reg != null)
  589. {
  590. reg.Close();
  591. }
  592. }
  593. private void DelRegistryKey(String subKey, String key)
  594. {
  595. RegistryKey reg;
  596. RegistryKey reglocal = Registry.CurrentUser;
  597. reg = reglocal.OpenSubKey(subKey, true);
  598. if (reg != null)
  599. {
  600. var res = reg.GetValue(key);
  601. if (res != null)
  602. {
  603. reg.DeleteValue(key);
  604. }
  605. }
  606. reg.Close();
  607. }
  608. #endregion
  609. }
  610. }