mirror of
				https://github.com/bolucat/Archive.git
				synced 2025-10-31 11:57:05 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			306 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C#
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			306 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C#
		
	
	
		
			Executable File
		
	
	
	
	
| using NLog;
 | |
| 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;
 | |
| using Shadowsocks.Model;
 | |
| using System.Drawing;
 | |
| using ZXing;
 | |
| using ZXing.QrCode;
 | |
| using ZXing.Common;
 | |
| 
 | |
| 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 Logger logger = LogManager.GetCurrentClassLogger();
 | |
| 
 | |
|         private static string _tempPath = null;
 | |
| 
 | |
|         // return path to store temporary files
 | |
|         public static string GetTempPath()
 | |
|         {
 | |
|             if (_tempPath == null)
 | |
|             {
 | |
|                 bool isPortableMode = Configuration.Load().portableMode;
 | |
|                 try
 | |
|                 {
 | |
|                     if (isPortableMode)
 | |
|                     {
 | |
|                         _tempPath = Directory.CreateDirectory("ss_win_temp").FullName;
 | |
|                         // don't use "/", it will fail when we call explorer /select xxx/ss_win_temp\xxx.log
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         _tempPath = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), @"Shadowsocks\ss_win_temp_" + Program.ExecutablePath.GetHashCode())).FullName;
 | |
|                     }
 | |
|                 }
 | |
|                 catch (Exception e)
 | |
|                 {
 | |
|                     logger.Error(e);
 | |
|                     throw;
 | |
|                 }
 | |
|             }
 | |
|             return _tempPath;
 | |
|         }
 | |
| 
 | |
|         public enum WindowsThemeMode { Dark, Light }
 | |
| 
 | |
|         // Support on Windows 10 1903+
 | |
|         public static WindowsThemeMode GetWindows10SystemThemeSetting()
 | |
|         {
 | |
|             WindowsThemeMode themeMode = WindowsThemeMode.Dark;
 | |
|             try
 | |
|             {
 | |
|                 RegistryKey reg_ThemesPersonalize = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", false);
 | |
|                 if (reg_ThemesPersonalize.GetValue("SystemUsesLightTheme") != null)
 | |
|                 {
 | |
|                     if ((int)(reg_ThemesPersonalize.GetValue("SystemUsesLightTheme")) == 0) // 0:dark mode, 1:light mode
 | |
|                         themeMode = WindowsThemeMode.Dark;
 | |
|                     else
 | |
|                         themeMode = WindowsThemeMode.Light;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     throw new Exception("Reg-Value SystemUsesLightTheme not found.");
 | |
|                 }
 | |
|             }
 | |
|             catch
 | |
|             {
 | |
| 
 | |
|                 logger.Debug(
 | |
|                         $"Cannot get Windows 10 system theme mode, return default value 0 (dark mode).");
 | |
| 
 | |
|             }
 | |
|             return themeMode;
 | |
|         }
 | |
| 
 | |
|         // 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 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";
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Return scaled bandwidth
 | |
|         /// </summary>
 | |
|         /// <param name="n">Raw bandwidth</param>
 | |
|         /// <returns>
 | |
|         /// The BandwidthScaleInfo struct
 | |
|         /// </returns>
 | |
|         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 (string.IsNullOrEmpty(name)) 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)
 | |
|             {
 | |
|                 logger.LogUsefulException(e);
 | |
|                 return null;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public static bool IsWinVistaOrHigher()
 | |
|         {
 | |
|             return Environment.OSVersion.Version.Major > 5;
 | |
|         }
 | |
| 
 | |
|         public static string ScanQRCodeFromScreen()
 | |
|         {
 | |
|             foreach (Screen screen in Screen.AllScreens)
 | |
|             {
 | |
|                 using (Bitmap fullImage = new Bitmap(screen.Bounds.Width,
 | |
|                                                 screen.Bounds.Height))
 | |
|                 {
 | |
|                     using (Graphics g = Graphics.FromImage(fullImage))
 | |
|                     {
 | |
|                         g.CopyFromScreen(screen.Bounds.X,
 | |
|                                          screen.Bounds.Y,
 | |
|                                          0, 0,
 | |
|                                          fullImage.Size,
 | |
|                                          CopyPixelOperation.SourceCopy);
 | |
|                     }
 | |
|                     int maxTry = 10;
 | |
|                     for (int i = 0; i < maxTry; i++)
 | |
|                     {
 | |
|                         int marginLeft = (int)((double)fullImage.Width * i / 2.5 / maxTry);
 | |
|                         int marginTop = (int)((double)fullImage.Height * i / 2.5 / maxTry);
 | |
|                         Rectangle cropRect = new Rectangle(marginLeft, marginTop, fullImage.Width - marginLeft * 2, fullImage.Height - marginTop * 2);
 | |
|                         Bitmap target = new Bitmap(screen.Bounds.Width, screen.Bounds.Height);
 | |
| 
 | |
|                         double imageScale = (double)screen.Bounds.Width / (double)cropRect.Width;
 | |
|                         using (Graphics g = Graphics.FromImage(target))
 | |
|                         {
 | |
|                             g.DrawImage(fullImage, new Rectangle(0, 0, target.Width, target.Height),
 | |
|                                             cropRect,
 | |
|                                             GraphicsUnit.Pixel);
 | |
|                         }
 | |
|                         var source = new BitmapLuminanceSource(target);
 | |
|                         var bitmap = new BinaryBitmap(new HybridBinarizer(source));
 | |
|                         QRCodeReader reader = new QRCodeReader();
 | |
|                         var result = reader.decode(bitmap);
 | |
|                         if (result != null)
 | |
|                             return result.Text;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             return null;
 | |
|         }
 | |
| 
 | |
|         // 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;
 | |
|         }
 | |
|     }
 | |
| }
 | 
![github-action[bot]](/assets/img/avatar_default.png)