OSDN Git Service

プロキシの自動設定をバージョン9の方法に戻す
authorKazuhiro Fujieda <fujieda@users.osdn.me>
Sat, 3 Feb 2018 11:01:46 +0000 (20:01 +0900)
committerKazuhiro Fujieda <fujieda@users.osdn.me>
Thu, 8 Feb 2018 10:45:24 +0000 (19:45 +0900)
KancolleSniffer/ProxyManager.cs
KancolleSniffer/SystemProxy.cs

index 283564d..b01c4fc 100644 (file)
@@ -25,7 +25,7 @@ namespace KancolleSniffer
     {\r
         private readonly Config _config;\r
         private readonly Control _parent;\r
-        private string _prevAutoConfigUrl;\r
+        private readonly SystemProxy _systemProxy = new SystemProxy();\r
         private int _prevProxyPort;\r
         private int _autoConfigRetryCount;\r
         private readonly Timer _timer = new Timer {Interval = 1000};\r
@@ -57,11 +57,6 @@ namespace KancolleSniffer
             }\r
             if (_config.Proxy.Auto && result)\r
             {\r
-                if (_prevAutoConfigUrl == null)\r
-                {\r
-                    SystemProxy.AdjustLocalIntranetZoneFlags();\r
-                    _prevAutoConfigUrl = SystemProxy.AutoConfigUrl;\r
-                }\r
                 SetAndCheckAutoConfigUrl();\r
             }\r
             _prevProxyPort = _config.Proxy.Listen;\r
@@ -173,43 +168,14 @@ namespace KancolleSniffer
         private void SetAutoConfigUrl()\r
         {\r
             var count = _autoConfigRetryCount == 0 ? "" : _autoConfigRetryCount.ToString();\r
-            SystemProxy.AutoConfigUrl = $"http://localhost:{_config.Proxy.Listen}/proxy{count}.pac";\r
+            _systemProxy.SetAutoConfigUrl(\r
+                $"http://localhost:{_config.Proxy.Listen}/proxy{count}.pac");\r
         }\r
 \r
         private void RestoreSystemProxy()\r
         {\r
             _timer.Stop();\r
-            if (_prevAutoConfigUrl == null)\r
-                return;\r
-            if (_prevAutoConfigUrl == "")\r
-            {\r
-                SystemProxy.AutoConfigUrl = "";\r
-                return;\r
-            }\r
-            HttpWebRequest request;\r
-            try\r
-            {\r
-                request = WebRequest.CreateHttp(_prevAutoConfigUrl);\r
-                if (!request.Address.IsLoopback)\r
-                    throw new Exception();\r
-            }\r
-            catch\r
-            {\r
-                // httpではなくloopbackでもない\r
-                SystemProxy.AutoConfigUrl = _prevAutoConfigUrl;\r
-                return;\r
-            }\r
-            try\r
-            {\r
-                request.GetResponse().Dispose();\r
-            }\r
-            catch\r
-            {\r
-                // httpサーバーが応答しない\r
-                SystemProxy.AutoConfigUrl = "";\r
-                return;\r
-            }\r
-            SystemProxy.AutoConfigUrl = _prevAutoConfigUrl;\r
+            _systemProxy.RestoreSettings();\r
         }\r
 \r
         public void UpdatePacFile()\r
index 3ba1ff4..bcc47d3 100644 (file)
 \r
 using System;\r
 using System.Runtime.InteropServices;\r
-using Microsoft.Win32;\r
-\r
-// ReSharper disable InconsistentNaming\r
+using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;\r
 \r
 namespace KancolleSniffer\r
 {\r
-    public static class SystemProxy\r
+    public class SystemProxy\r
     {\r
-        private const string _regPath = @"Software\Microsoft\Windows\CurrentVersion\Internet Settings";\r
-        private const string _regName = "AutoConfigURL";\r
+        private InternetPerConnOptionList _orgList;\r
+        private string _currentUrl;\r
 \r
-        public static string AutoConfigUrl\r
+        private void SaveSettings()\r
         {\r
-            get\r
+            if (_orgList.dwSize != 0)\r
+                return;\r
+            var opts = new[]\r
             {\r
-                using (var regkey = Registry.CurrentUser.OpenSubKey(_regPath))\r
-                {\r
-                    if (regkey == null)\r
-                        return "";\r
-                    return regkey.GetValue(_regName) as string ?? "";\r
-                }\r
-            }\r
-            set\r
+                new InternetPerConnOption {dwOption = PerConnOption.INTERNET_PER_CONN_FLAGS},\r
+                new InternetPerConnOption {dwOption = PerConnOption.INTERNET_PER_CONN_AUTOCONFIG_URL}\r
+            };\r
+            var list = new InternetPerConnOptionList\r
+            {\r
+                pOptions = MarshalOptions(opts),\r
+                pszConnection = IntPtr.Zero,\r
+                dwOptionCount = opts.Length,\r
+                dwOptionError = 0\r
+            };\r
+            var listSize = list.dwSize = Marshal.SizeOf(list);\r
+            if (InternetQueryOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION,\r
+                ref list, ref listSize))\r
             {\r
-                using (var regkey = Registry.CurrentUser.OpenSubKey(_regPath, true))\r
-                {\r
-                    if (regkey == null)\r
-                        return;\r
-                    if (value == "")\r
-                    {\r
-                        regkey.DeleteValue(_regName, false);\r
-                    }\r
-                    else\r
-                    {\r
-                        regkey.SetValue(_regName, value);\r
-                    }\r
-                }\r
-                Refresh();\r
+                _orgList = list;\r
             }\r
         }\r
 \r
-        /// <summary>\r
-        /// PACファイルでDIRECTを指定すると、すべてのサイトがローカルイントラネットになり、\r
-        /// IEが互換表示になるなどの不具合があるので、イントラネットにならないようにする\r
-        /// </summary>\r
-        public static void AdjustLocalIntranetZoneFlags()\r
+        public void SetAutoConfigUrl(string url)\r
         {\r
-            var zones = Registry.CurrentUser.OpenSubKey(_regPath + @"\Zones\1", true);\r
-            if (zones == null)\r
-                return;\r
-            if (!(zones.GetValue("Flags") is int flags))\r
+            SaveSettings();\r
+            var flagValue = new InternetPerConnOptionValue {dwValue = (int)PerConnFlags.PROXY_TYPE_AUTO_PROXY_URL};\r
+            var urlValue = new InternetPerConnOptionValue {pszValue = Marshal.StringToHGlobalAuto(url)};\r
+            _currentUrl = url;\r
+            var opts = new[]\r
+            {\r
+                new InternetPerConnOption {dwOption = PerConnOption.INTERNET_PER_CONN_FLAGS, Value = flagValue},\r
+                new InternetPerConnOption {dwOption = PerConnOption.INTERNET_PER_CONN_AUTOCONFIG_URL, Value = urlValue}\r
+            };\r
+            var list = new InternetPerConnOptionList\r
+            {\r
+                pOptions = MarshalOptions(opts),\r
+                pszConnection = IntPtr.Zero,\r
+                dwOptionCount = opts.Length,\r
+                dwOptionError = 0\r
+            };\r
+            var listSize = list.dwSize = Marshal.SizeOf(list);\r
+            var listBuff = Marshal.AllocCoTaskMem(listSize);\r
+            Marshal.StructureToPtr(list, listBuff, false);\r
+            InternetSetOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION, listBuff, listSize);\r
+            Refresh();\r
+\r
+            Marshal.FreeHGlobal(urlValue.pszValue);\r
+            Marshal.FreeCoTaskMem(list.pOptions);\r
+            Marshal.FreeCoTaskMem(listBuff);\r
+        }\r
+\r
+        public void RestoreSettings()\r
+        {\r
+            if (_orgList.dwSize == 0)\r
                 return;\r
-            zones.SetValue("Flags", flags & (-1 ^ 0x108));\r
+            var size = Marshal.SizeOf(typeof(InternetPerConnOption));\r
+            var urlOpt = (InternetPerConnOption)\r
+                Marshal.PtrToStructure((IntPtr)((long)_orgList.pOptions + size), typeof(InternetPerConnOption));\r
+            var orgUrl = Marshal.PtrToStringUni(urlOpt.Value.pszValue);\r
+            if (orgUrl == _currentUrl) // The restoration was sikipped or failed at last time.\r
+            {\r
+                // Unselect the Use automatic configration script check box.\r
+                var flagsOpt =\r
+                    (InternetPerConnOption)Marshal.PtrToStructure(_orgList.pOptions, typeof(InternetPerConnOption));\r
+                flagsOpt.Value.dwValue &= ~(int)PerConnFlags.PROXY_TYPE_AUTO_PROXY_URL;\r
+                Marshal.StructureToPtr(flagsOpt, _orgList.pOptions, false);\r
+            }\r
+            var listSize = _orgList.dwSize;\r
+            var listBuff = Marshal.AllocCoTaskMem(listSize);\r
+            Marshal.StructureToPtr(_orgList, listBuff, false);\r
+            InternetSetOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION, listBuff, listSize);\r
+            Refresh();\r
+\r
+            Marshal.FreeCoTaskMem(listBuff);\r
+            Marshal.FreeHGlobal(urlOpt.Value.pszValue);\r
+            Marshal.FreeCoTaskMem(_orgList.pOptions);\r
+            _orgList.dwSize = 0;\r
+        }\r
+\r
+        private IntPtr MarshalOptions(InternetPerConnOption[] opts)\r
+        {\r
+            var buff = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(InternetPerConnOption)) * opts.Length);\r
+            var size = Marshal.SizeOf(typeof(InternetPerConnOption));\r
+            for (var i = 0; i < opts.Length; i++)\r
+            {\r
+                var ptr = (IntPtr)((long)buff + (i * size));\r
+                Marshal.StructureToPtr(opts[i], ptr, false);\r
+            }\r
+            return buff;\r
         }\r
 \r
         public static void Refresh()\r
         {\r
-            InternetSetOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_SETTINGS_CHANGED, IntPtr.Zero, 0);\r
-            InternetSetOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_REFRESH, IntPtr.Zero, 0);\r
+            InternetSetOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_PROXY_SETTINGS_CHANGED, IntPtr.Zero, 0);\r
         }\r
 \r
-        [DllImport("WinInet.dll", SetLastError = true, CharSet = CharSet.Auto)]\r
+        [DllImport("WinInet.dll", CharSet = CharSet.Unicode)]\r
+        private static extern bool InternetQueryOption(IntPtr hInternet, InternetOption dwOption,\r
+            ref InternetPerConnOptionList optionList, ref int lpdwBufferLength);\r
+\r
+        [DllImport("WinInet.dll", CharSet = CharSet.Unicode)]\r
         private static extern bool InternetSetOption(IntPtr hInternet, InternetOption dwOption,\r
             IntPtr lpBuffer, int dwBufferLength);\r
 \r
+        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]\r
+        private struct InternetPerConnOptionList\r
+        {\r
+            public int dwSize;\r
+            public IntPtr pszConnection;\r
+            public int dwOptionCount;\r
+            public int dwOptionError;\r
+            public IntPtr pOptions;\r
+        }\r
+\r
+        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]\r
+        private struct InternetPerConnOption\r
+        {\r
+            public PerConnOption dwOption;\r
+            public InternetPerConnOptionValue Value;\r
+        }\r
+\r
+        [StructLayout(LayoutKind.Explicit)]\r
+        public struct InternetPerConnOptionValue\r
+        {\r
+            [FieldOffset(0)] public int dwValue;\r
+            [FieldOffset(0)] public IntPtr pszValue;\r
+            [FieldOffset(0)] public FILETIME ftValue;\r
+        }\r
+\r
+// ReSharper disable UnusedMember.Local\r
+// ReSharper disable InconsistentNaming\r
+\r
         private enum InternetOption : uint\r
         {\r
-            INTERNET_OPTION_REFRESH = 37,\r
-            INTERNET_OPTION_SETTINGS_CHANGED = 39\r
+            INTERNET_OPTION_REFRESH = 0x00000025,\r
+            INTERNET_OPTION_PER_CONNECTION_OPTION = 0x0000004B,\r
+            INTERNET_OPTION_PROXY_SETTINGS_CHANGED = 0x0000005F\r
+        }\r
+\r
+        private enum PerConnOption\r
+        {\r
+            INTERNET_PER_CONN_FLAGS = 1,\r
+            INTERNET_PER_CONN_PROXY_SERVER = 2,\r
+            INTERNET_PER_CONN_PROXY_BYPASS = 3,\r
+            INTERNET_PER_CONN_AUTOCONFIG_URL = 4,\r
+            INTERNET_PER_CONN_AUTODISCOVERY_FLAGS = 5\r
+        }\r
+\r
+        [Flags]\r
+        private enum PerConnFlags\r
+        {\r
+            PROXY_TYPE_DIRECT = 0x00000001,\r
+            PROXY_TYPE_PROXY = 0x00000002,\r
+            PROXY_TYPE_AUTO_PROXY_URL = 0x00000004,\r
+            PROXY_TYPE_AUTO_DETECT = 0x00000008\r
         }\r
     }\r
 }
\ No newline at end of file