Get rid of tricky registry handling Several files come from https://code.msdn.microsoft.com/windowsapps/CSWebBrowserWithProxy-c8535715/view/SourceCode Signed-off-by: Syrone Wong <wong.syrone@gmail.com>tags/3.3.3
@@ -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.Model; | ||||
using Shadowsocks.Util; | |||||
using Shadowsocks.Util.SystemProxy; | |||||
namespace Shadowsocks.Controller | namespace Shadowsocks.Controller | ||||
{ | { | ||||
public static class SystemProxy | 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) | private static string GetTimestamp(DateTime value) | ||||
{ | { | ||||
return value.ToString("yyyyMMddHHmmssfff"); | return value.ToString("yyyyMMddHHmmssfff"); | ||||
@@ -43,139 +20,27 @@ namespace Shadowsocks.Controller | |||||
{ | { | ||||
enabled = false; | 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); } | |||||
} | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// Checks or unchecks the IE Options Connection setting of "Automatically detect Proxy" | |||||
/// </summary> | |||||
/// <param name="set">Provide 'true' if you want to check the 'Automatically detect Proxy' check box. To uncheck, pass 'false'</param> | |||||
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, "", ""); | |||||
} | |||||
} | } | ||||
} | } | ||||
} | |||||
} |
@@ -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 | |||||
} | |||||
} |
@@ -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 | |||||
{ | |||||
/// <summary> | |||||
/// Constants used in INTERNET_PER_CONN_OPTION_OptionUnion struct. | |||||
/// </summary> | |||||
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 | |||||
} | |||||
/// <summary> | |||||
/// Constants used in INTERNET_PER_CONN_OPTON struct. | |||||
/// </summary> | |||||
[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 | |||||
} | |||||
/// <summary> | |||||
/// 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 | |||||
/// </summary> | |||||
[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 | |||||
} | |||||
/// <summary> | |||||
/// 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. | |||||
/// </summary> | |||||
[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; | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} |
@@ -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 | |||||
{ | |||||
/// <summary> | |||||
/// Sets an Internet option. | |||||
/// </summary> | |||||
[DllImport("wininet.dll", CharSet = CharSet.Ansi, SetLastError = true)] | |||||
internal static extern bool InternetSetOption( | |||||
IntPtr hInternet, | |||||
INTERNET_OPTION dwOption, | |||||
IntPtr lpBuffer, | |||||
int lpdwBufferLength); | |||||
} | |||||
} |
@@ -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 | |||||
{ | |||||
/// <summary> | |||||
/// Set IE settings for LAN connection. | |||||
/// </summary> | |||||
public static void SetIEProxy(bool enable, bool global, string proxyServer, string pacURL) | |||||
{ | |||||
List<INTERNET_PER_CONN_OPTION> _optionlist = new List<INTERNET_PER_CONN_OPTION>(); | |||||
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("<local>") } | |||||
}); | |||||
} | |||||
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); | |||||
} | |||||
} | |||||
} |
@@ -5,6 +5,7 @@ using System.IO; | |||||
using System.IO.Compression; | using System.IO.Compression; | ||||
using System.Linq; | using System.Linq; | ||||
using System.Runtime.InteropServices; | using System.Runtime.InteropServices; | ||||
using System.Security; | |||||
using System.Windows.Forms; | using System.Windows.Forms; | ||||
using Microsoft.Win32; | using Microsoft.Win32; | ||||
using Shadowsocks.Controller; | using Shadowsocks.Controller; | ||||
@@ -210,14 +211,34 @@ namespace Shadowsocks.Util | |||||
return new BandwidthScaleInfo(f, unit, scale); | 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 | // we are building x86 binary for both x86 and x64, which will | ||||
// cause problem when opening registry key | // cause problem when opening registry key | ||||
// detect operating system instead of CPU | // 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() { | public static bool IsWinVistaOrHigher() { | ||||
@@ -190,6 +190,11 @@ | |||||
<Compile Include="Util\Sockets\LineReader.cs" /> | <Compile Include="Util\Sockets\LineReader.cs" /> | ||||
<Compile Include="Util\Sockets\SocketUtil.cs" /> | <Compile Include="Util\Sockets\SocketUtil.cs" /> | ||||
<Compile Include="Util\Sockets\WrappedSocket.cs" /> | <Compile Include="Util\Sockets\WrappedSocket.cs" /> | ||||
<Compile Include="Util\SystemProxy\INTERNET_OPTION.cs" /> | |||||
<Compile Include="Util\SystemProxy\INTERNET_PER_CONN_OPTION.cs" /> | |||||
<Compile Include="Util\SystemProxy\INTERNET_PER_CONN_OPTION_LIST.cs" /> | |||||
<Compile Include="Util\SystemProxy\NativeMethods.cs" /> | |||||
<Compile Include="Util\SystemProxy\WinINet.cs" /> | |||||
<Compile Include="Util\Util.cs" /> | <Compile Include="Util\Util.cs" /> | ||||
<Compile Include="View\ConfigForm.cs"> | <Compile Include="View\ConfigForm.cs"> | ||||
<SubType>Form</SubType> | <SubType>Form</SubType> | ||||