/
ConnectionSettings.cs
317 lines (265 loc) · 13 KB
/
ConnectionSettings.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
using System;
using System.ComponentModel;
using System.Runtime.Serialization;
using Marshal = System.Runtime.InteropServices.Marshal;
namespace ProxyManager
{
[Flags()]
public enum ConnectionType
{
NoProxy,
ManualProxy = 1 << 1,
AutoConfigUrl = 1 << 2,
AutoDetect = 1 << 3,
}
[Serializable()]
public class ConnectionSettings
{
#region P/Invoke
private const int INTERNET_OPEN_NO_PROXY = 1;
private const int INTERNET_OPEN_TYPE_PROXY = 3;
private const int INTERNET_OPTION_REFRESH = 37;
private const int INTERNET_OPTION_PROXY = 38;
private const int INTERNET_OPTION_SETTINGS_CHANGED = 39;
struct INTERNET_PROXY_INFO
{
public int dwAccessType;
public IntPtr proxy;
public IntPtr proxyBypass;
};
[System.Runtime.InteropServices.DllImport("wininet.dll")]
private static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength);
#endregion P/Invoke
private const string keyName = @"Software\Microsoft\Windows\CurrentVersion\Internet Settings"; // @HKCU\
private ProxySettings _proxies;
#region Constructors
/// <summary>Initializes a new instance of the <see cref="ConnectionSettings"/> class.</summary>
public ConnectionSettings()
: this(ConnectionType.NoProxy) { }
/// <summary>Initializes a new instance of the <see cref="ConnectionSettings"/> class.</summary>
/// <param name="autoConfigUrl">The automatic configuration URL.</param>
public ConnectionSettings(string autoConfigUrl)
: this(ConnectionType.AutoConfigUrl)
{
this.AutoConfigUrl = autoConfigUrl;
}
/// <summary>Initializes a new instance of the <see cref="ConnectionSettings"/> class.</summary>
/// <param name="address">The proxy address to use for all protocols.</param>
public ConnectionSettings(ProxyAddress address)
: this(address, address, address, address) { }
/// <summary>Initializes a new instance of the <see cref="ConnectionSettings"/> class.</summary>
/// <param name="httpProxy">The HTTP proxy.</param>
/// <param name="httpsProxy">The HTTPS proxy.</param>
/// <param name="ftpProxy">The FTP proxy.</param>
/// <param name="socksProxy">The socks proxy.</param>
public ConnectionSettings(ProxyAddress httpProxy, ProxyAddress httpsProxy,
ProxyAddress ftpProxy, ProxyAddress socksProxy)
: this(ConnectionType.ManualProxy)
{
this.ConnectionType = ConnectionType.ManualProxy;
_proxies = new ProxySettings(httpProxy, httpsProxy, ftpProxy, socksProxy);
}
/// <summary>Initializes a new instance of the <see cref="ConnectionSettings"/> class.</summary>
/// <param name="proxyMode">The proxy mode.</param>
public ConnectionSettings(ConnectionType proxyMode)
{
this.ConnectionType = proxyMode;
this.AutoConfigUrl = "";
_proxies = new ProxySettings();
}
#endregion Constructors
// properties
/// <summary>Gets or sets the url to the script for automatic configuration.</summary>
/// <value>The Auto Configuration URL address.</value>
[DefaultValue("")]
public string AutoConfigUrl { get; set; }
/// <summary>Gets or sets the type of connection.</summary>
/// <value>The type.</value>
public ConnectionType ConnectionType
{
get;
set;
}
/// <summary>Gets the manual proxy configuration.</summary>
[DefaultValue(null)]
public ProxySettings ManualProxy
{
get { return _proxies; }
}
// Methods
/// <summary>Gets the current configuration.</summary>
/// <returns>
/// A <see cref="ConnectionSettings" /> instance representing the current network configuration.
/// </returns>
public static ConnectionSettings GetCurrentConfig()
{
var sep = new[] { ';' };
var rmvEmpty = StringSplitOptions.RemoveEmptyEntries;
var nc = new ConnectionSettings();
var reg = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(keyName);
// connection type checkboxes
var checks = reg.OpenSubKey("Connections")
.GetValue("DefaultConnectionSettings", new byte[10])
.As<byte[]>()[8];
foreach (var flag in ((ConnectionType)checks).GetAllFlagsPresent())
nc.ConnectionType |= flag;
//
// This check may not be needed since the value is likely to be set from
// DefaultConnectionSettings. It is however kept here as a fail-safe measure
// since Microsoft decided to set the value at two different locations.
//
if (reg.GetValue("ProxyEnable", 0).As<int>() == 1)
nc.ConnectionType |= ConnectionType.ManualProxy;
// autoconfig url
nc.AutoConfigUrl = (string)reg.GetValue("AutoConfigUrl", "");
// proxy overrides
var overrides = reg.GetValue("ProxyOverride", "").As<string>().Split(sep, rmvEmpty);
// proxy servers; initialize them all to default
ProxyAddress http = ProxyAddress.Default, https = http, ftp = http, socks = http;
var proxies = reg.GetValue("ProxyServer", "").As<string>().ToLower().Split(sep, rmvEmpty);
if (proxies.Length == 1 && !proxies[0].Contains("=")) // single HTTP proxy won't have an equal sign
http = new ProxyAddress(proxies[0]);
else
foreach (var proxy in proxies)
{
var p = proxy.Split(new[] { '=' }, rmvEmpty);
if (p[0] == "http")
http = new ProxyAddress(p[1]);
else if (p[0] == "https")
https = new ProxyAddress(p[1]);
else if (p[0] == "ftp")
ftp = new ProxyAddress(p[1]);
else if (p[0] == "socks")
socks = new ProxyAddress(p[1]);
}
nc._proxies = new ProxySettings(http, https, ftp, socks, overrides);
return nc;
}
/// <summary>Sets the network configuration via the Windows registry.</summary>
/// <param name="config">The configuration to apply for the network.</param>
/// <returns><c>true</c> if settings are applied successfully; otherwise <c>false</c>.</returns>
public static bool SetConfig(ConnectionSettings config)
{
// bypass registry and use WinAPI if connection type is No Proxy
if (config.ConnectionType == ConnectionType.NoProxy)
return SetConfigWinApi(config);
// main registry key
var reg = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(keyName, true);
// set the check boxes for the connection settings
var checks = reg.OpenSubKey("Connections")
.GetValue("DefaultConnectionSettings", new byte[10])
.As<byte[]>();
checks[8] = (byte)(config.ConnectionType);
reg.OpenSubKey("Connections", true).SetValue("DefaultConnectionSettings",
checks, Microsoft.Win32.RegistryValueKind.Binary);
reg.OpenSubKey("Connections", true).SetValue("SavedLegacySettings",
checks, Microsoft.Win32.RegistryValueKind.Binary);
// proxy settings
if (config.ConnectionType.HasFlag(ConnectionType.ManualProxy))
{
reg.SetValue("ProxyEnable", 1);
reg.SetValue("ProxyServer", config.ManualProxy.ToString());
reg.SetValue("ProxyOverride", config.ManualProxy.ProxyOverrides);
}
else
{
reg.DeleteValue("ProxyEnable", false);
reg.DeleteValue("ProxyServer", false);
}
// auto config url
if (config.ConnectionType.HasFlag(ConnectionType.AutoConfigUrl))
reg.SetValue("AutoConfigUrl", config.AutoConfigUrl);
else
reg.DeleteValue("AutoConfigUrl", false);
// apply the configuration
bool result;
result = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_SETTINGS_CHANGED, IntPtr.Zero, 0);
result &= InternetSetOption(IntPtr.Zero, INTERNET_OPTION_REFRESH, IntPtr.Zero, 0);
return result;
}
/// <summary>Sets the network configuration using WinApi.</summary>
/// <param name="config">The configuration to apply for the network.</param>
/// <returns><c>true</c> if settings are applied successfully; otherwise <c>false</c>.</returns>
public static bool SetConfigWinApi(ConnectionSettings config)
{
var proxy = config.ManualProxy;
return SetProxy.ProxyRoutines.SetProxy(config.ConnectionType != ConnectionType.NoProxy,
config.ConnectionType == ConnectionType.AutoDetect,
proxy.ToString(true),
proxy.BypassList.Count > 0 ? proxy.ProxyOverrides : "",
config.AutoConfigUrl);
/* //!+ Convert C++ implementation to C#
* See http://www.codeproject.com/Articles/3651/Change-Internet-Proxy-settings for a C++
* implementation and try ton convert to C#
*
* The page has been downloaded and saved to the solution directory
*/
}
/// <summary>
/// Determines whether the specified <see cref="System.Object" /> is equal to this instance.
/// </summary>
/// <param name="obj">The <see cref="System.Object" /> to compare with this instance.</param>
/// <returns>
/// <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.
/// </returns>
public override bool Equals(object obj)
{
if (obj.GetType() != typeof(ConnectionSettings)) return false;
var o = (ConnectionSettings)obj;
var result = o != null && this != null;
result &= o.ConnectionType == ConnectionType;
result &= o.ConnectionType == ProxyManager.ConnectionType.AutoConfigUrl ?
o.AutoConfigUrl.Equals(AutoConfigUrl, StringComparison.OrdinalIgnoreCase) : true;
result &= o.ConnectionType == ProxyManager.ConnectionType.ManualProxy ?
o.ManualProxy.NullCheckEquality(ManualProxy) : true;
return result;
}
/// <summary>Returns a hash code for this instance.</summary>
/// <returns>
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
/// </returns>
public override int GetHashCode()
{
return this.ToString().GetHashCode();
}
/// <summary>Returns a <see cref="System.String" /> that represents this ProxySettings instance.</summary>
/// <returns>A <see cref="System.String" /> that represents this instance.</returns>
public override string ToString()
{
// switch on the flags present in the current connection type and return the first
// NB: The order is ManualProxy, AutoConfigUrl, AutoDetect when all flags are present
foreach (var f in this.ConnectionType.GetAllFlagsPresent())
switch (f)
{
case ConnectionType.AutoDetect:
return "Auto detect";
case ConnectionType.AutoConfigUrl:
return "Auto Config URL: " + AutoConfigUrl;
case ConnectionType.ManualProxy:
return "Manual Proxy: " + _proxies.ToString(false);
}
if (this.ConnectionType == ProxyManager.ConnectionType.NoProxy)
return "No Proxy";
else
return "<Unknown>";
}
[OnDeserialized()]
private void OnDeserialized(StreamingContext sc)
{
if (_proxies == null) _proxies = new ProxySettings();
}
[OnSerializing()]
private void OnSerializing(StreamingContext sc)
{
if (!ConnectionType.HasFlag(ConnectionType.ManualProxy))
_proxies = null;
if (!ConnectionType.HasFlag(ConnectionType.AutoConfigUrl))
AutoConfigUrl = "";
}
[OnSerialized()]
private void OnSerialized(StreamingContext sc)
{
if (_proxies == null) _proxies = new ProxySettings();
}
}
}