The WebBrowser control won't work with Proxies from a text file

房东的猫 提交于 2021-02-04 08:07:32

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!