-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathConnectionProxy.bas
484 lines (415 loc) · 18.5 KB
/
ConnectionProxy.bas
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
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
Attribute VB_Name = "ConnectionProxy"
Option Explicit
' Author: Mohammad Maysami
' Usage: Detecting Various Proxy Configurations (Auto Detect, Auto Config URL PAC, Proxy ...)
' GetProxyInfoForUrl(Optional URL, Optional ProxyDetails As Variant) As ProxyInfo
' Syntax1: GetProxyInfoForUrl()
' Syntax2: GetProxyInfoForUrl("http://www.google.com", ProxyDetails)
' Syntax3: GetProxyInfoForUrl(Array("http://www.google.com", "http://www.microsoft.com"), ProxyDetails)
'
'
' Possible AutoProxy Errors:
' 12166 - error in proxy auto-config script code
' 12167 - unable to download proxy auto-config script
' 12180 - WPAD detection failed
'
' Adapted from Stephen Sulzer 2004
'=============================================================
' Type Structure Definitions
'=============================================================
'--------------------------------------
' My ProxyInfo
'--------------------------------------
' Type Structure for my Connection Proxy Information
Public Type ProxyInfo
ProxyActive As Boolean
ProxyServer As String
ProxyBypass As String
End Type
#If VBA7 Then
'--------------------------------------
' IE PROXY CONFIG
'--------------------------------------
' Type Structure for IE Proxy Settings
Private Type WINHTTP_CURRENT_USER_IE_PROXY_CONFIG
fAutoDetect As Long
lpszAutoConfigUrl As LongPtr
lpszProxy As LongPtr
lpszProxyBypass As LongPtr
End Type
'--------------------------------------
' WinHttp Proxy Info
'--------------------------------------
Private Type WINHTTP_PROXY_INFO
dwAccessType As Long
lpszProxy As LongPtr
lpszProxyBypass As LongPtr
End Type
'--------------------------------------
' AutoProxy Options
'--------------------------------------
' Type Structure for AutoProxy Options
Private Type WINHTTP_AUTOPROXY_OPTIONS
dwFlags As Long
dwAutoDetectFlags As Long
lpszAutoConfigUrl As LongPtr
lpvReserved As LongPtr
dwReserved As Long
fAutoLogonIfChallenged As Long
End Type
#Else
'--------------------------------------
' IE PROXY CONFIG
'--------------------------------------
' Type Structure for IE Proxy Settings
Private Type WINHTTP_CURRENT_USER_IE_PROXY_CONFIG
fAutoDetect As Long
lpszAutoConfigUrl As Long
lpszProxy As Long
lpszProxyBypass As Long
End Type
'--------------------------------------
' WinHttp Proxy Info
'--------------------------------------
Private Type WINHTTP_PROXY_INFO
dwAccessType As Long
lpszProxy As Long
lpszProxyBypass As Long
End Type
'--------------------------------------
' AutoProxy Options
'--------------------------------------
' Type Structure for AutoProxy Options
Private Type WINHTTP_AUTOPROXY_OPTIONS
dwFlags As Long
dwAutoDetectFlags As Long
lpszAutoConfigUrl As Long
lpvReserved As Long
dwReserved As Long
fAutoLogonIfChallenged As Long
End Type
#End If
' AutoProxy Options Constants
'--------------------------------------
' Constants for dwFlags of WINHTTP_AUTOPROXY_OPTIONS
Private Const WINHTTP_AUTOPROXY_AUTO_DETECT = 1
Private Const WINHTTP_AUTOPROXY_CONFIG_URL = 2
' Constants for dwAutoDetectFlags of WINHTTP_AUTOPROXY_OPTIONS
Private Const WINHTTP_AUTO_DETECT_TYPE_DHCP = 1
Private Const WINHTTP_AUTO_DETECT_TYPE_DNS = 2
' Constants for URLs to Ping and AutoDetect Proxy
Private Const NRConnectionURL1 As String = "http://www.microsoft.com"
Private Const NRConnectionURL2 As String = "http://www.google.com"
Private Const NRConnectionURL3 As String = "http://www.wikipedia.com"
'=============================================================
' Lib Declarations
'=============================================================
' VBA7 IF To Address both 32/64-bits
#If VBA7 Then
' Need CopyMemory to copy BSTR pointers around
Private Declare PtrSafe Sub CopyMemory Lib "kernel32" _
Alias "RtlMoveMemory" (ByVal lpDest As LongPtr, _
ByVal lpSource As LongPtr, ByVal cbCopy As Long)
' SysAllocString creates a UNICODE BSTR string based on a UNICODE string
Private Declare PtrSafe Function SysAllocString Lib "oleaut32" (ByVal pwsz As LongPtr) As LongPtr
' Need GlobalFree to free the pointers in the CURRENT_USER_IE_PROXY_CONFIG
' structure returned from WinHttpGetIEProxyConfigForCurrentUser, per the documentation
Private Declare PtrSafe Function GlobalFree Lib "kernel32" (ByVal p As LongPtr) As LongPtr
' https://docs.microsoft.com/en-us/windows/desktop/api/winhttp/nf-winhttp-winhttpgetieproxyconfigforcurrentuser
'BOOLAPI WinHttpGetIEProxyConfigForCurrentUser(
' IN OUT WINHTTP_CURRENT_USER_IE_PROXY_CONFIG *pProxyConfig);
Private Declare PtrSafe Function WinHttpGetIEProxyConfigForCurrentUser Lib "WinHTTP.dll" _
(ByRef proxyConfig As WINHTTP_CURRENT_USER_IE_PROXY_CONFIG) As Long
' https://docs.microsoft.com/en-us/windows/desktop/api/winhttp/nf-winhttp-winhttpgetproxyforurl
' Returns 0 on Fail, Number Otherwise ?
' BOOLAPI WinHttpGetProxyForUrl(
' IN HINTERNET hSession,
' IN LPCWSTR lpcwszUrl,
' IN WINHTTP_AUTOPROXY_OPTIONS *pAutoProxyOptions,
' OUT WINHTTP_PROXY_INFO *pProxyInfo);
Private Declare PtrSafe Function WinHttpGetProxyForUrl Lib "WinHTTP.dll" _
(ByVal hSession As LongPtr, _
ByVal pszUrl As LongPtr, _
ByRef pAutoProxyOptions As WINHTTP_AUTOPROXY_OPTIONS, _
ByRef pProxyInfo As WINHTTP_PROXY_INFO) As Long
' https://docs.microsoft.com/en-us/windows/desktop/api/winhttp/nf-winhttp-winhttpopen
'WINHTTPAPI HINTERNET WinHttpOpen(
' LPCWSTR pszAgentW,
' DWORD dwAccessType,
' LPCWSTR pszProxyW,
' LPCWSTR pszProxyBypassW,
' DWORD dwFlags);
Private Declare PtrSafe Function WinHttpOpen Lib "WinHTTP.dll" _
(ByVal pszUserAgent As LongPtr, _
ByVal dwAccessType As Long, _
ByVal pszProxyName As LongPtr, _
ByVal pszProxyBypass As LongPtr, _
ByVal dwFlags As Long) As LongPtr
' https://docs.microsoft.com/en-us/windows/desktop/api/winhttp/nf-winhttp-winhttpclosehandle
' BOOLAPI WinHttpCloseHandle(
' IN HINTERNET hInternet);
Private Declare PtrSafe Function WinHttpCloseHandle Lib "WinHTTP.dll" _
(ByVal hInternet As LongPtr) As Long
#Else
Private Declare Sub CopyMemory Lib "kernel32" _
Alias "RtlMoveMemory" (ByVal lpDest As Long, _
ByVal lpSource As Long, ByVal cbCopy As Long)
Private Declare Function SysAllocString Lib "oleaut32" (ByVal pwsz As Long) As Long
Private Declare Function GlobalFree Lib "kernel32" (ByVal p As Long) As Long
Private Declare Function WinHttpGetIEProxyConfigForCurrentUser Lib "WinHTTP.dll" _
(ByRef proxyConfig As WINHTTP_CURRENT_USER_IE_PROXY_CONFIG) As Long
Private Declare Function WinHttpGetProxyForUrl Lib "WinHTTP.dll" _
(ByVal hSession As Long, _
ByVal pszUrl As Long, _
ByRef pAutoProxyOptions As WINHTTP_AUTOPROXY_OPTIONS, _
ByRef pProxyInfo As WINHTTP_PROXY_INFO) As Long
Private Declare Function WinHttpOpen Lib "WinHTTP.dll" _
(ByVal pszUserAgent As Long, _
ByVal dwAccessType As Long, _
ByVal pszProxyName As Long, _
ByVal pszProxyBypass As Long, _
ByVal dwFlags As Long) As Long
Private Declare Function WinHttpCloseHandle Lib "WinHTTP.dll" _
(ByVal hInternet As Long) As Long
#End If
'**************************************************************************************************************************
'**************************************************************************************************************************
'**************************************************************************************************************************
'=============================================================
' Get Proxy Info
'=============================================================
Public Function GetProxyInfoForUrl(Optional URL, Optional ProxyDetails As Variant) As ProxyInfo
' Using a user-defined Full (Array of) URL(s), Get IE Proxy Config and
' Find Proxy based on Auto Detect Protocols (AutoDetect, AutoConfigURL for PAC File)
' or by IE Proxy if available
' It returns ProxyInfo Structure (Boolean Active,String Proxy, String ProxyByPass
'
' Syntax1: GetProxyInfoForUrl()
' Syntax2: GetProxyInfoForUrl("http://www.google.com", ProxyDetails)
' Syntax3: GetProxyInfoForUrl(Array("http://www.google.com", "http://www.microsoft.com"), ProxyDetails)
'
' Inputs:
' opt IN URL(s) : Array of or Single String Full URLs to AutoDetect Proxy
' opt OUT ProxyDetails: Custom IE Proxy Structure to Pass out IE Proxy Details and Status Code
' (1) = IE AutoDetect (fAutoDetect)
' (2) = IE AutoCofigUrl (lpszAutoConfigUrl)
' (3) = IE Proxy (lpszProxy)
' (4) = IE Proxy Bypass (lpszProxyBypass)
' (5) = DevCode
'
' Outputs:
' OUT ProxyInfo : Boolean Active, String Proxy, String ProxyBypass
'
' Notes, Possible AutoProxy Errors:
' 12166 - error in proxy auto-config script code
' 12167 - unable to download proxy auto-config script
' 12180 - WPAD detection failed
'
Dim IEProxyConfig As WINHTTP_CURRENT_USER_IE_PROXY_CONFIG
Dim AutoProxyOptions As WINHTTP_AUTOPROXY_OPTIONS
Dim WinHttpProxyInfo As WINHTTP_PROXY_INFO
Dim ProxyInfo As ProxyInfo
'Dim fStatusProxy As Integer
Dim fDoAutoProxy As Boolean
#If VBA7 Then
Dim ProxyStringPtr As LongPtr
Dim ptr As LongPtr
#Else
Dim ProxyStringPtr As Long
Dim ptr As Long
#End If
Dim error As Long
Dim DevCode As String
Dim trial As Integer
Dim MaxTrial As Integer
' --------------------------------------------
' Init. URLs and Max Trials
' --------------------------------------------
If IsMissing(URL) Then
URL = Array(NRConnectionURL1)
MaxTrial = 1
Else
'
If IsArray(URL) Then
MaxTrial = UBound(URL) - LBound(URL) + 1
ElseIf WorksheetFunction.IsText(URL) Then
URL = Array(URL)
MaxTrial = 1
Else
URL = Array(NRConnectionURL1)
MaxTrial = 1
End If
End If
' --------------------------------------------
' Reset/Init Class Instances
' --------------------------------------------
' Init ProxyInfo
ProxyInfo.ProxyActive = False
ProxyInfo.ProxyServer = vbNullString
ProxyInfo.ProxyBypass = vbNullString
' Init WinHttpProxyInfo
WinHttpProxyInfo.dwAccessType = 0
WinHttpProxyInfo.lpszProxy = 0
WinHttpProxyInfo.lpszProxyBypass = 0
' Init IEProxyConfig
IEProxyConfig.fAutoDetect = 0
IEProxyConfig.lpszAutoConfigUrl = 0
IEProxyConfig.lpszProxy = 0
IEProxyConfig.lpszProxyBypass = 0
' Init AutoProxyOptions
AutoProxyOptions.dwFlags = 0
AutoProxyOptions.dwAutoDetectFlags = 0
AutoProxyOptions.lpszAutoConfigUrl = 0
AutoProxyOptions.dwReserved = 0
AutoProxyOptions.lpvReserved = 0
AutoProxyOptions.fAutoLogonIfChallenged = 1
' Other Flags
'fStatusProxy = 0
fDoAutoProxy = False
ProxyStringPtr = 0
ptr = 0
DevCode = ""
trial = 0
' --------------------------------------------
' Check IE's proxy configuration
' --------------------------------------------
If (WinHttpGetIEProxyConfigForCurrentUser(IEProxyConfig) > 0) Then
' If IE is configured to auto-detect, then we will too.
If (IEProxyConfig.fAutoDetect <> 0) Then
'fStatusProxy = fStatusProxy + 1
DevCode = DevCode & vbCrLf & "[IE Auto Detect]"
AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT
AutoProxyOptions.dwAutoDetectFlags = _
WINHTTP_AUTO_DETECT_TYPE_DHCP + _
WINHTTP_AUTO_DETECT_TYPE_DNS
fDoAutoProxy = True
End If
' If IE is configured to use an auto-config script, then
' we will use it too
If (IEProxyConfig.lpszAutoConfigUrl <> 0) Then
'fStatusProxy = fStatusProxy + 10
DevCode = DevCode & vbCrLf & "[AutoConfigUrl PAC]"
AutoProxyOptions.dwFlags = AutoProxyOptions.dwFlags + _
WINHTTP_AUTOPROXY_CONFIG_URL
'If dwFlags includes the WINHTTP_AUTOPROXY_CONFIG_URL flag,
' the lpszAutoConfigUrl must point to a null-terminated Unicode string
' that contains the URL of the proxy auto-configuration (PAC) file.
AutoProxyOptions.lpszAutoConfigUrl = IEProxyConfig.lpszAutoConfigUrl
fDoAutoProxy = True
End If
Else
'fStatusProxy = fStatusProxy + 100
DevCode = DevCode & vbCrLf & "[No Proxy Config]"
' if the IE proxy config is not available, then
' we will try auto-detection
AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT
AutoProxyOptions.dwAutoDetectFlags = _
WINHTTP_AUTO_DETECT_TYPE_DHCP + _
WINHTTP_AUTO_DETECT_TYPE_DNS
fDoAutoProxy = True
End If
' --------------------------------------------
' Handle Auto Proxy Configurations
' --------------------------------------------
If fDoAutoProxy Then
#If VBA7 Then
Dim hSession As LongPtr
#Else
Dim hSession As Long
#End If
' Need to create a temporary WinHttp session handle
' Note: performance of this GetProxyInfoForUrl function can be
' improved by saving this hSession handle across calls
' instead of creating a new handle each time
hSession = WinHttpOpen(0, 1, 0, 0, 0)
Do While trial < MaxTrial
trial = trial + 1
If (WinHttpGetProxyForUrl(hSession, StrPtr(URL(trial - 1)), AutoProxyOptions, _
WinHttpProxyInfo) > 0) Then
DevCode = DevCode & vbCrLf & "{Pass" & trial & ": " & WinHttpProxyInfo.lpszProxy & "}"
ProxyStringPtr = WinHttpProxyInfo.lpszProxy
' Ignore WinHttpProxyInfo.lpszProxyBypass, it will not be set
If (ProxyStringPtr <> 0) Then
' Terminate Trial Loop if Found
trial = MaxTrial + 1
End If
Else
' some possibly autoproxy errors:
' 12166 - error in proxy auto-config script code
' 12167 - unable to download proxy auto-config script
' 12180 - WPAD detection failed
error = Err.LastDllError
Select Case error
Case 12166
DevCode = DevCode & vbCrLf & "{Fail" & trial & ": PAC Script Execution}"
Case 12167
DevCode = DevCode & vbCrLf & "{Fail" & trial & ": PAC File Download}"
Case 12180
DevCode = DevCode & vbCrLf & "{Fail" & trial & ": PAC URL (WPAD) Detection}"
Case Else
DevCode = DevCode & vbCrLf & "{Fail" & trial & ": " & error & "}"
End Select
End If
Loop
WinHttpCloseHandle (hSession)
End If
' --------------------------------------------
' Check IE Proxy, If NO Proxy Detected
' --------------------------------------------
' If we don't have a proxy server from WinHttpGetProxyForUrl,
' then pick one up from the IE proxy config (if given)
If (ProxyStringPtr = 0) Then
DevCode = DevCode & vbCrLf & "[Empty ProxyForUrl String]"
ProxyStringPtr = IEProxyConfig.lpszProxy
End If
' --------------------------------------------
' Convert Proxy to Basic Strings ==> ProxyInfo
' --------------------------------------------
' If there's a proxy string, convert it to a Basic string
If (ProxyStringPtr <> 0) Then
'fStatusProxy = fStatusProxy + 1000
DevCode = DevCode & vbCrLf & "[IE Proxy Config]"
ptr = SysAllocString(ProxyStringPtr)
CopyMemory VarPtr(ProxyInfo.ProxyServer), VarPtr(ptr), 4
ProxyInfo.ProxyActive = True
End If
' --------------------------------------------
' Pick IE Proxy ByPass ==> ProxyInfo
' --------------------------------------------
' Pick up any bypass string from the IEProxyConfig
If (IEProxyConfig.lpszProxyBypass <> 0) Then
ptr = SysAllocString(IEProxyConfig.lpszProxyBypass)
CopyMemory VarPtr(ProxyInfo.ProxyBypass), VarPtr(ptr), 4
End If
If Not IsMissing(ProxyDetails) Then
ReDim ProxyDetails(5) As Variant
ProxyDetails(1) = IEProxyConfig.fAutoDetect
ProxyDetails(2) = IEProxyConfig.lpszAutoConfigUrl
ProxyDetails(3) = IEProxyConfig.lpszProxy
ProxyDetails(4) = IEProxyConfig.lpszProxyBypass
ProxyDetails(5) = DevCode
End If
GetProxyInfoForUrl = ProxyInfo
' --------------------------------------------
' Free Up Memory/Pointers
' --------------------------------------------
' Free any strings received from WinHttp APIs
If (IEProxyConfig.lpszAutoConfigUrl <> 0) Then
GlobalFree (IEProxyConfig.lpszAutoConfigUrl)
End If
If (IEProxyConfig.lpszProxy <> 0) Then
GlobalFree (IEProxyConfig.lpszProxy)
End If
If (IEProxyConfig.lpszProxyBypass <> 0) Then
GlobalFree (IEProxyConfig.lpszProxyBypass)
End If
If (WinHttpProxyInfo.lpszProxy <> 0) Then
GlobalFree (WinHttpProxyInfo.lpszProxy)
End If
If (WinHttpProxyInfo.lpszProxyBypass <> 0) Then
GlobalFree (WinHttpProxyInfo.lpszProxyBypass)
End If
End Function
'**************************************************************************************************************************
'**************************************************************************************************************************
'**************************************************************************************************************************