diff --git a/shadowsocks-csharp/Controller/System/SystemProxy.cs b/shadowsocks-csharp/Controller/System/SystemProxy.cs index b53f4a65..b932b240 100644 --- a/shadowsocks-csharp/Controller/System/SystemProxy.cs +++ b/shadowsocks-csharp/Controller/System/SystemProxy.cs @@ -1,34 +1,11 @@ -using System.Windows.Forms; -using Microsoft.Win32; -using System; -using System.Runtime.InteropServices; -using System.IO; +using System; using Shadowsocks.Model; -using Shadowsocks.Util; +using Shadowsocks.Util.SystemProxy; namespace Shadowsocks.Controller { public static class SystemProxy { - - [DllImport("wininet.dll")] - public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength); - public const int INTERNET_OPTION_SETTINGS_CHANGED = 39; - public const int INTERNET_OPTION_REFRESH = 37; - static bool _settingsReturn, _refreshReturn; - - public static void NotifyIE() - { - // These lines implement the Interface in the beginning of program - // They cause the OS to refresh the settings, causing IP to realy update - _settingsReturn = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_SETTINGS_CHANGED, IntPtr.Zero, 0); - _refreshReturn = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_REFRESH, IntPtr.Zero, 0); - } - - private static readonly DateTime UnixEpoch - = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); - public static long ToUnixEpochMilliseconds(this DateTime dt) - => (long)(dt - UnixEpoch).TotalMilliseconds; private static string GetTimestamp(DateTime value) { return value.ToString("yyyyMMddHHmmssfff"); @@ -43,139 +20,27 @@ namespace Shadowsocks.Controller { enabled = false; } - RegistryKey registry = null; - try { - registry = Utils.OpenUserRegKey( @"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true ); - if ( registry == null ) { - Logging.Error( @"Cannot find HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" ); - return; - } - if ( enabled ) { - if ( global ) { - registry.SetValue( "ProxyEnable", 1 ); - registry.SetValue( "ProxyServer", "127.0.0.1:" + config.localPort.ToString() ); - registry.SetValue( "AutoConfigURL", "" ); - } else { - string pacUrl; - if ( config.useOnlinePac && ! config.pacUrl.IsNullOrEmpty() ) - pacUrl = config.pacUrl; - else - pacUrl = $"http://127.0.0.1:{config.localPort}/pac?t={GetTimestamp( DateTime.Now )}"; - registry.SetValue( "ProxyEnable", 0 ); - var readProxyServer = registry.GetValue( "ProxyServer" ); - registry.SetValue( "ProxyServer", "" ); - registry.SetValue( "AutoConfigURL", pacUrl ); - } - } else { - registry.SetValue( "ProxyEnable", 0 ); - registry.SetValue( "ProxyServer", "" ); - registry.SetValue( "AutoConfigURL", "" ); - } - - //Set AutoDetectProxy - IEAutoDetectProxy( ! enabled ); - NotifyIE(); - //Must Notify IE first, or the connections do not chanage - CopyProxySettingFromLan(); - } catch ( Exception e ) { - Logging.LogUsefulException( e ); - // TODO this should be moved into views - MessageBox.Show( I18N.GetString( "Failed to update registry" ) ); - } finally { - if ( registry != null ) { - try { - registry.Close(); - registry.Dispose(); - } catch (Exception e) - { Logging.LogUsefulException(e); } - } - } - } - - private static void CopyProxySettingFromLan() - { - RegistryKey registry = null; - try { - registry = Utils.OpenUserRegKey( @"Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections", true ); - if ( registry == null ) { - Logging.Error( @"Cannot find HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections" ); - return; - } - var defaultValue = registry.GetValue( "DefaultConnectionSettings" ); - var connections = registry.GetValueNames(); - foreach ( var each in connections ) { - switch ( each.ToUpperInvariant() ) { - case "DEFAULTCONNECTIONSETTINGS": - case "LAN CONNECTION": - case "SAVEDLEGACYSETTINGS": - continue; - default: - //set all the connections's proxy as the lan - registry.SetValue( each, defaultValue ); - continue; - } - } - NotifyIE(); - } catch ( IOException e ) { - Logging.LogUsefulException( e ); - } finally { - if ( registry != null ) { - try { - registry.Close(); - registry.Dispose(); - } catch (Exception e) - { Logging.LogUsefulException(e); } - } - } - } - - /// - /// Checks or unchecks the IE Options Connection setting of "Automatically detect Proxy" - /// - /// Provide 'true' if you want to check the 'Automatically detect Proxy' check box. To uncheck, pass 'false' - private static void IEAutoDetectProxy(bool set) - { - RegistryKey registry = null; - try { - registry = Utils.OpenUserRegKey( @"Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections", true ); - if ( registry == null ) { - Logging.Error( @"Cannot find HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections" ); - return; - } - var defConnection = ( byte[] ) registry.GetValue( "DefaultConnectionSettings" ); - var savedLegacySetting = ( byte[] ) registry.GetValue( "SavedLegacySettings" ); - - const int versionOffset = 4; - const int optionsOffset = 8; - - if ( set ) { - defConnection[ optionsOffset ] = ( byte ) ( defConnection[ optionsOffset ] | 8 ); - savedLegacySetting[ optionsOffset ] = ( byte ) ( savedLegacySetting[ optionsOffset ] | 8 ); - } else { - defConnection[ optionsOffset ] = ( byte ) ( defConnection[ optionsOffset ] & ~8 ); - savedLegacySetting[ optionsOffset ] = ( byte ) ( savedLegacySetting[ optionsOffset ] & ~8 ); + if (enabled) + { + if (global) + { + WinINet.SetIEProxy(true, true, "127.0.0.1:" + config.localPort.ToString(), ""); } - - BitConverter.GetBytes(unchecked( BitConverter.ToUInt32( defConnection, versionOffset ) + 1 ) ) - .CopyTo( defConnection, versionOffset ); - BitConverter.GetBytes(unchecked( BitConverter.ToUInt32( savedLegacySetting, versionOffset ) + 1 ) ) - .CopyTo( savedLegacySetting, versionOffset ); - - registry.SetValue( "DefaultConnectionSettings", defConnection ); - registry.SetValue( "SavedLegacySettings", savedLegacySetting ); - } catch ( Exception e ) { - Logging.LogUsefulException( e ); - } finally { - if (registry != null) + else { - try { - registry.Close(); - registry.Dispose(); - } catch (Exception e) - { Logging.LogUsefulException(e); } + string pacUrl; + if (config.useOnlinePac && !config.pacUrl.IsNullOrEmpty()) + pacUrl = config.pacUrl; + else + pacUrl = $"http://127.0.0.1:{config.localPort}/pac?t={GetTimestamp(DateTime.Now)}"; + WinINet.SetIEProxy(true, false, "", pacUrl); } } + else + { + WinINet.SetIEProxy(false, false, "", ""); + } } } -} +} \ No newline at end of file diff --git a/shadowsocks-csharp/Util/SystemProxy/INTERNET_OPTION.cs b/shadowsocks-csharp/Util/SystemProxy/INTERNET_OPTION.cs new file mode 100644 index 00000000..584b8e97 --- /dev/null +++ b/shadowsocks-csharp/Util/SystemProxy/INTERNET_OPTION.cs @@ -0,0 +1,36 @@ +/****************************** Module Header ******************************\ + Module Name: INTERNET_OPTION.cs + Project: CSWebBrowserWithProxy + Copyright (c) Microsoft Corporation. + + This enum contains 4 WinINet constants used in method InternetQueryOption and + InternetSetOption functions. + Visit http://msdn.microsoft.com/en-us/library/aa385328(VS.85).aspx to get the + whole constants list. + + This source is subject to the Microsoft Public License. + See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL. + All other rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, + EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. +\***************************************************************************/ + +namespace Shadowsocks.Util.SystemProxy +{ + public enum INTERNET_OPTION + { + // Sets or retrieves an INTERNET_PER_CONN_OPTION_LIST structure that specifies + // a list of options for a particular connection. + INTERNET_OPTION_PER_CONNECTION_OPTION = 75, + + // Notify the system that the registry settings have been changed so that + // it verifies the settings on the next call to InternetConnect. + INTERNET_OPTION_SETTINGS_CHANGED = 39, + + // Causes the proxy data to be reread from the registry for a handle. + INTERNET_OPTION_REFRESH = 37 + + } +} diff --git a/shadowsocks-csharp/Util/SystemProxy/INTERNET_PER_CONN_OPTION.cs b/shadowsocks-csharp/Util/SystemProxy/INTERNET_PER_CONN_OPTION.cs new file mode 100644 index 00000000..351aa1ca --- /dev/null +++ b/shadowsocks-csharp/Util/SystemProxy/INTERNET_PER_CONN_OPTION.cs @@ -0,0 +1,97 @@ +/****************************** Module Header ******************************\ + Module Name: INTERNET_PER_CONN_OPTION.cs + Project: CSWebBrowserWithProxy + Copyright (c) Microsoft Corporation. + + This file defines the struct INTERNET_PER_CONN_OPTION and constants used by it. + The struct INTERNET_PER_CONN_OPTION contains the value of an option that to be + set to internet settings. + Visit http://msdn.microsoft.com/en-us/library/aa385145(VS.85).aspx to get the + detailed description. + + This source is subject to the Microsoft Public License. + See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL. + All other rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, + EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. +\***************************************************************************/ + +using System; +using System.Runtime.InteropServices; + +namespace Shadowsocks.Util.SystemProxy +{ + /// + /// Constants used in INTERNET_PER_CONN_OPTION_OptionUnion struct. + /// + public enum INTERNET_PER_CONN_OptionEnum + { + INTERNET_PER_CONN_FLAGS = 1, + INTERNET_PER_CONN_PROXY_SERVER = 2, + INTERNET_PER_CONN_PROXY_BYPASS = 3, + INTERNET_PER_CONN_AUTOCONFIG_URL = 4, + INTERNET_PER_CONN_AUTODISCOVERY_FLAGS = 5, + INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL = 6, + INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS = 7, + INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME = 8, + INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL = 9, + INTERNET_PER_CONN_FLAGS_UI = 10 + } + + /// + /// Constants used in INTERNET_PER_CONN_OPTON struct. + /// + [Flags] + public enum INTERNET_OPTION_PER_CONN_FLAGS + { + PROXY_TYPE_DIRECT = 0x00000001, // direct to net + PROXY_TYPE_PROXY = 0x00000002, // via named proxy + PROXY_TYPE_AUTO_PROXY_URL = 0x00000004, // autoproxy URL + PROXY_TYPE_AUTO_DETECT = 0x00000008 // use autoproxy detection + } + + /// + /// Constants used in INTERNET_PER_CONN_OPTON struct. + /// Windows 7 and later: + /// Clients that support Internet Explorer 8 should query the connection type using INTERNET_PER_CONN_FLAGS_UI. + /// If this query fails, then the system is running a previous version of Internet Explorer and the client should + /// query again with INTERNET_PER_CONN_FLAGS. + /// Restore the connection type using INTERNET_PER_CONN_FLAGS regardless of the version of Internet Explorer. + /// XXX: If fails, notify user to upgrade Internet Explorer + /// + [Flags] + public enum INTERNET_OPTION_PER_CONN_FLAGS_UI + { + PROXY_TYPE_DIRECT = 0x00000001, // direct to net + PROXY_TYPE_PROXY = 0x00000002, // via named proxy + PROXY_TYPE_AUTO_PROXY_URL = 0x00000004, // autoproxy URL + PROXY_TYPE_AUTO_DETECT = 0x00000008 // use autoproxy detection + } + + /// + /// Used in INTERNET_PER_CONN_OPTION. + /// When create a instance of OptionUnion, only one filed will be used. + /// The StructLayout and FieldOffset attributes could help to decrease the struct size. + /// + [StructLayout(LayoutKind.Explicit)] + public struct INTERNET_PER_CONN_OPTION_OptionUnion + { + // A value in INTERNET_OPTION_PER_CONN_FLAGS. + [FieldOffset(0)] + public int dwValue; + [FieldOffset(0)] + public System.IntPtr pszValue; + [FieldOffset(0)] + public System.Runtime.InteropServices.ComTypes.FILETIME ftValue; + } + + [StructLayout(LayoutKind.Sequential)] + public struct INTERNET_PER_CONN_OPTION + { + // A value in INTERNET_PER_CONN_OptionEnum. + public int dwOption; + public INTERNET_PER_CONN_OPTION_OptionUnion Value; + } +} diff --git a/shadowsocks-csharp/Util/SystemProxy/INTERNET_PER_CONN_OPTION_LIST.cs b/shadowsocks-csharp/Util/SystemProxy/INTERNET_PER_CONN_OPTION_LIST.cs new file mode 100644 index 00000000..b15870ce --- /dev/null +++ b/shadowsocks-csharp/Util/SystemProxy/INTERNET_PER_CONN_OPTION_LIST.cs @@ -0,0 +1,38 @@ +/****************************** Module Header ******************************\ + Module Name: INTERNET_PER_CONN_OPTION_LIST.cs + Project: CSWebBrowserWithProxy + Copyright (c) Microsoft Corporation. + + The struct INTERNET_PER_CONN_OPTION contains a list of options that to be + set to internet connection. + Visit http://msdn.microsoft.com/en-us/library/aa385146(VS.85).aspx to get the + detailed description. + + This source is subject to the Microsoft Public License. + See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL. + All other rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, + EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. +\***************************************************************************/ + +using System.Runtime.InteropServices; + +namespace Shadowsocks.Util.SystemProxy +{ + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + public struct INTERNET_PER_CONN_OPTION_LIST + { + public int Size; + + // The connection to be set. NULL means LAN. + public System.IntPtr Connection; + + public int OptionCount; + public int OptionError; + + // List of INTERNET_PER_CONN_OPTIONs. + public System.IntPtr pOptions; + } +} diff --git a/shadowsocks-csharp/Util/SystemProxy/NativeMethods.cs b/shadowsocks-csharp/Util/SystemProxy/NativeMethods.cs new file mode 100644 index 00000000..ab90c569 --- /dev/null +++ b/shadowsocks-csharp/Util/SystemProxy/NativeMethods.cs @@ -0,0 +1,36 @@ +/****************************** Module Header ******************************\ + Module Name: NativeMethods.cs + Project: CSWebBrowserWithProxy + Copyright (c) Microsoft Corporation. + + This class is a simple .NET wrapper of wininet.dll. It contains 4 extern + methods in wininet.dll. They are InternetOpen, InternetCloseHandle, + InternetSetOption and InternetQueryOption. + + This source is subject to the Microsoft Public License. + See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL. + All other rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, + EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. +\***************************************************************************/ + +using System; +using System.Runtime.InteropServices; + +namespace Shadowsocks.Util.SystemProxy +{ + internal static class NativeMethods + { + /// + /// Sets an Internet option. + /// + [DllImport("wininet.dll", CharSet = CharSet.Ansi, SetLastError = true)] + internal static extern bool InternetSetOption( + IntPtr hInternet, + INTERNET_OPTION dwOption, + IntPtr lpBuffer, + int lpdwBufferLength); + } +} diff --git a/shadowsocks-csharp/Util/SystemProxy/WinINet.cs b/shadowsocks-csharp/Util/SystemProxy/WinINet.cs new file mode 100644 index 00000000..a1de566c --- /dev/null +++ b/shadowsocks-csharp/Util/SystemProxy/WinINet.cs @@ -0,0 +1,152 @@ +/****************************** Module Header ******************************\ + Module Name: WinINet.cs + Project: CSWebBrowserWithProxy + Copyright (c) Microsoft Corporation. + + This class is used to set the proxy. or restore to the system proxy for the + current application + + This source is subject to the Microsoft Public License. + See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL. + All other rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, + EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. +\***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; + +namespace Shadowsocks.Util.SystemProxy +{ + public static class WinINet + { + /// + /// Set IE settings for LAN connection. + /// + public static void SetIEProxy(bool enable, bool global, string proxyServer, string pacURL) + { + List _optionlist = new List(); + if (enable) + { + if (global) + { + // global proxy + _optionlist.Add(new INTERNET_PER_CONN_OPTION + { + dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_FLAGS_UI, + Value = { dwValue = (int)INTERNET_OPTION_PER_CONN_FLAGS_UI.PROXY_TYPE_PROXY } + }); + _optionlist.Add(new INTERNET_PER_CONN_OPTION + { + dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_PROXY_SERVER, + Value = { pszValue = Marshal.StringToHGlobalAnsi(proxyServer) } + }); + _optionlist.Add(new INTERNET_PER_CONN_OPTION + { + dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_PROXY_BYPASS, + Value = { pszValue = Marshal.StringToHGlobalAnsi("") } + }); + } + else + { + // pac + _optionlist.Add(new INTERNET_PER_CONN_OPTION + { + dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_FLAGS_UI, + Value = { dwValue = (int)INTERNET_OPTION_PER_CONN_FLAGS_UI.PROXY_TYPE_AUTO_PROXY_URL } + }); + _optionlist.Add(new INTERNET_PER_CONN_OPTION + { + dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_AUTOCONFIG_URL, + Value = { pszValue = Marshal.StringToHGlobalAnsi(pacURL) } + }); + } + } + else + { + // direct + _optionlist.Add(new INTERNET_PER_CONN_OPTION + { + dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_FLAGS_UI, + Value = { dwValue = (int)(INTERNET_OPTION_PER_CONN_FLAGS_UI.PROXY_TYPE_AUTO_DETECT + | INTERNET_OPTION_PER_CONN_FLAGS_UI.PROXY_TYPE_DIRECT) } + }); + } + + // Get total length of INTERNET_PER_CONN_OPTIONs + var len = _optionlist.Sum(each => Marshal.SizeOf(each)); + + // Allocate a block of memory of the options. + IntPtr buffer = Marshal.AllocCoTaskMem(len); + + IntPtr current = buffer; + + // Marshal data from a managed object to an unmanaged block of memory. + foreach (INTERNET_PER_CONN_OPTION eachOption in _optionlist) + { + Marshal.StructureToPtr(eachOption, current, false); + current = (IntPtr)((int)current + Marshal.SizeOf(eachOption)); + } + + // Initialize a INTERNET_PER_CONN_OPTION_LIST instance. + INTERNET_PER_CONN_OPTION_LIST optionList = new INTERNET_PER_CONN_OPTION_LIST(); + + // Point to the allocated memory. + optionList.pOptions = buffer; + + // Return the unmanaged size of an object in bytes. + optionList.Size = Marshal.SizeOf(optionList); + + // IntPtr.Zero means LAN connection. + optionList.Connection = IntPtr.Zero; + + optionList.OptionCount = _optionlist.Count; + optionList.OptionError = 0; + int optionListSize = Marshal.SizeOf(optionList); + + // Allocate memory for the INTERNET_PER_CONN_OPTION_LIST instance. + IntPtr intptrStruct = Marshal.AllocCoTaskMem(optionListSize); + + // Marshal data from a managed object to an unmanaged block of memory. + Marshal.StructureToPtr(optionList, intptrStruct, true); + + // Set internet settings. + bool bReturn = NativeMethods.InternetSetOption( + IntPtr.Zero, + INTERNET_OPTION.INTERNET_OPTION_PER_CONNECTION_OPTION, + intptrStruct, optionListSize); + + // Free the allocated memory. + foreach (var v in _optionlist) + { + // free strings + if (v.Value.pszValue != IntPtr.Zero) + Marshal.FreeHGlobal(v.Value.pszValue); + } + Marshal.FreeCoTaskMem(buffer); + Marshal.FreeCoTaskMem(intptrStruct); + + // Throw an exception if this operation failed. + if (!bReturn) + { + throw new Exception("InternetSetOption: " + Marshal.GetLastWin32Error()); + } + + // Notify the system that the registry settings have been changed and cause + // the proxy data to be reread from the registry for a handle. + NativeMethods.InternetSetOption( + IntPtr.Zero, + INTERNET_OPTION.INTERNET_OPTION_SETTINGS_CHANGED, + IntPtr.Zero, 0); + + NativeMethods.InternetSetOption( + IntPtr.Zero, + INTERNET_OPTION.INTERNET_OPTION_REFRESH, + IntPtr.Zero, 0); + } + } +} diff --git a/shadowsocks-csharp/Util/Util.cs b/shadowsocks-csharp/Util/Util.cs index d59cfaf1..e6017432 100755 --- a/shadowsocks-csharp/Util/Util.cs +++ b/shadowsocks-csharp/Util/Util.cs @@ -5,6 +5,7 @@ using System.IO; using System.IO.Compression; using System.Linq; using System.Runtime.InteropServices; +using System.Security; using System.Windows.Forms; using Microsoft.Win32; using Shadowsocks.Controller; @@ -210,14 +211,34 @@ namespace Shadowsocks.Util return new BandwidthScaleInfo(f, unit, scale); } - public static RegistryKey OpenUserRegKey( string name, bool writable ) { + public static RegistryKey OpenUserRegKey( string name, bool writable ) + { // we are building x86 binary for both x86 and x64, which will // cause problem when opening registry key // detect operating system instead of CPU - RegistryKey userKey = RegistryKey.OpenRemoteBaseKey( RegistryHive.CurrentUser, "", - Environment.Is64BitOperatingSystem ? RegistryView.Registry64 : RegistryView.Registry32 ) - .OpenSubKey( name, writable ); - return userKey; + if (name.IsNullOrEmpty()) throw new ArgumentException(nameof(name)); + try + { + RegistryKey userKey = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, + Environment.Is64BitOperatingSystem ? RegistryView.Registry64 : RegistryView.Registry32) + .OpenSubKey(name, writable); + return userKey; + } + catch (UnauthorizedAccessException uae) + { + Logging.LogUsefulException(uae); + return null; + } + catch (SecurityException se) + { + Logging.LogUsefulException(se); + return null; + } + catch (ArgumentException ae) + { + MessageBox.Show("OpenUserRegKey: " + ae.ToString()); + return null; + } } public static bool IsWinVistaOrHigher() { diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj index 36ef328d..92680f73 100644 --- a/shadowsocks-csharp/shadowsocks-csharp.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp.csproj @@ -190,6 +190,11 @@ + + + + + Form