UpdateWork.cs 23 KB

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