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.

Util.cs 11 kB

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