1 // Copyright (C) 2015 Kazuhiro Fujieda <fujieda@users.osdn.me>
\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
7 // http://www.apache.org/licenses/LICENSE-2.0
\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
16 using System.Runtime.InteropServices;
\r
17 using Microsoft.Win32;
\r
18 // ReSharper disable once IdentifierTypo
\r
19 using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
\r
21 namespace KancolleSniffer.Net
\r
23 public class SystemProxy
\r
25 private InternetPerConnOptionList _orgList;
\r
26 private Uri _initialUri;
\r
28 private void SaveSettings()
\r
30 if (_orgList.dwSize != 0)
\r
34 new InternetPerConnOption {dwOption = PerConnOption.INTERNET_PER_CONN_FLAGS},
\r
35 new InternetPerConnOption {dwOption = PerConnOption.INTERNET_PER_CONN_AUTOCONFIG_URL}
\r
37 var list = new InternetPerConnOptionList
\r
39 pOptions = MarshalOptions(opts),
\r
40 pszConnection = IntPtr.Zero,
\r
41 dwOptionCount = opts.Length,
\r
44 var listSize = list.dwSize = Marshal.SizeOf(list);
\r
45 if (InternetQueryOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION,
\r
46 ref list, ref listSize))
\r
50 AdjustLocalIntranetZoneFlags();
\r
53 public void SetAutoConfigUrl(string url)
\r
56 var flagValue = new InternetPerConnOptionValue {dwValue = (int)PerConnFlags.PROXY_TYPE_AUTO_PROXY_URL};
\r
57 var urlValue = new InternetPerConnOptionValue {pszValue = Marshal.StringToHGlobalAuto(url)};
\r
58 if (_initialUri == null)
\r
59 Uri.TryCreate(url, UriKind.Absolute, out _initialUri);
\r
62 new InternetPerConnOption {dwOption = PerConnOption.INTERNET_PER_CONN_FLAGS, Value = flagValue},
\r
63 new InternetPerConnOption {dwOption = PerConnOption.INTERNET_PER_CONN_AUTOCONFIG_URL, Value = urlValue}
\r
65 var list = new InternetPerConnOptionList
\r
67 pOptions = MarshalOptions(opts),
\r
68 pszConnection = IntPtr.Zero,
\r
69 dwOptionCount = opts.Length,
\r
72 var listSize = list.dwSize = Marshal.SizeOf(list);
\r
73 var listBuff = Marshal.AllocCoTaskMem(listSize);
\r
74 Marshal.StructureToPtr(list, listBuff, false);
\r
75 InternetSetOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION, listBuff, listSize);
\r
78 Marshal.FreeHGlobal(urlValue.pszValue);
\r
79 Marshal.FreeCoTaskMem(list.pOptions);
\r
80 Marshal.FreeCoTaskMem(listBuff);
\r
83 public void RestoreSettings()
\r
85 if (_orgList.dwSize == 0)
\r
87 var size = Marshal.SizeOf(typeof(InternetPerConnOption));
\r
88 var urlOpt = (InternetPerConnOption)
\r
89 Marshal.PtrToStructure((IntPtr)((long)_orgList.pOptions + size), typeof(InternetPerConnOption));
\r
90 Uri.TryCreate(Marshal.PtrToStringUni(urlOpt.Value.pszValue) ?? "", UriKind.Absolute, out var orgUri);
\r
91 if (orgUri?.Authority == _initialUri?.Authority) // The restoration was sikipped or failed at last time.
\r
93 // Unselect the Use automatic configration script check box.
\r
95 (InternetPerConnOption)Marshal.PtrToStructure(_orgList.pOptions, typeof(InternetPerConnOption));
\r
96 flagsOpt.Value.dwValue &= ~(int)PerConnFlags.PROXY_TYPE_AUTO_PROXY_URL;
\r
97 Marshal.StructureToPtr(flagsOpt, _orgList.pOptions, false);
\r
99 var listSize = _orgList.dwSize;
\r
100 var listBuff = Marshal.AllocCoTaskMem(listSize);
\r
101 Marshal.StructureToPtr(_orgList, listBuff, false);
\r
102 InternetSetOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION, listBuff, listSize);
\r
105 Marshal.FreeCoTaskMem(listBuff);
\r
106 Marshal.FreeHGlobal(urlOpt.Value.pszValue);
\r
107 Marshal.FreeCoTaskMem(_orgList.pOptions);
\r
108 _orgList.dwSize = 0;
\r
111 private IntPtr MarshalOptions(InternetPerConnOption[] opts)
\r
113 var buff = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(InternetPerConnOption)) * opts.Length);
\r
114 var size = Marshal.SizeOf(typeof(InternetPerConnOption));
\r
115 for (var i = 0; i < opts.Length; i++)
\r
117 var ptr = (IntPtr)((long)buff + (i * size));
\r
118 Marshal.StructureToPtr(opts[i], ptr, false);
\r
123 public static void Refresh()
\r
125 InternetSetOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_SETTINGS_CHANGED, IntPtr.Zero, 0);
\r
126 InternetSetOption(IntPtr.Zero, InternetOption.INTERNET_OPTION_PROXY_SETTINGS_CHANGED, IntPtr.Zero, 0);
\r
130 /// PACファイルでDIRECTを指定すると、すべてのサイトがローカルイントラネットになり、
\r
131 /// IEが互換表示になるなどの不具合があるので、イントラネットにならないようにする
\r
133 private void AdjustLocalIntranetZoneFlags()
\r
135 var zones = Registry.CurrentUser.OpenSubKey(
\r
136 @"Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\1", true);
\r
139 if (!(zones.GetValue("Flags") is int flags))
\r
141 zones.SetValue("Flags", flags & (-1 ^ 0x108));
\r
144 [DllImport("WinInet.dll", CharSet = CharSet.Unicode)]
\r
145 private static extern bool InternetQueryOption(IntPtr hInternet, InternetOption dwOption,
\r
146 // ReSharper disable once IdentifierTypo
\r
147 ref InternetPerConnOptionList optionList, ref int lpdwBufferLength);
\r
149 [DllImport("WinInet.dll", CharSet = CharSet.Unicode)]
\r
150 private static extern bool InternetSetOption(IntPtr hInternet, InternetOption dwOption,
\r
151 IntPtr lpBuffer, int dwBufferLength);
\r
153 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
\r
154 private struct InternetPerConnOptionList
\r
157 public IntPtr pszConnection;
\r
158 public int dwOptionCount;
\r
159 public int dwOptionError;
\r
160 public IntPtr pOptions;
\r
163 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
\r
164 private struct InternetPerConnOption
\r
166 public PerConnOption dwOption;
\r
167 public InternetPerConnOptionValue Value;
\r
170 [StructLayout(LayoutKind.Explicit)]
\r
171 public struct InternetPerConnOptionValue
\r
173 [FieldOffset(0)] public int dwValue;
\r
174 [FieldOffset(0)] public IntPtr pszValue;
\r
175 [FieldOffset(0)] public FILETIME ftValue;
\r
178 // ReSharper disable UnusedMember.Global
\r
179 // ReSharper disable UnusedMember.Local
\r
180 // ReSharper disable InconsistentNaming
\r
181 // ReSharper disable IdentifierTypo
\r
182 private enum InternetOption : uint
\r
185 INTERNET_OPTION_REFRESH = 0x00000025,
\r
187 INTERNET_OPTION_SETTINGS_CHANGED = 0x00000027,
\r
188 INTERNET_OPTION_PER_CONNECTION_OPTION = 0x0000004B,
\r
189 INTERNET_OPTION_PROXY_SETTINGS_CHANGED = 0x0000005F
\r
192 private enum PerConnOption
\r
195 INTERNET_PER_CONN_FLAGS = 1,
\r
197 INTERNET_PER_CONN_PROXY_SERVER = 2,
\r
198 INTERNET_PER_CONN_PROXY_BYPASS = 3,
\r
199 INTERNET_PER_CONN_AUTOCONFIG_URL = 4,
\r
201 INTERNET_PER_CONN_AUTODISCOVERY_FLAGS = 5
\r
205 private enum PerConnFlags
\r
207 PROXY_TYPE_DIRECT = 0x00000001,
\r
208 PROXY_TYPE_PROXY = 0x00000002,
\r
209 PROXY_TYPE_AUTO_PROXY_URL = 0x00000004,
\r
210 PROXY_TYPE_AUTO_DETECT = 0x00000008
\r