OSDN Git Service

IEのゾーンがローカルイントラネットになることがあるのを防ぐ
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / SystemProxy.cs
1 // Copyright (C) 2015 Kazuhiro Fujieda <fujieda@users.osdn.me>\r
2 //\r
3 // Licensed under the Apache License, Version 2.0 (the "License");\r
4 // you may not use this file except in compliance with the License.\r
5 // You may obtain a copy of the License at\r
6 //\r
7 //    http://www.apache.org/licenses/LICENSE-2.0\r
8 //\r
9 // Unless required by applicable law or agreed to in writing, software\r
10 // distributed under the License is distributed on an "AS IS" BASIS,\r
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
12 // See the License for the specific language governing permissions and\r
13 // limitations under the License.\r
14 \r
15 using System;\r
16 using System.Runtime.InteropServices;\r
17 using Microsoft.Win32;\r
18 using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;\r
19 \r
20 namespace KancolleSniffer\r
21 {\r
22     public class SystemProxy\r
23     {\r
24         private InternetPerConnOptionList _orgList;\r
25         private string _currentUrl;\r
26 \r
27         private void SaveSettings()\r
28         {\r
29             if (_orgList.dwSize != 0)\r
30                 return;\r
31             var opts = new[]\r
32             {\r
33                 new InternetPerConnOption {dwOption = PerConnOption.INTERNET_PER_CONN_FLAGS},\r
34                 new InternetPerConnOption {dwOption = PerConnOption.INTERNET_PER_CONN_AUTOCONFIG_URL}\r
35             };\r
36             var list = new InternetPerConnOptionList\r
37             {\r
38                 pOptions = MarshalOptions(opts),\r
39                 pszConnection = IntPtr.Zero,\r
40                 dwOptionCount = opts.Length,\r
41                 dwOptionError = 0\r
42             };\r
43             var listSize = list.dwSize = Marshal.SizeOf(list);\r
44             if (InternetQueryOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION,\r
45                 ref list, ref listSize))\r
46             {\r
47                 _orgList = list;\r
48             }\r
49             AdjustLocalIntranetZoneFlags();\r
50         }\r
51 \r
52         public void SetAutoConfigUrl(string url)\r
53         {\r
54             SaveSettings();\r
55             var flagValue = new InternetPerConnOptionValue {dwValue = (int)PerConnFlags.PROXY_TYPE_AUTO_PROXY_URL};\r
56             var urlValue = new InternetPerConnOptionValue {pszValue = Marshal.StringToHGlobalAuto(url)};\r
57             _currentUrl = url;\r
58             var opts = new[]\r
59             {\r
60                 new InternetPerConnOption {dwOption = PerConnOption.INTERNET_PER_CONN_FLAGS, Value = flagValue},\r
61                 new InternetPerConnOption {dwOption = PerConnOption.INTERNET_PER_CONN_AUTOCONFIG_URL, Value = urlValue}\r
62             };\r
63             var list = new InternetPerConnOptionList\r
64             {\r
65                 pOptions = MarshalOptions(opts),\r
66                 pszConnection = IntPtr.Zero,\r
67                 dwOptionCount = opts.Length,\r
68                 dwOptionError = 0\r
69             };\r
70             var listSize = list.dwSize = Marshal.SizeOf(list);\r
71             var listBuff = Marshal.AllocCoTaskMem(listSize);\r
72             Marshal.StructureToPtr(list, listBuff, false);\r
73             InternetSetOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION, listBuff, listSize);\r
74             Refresh();\r
75 \r
76             Marshal.FreeHGlobal(urlValue.pszValue);\r
77             Marshal.FreeCoTaskMem(list.pOptions);\r
78             Marshal.FreeCoTaskMem(listBuff);\r
79         }\r
80 \r
81         public void RestoreSettings()\r
82         {\r
83             if (_orgList.dwSize == 0)\r
84                 return;\r
85             var size = Marshal.SizeOf(typeof(InternetPerConnOption));\r
86             var urlOpt = (InternetPerConnOption)\r
87                 Marshal.PtrToStructure((IntPtr)((long)_orgList.pOptions + size), typeof(InternetPerConnOption));\r
88             var orgUrl = Marshal.PtrToStringUni(urlOpt.Value.pszValue);\r
89             if (orgUrl == _currentUrl) // The restoration was sikipped or failed at last time.\r
90             {\r
91                 // Unselect the Use automatic configration script check box.\r
92                 var flagsOpt =\r
93                     (InternetPerConnOption)Marshal.PtrToStructure(_orgList.pOptions, typeof(InternetPerConnOption));\r
94                 flagsOpt.Value.dwValue &= ~(int)PerConnFlags.PROXY_TYPE_AUTO_PROXY_URL;\r
95                 Marshal.StructureToPtr(flagsOpt, _orgList.pOptions, false);\r
96             }\r
97             var listSize = _orgList.dwSize;\r
98             var listBuff = Marshal.AllocCoTaskMem(listSize);\r
99             Marshal.StructureToPtr(_orgList, listBuff, false);\r
100             InternetSetOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION, listBuff, listSize);\r
101             Refresh();\r
102 \r
103             Marshal.FreeCoTaskMem(listBuff);\r
104             Marshal.FreeHGlobal(urlOpt.Value.pszValue);\r
105             Marshal.FreeCoTaskMem(_orgList.pOptions);\r
106             _orgList.dwSize = 0;\r
107         }\r
108 \r
109         private IntPtr MarshalOptions(InternetPerConnOption[] opts)\r
110         {\r
111             var buff = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(InternetPerConnOption)) * opts.Length);\r
112             var size = Marshal.SizeOf(typeof(InternetPerConnOption));\r
113             for (var i = 0; i < opts.Length; i++)\r
114             {\r
115                 var ptr = (IntPtr)((long)buff + (i * size));\r
116                 Marshal.StructureToPtr(opts[i], ptr, false);\r
117             }\r
118             return buff;\r
119         }\r
120 \r
121         public static void Refresh()\r
122         {\r
123             InternetSetOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_PROXY_SETTINGS_CHANGED, IntPtr.Zero, 0);\r
124         }\r
125 \r
126         /// <summary>\r
127         /// PACファイルでDIRECTを指定すると、すべてのサイトがローカルイントラネットになり、\r
128         /// IEが互換表示になるなどの不具合があるので、イントラネットにならないようにする\r
129         /// </summary>\r
130         private void AdjustLocalIntranetZoneFlags()\r
131         {\r
132             var zones = Registry.CurrentUser.OpenSubKey(\r
133                 @"Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\1", true);\r
134             if (zones == null)\r
135                 return;\r
136             if (!(zones.GetValue("Flags") is int flags))\r
137                 return;\r
138             zones.SetValue("Flags", flags & (-1 ^ 0x108));\r
139         }\r
140 \r
141         [DllImport("WinInet.dll", CharSet = CharSet.Unicode)]\r
142         private static extern bool InternetQueryOption(IntPtr hInternet, InternetOption dwOption,\r
143             ref InternetPerConnOptionList optionList, ref int lpdwBufferLength);\r
144 \r
145         [DllImport("WinInet.dll", CharSet = CharSet.Unicode)]\r
146         private static extern bool InternetSetOption(IntPtr hInternet, InternetOption dwOption,\r
147             IntPtr lpBuffer, int dwBufferLength);\r
148 \r
149         [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]\r
150         private struct InternetPerConnOptionList\r
151         {\r
152             public int dwSize;\r
153             public IntPtr pszConnection;\r
154             public int dwOptionCount;\r
155             public int dwOptionError;\r
156             public IntPtr pOptions;\r
157         }\r
158 \r
159         [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]\r
160         private struct InternetPerConnOption\r
161         {\r
162             public PerConnOption dwOption;\r
163             public InternetPerConnOptionValue Value;\r
164         }\r
165 \r
166         [StructLayout(LayoutKind.Explicit)]\r
167         public struct InternetPerConnOptionValue\r
168         {\r
169             [FieldOffset(0)] public int dwValue;\r
170             [FieldOffset(0)] public IntPtr pszValue;\r
171             [FieldOffset(0)] public FILETIME ftValue;\r
172         }\r
173 \r
174 // ReSharper disable UnusedMember.Local\r
175 // ReSharper disable InconsistentNaming\r
176 \r
177         private enum InternetOption : uint\r
178         {\r
179             INTERNET_OPTION_REFRESH = 0x00000025,\r
180             INTERNET_OPTION_PER_CONNECTION_OPTION = 0x0000004B,\r
181             INTERNET_OPTION_PROXY_SETTINGS_CHANGED = 0x0000005F\r
182         }\r
183 \r
184         private enum PerConnOption\r
185         {\r
186             INTERNET_PER_CONN_FLAGS = 1,\r
187             INTERNET_PER_CONN_PROXY_SERVER = 2,\r
188             INTERNET_PER_CONN_PROXY_BYPASS = 3,\r
189             INTERNET_PER_CONN_AUTOCONFIG_URL = 4,\r
190             INTERNET_PER_CONN_AUTODISCOVERY_FLAGS = 5\r
191         }\r
192 \r
193         [Flags]\r
194         private enum PerConnFlags\r
195         {\r
196             PROXY_TYPE_DIRECT = 0x00000001,\r
197             PROXY_TYPE_PROXY = 0x00000002,\r
198             PROXY_TYPE_AUTO_PROXY_URL = 0x00000004,\r
199             PROXY_TYPE_AUTO_DETECT = 0x00000008\r
200         }\r
201     }\r
202 }