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.

10 years ago
8 years ago
10 years ago
10 years ago
8 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. using System;
  2. using System.Diagnostics;
  3. using System.IO;
  4. using System.IO.Compression;
  5. using System.Runtime.InteropServices;
  6. using System.Windows.Forms;
  7. using Microsoft.Win32;
  8. using Shadowsocks.Controller;
  9. using Shadowsocks.Model;
  10. namespace Shadowsocks.Util
  11. {
  12. public struct BandwidthScaleInfo
  13. {
  14. public float value;
  15. public string unitName;
  16. public long unit;
  17. public BandwidthScaleInfo(float value, string unitName, long unit)
  18. {
  19. this.value = value;
  20. this.unitName = unitName;
  21. this.unit = unit;
  22. }
  23. }
  24. public static class Utils
  25. {
  26. private static string _tempPath = null;
  27. // return path to store temporary files
  28. public static string GetTempPath()
  29. {
  30. if (_tempPath == null)
  31. {
  32. bool isPortableMode = Configuration.Load().portableMode;
  33. try
  34. {
  35. if (isPortableMode)
  36. {
  37. _tempPath = Directory.CreateDirectory("ss_win_temp").FullName;
  38. // don't use "/", it will fail when we call explorer /select xxx/ss_win_temp\xxx.log
  39. }
  40. else
  41. {
  42. _tempPath = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), @"Shadowsocks\ss_win_temp_" + Application.ExecutablePath.GetHashCode())).FullName;
  43. }
  44. }
  45. catch (Exception e)
  46. {
  47. Logging.Error(e);
  48. throw;
  49. }
  50. }
  51. return _tempPath;
  52. }
  53. public enum WindowsThemeMode { Dark, Light }
  54. // Support on Windows 10 1903+
  55. public static WindowsThemeMode GetWindows10SystemThemeSetting(bool isVerbose)
  56. {
  57. WindowsThemeMode themeMode = WindowsThemeMode.Dark;
  58. try
  59. {
  60. RegistryKey reg_ThemesPersonalize = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", false);
  61. if (reg_ThemesPersonalize.GetValue("SystemUsesLightTheme") != null)
  62. {
  63. if ((int)(reg_ThemesPersonalize.GetValue("SystemUsesLightTheme")) == 0) // 0:dark mode, 1:light mode
  64. themeMode = WindowsThemeMode.Dark;
  65. else
  66. themeMode = WindowsThemeMode.Light;
  67. }
  68. else
  69. {
  70. throw new Exception("Reg-Value SystemUsesLightTheme not found.");
  71. }
  72. }
  73. catch
  74. {
  75. if (isVerbose)
  76. {
  77. Logging.Info(
  78. $"Cannot get Windows 10 system theme mode, return default value 0 (dark mode).");
  79. }
  80. }
  81. return themeMode;
  82. }
  83. // return a full path with filename combined which pointed to the temporary directory
  84. public static string GetTempPath(string filename)
  85. {
  86. return Path.Combine(GetTempPath(), filename);
  87. }
  88. public static void ReleaseMemory(bool removePages)
  89. {
  90. // release any unused pages
  91. // making the numbers look good in task manager
  92. // this is totally nonsense in programming
  93. // but good for those users who care
  94. // making them happier with their everyday life
  95. // which is part of user experience
  96. GC.Collect(GC.MaxGeneration);
  97. GC.WaitForPendingFinalizers();
  98. if (removePages)
  99. {
  100. // as some users have pointed out
  101. // removing pages from working set will cause some IO
  102. // which lowered user experience for another group of users
  103. //
  104. // so we do 2 more things here to satisfy them:
  105. // 1. only remove pages once when configuration is changed
  106. // 2. add more comments here to tell users that calling
  107. // this function will not be more frequent than
  108. // IM apps writing chat logs, or web browsers writing cache files
  109. // if they're so concerned about their disk, they should
  110. // uninstall all IM apps and web browsers
  111. //
  112. // please open an issue if you're worried about anything else in your computer
  113. // no matter it's GPU performance, monitor contrast, audio fidelity
  114. // or anything else in the task manager
  115. // we'll do as much as we can to help you
  116. //
  117. // just kidding
  118. SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle,
  119. (UIntPtr)0xFFFFFFFF,
  120. (UIntPtr)0xFFFFFFFF);
  121. }
  122. }
  123. public static string UnGzip(byte[] buf)
  124. {
  125. byte[] buffer = new byte[1024];
  126. int n;
  127. using (MemoryStream sb = new MemoryStream())
  128. {
  129. using (GZipStream input = new GZipStream(new MemoryStream(buf),
  130. CompressionMode.Decompress,
  131. false))
  132. {
  133. while ((n = input.Read(buffer, 0, buffer.Length)) > 0)
  134. {
  135. sb.Write(buffer, 0, n);
  136. }
  137. }
  138. return System.Text.Encoding.UTF8.GetString(sb.ToArray());
  139. }
  140. }
  141. public static string FormatBandwidth(long n)
  142. {
  143. var result = GetBandwidthScale(n);
  144. return $"{result.value:0.##}{result.unitName}";
  145. }
  146. public static string FormatBytes(long bytes)
  147. {
  148. const long K = 1024L;
  149. const long M = K * 1024L;
  150. const long G = M * 1024L;
  151. const long T = G * 1024L;
  152. const long P = T * 1024L;
  153. const long E = P * 1024L;
  154. if (bytes >= P * 990)
  155. return (bytes / (double)E).ToString("F5") + "EiB";
  156. if (bytes >= T * 990)
  157. return (bytes / (double)P).ToString("F5") + "PiB";
  158. if (bytes >= G * 990)
  159. return (bytes / (double)T).ToString("F5") + "TiB";
  160. if (bytes >= M * 990)
  161. {
  162. return (bytes / (double)G).ToString("F4") + "GiB";
  163. }
  164. if (bytes >= M * 100)
  165. {
  166. return (bytes / (double)M).ToString("F1") + "MiB";
  167. }
  168. if (bytes >= M * 10)
  169. {
  170. return (bytes / (double)M).ToString("F2") + "MiB";
  171. }
  172. if (bytes >= K * 990)
  173. {
  174. return (bytes / (double)M).ToString("F3") + "MiB";
  175. }
  176. if (bytes > K * 2)
  177. {
  178. return (bytes / (double)K).ToString("F1") + "KiB";
  179. }
  180. return bytes.ToString() + "B";
  181. }
  182. /// <summary>
  183. /// Return scaled bandwidth
  184. /// </summary>
  185. /// <param name="n">Raw bandwidth</param>
  186. /// <returns>
  187. /// The BandwidthScaleInfo struct
  188. /// </returns>
  189. public static BandwidthScaleInfo GetBandwidthScale(long n)
  190. {
  191. long scale = 1;
  192. float f = n;
  193. string unit = "B";
  194. if (f > 1024)
  195. {
  196. f = f / 1024;
  197. scale <<= 10;
  198. unit = "KiB";
  199. }
  200. if (f > 1024)
  201. {
  202. f = f / 1024;
  203. scale <<= 10;
  204. unit = "MiB";
  205. }
  206. if (f > 1024)
  207. {
  208. f = f / 1024;
  209. scale <<= 10;
  210. unit = "GiB";
  211. }
  212. if (f > 1024)
  213. {
  214. f = f / 1024;
  215. scale <<= 10;
  216. unit = "TiB";
  217. }
  218. return new BandwidthScaleInfo(f, unit, scale);
  219. }
  220. public static RegistryKey OpenRegKey(string name, bool writable, RegistryHive hive = RegistryHive.CurrentUser)
  221. {
  222. // we are building x86 binary for both x86 and x64, which will
  223. // cause problem when opening registry key
  224. // detect operating system instead of CPU
  225. if (name.IsNullOrEmpty()) throw new ArgumentException(nameof(name));
  226. try
  227. {
  228. RegistryKey userKey = RegistryKey.OpenBaseKey(hive,
  229. Environment.Is64BitOperatingSystem ? RegistryView.Registry64 : RegistryView.Registry32)
  230. .OpenSubKey(name, writable);
  231. return userKey;
  232. }
  233. catch (ArgumentException ae)
  234. {
  235. MessageBox.Show("OpenRegKey: " + ae.ToString());
  236. return null;
  237. }
  238. catch (Exception e)
  239. {
  240. Logging.LogUsefulException(e);
  241. return null;
  242. }
  243. }
  244. public static bool IsWinVistaOrHigher()
  245. {
  246. return Environment.OSVersion.Version.Major > 5;
  247. }
  248. [DllImport("kernel32.dll")]
  249. [return: MarshalAs(UnmanagedType.Bool)]
  250. private static extern bool SetProcessWorkingSetSize(IntPtr process,
  251. UIntPtr minimumWorkingSetSize, UIntPtr maximumWorkingSetSize);
  252. // See: https://msdn.microsoft.com/en-us/library/hh925568(v=vs.110).aspx
  253. public static bool IsSupportedRuntimeVersion()
  254. {
  255. /*
  256. * +-----------------------------------------------------------------+----------------------------+
  257. * | Version | Value of the Release DWORD |
  258. * +-----------------------------------------------------------------+----------------------------+
  259. * | .NET Framework 4.6.2 installed on Windows 10 Anniversary Update | 394802 |
  260. * | .NET Framework 4.6.2 installed on all other Windows OS versions | 394806 |
  261. * +-----------------------------------------------------------------+----------------------------+
  262. */
  263. const int minSupportedRelease = 394802;
  264. const string subkey = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\";
  265. using (var ndpKey = OpenRegKey(subkey, false, RegistryHive.LocalMachine))
  266. {
  267. if (ndpKey?.GetValue("Release") != null)
  268. {
  269. var releaseKey = (int)ndpKey.GetValue("Release");
  270. if (releaseKey >= minSupportedRelease)
  271. {
  272. return true;
  273. }
  274. }
  275. }
  276. return false;
  277. }
  278. }
  279. }