问题
I'm not that great with visual basic so sorry about that, but I have a basic understanding of java, and a few other programming languages so I'm not completely new.
I want to make a program that connects to a website with a proxy loaded from a text file, but when I debug it, it gives me a bunch of different error messages, like:
- HTTP Error 503. The service is unavailable
- The webpage cannot be found
etc.
Here is my code for loading in the proxies into a listbox:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
OpenFileDialog1.ShowDialog()
streamer = IO.File.OpenText(OpenFileDialog1.FileName)
Dim mystring() As String = streamer.ReadToEnd.Split(vbNewLine)
ListBox1.Items.AddRange(mystring)
End Sub
Here's the code for using the proxies:
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Button2.Enabled = False
Button1.Enabled = False
For Each item In ListBox1.Items
UseProxy(item.ToString)
Label4.Text = item
WebBrowser1.Navigate(TextBox3.Text)
pause(10000)
Next
End Sub
And here's useproxy:
Private Sub UseProxy(ByVal strProxy As String)
Const INTERNET_OPTION_PROXY As Integer = 38
Const INTERNET_OPEN_TYPE_PROXY As Integer = 3
Dim struct_IPI As Struct_INTERNET_PROXY_INFO
struct_IPI.dwAccessType = INTERNET_OPEN_TYPE_PROXY
struct_IPI.proxy = Marshal.StringToHGlobalAnsi(strProxy)
struct_IPI.proxyBypass = Marshal.StringToHGlobalAnsi("local")
Dim intptrStruct As IntPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(struct_IPI))
Marshal.StructureToPtr(struct_IPI, intptrStruct, True)
Dim iReturn As Boolean = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_PROXY, intptrStruct, System.Runtime.InteropServices.Marshal.SizeOf(struct_IPI))
End Sub
I also get an error at the end of the button 2 click sub saying this
Actually sometimes when I close the program, I get an error in visual studio on the end of the button2 click sub (Next)
System.InvalidOperationException: 'List that this enumerator is bound to has been modified. An enumerator can only be used if the list does not change.'
回答1:
I think this is the most straightforward method to change the System Proxy settings on a System-wide basis.
Sometimes, a per-connection setting is preferable. See the linked documents in this case.
Use the Registry class to set the required value in the Internet Settings Subkey:Software\Microsoft\Windows\CurrentVersion\Internet Settings
Then, perform a System notification of the change, using InternetSetOption with the INTERNET_OPTION_SETTINGS_CHANGED
and INTERNET_OPTION_REFRESH
Flags:
(These are flags, but should not be combined in this case)INTERNET_OPTION_REFRESH
must also be called if INTERNET_OPTION_PER_CONNECTION_OPTION
is used to modify the settings on a per-connection basis.
Declaration of InternetSetOption
and a helper function.
Imports Microsoft.Win32
Imports System.Runtime.InteropServices
Imports System.Security.AccessControl
<SecurityCritical>
<DllImport("wininet.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
Friend Shared Function InternetSetOption(hInternet As IntPtr, dwOption As Integer, lpBuffer As IntPtr, dwBufferLength As Integer) As Boolean
End Function
Friend Const INTERNET_OPTION_SETTINGS_CHANGED As Integer = 39
Friend Const INTERNET_OPTION_REFRESH As Integer = 37
<SecuritySafeCritical>
Private Sub InternetSetProxy(ProxyAddress As String, ProxyPort As Integer, UseProxy As Boolean)
Dim keyName As String = "Software\Microsoft\Windows\CurrentVersion\Internet Settings"
Dim KeyValue As Object = ProxyAddress + ":" + ProxyPort.ToString()
Dim InternetSettingsKey As RegistryKey =
Registry.CurrentUser.OpenSubKey(keyName,
RegistryKeyPermissionCheck.ReadWriteSubTree,
RegistryRights.WriteKey)
InternetSettingsKey.SetValue("ProxyServer", KeyValue, RegistryValueKind.String)
InternetSettingsKey.SetValue("ProxyEnable", If(UseProxy, 1, 0), RegistryValueKind.DWord)
InternetSettingsKey.Close()
InternetSetOption(IntPtr.Zero, INTERNET_OPTION_SETTINGS_CHANGED, IntPtr.Zero, 0)
InternetSetOption(IntPtr.Zero, INTERNET_OPTION_REFRESH, IntPtr.Zero, 0)
InternetSettingsKey.Dispose()
End Sub
You can test it with Internet Explorer.
If you are using Fiddler, call the helper method with these parameters to use it as the default system proxy:
InternetSetProxy("127.0.0.1", 8888, True)
To disable the Proxy setting, just set the UseProxy
parameter to False
:
InternetSetProxy("127.0.0.1", 8888, False)
Navigate an Internet address as usual:
WebBrowser1.Navigate("https://www.google.com")
A note about the .Net WebBrowser control.
The WebBrowser control uses the current cache (as specified in the Internet Explorer settings) to load visited resources as the pre-defined behaviour.
If you enable the Proxy but you can still see the (first) page of a Website, this depends on this default behaviour.
If you try to click on a link, this new link will not be reachable, and the message:
The proxy server isn’t responding
will be presented.
This kind of result is not constant, it depends on the cache settings.
Edit:
A way to let the WebBrowser
control Navigate
one or more Internet addresses, using a different Proxy server for each address:
Add an event handler for the WebBrowser
DocumentCompleted event.
When the WebBrowser.Navigate()
method is first called, the event handler will cycle through the list of Proxies (read from a ListBox
control Items
list).
This code supposes that the Proxy list is composed of strings that include both the address and the port of each Proxy. (e.g.
"127.0.0.1:8888"
for Fiddler).
Here, as in the OP example, the Internet Address is the same for all Proxies (a parameter of the WaitDocumentsComplete()
method), but of course can be read from another List.
Both the DocumentCompleted
Handler and the helper method NavigateNextProxy()
are marked as Asynchronous, thus the UI is not blocked throughout the whole process.
This process can be stopped at any time, using the WebBrowser.Stop() method, or setting the ProxyIndex
field to a negative value.
If the process is interrupted before its natural completion, it's necessary to explicitly remove the Handler, using:
RemoveHandler WebBrowser1.DocumentCompleted, DocumentCompletedHandler
Event Handler declaration and the Wrapper and Helper functions:
Protected Friend DocumentCompletedHandler As WebBrowserDocumentCompletedEventHandler
Private Sub WaitDocumentsComplete(ByVal Address As String, ByVal TimeOutSeconds As Integer)
DocumentCompletedHandler =
Async Sub(s, e)
If WebBrowser1.ReadyState = WebBrowserReadyState.Complete AndAlso ProxyIndex > -1 Then
If (Not WebBrowser1.IsBusy) Then
Dim ProxyParts() As String = ListBox1.GetItemText(ListBox1.Items(ProxyIndex)).Split(":"c)
Await NavigateNextProxy(Address, ProxyParts(0), CInt(ProxyParts(1)), TimeOutSeconds)
ProxyIndex += 1
If ProxyIndex > ProxyIndexMaxValue Then
ProxyIndex = -1
RemoveHandler WebBrowser1.DocumentCompleted, DocumentCompletedHandler
End If
End If
End If
End Sub
AddHandler WebBrowser1.DocumentCompleted, DocumentCompletedHandler
End Sub
Protected Async Function NavigateNextProxy(Address As String, ByVal ProxyAddr As String, ProxyPort As Integer, TimeOutSeconds As Integer) As Task
InternetSetProxy(ProxyAddr, ProxyPort, True)
Await Task.Delay(TimeSpan.FromSeconds(TimeOutSeconds))
If WebBrowser1.IsBusy Then WebBrowser1.Stop()
WebBrowser1.Navigate(Address)
End Function
From a Button.Click()
event, set the Indexes of the first and last Proxy in the List, a Timeout value (in seconds) between each navigation
, and call the wrapper method WaitDocumentsComplete()
, which will initialize the DocumentCompleted
event handler.
To begin the process, initialize the WebBrowser
control with WebBrowser1.Navigate("")
It's also important to suppress the
WebBrowser
script error dialog, otherwise it will compromise the whole procedure.
Private ProxyIndex As Integer = -1
Private ProxyIndexMaxValue As Integer = 0
Private Sub btnForm2_Click(sender As Object, e As EventArgs) Handles btnForm2.Click
ProxyIndex = 0
ProxyIndexMaxValue = ListBox1.Items.Count - 1
Dim BrowsingTimeoutSeconds As Integer = 3
Dim Address As String = "https://www.google.com"
WaitDocumentsComplete(Address, BrowsingTimeoutSeconds)
WebBrowser1.ScriptErrorsSuppressed = True
WebBrowser1.Navigate("")
End Sub
来源:https://stackoverflow.com/questions/51470532/the-webbrowser-control-wont-work-with-proxies-from-a-text-file