You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

AutoStartup.cs 5.9 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. using Microsoft.Win32;
  2. using Splat;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Diagnostics;
  6. using System.Linq;
  7. using System.Runtime.InteropServices;
  8. namespace Shadowsocks.WPF.Utils
  9. {
  10. public static class AutoStartup
  11. {
  12. private static readonly string registryRunKey = @"Software\Microsoft\Windows\CurrentVersion\Run";
  13. private static readonly string Key = "Shadowsocks_" + Utilities.ExecutablePath.GetHashCode();
  14. public static bool Set(bool enabled)
  15. {
  16. RegistryKey? runKey = null;
  17. try
  18. {
  19. runKey = Registry.CurrentUser.CreateSubKey(registryRunKey, RegistryKeyPermissionCheck.ReadWriteSubTree);
  20. if (runKey == null)
  21. {
  22. LogHost.Default.Error(@"Cannot find HKCU\{registryRunKey}.");
  23. return false;
  24. }
  25. if (enabled)
  26. {
  27. runKey.SetValue(Key, Utilities.ExecutablePath);
  28. }
  29. else
  30. {
  31. runKey.DeleteValue(Key);
  32. }
  33. // When autostartup setting change, change RegisterForRestart state to avoid start 2 times
  34. RegisterForRestart(!enabled);
  35. return true;
  36. }
  37. catch (Exception e)
  38. {
  39. LogHost.Default.Error(e, "An error occurred while setting auto startup registry entry.");
  40. return false;
  41. }
  42. finally
  43. {
  44. if (runKey != null)
  45. {
  46. try
  47. {
  48. runKey.Close();
  49. runKey.Dispose();
  50. }
  51. catch (Exception e)
  52. {
  53. LogHost.Default.Error(e, "An error occurred while setting auto startup registry entry.");
  54. }
  55. }
  56. }
  57. }
  58. public static bool Check()
  59. {
  60. RegistryKey? runKey = null;
  61. try
  62. {
  63. runKey = Registry.CurrentUser.CreateSubKey(registryRunKey, RegistryKeyPermissionCheck.ReadWriteSubTree);
  64. if (runKey == null)
  65. {
  66. LogHost.Default.Error(@"Cannot find HKCU\{registryRunKey}.");
  67. return false;
  68. }
  69. var check = false;
  70. foreach (var valueName in runKey.GetValueNames())
  71. {
  72. if (valueName.Equals(Key, StringComparison.InvariantCultureIgnoreCase))
  73. {
  74. check = true;
  75. continue;
  76. }
  77. // Remove other startup keys with the same executable path. fixes #3011 and also assures compatibility with older versions
  78. if (Utilities.ExecutablePath.Equals(runKey.GetValue(valueName)?.ToString(), StringComparison.InvariantCultureIgnoreCase)
  79. is bool matchedDuplicate && matchedDuplicate)
  80. {
  81. runKey.DeleteValue(valueName);
  82. runKey.SetValue(Key, Utilities.ExecutablePath);
  83. check = true;
  84. }
  85. }
  86. return check;
  87. }
  88. catch (Exception e)
  89. {
  90. LogHost.Default.Error(e, "An error occurred while checking auto startup registry entries.");
  91. return false;
  92. }
  93. finally
  94. {
  95. if (runKey != null)
  96. {
  97. try
  98. {
  99. runKey.Close();
  100. runKey.Dispose();
  101. }
  102. catch (Exception e)
  103. {
  104. LogHost.Default.Error(e, "An error occurred while checking auto startup registry entries.");
  105. }
  106. }
  107. }
  108. }
  109. [DllImport("kernel32.dll", SetLastError = true)]
  110. static extern int RegisterApplicationRestart([MarshalAs(UnmanagedType.LPWStr)] string commandLineArgs, int Flags);
  111. [DllImport("kernel32.dll", SetLastError = true)]
  112. static extern int UnregisterApplicationRestart();
  113. [Flags]
  114. enum ApplicationRestartFlags
  115. {
  116. RESTART_ALWAYS = 0,
  117. RESTART_NO_CRASH = 1,
  118. RESTART_NO_HANG = 2,
  119. RESTART_NO_PATCH = 4,
  120. RESTART_NO_REBOOT = 8,
  121. }
  122. // register restart after system reboot/update
  123. public static void RegisterForRestart(bool register)
  124. {
  125. // requested register and not autostartup
  126. if (register && !Check())
  127. {
  128. // escape command line parameter
  129. string[] args = new List<string>(Environment.GetCommandLineArgs())
  130. .Select(p => p.Replace("\"", "\\\"")) // escape " to \"
  131. .Select(p => p.IndexOf(" ") >= 0 ? "\"" + p + "\"" : p) // encapsule with "
  132. .ToArray();
  133. string cmdline = string.Join(" ", args);
  134. // first parameter is process command line parameter
  135. // needn't include the name of the executable in the command line
  136. RegisterApplicationRestart(cmdline, (int)(ApplicationRestartFlags.RESTART_NO_CRASH | ApplicationRestartFlags.RESTART_NO_HANG));
  137. LogHost.Default.Debug("Register restart after system reboot, command line:" + cmdline);
  138. }
  139. // requested unregister, which has no side effect
  140. else if (!register)
  141. {
  142. UnregisterApplicationRestart();
  143. LogHost.Default.Debug("Unregister restart after system reboot");
  144. }
  145. }
  146. }
  147. }