Browse Source

Merge branch 'net-core' of https://github.com/shadowsocks/shadowsocks-windows into net-core

pull/2877/head
database64128 5 years ago
parent
commit
0348156ea0
9 changed files with 551 additions and 313 deletions
  1. +5
    -10
      shadowsocks-csharp/Controller/System/SystemProxy.cs
  2. BIN
      shadowsocks-csharp/Data/sysproxy.exe.gz
  3. BIN
      shadowsocks-csharp/Data/sysproxy64.exe.gz
  4. +0
    -6
      shadowsocks-csharp/Properties/Resources.resx
  5. +92
    -0
      shadowsocks-csharp/Util/SystemProxy/RAS.cs
  6. +0
    -291
      shadowsocks-csharp/Util/SystemProxy/Sysproxy.cs
  7. +447
    -0
      shadowsocks-csharp/Util/SystemProxy/WinINet.cs
  8. +7
    -2
      shadowsocks-csharp/View/MenuViewController.cs
  9. +0
    -4
      shadowsocks-csharp/shadowsocks-csharp.csproj

+ 5
- 10
shadowsocks-csharp/Controller/System/SystemProxy.cs View File

@@ -10,17 +10,12 @@ namespace Shadowsocks.Controller
{
private static Logger logger = LogManager.GetCurrentClassLogger();
private static string GetTimestamp(DateTime value)
{
return value.ToString("yyyyMMddHHmmssfff");
}
public static void Update(Configuration config, bool forceDisable, PACServer pacSrv, bool noRetry = false)
{
bool global = config.global;
bool enabled = config.enabled;
if (forceDisable)
if (forceDisable || WinINet.operational)
{
enabled = false;
}
@@ -31,7 +26,7 @@ namespace Shadowsocks.Controller
{
if (global)
{
Sysproxy.SetIEProxy(true, true, "localhost:" + config.localPort.ToString(), null);
WinINet.ProxyGlobal("localhost:" + config.localPort.ToString(), "<local>");
}
else
{
@@ -45,12 +40,12 @@ namespace Shadowsocks.Controller
pacUrl = pacSrv.PacUrl;
}
Sysproxy.SetIEProxy(true, false, null, pacUrl);
WinINet.ProxyPAC(pacUrl);
}
}
else
{
Sysproxy.SetIEProxy(false, false, null, null);
WinINet.Restore();
}
}
catch (ProxyException ex)
@@ -61,7 +56,7 @@ namespace Shadowsocks.Controller
var ret = MessageBox.Show(I18N.GetString("Error occured when process proxy setting, do you want reset current setting and retry?"), I18N.GetString("Shadowsocks"), MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
if (ret == DialogResult.Yes)
{
Sysproxy.ResetIEProxy();
WinINet.Reset();
Update(config, forceDisable, pacSrv, true);
}
}


BIN
shadowsocks-csharp/Data/sysproxy.exe.gz View File


BIN
shadowsocks-csharp/Data/sysproxy64.exe.gz View File


+ 0
- 6
shadowsocks-csharp/Properties/Resources.resx View File

@@ -151,12 +151,6 @@
<data name="ssw128" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\ssw128.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="sysproxy64_exe" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Data\sysproxy64.exe.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="sysproxy_exe" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Data\sysproxy.exe.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="user_rule" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\data\user-rule.txt;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>

+ 92
- 0
shadowsocks-csharp/Util/SystemProxy/RAS.cs View File

@@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace Shadowsocks.Util.SystemProxy
{

enum RasFieldSizeConst
{
MaxEntryName = 256,
MaxPath = 260,
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct RasEntryName
{
public int dwSize;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS.MaxEntryName + 1)]
public string szEntryName;

public int dwFlags;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS.MaxPath + 1)]
public string szPhonebookPath;
}
class RAS
{
public const int MaxEntryName = 256;
public const int MaxPath = 260;

const int ESuccess = 0;
const int RasBase = 600;
const int EBufferTooSmall = 603;

[DllImport("rasapi32.dll", CharSet = CharSet.Auto)]
private static extern uint RasEnumEntries(
// reserved, must be NULL
string reserved,
// pointer to full path and file name of phone-book file
string lpszPhonebook,
// buffer to receive phone-book entries
[In, Out] RasEntryName[] lprasentryname,
// size in bytes of buffer
ref int lpcb,
// number of entries written to buffer
out int lpcEntries
);

public static string[] GetAllConnections()
{
int lpNames = 0;
int entryNameSize = 0;
int lpSize = 0;
uint retval = ESuccess;
RasEntryName[] names = null;

entryNameSize = Marshal.SizeOf(typeof(RasEntryName));

// Windows Vista or later: To determine the required buffer size, call RasEnumEntries
// with lprasentryname set to NULL. The variable pointed to by lpcb should be set to zero.
// The function will return the required buffer size in lpcb and an error code of ERROR_BUFFER_TOO_SMALL.
retval = RasEnumEntries(null, null, null, ref lpSize, out lpNames);
if (retval == EBufferTooSmall)
{
names = new RasEntryName[lpNames];
for (int i = 0; i < names.Length; i++)
{
names[i].dwSize = entryNameSize;
}

retval = RasEnumEntries(null, null, names, ref lpSize, out lpNames);
}

if (retval == ESuccess)
{
if (lpNames == 0)
{
// no entries found.
return Array.Empty<string>();
}
return names.Select(n => n.szEntryName).ToArray();
}
else
{
throw new Exception();
}
}
}
}

+ 0
- 291
shadowsocks-csharp/Util/SystemProxy/Sysproxy.cs View File

@@ -1,291 +0,0 @@
using Newtonsoft.Json;
using NLog;
using Shadowsocks.Controller;
using Shadowsocks.Model;
using Shadowsocks.Properties;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
namespace Shadowsocks.Util.SystemProxy
{
public static class Sysproxy
{
private static Logger logger = LogManager.GetCurrentClassLogger();
private const string _userWininetConfigFile = "user-wininet.json";
private readonly static string[] _lanIP = {
"<local>",
"localhost",
"127.*",
"10.*",
"172.16.*",
"172.17.*",
"172.18.*",
"172.19.*",
"172.20.*",
"172.21.*",
"172.22.*",
"172.23.*",
"172.24.*",
"172.25.*",
"172.26.*",
"172.27.*",
"172.28.*",
"172.29.*",
"172.30.*",
"172.31.*",
"192.168.*"
};
private static string _queryStr;
// In general, this won't change
// format:
// <flags><CR-LF>
// <proxy-server><CR-LF>
// <bypass-list><CR-LF>
// <pac-url>
private static SysproxyConfig _userSettings = null;
enum RET_ERRORS : int
{
RET_NO_ERROR = 0,
INVALID_FORMAT = 1,
NO_PERMISSION = 2,
SYSCALL_FAILED = 3,
NO_MEMORY = 4,
INVAILD_OPTION_COUNT = 5,
};
static Sysproxy()
{
try
{
FileManager.UncompressFile(Utils.GetTempPath("sysproxy.exe"),
Environment.Is64BitOperatingSystem ? Resources.sysproxy64_exe : Resources.sysproxy_exe);
}
catch (IOException e)
{
logger.LogUsefulException(e);
}
}
public static void SetIEProxy(bool enable, bool global, string proxyServer, string pacURL)
{
Read();
if (!_userSettings.UserSettingsRecorded)
{
// record user settings
ExecSysproxy("query");
ParseQueryStr(_queryStr);
}
string arguments;
if (enable)
{
string customBypassString = _userSettings.BypassList ?? "";
List<string> customBypassList = new List<string>(customBypassString.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries));
customBypassList.AddRange(_lanIP);
string[] realBypassList = customBypassList.Distinct().ToArray();
string realBypassString = string.Join(";", realBypassList);
arguments = global
? $"global {proxyServer} {realBypassString}"
: $"pac {pacURL}";
}
else
{
// restore user settings
var flags = _userSettings.Flags;
var proxy_server = _userSettings.ProxyServer ?? "-";
var bypass_list = _userSettings.BypassList ?? "-";
var pac_url = _userSettings.PacUrl ?? "-";
arguments = $"set {flags} {proxy_server} {bypass_list} {pac_url}";
// have to get new settings
_userSettings.UserSettingsRecorded = false;
}
Save();
ExecSysproxy(arguments);
}
// set system proxy to 1 (null) (null) (null)
public static bool ResetIEProxy()
{
try
{
// clear user-wininet.json
_userSettings = new SysproxyConfig();
Save();
// clear system setting
ExecSysproxy("set 1 - - -");
}
catch (Exception)
{
return false;
}
return true;
}
private static void ExecSysproxy(string arguments)
{
// using event to avoid hanging when redirect standard output/error
// ref: https://stackoverflow.com/questions/139593/processstartinfo-hanging-on-waitforexit-why
// and http://blog.csdn.net/zhangweixing0/article/details/7356841
using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false))
using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false))
{
using (var process = new Process())
{
// Configure the process using the StartInfo properties.
process.StartInfo.FileName = Utils.GetTempPath("sysproxy.exe");
process.StartInfo.Arguments = arguments;
process.StartInfo.WorkingDirectory = Utils.GetTempPath();
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
// Need to provide encoding info, or output/error strings we got will be wrong.
process.StartInfo.StandardOutputEncoding = Encoding.Unicode;
process.StartInfo.StandardErrorEncoding = Encoding.Unicode;
process.StartInfo.CreateNoWindow = true;
StringBuilder output = new StringBuilder();
StringBuilder error = new StringBuilder();
process.OutputDataReceived += (sender, e) =>
{
if (e.Data == null)
{
outputWaitHandle.Set();
}
else
{
output.AppendLine(e.Data);
}
};
process.ErrorDataReceived += (sender, e) =>
{
if (e.Data == null)
{
errorWaitHandle.Set();
}
else
{
error.AppendLine(e.Data);
}
};
try
{
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
process.WaitForExit();
}
catch (System.ComponentModel.Win32Exception e)
{
// log the arguments
throw new ProxyException(ProxyExceptionType.FailToRun, process.StartInfo.Arguments, e);
}
var stderr = error.ToString();
var stdout = output.ToString();
var exitCode = process.ExitCode;
if (exitCode != (int)RET_ERRORS.RET_NO_ERROR)
{
throw new ProxyException(ProxyExceptionType.SysproxyExitError, stderr);
}
if (arguments == "query")
{
if (stdout.IsNullOrWhiteSpace() || stdout.IsNullOrEmpty())
{
// we cannot get user settings
throw new ProxyException(ProxyExceptionType.QueryReturnEmpty);
}
_queryStr = stdout;
}
}
}
}
private static void Save()
{
try
{
using (StreamWriter sw = new StreamWriter(File.Open(Utils.GetTempPath(_userWininetConfigFile), FileMode.Create)))
{
string jsonString = JsonConvert.SerializeObject(_userSettings, Formatting.Indented);
sw.Write(jsonString);
sw.Flush();
}
}
catch (IOException e)
{
logger.LogUsefulException(e);
}
}
private static void Read()
{
try
{
string configContent = File.ReadAllText(Utils.GetTempPath(_userWininetConfigFile));
_userSettings = JsonConvert.DeserializeObject<SysproxyConfig>(configContent);
}
catch (Exception)
{
// Suppress all exceptions. finally block will initialize new user config settings.
}
finally
{
if (_userSettings == null) _userSettings = new SysproxyConfig();
}
}
private static void ParseQueryStr(string str)
{
string[] userSettingsArr = str.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
// sometimes sysproxy output in utf16le instead of ascii
// manually translate it
if (userSettingsArr.Length != 4)
{
byte[] strByte = Encoding.ASCII.GetBytes(str);
str = Encoding.Unicode.GetString(strByte);
userSettingsArr = str.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
// still fail, throw exception with string hexdump
if (userSettingsArr.Length != 4)
{
throw new ProxyException(ProxyExceptionType.QueryReturnMalformed, BitConverter.ToString(strByte));
}
}
_userSettings.Flags = userSettingsArr[0];
// handle output from WinINET
if (userSettingsArr[1] == "(null)") _userSettings.ProxyServer = null;
else _userSettings.ProxyServer = userSettingsArr[1];
if (userSettingsArr[2] == "(null)") _userSettings.BypassList = null;
else _userSettings.BypassList = userSettingsArr[2];
if (userSettingsArr[3] == "(null)") _userSettings.PacUrl = null;
else _userSettings.PacUrl = userSettingsArr[3];
_userSettings.UserSettingsRecorded = true;
}
}
}

+ 447
- 0
shadowsocks-csharp/Util/SystemProxy/WinINet.cs View File

@@ -0,0 +1,447 @@
using Newtonsoft.Json;
using NLog;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;

namespace Shadowsocks.Util.SystemProxy
{
public enum InternetOptions
{
Refresh = 37,
SettingsChanged = 39,
PerConnectionOption = 75,
ProxySettingChanged = 95,
}

public enum InternetPerConnectionOptionEnum
{
Flags = 1,
ProxyServer = 2,
ProxyBypass = 3,
AutoConfigUrl = 4,
AutoDiscovery = 5,
AutoConfigSecondaryUrl = 6,
AutoConfigReloadDelay = 7,
AutoConfigLastDetectTime = 8,
AutoConfigLastDetectUrl = 9,
FlagsUI = 10,
}

[Flags]
public enum InternetPerConnectionFlags
{
Direct = 0x01,
Proxy = 0x02,
AutoProxyUrl = 0x04,
AutoDetect = 0x08,
}

[StructLayout(LayoutKind.Explicit)]
public struct InternetPerConnectionOptionUnion : IDisposable
{
[FieldOffset(0)]
public int dwValue;

[FieldOffset(0)]
public IntPtr pszValue;

[FieldOffset(0)]
public System.Runtime.InteropServices.ComTypes.FILETIME ftValue;

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

private void Dispose(bool disposing)
{
if (disposing)
{
if (pszValue != IntPtr.Zero)
{
Marshal.FreeHGlobal(pszValue);
pszValue = IntPtr.Zero;
}
}
}
}



[StructLayout(LayoutKind.Sequential)]
public struct InternetPerConnectionOption
{
public int dwOption;
public InternetPerConnectionOptionUnion Value;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct InternetPerConnectionOptionList : IDisposable
{
public int Size;

// The connection to be set. NULL means LAN.
public IntPtr Connection;

public int OptionCount;
public int OptionError;

// List of INTERNET_PER_CONN_OPTIONs.
public IntPtr pOptions;

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (disposing)
{
if (Connection != IntPtr.Zero)
{
Marshal.FreeHGlobal(Connection);
Connection = IntPtr.Zero;
}

if (pOptions != IntPtr.Zero)
{
Marshal.FreeHGlobal(pOptions);
pOptions = IntPtr.Zero;
}
}
}
}

public class WinINetSetting
{
public InternetPerConnectionFlags Flags = InternetPerConnectionFlags.Direct;
public string ProxyServer;
public string ProxyBypass;
public string AutoConfigUrl;
}

public class WinINet
{
private static readonly Logger logger = LogManager.GetCurrentClassLogger();

private const string SettingFile = "wininet-setting.json";
private static WinINetSetting initialSetting;

public static bool operational { get; private set; } = true;
static WinINet()
{
try
{
Query();
}
catch (DllNotFoundException)
{
operational = false;
// Not on windows
logger.Info("You are not running on Windows platform, system proxy will disable");
}
catch (Win32Exception we)
{
if (we.NativeErrorCode == 12178)
{
logger.Warn("WPAD service is not running, system proxy will disable");
// WPAD not running
}
else
{
throw we;
}
}

Load();
}

public static void ProxyGlobal(string server, string bypass)
{
List<InternetPerConnectionOption> options = new List<InternetPerConnectionOption>
{
GetOption(InternetPerConnectionOptionEnum.Flags,InternetPerConnectionFlags.Proxy|InternetPerConnectionFlags.Direct),
GetOption(InternetPerConnectionOptionEnum.ProxyServer,server),
GetOption(InternetPerConnectionOptionEnum.ProxyBypass,bypass),
};
Exec(options);
}
public static void ProxyPAC(string url)
{
List<InternetPerConnectionOption> options = new List<InternetPerConnectionOption>
{
GetOption(InternetPerConnectionOptionEnum.Flags,InternetPerConnectionFlags.AutoProxyUrl|InternetPerConnectionFlags.Direct),
GetOption(InternetPerConnectionOptionEnum.AutoConfigUrl,url),
};
Exec(options);
}
public static void Direct()
{
List<InternetPerConnectionOption> options = new List<InternetPerConnectionOption>
{
GetOption(InternetPerConnectionOptionEnum.Flags,InternetPerConnectionFlags.Direct),
};
Exec(options);
}

private static void Load()
{
try
{
string configContent = File.ReadAllText(Utils.GetTempPath(SettingFile));
initialSetting = JsonConvert.DeserializeObject<WinINetSetting>(configContent);
}
catch (Exception)
{
// Suppress all exceptions. finally block will initialize new user config settings.
}
finally
{
initialSetting ??= new WinINetSetting();
}
}
private static void Save()
{
try
{
using (StreamWriter sw = new StreamWriter(File.Open(Utils.GetTempPath(SettingFile), FileMode.Create)))
{
string jsonString = JsonConvert.SerializeObject(initialSetting, Formatting.Indented);
sw.Write(jsonString);
sw.Flush();
}
}
catch (IOException)
{
// logger.LogUsefulException(e);
}
}
private static void Record()
{
initialSetting ??= Query();
}
public static void Restore()
{
Set(initialSetting);
}

public static void Set(WinINetSetting setting)
{
List<InternetPerConnectionOption> options = new List<InternetPerConnectionOption>
{
GetOption(InternetPerConnectionOptionEnum.Flags,setting.Flags),
GetOption(InternetPerConnectionOptionEnum.ProxyServer,setting.ProxyServer),
GetOption(InternetPerConnectionOptionEnum.ProxyBypass,setting.ProxyBypass),
GetOption(InternetPerConnectionOptionEnum.AutoConfigUrl,setting.AutoConfigUrl),
};
Exec(options);
}
public static void Reset()
{
Set(new WinINetSetting
{
Flags = InternetPerConnectionFlags.Direct,
ProxyServer = "",
ProxyBypass = "",
AutoConfigUrl = "",
});
}

public static WinINetSetting Query()
{
if (!operational)
{
return new WinINetSetting();
}

List<InternetPerConnectionOption> options = new List<InternetPerConnectionOption>
{
new InternetPerConnectionOption{dwOption = (int)InternetPerConnectionOptionEnum.FlagsUI},
new InternetPerConnectionOption{dwOption = (int)InternetPerConnectionOptionEnum.ProxyServer},
new InternetPerConnectionOption{dwOption = (int)InternetPerConnectionOptionEnum.ProxyBypass},
new InternetPerConnectionOption{dwOption = (int)InternetPerConnectionOptionEnum.AutoConfigUrl},
};

(IntPtr unmanagedList, int listSize) = PrepareOptionList(options, null);
bool ok = InternetQueryOption(IntPtr.Zero, (int)InternetOptions.PerConnectionOption, unmanagedList, ref listSize);
if (!ok)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}

WinINetSetting proxy = new WinINetSetting();

InternetPerConnectionOptionList ret = Marshal.PtrToStructure<InternetPerConnectionOptionList>(unmanagedList);
IntPtr p = ret.pOptions;
int nOption = ret.OptionCount;
List<InternetPerConnectionOption> outOptions = new List<InternetPerConnectionOption>();
for (int i = 0; i < nOption; i++)
{
InternetPerConnectionOption o = Marshal.PtrToStructure<InternetPerConnectionOption>(p);
outOptions.Add(o);
p += Marshal.SizeOf(o);
}

foreach (InternetPerConnectionOption o in outOptions)
{
switch ((InternetPerConnectionOptionEnum)o.dwOption)
{
case InternetPerConnectionOptionEnum.FlagsUI:
case InternetPerConnectionOptionEnum.Flags:
proxy.Flags = (InternetPerConnectionFlags)o.Value.dwValue;
break;
case InternetPerConnectionOptionEnum.AutoConfigUrl:
proxy.AutoConfigUrl = Marshal.PtrToStringAuto(o.Value.pszValue);
break;
case InternetPerConnectionOptionEnum.ProxyBypass:
proxy.ProxyBypass = Marshal.PtrToStringAuto(o.Value.pszValue);
break;
case InternetPerConnectionOptionEnum.ProxyServer:
proxy.ProxyServer = Marshal.PtrToStringAuto(o.Value.pszValue);
break;
default:
break;
}
}
return proxy;
}

private static InternetPerConnectionOption GetOption(
InternetPerConnectionOptionEnum option,
InternetPerConnectionFlags flag
)
{
return new InternetPerConnectionOption
{
dwOption = (int)option,
Value =
{
dwValue = (int)flag,
}
};
}

private static InternetPerConnectionOption GetOption(
InternetPerConnectionOptionEnum option,
string param
)
{
return new InternetPerConnectionOption
{
dwOption = (int)option,
Value =
{
pszValue = Marshal.StringToCoTaskMemAuto(param),
}
};
}

private static (IntPtr, int) PrepareOptionList(List<InternetPerConnectionOption> options, string connName)
{
int len = options.Sum(o => Marshal.SizeOf(o));

IntPtr buf = Marshal.AllocCoTaskMem(len);
IntPtr cur = buf;

foreach (InternetPerConnectionOption o in options)
{
Marshal.StructureToPtr(o, cur, false);
cur += Marshal.SizeOf(o);
}
InternetPerConnectionOptionList optionList = new InternetPerConnectionOptionList
{
pOptions = buf,
OptionCount = options.Count,
Connection = string.IsNullOrEmpty(connName)
? IntPtr.Zero
: Marshal.StringToHGlobalAuto(connName),
OptionError = 0,
};
int listSize = Marshal.SizeOf(optionList);
optionList.Size = listSize;

IntPtr unmanagedList = Marshal.AllocCoTaskMem(listSize);
Marshal.StructureToPtr(optionList, unmanagedList, true);
return (unmanagedList, listSize);
}

private static void ClearOptionList(IntPtr list)
{
InternetPerConnectionOptionList l = Marshal.PtrToStructure<InternetPerConnectionOptionList>(list);
Marshal.FreeCoTaskMem(l.pOptions);
Marshal.FreeCoTaskMem(list);
}

private static void Exec(List<InternetPerConnectionOption> options)
{
// TODO: optimize load and save
Load();
Record();

Exec(options, null);
foreach (string conn in RAS.GetAllConnections())
{
Exec(options, conn);
}

Save();
}

private static void Exec(List<InternetPerConnectionOption> options, string connName)
{
if (!operational)
{
return;
}

(IntPtr unmanagedList, int listSize) = PrepareOptionList(options, connName);

bool ok = InternetSetOption(
IntPtr.Zero,
(int)InternetOptions.PerConnectionOption,
unmanagedList,
listSize
);

if (!ok)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
ClearOptionList(unmanagedList);
ok = InternetSetOption(
IntPtr.Zero,
(int)InternetOptions.ProxySettingChanged,
IntPtr.Zero,
0
);
if (!ok)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}

ok = InternetSetOption(
IntPtr.Zero,
(int)InternetOptions.Refresh,
IntPtr.Zero,
0
);
if (!ok)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}

[DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength);

[DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool InternetQueryOption(IntPtr hInternet, uint dwOption, IntPtr lpBuffer, ref int lpdwBufferLength);

}
}

+ 7
- 2
shadowsocks-csharp/View/MenuViewController.cs View File

@@ -3,6 +3,7 @@ using Shadowsocks.Controller;
using Shadowsocks.Model;
using Shadowsocks.Properties;
using Shadowsocks.Util;
using Shadowsocks.Util.SystemProxy;
using System;
using System.Diagnostics;
using System.Drawing;
@@ -38,7 +39,7 @@ namespace Shadowsocks.View
private ToolStripMenuItem disableItem;
private ToolStripMenuItem AutoStartupItem;
private ToolStripMenuItem ShareOverLANItem;
private ToolStripSeparator SeperatorItem;
private ToolStripSeparator SeperatorItem;
private ToolStripMenuItem ConfigItem;
private ToolStripMenuItem ProtocolHandlerItem;
private ToolStripMenuItem ServersItem;
@@ -507,7 +508,8 @@ namespace Shadowsocks.View
)
{
menuItem.Checked = true;
} else
}
else
{
menuItem.Checked = false;
}
@@ -671,6 +673,9 @@ namespace Shadowsocks.View
globalModeItem.Checked = config.global;
PACModeItem.Checked = !config.global;
}
globalModeItem.Enabled = WinINet.operational;
PACModeItem.Enabled = WinINet.operational;
}
private void GlobalModeItem_Click(object sender, EventArgs e)


+ 0
- 4
shadowsocks-csharp/shadowsocks-csharp.csproj View File

@@ -31,8 +31,6 @@
<None Remove="Data\NLog.config" />
<None Remove="Data\privoxy.exe.gz" />
<None Remove="Data\privoxy_conf.txt" />
<None Remove="Data\sysproxy.exe.gz" />
<None Remove="Data\sysproxy64.exe.gz" />
<None Remove="Data\user-rule.txt" />
<None Remove="Resources\ss128.pdn" />
<None Remove="Resources\ss32.pdn" />
@@ -95,8 +93,6 @@
<Resource Include="Data\NLog.config" />
<Resource Include="Data\privoxy.exe.gz" />
<Resource Include="Data\privoxy_conf.txt" />
<Resource Include="Data\sysproxy.exe.gz" />
<Resource Include="Data\sysproxy64.exe.gz" />
<Resource Include="Data\user-rule.txt" />
<Resource Include="Resources\ss128.pdn" />
<Resource Include="Resources\ss32.pdn" />


Loading…
Cancel
Save