diff --git a/test/source.cs b/test/source.cs index e69de29..b2aad3b 100644 --- a/test/source.cs +++ b/test/source.cs @@ -0,0 +1,259 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.IO.Compression; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using Microsoft.Win32; +using Shadowsocks.Controller; + +namespace Shadowsocks.Util +{ + public struct BandwidthScaleInfo + { + public float value; + public string unitName; + public long unit; + + public BandwidthScaleInfo(float value, string unitName, long unit) + { + this.value = value; + this.unitName = unitName; + this.unit = unit; + } + } + + public static class Utils + { + private static string _tempPath = null; + + // return path to store temporary files + public static string GetTempPath() + { + if (_tempPath == null) + { + try + { + Directory.CreateDirectory(Path.Combine(Application.StartupPath, "ss_win_temp")); + // don't use "/", it will fail when we call explorer /select xxx/ss_win_temp\xxx.log + _tempPath = Path.Combine(Application.StartupPath, "ss_win_temp"); + } + catch (Exception e) + { + Logging.Error(e); + throw; + } + } + return _tempPath; + } + + // return a full path with filename combined which pointed to the temporary directory + public static string GetTempPath(string filename) + { + return Path.Combine(GetTempPath(), filename); + } + + public static void ReleaseMemory(bool removePages) + { + // release any unused pages + // making the numbers look good in task manager + // this is totally nonsense in programming + // but good for those users who care + // making them happier with their everyday life + // which is part of user experience + GC.Collect(GC.MaxGeneration); + GC.WaitForPendingFinalizers(); + if (removePages) + { + // as some users have pointed out + // removing pages from working set will cause some IO + // which lowered user experience for another group of users + // + // so we do 2 more things here to satisfy them: + // 1. only remove pages once when configuration is changed + // 2. add more comments here to tell users that calling + // this function will not be more frequent than + // IM apps writing chat logs, or web browsers writing cache files + // if they're so concerned about their disk, they should + // uninstall all IM apps and web browsers + // + // please open an issue if you're worried about anything else in your computer + // no matter it's GPU performance, monitor contrast, audio fidelity + // or anything else in the task manager + // we'll do as much as we can to help you + // + // just kidding + SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle, + (UIntPtr)0xFFFFFFFF, + (UIntPtr)0xFFFFFFFF); + } + } + + public static string UnGzip(byte[] buf) + { + byte[] buffer = new byte[1024]; + int n; + using (MemoryStream sb = new MemoryStream()) + { + using (GZipStream input = new GZipStream(new MemoryStream(buf), + CompressionMode.Decompress, + false)) + { + while ((n = input.Read(buffer, 0, buffer.Length)) > 0) + { + sb.Write(buffer, 0, n); + } + } + return System.Text.Encoding.UTF8.GetString(sb.ToArray()); + } + } + + public static string FormatBandwidth(long n) + { + var result = GetBandwidthScale(n); + return $"{result.value:0.##}{result.unitName}"; + } + + public static string FormatBytes(long bytes) + { + const long K = 1024L; + const long M = K * 1024L; + const long G = M * 1024L; + const long T = G * 1024L; + const long P = T * 1024L; + const long E = P * 1024L; + + if (bytes >= P * 990) + return (bytes / (double)E).ToString("F5") + "EiB"; + if (bytes >= T * 990) + return (bytes / (double)P).ToString("F5") + "PiB"; + if (bytes >= G * 990) + return (bytes / (double)T).ToString("F5") + "TiB"; + if (bytes >= M * 990) + { + return (bytes / (double)G).ToString("F4") + "GiB"; + } + if (bytes >= M * 100) + { + return (bytes / (double)M).ToString("F1") + "MiB"; + } + if (bytes >= M * 10) + { + return (bytes / (double)M).ToString("F2") + "MiB"; + } + if (bytes >= K * 990) + { + return (bytes / (double)M).ToString("F3") + "MiB"; + } + if (bytes > K * 2) + { + return (bytes / (double)K).ToString("F1") + "KiB"; + } + return bytes.ToString() + "B"; + } + + /// + /// Return scaled bandwidth + /// + /// Raw bandwidth + /// + /// The BandwidthScaleInfo struct + /// + public static BandwidthScaleInfo GetBandwidthScale(long n) + { + long scale = 1; + float f = n; + string unit = "B"; + if (f > 1024) + { + f = f / 1024; + scale <<= 10; + unit = "KiB"; + } + if (f > 1024) + { + f = f / 1024; + scale <<= 10; + unit = "MiB"; + } + if (f > 1024) + { + f = f / 1024; + scale <<= 10; + unit = "GiB"; + } + if (f > 1024) + { + f = f / 1024; + scale <<= 10; + unit = "TiB"; + } + return new BandwidthScaleInfo(f, unit, scale); + } + + public static RegistryKey OpenRegKey(string name, bool writable, RegistryHive hive = RegistryHive.CurrentUser) + { + // we are building x86 binary for both x86 and x64, which will + // cause problem when opening registry key + // detect operating system instead of CPU + if (name.IsNullOrEmpty()) throw new ArgumentException(nameof(name)); + try + { + RegistryKey userKey = RegistryKey.OpenBaseKey(hive, + Environment.Is64BitOperatingSystem ? RegistryView.Registry64 : RegistryView.Registry32) + .OpenSubKey(name, writable); + return userKey; + } + catch (ArgumentException ae) + { + MessageBox.Show("OpenRegKey: " + ae.ToString()); + return null; + } + catch (Exception e) + { + Logging.LogUsefulException(e); + return null; + } + } + + public static bool IsWinVistaOrHigher() + { + return Environment.OSVersion.Version.Major > 5; + } + + [DllImport("kernel32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool SetProcessWorkingSetSize(IntPtr process, + UIntPtr minimumWorkingSetSize, UIntPtr maximumWorkingSetSize); + + + // See: https://msdn.microsoft.com/en-us/library/hh925568(v=vs.110).aspx + public static bool IsSupportedRuntimeVersion() + { + /* + * +-----------------------------------------------------------------+----------------------------+ + * | Version | Value of the Release DWORD | + * +-----------------------------------------------------------------+----------------------------+ + * | .NET Framework 4.6.2 installed on Windows 10 Anniversary Update | 394802 | + * | .NET Framework 4.6.2 installed on all other Windows OS versions | 394806 | + * +-----------------------------------------------------------------+----------------------------+ + */ + const int minSupportedRelease = 394802; + + const string subkey = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\"; + using (var ndpKey = OpenRegKey(subkey, false, RegistryHive.LocalMachine)) + { + if (ndpKey?.GetValue("Release") != null) + { + var releaseKey = (int)ndpKey.GetValue("Release"); + + if (releaseKey >= minSupportedRelease) + { + return true; + } + } + } + return false; + } + } +} \ No newline at end of file