From 5ad4d7d81641e300cbe751f284096d64adc07ded Mon Sep 17 00:00:00 2001 From: Kazuhiro Fujieda Date: Sat, 3 Feb 2018 20:01:46 +0900 Subject: [PATCH] =?utf8?q?=E3=83=97=E3=83=AD=E3=82=AD=E3=82=B7=E3=81=AE?= =?utf8?q?=E8=87=AA=E5=8B=95=E8=A8=AD=E5=AE=9A=E3=82=92=E3=83=90=E3=83=BC?= =?utf8?q?=E3=82=B8=E3=83=A7=E3=83=B39=E3=81=AE=E6=96=B9=E6=B3=95=E3=81=AB?= =?utf8?q?=E6=88=BB=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- KancolleSniffer/ProxyManager.cs | 42 +-------- KancolleSniffer/SystemProxy.cs | 187 ++++++++++++++++++++++++++++++---------- 2 files changed, 146 insertions(+), 83 deletions(-) diff --git a/KancolleSniffer/ProxyManager.cs b/KancolleSniffer/ProxyManager.cs index 283564d..b01c4fc 100644 --- a/KancolleSniffer/ProxyManager.cs +++ b/KancolleSniffer/ProxyManager.cs @@ -25,7 +25,7 @@ namespace KancolleSniffer { private readonly Config _config; private readonly Control _parent; - private string _prevAutoConfigUrl; + private readonly SystemProxy _systemProxy = new SystemProxy(); private int _prevProxyPort; private int _autoConfigRetryCount; private readonly Timer _timer = new Timer {Interval = 1000}; @@ -57,11 +57,6 @@ namespace KancolleSniffer } if (_config.Proxy.Auto && result) { - if (_prevAutoConfigUrl == null) - { - SystemProxy.AdjustLocalIntranetZoneFlags(); - _prevAutoConfigUrl = SystemProxy.AutoConfigUrl; - } SetAndCheckAutoConfigUrl(); } _prevProxyPort = _config.Proxy.Listen; @@ -173,43 +168,14 @@ namespace KancolleSniffer private void SetAutoConfigUrl() { var count = _autoConfigRetryCount == 0 ? "" : _autoConfigRetryCount.ToString(); - SystemProxy.AutoConfigUrl = $"http://localhost:{_config.Proxy.Listen}/proxy{count}.pac"; + _systemProxy.SetAutoConfigUrl( + $"http://localhost:{_config.Proxy.Listen}/proxy{count}.pac"); } private void RestoreSystemProxy() { _timer.Stop(); - if (_prevAutoConfigUrl == null) - return; - if (_prevAutoConfigUrl == "") - { - SystemProxy.AutoConfigUrl = ""; - return; - } - HttpWebRequest request; - try - { - request = WebRequest.CreateHttp(_prevAutoConfigUrl); - if (!request.Address.IsLoopback) - throw new Exception(); - } - catch - { - // httpではなくloopbackでもない - SystemProxy.AutoConfigUrl = _prevAutoConfigUrl; - return; - } - try - { - request.GetResponse().Dispose(); - } - catch - { - // httpサーバーが応答しない - SystemProxy.AutoConfigUrl = ""; - return; - } - SystemProxy.AutoConfigUrl = _prevAutoConfigUrl; + _systemProxy.RestoreSettings(); } public void UpdatePacFile() diff --git a/KancolleSniffer/SystemProxy.cs b/KancolleSniffer/SystemProxy.cs index 3ba1ff4..bcc47d3 100644 --- a/KancolleSniffer/SystemProxy.cs +++ b/KancolleSniffer/SystemProxy.cs @@ -14,75 +14,172 @@ using System; using System.Runtime.InteropServices; -using Microsoft.Win32; - -// ReSharper disable InconsistentNaming +using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME; namespace KancolleSniffer { - public static class SystemProxy + public class SystemProxy { - private const string _regPath = @"Software\Microsoft\Windows\CurrentVersion\Internet Settings"; - private const string _regName = "AutoConfigURL"; + private InternetPerConnOptionList _orgList; + private string _currentUrl; - public static string AutoConfigUrl + private void SaveSettings() { - get + if (_orgList.dwSize != 0) + return; + var opts = new[] { - using (var regkey = Registry.CurrentUser.OpenSubKey(_regPath)) - { - if (regkey == null) - return ""; - return regkey.GetValue(_regName) as string ?? ""; - } - } - set + new InternetPerConnOption {dwOption = PerConnOption.INTERNET_PER_CONN_FLAGS}, + new InternetPerConnOption {dwOption = PerConnOption.INTERNET_PER_CONN_AUTOCONFIG_URL} + }; + var list = new InternetPerConnOptionList + { + pOptions = MarshalOptions(opts), + pszConnection = IntPtr.Zero, + dwOptionCount = opts.Length, + dwOptionError = 0 + }; + var listSize = list.dwSize = Marshal.SizeOf(list); + if (InternetQueryOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION, + ref list, ref listSize)) { - using (var regkey = Registry.CurrentUser.OpenSubKey(_regPath, true)) - { - if (regkey == null) - return; - if (value == "") - { - regkey.DeleteValue(_regName, false); - } - else - { - regkey.SetValue(_regName, value); - } - } - Refresh(); + _orgList = list; } } - /// - /// PACファイルでDIRECTを指定すると、すべてのサイトがローカルイントラネットになり、 - /// IEが互換表示になるなどの不具合があるので、イントラネットにならないようにする - /// - public static void AdjustLocalIntranetZoneFlags() + public void SetAutoConfigUrl(string url) { - var zones = Registry.CurrentUser.OpenSubKey(_regPath + @"\Zones\1", true); - if (zones == null) - return; - if (!(zones.GetValue("Flags") is int flags)) + SaveSettings(); + var flagValue = new InternetPerConnOptionValue {dwValue = (int)PerConnFlags.PROXY_TYPE_AUTO_PROXY_URL}; + var urlValue = new InternetPerConnOptionValue {pszValue = Marshal.StringToHGlobalAuto(url)}; + _currentUrl = url; + var opts = new[] + { + new InternetPerConnOption {dwOption = PerConnOption.INTERNET_PER_CONN_FLAGS, Value = flagValue}, + new InternetPerConnOption {dwOption = PerConnOption.INTERNET_PER_CONN_AUTOCONFIG_URL, Value = urlValue} + }; + var list = new InternetPerConnOptionList + { + pOptions = MarshalOptions(opts), + pszConnection = IntPtr.Zero, + dwOptionCount = opts.Length, + dwOptionError = 0 + }; + var listSize = list.dwSize = Marshal.SizeOf(list); + var listBuff = Marshal.AllocCoTaskMem(listSize); + Marshal.StructureToPtr(list, listBuff, false); + InternetSetOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION, listBuff, listSize); + Refresh(); + + Marshal.FreeHGlobal(urlValue.pszValue); + Marshal.FreeCoTaskMem(list.pOptions); + Marshal.FreeCoTaskMem(listBuff); + } + + public void RestoreSettings() + { + if (_orgList.dwSize == 0) return; - zones.SetValue("Flags", flags & (-1 ^ 0x108)); + var size = Marshal.SizeOf(typeof(InternetPerConnOption)); + var urlOpt = (InternetPerConnOption) + Marshal.PtrToStructure((IntPtr)((long)_orgList.pOptions + size), typeof(InternetPerConnOption)); + var orgUrl = Marshal.PtrToStringUni(urlOpt.Value.pszValue); + if (orgUrl == _currentUrl) // The restoration was sikipped or failed at last time. + { + // Unselect the Use automatic configration script check box. + var flagsOpt = + (InternetPerConnOption)Marshal.PtrToStructure(_orgList.pOptions, typeof(InternetPerConnOption)); + flagsOpt.Value.dwValue &= ~(int)PerConnFlags.PROXY_TYPE_AUTO_PROXY_URL; + Marshal.StructureToPtr(flagsOpt, _orgList.pOptions, false); + } + var listSize = _orgList.dwSize; + var listBuff = Marshal.AllocCoTaskMem(listSize); + Marshal.StructureToPtr(_orgList, listBuff, false); + InternetSetOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION, listBuff, listSize); + Refresh(); + + Marshal.FreeCoTaskMem(listBuff); + Marshal.FreeHGlobal(urlOpt.Value.pszValue); + Marshal.FreeCoTaskMem(_orgList.pOptions); + _orgList.dwSize = 0; + } + + private IntPtr MarshalOptions(InternetPerConnOption[] opts) + { + var buff = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(InternetPerConnOption)) * opts.Length); + var size = Marshal.SizeOf(typeof(InternetPerConnOption)); + for (var i = 0; i < opts.Length; i++) + { + var ptr = (IntPtr)((long)buff + (i * size)); + Marshal.StructureToPtr(opts[i], ptr, false); + } + return buff; } public static void Refresh() { - InternetSetOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_SETTINGS_CHANGED, IntPtr.Zero, 0); - InternetSetOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_REFRESH, IntPtr.Zero, 0); + InternetSetOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_PROXY_SETTINGS_CHANGED, IntPtr.Zero, 0); } - [DllImport("WinInet.dll", SetLastError = true, CharSet = CharSet.Auto)] + [DllImport("WinInet.dll", CharSet = CharSet.Unicode)] + private static extern bool InternetQueryOption(IntPtr hInternet, InternetOption dwOption, + ref InternetPerConnOptionList optionList, ref int lpdwBufferLength); + + [DllImport("WinInet.dll", CharSet = CharSet.Unicode)] private static extern bool InternetSetOption(IntPtr hInternet, InternetOption dwOption, IntPtr lpBuffer, int dwBufferLength); + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + private struct InternetPerConnOptionList + { + public int dwSize; + public IntPtr pszConnection; + public int dwOptionCount; + public int dwOptionError; + public IntPtr pOptions; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + private struct InternetPerConnOption + { + public PerConnOption dwOption; + public InternetPerConnOptionValue Value; + } + + [StructLayout(LayoutKind.Explicit)] + public struct InternetPerConnOptionValue + { + [FieldOffset(0)] public int dwValue; + [FieldOffset(0)] public IntPtr pszValue; + [FieldOffset(0)] public FILETIME ftValue; + } + +// ReSharper disable UnusedMember.Local +// ReSharper disable InconsistentNaming + private enum InternetOption : uint { - INTERNET_OPTION_REFRESH = 37, - INTERNET_OPTION_SETTINGS_CHANGED = 39 + INTERNET_OPTION_REFRESH = 0x00000025, + INTERNET_OPTION_PER_CONNECTION_OPTION = 0x0000004B, + INTERNET_OPTION_PROXY_SETTINGS_CHANGED = 0x0000005F + } + + private enum PerConnOption + { + 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 + } + + [Flags] + private enum PerConnFlags + { + PROXY_TYPE_DIRECT = 0x00000001, + PROXY_TYPE_PROXY = 0x00000002, + PROXY_TYPE_AUTO_PROXY_URL = 0x00000004, + PROXY_TYPE_AUTO_DETECT = 0x00000008 } } } \ No newline at end of file -- 2.11.0