6

I have found all kind of examples about how to make TWebBrowser use a proxy (like 202.8.128.5:8080). However all those examples are changing the proxy globally for all running instances of TWebBrowser. I have two instances. How do I set a different proxy for each browser?

t1f
  • 3,021
  • 3
  • 31
  • 61
Beno
  • 163
  • 8
  • 1
    https://msdn.microsoft.com/en-us/library/windows/desktop/aa385328.aspx#INTERNET_OPTION_PER_CONNECTION_OPTION – David Heffernan Feb 25 '15 at 11:12
  • 2
    Those options apply to the WinInet API, which `TWebBrowser` does not use. It uses the `IWebBrowser2` interface instead. Although `IWebBrowser2` is a wrapper for Internet Explorer, which itself uses WinInet internally, you cannot apply per-instance WinInet options to `IWebBrowser2`. They can only be used when the WinInet API is being used directly. – Remy Lebeau Feb 26 '15 at 01:40
  • 2
    That's too bad. Many thanks anyway. – Beno Feb 26 '15 at 13:53
  • @Beno - check out my answer, that should get you going. – t1f Aug 11 '17 at 21:02

1 Answers1

1

This can be achieved using the following code (public code, not mine):

{$DEFINE DELPHI2009_UP}

function SetProxy(Server: String): Boolean;
// Server z.B. '127.0.0.1:8080' oder ''
type
  INTERNET_PER_CONN_OPTION = record
    dwOption: DWORD;
    Value: record case Integer of 1: (dwValue: DWORD);
    2: (pszValue: {$IFDEF DELPHI2009_UP}PWideChar{$ELSE}PAnsiChar{$ENDIF});
    3: (ftValue: TFileTime);
  end;

end;
LPINTERNET_PER_CONN_OPTION = ^INTERNET_PER_CONN_OPTION;
INTERNET_PER_CONN_OPTION_LIST = record dwSize: DWORD;
pszConnection:
LPTSTR;
dwOptionCount:
DWORD;
dwOptionError:
DWORD;
pOptions:
LPINTERNET_PER_CONN_OPTION;
end;
LPINTERNET_PER_CONN_OPTION_LIST = ^INTERNET_PER_CONN_OPTION_LIST;

const
  INTERNET_PER_CONN_FLAGS = 1;
  INTERNET_PER_CONN_PROXY_SERVER = 2;
  INTERNET_PER_CONN_PROXY_BYPASS = 3;
  INTERNET_PER_CONN_AUTOCONFIG_URL = 4;
  INTERNET_PER_CONN_AUTODISCOVERY_FLAGS = 5;
  PROXY_TYPE_DIRECT = $00000001;
  PROXY_TYPE_PROXY = $00000002;
  PROXY_TYPE_AUTO_PROXY_URL = $00000004;
  PROXY_TYPE_AUTO_DETECT = $00000008;
  INTERNET_OPTION_REFRESH = 37;
  INTERNET_OPTION_PER_CONNECTION_OPTION = 75;
  INTERNET_OPTION_SETTINGS_CHANGED = 39;

var
  OptionsList: INTERNET_PER_CONN_OPTION_LIST;
  BufSize: DWORD;
  HInternet: Pointer;
  Agent: String;

begin
  Result := False;
  BufSize := SizeOf(OptionsList);
  OptionsList.dwSize := BufSize;
  OptionsList.pszConnection := nil; // nil -> LAN, sonst Verbindungsname
  OptionsList.dwOptionCount := 3; // 3 Optionen werden gesetzt
  OptionsList.pOptions := AllocMem(3 * SizeOf(INTERNET_PER_CONN_OPTION));
  try
    if not Assigned(OptionsList.pOptions) then
      EXIT;
    OptionsList.pOptions^.dwOption := INTERNET_PER_CONN_FLAGS;
    OptionsList.pOptions^.Value.dwValue := PROXY_TYPE_DIRECT or
      PROXY_TYPE_PROXY;
    inc(OptionsList.pOptions);
    OptionsList.pOptions^.dwOption := INTERNET_PER_CONN_PROXY_SERVER;
    OptionsList.pOptions^.Value.pszValue := PChar(Server);
    inc(OptionsList.pOptions);
    OptionsList.pOptions^.dwOption := INTERNET_PER_CONN_PROXY_BYPASS;
    OptionsList.pOptions^.Value.pszValue := 'local';
    dec(OptionsList.pOptions, 2);
    Agent := ExtractFileName(Application.ExeName);
    HInternet := InternetOpen
      ({$IFDEF DELPHI2009_UP}PWideChar{$ELSE}PAnsiChar{$ENDIF}
      (Agent), INTERNET_OPEN_TYPE_DIRECT, nil, nil, 0);
    try // Optionen setzen
      Result := InternetSetOption(HInternet,
        INTERNET_OPTION_PER_CONNECTION_OPTION, @OptionsList, BufSize);
      InternetSetOption(HInternet, INTERNET_OPTION_REFRESH, nil, 0);
    finally
      InternetCloseHandle(HInternet);
    end;
  finally
    FreeMem(OptionsList.pOptions); // Speicher freigeben
  end;
end;
  • Drop two TWebBrowser components on your form and two TButton
  • TWebBrowser components will have the default names WebBrowser1 and WebBrowser2
  • The twoTButton will have the default names Button1 and Button2
  • Add WinInet to your uses clause

Call the above function in Button1

Code for Button1 OnClick event:

procedure TForm1.Button1Click(Sender: TObject);
begin
SetProxy('ip:port');
WebBrowser1.Navigate('www.whatismyipaddress.com');
end;

Code for Button2 OnClick event:

procedure TForm1.Button2Click(Sender: TObject);
begin
SetProxy('ip:port');
WebBrowser2.Navigate('www.whatismyipaddress.com');
end;

And here is how it looks:

enter image description here

On the left is WebBrowser1 with a proxy and on the right is WebBrowser2 with a different proxy - both browsers are in the same application and apparently they worked. I've also visited the address from my regular browser (Chrome) while the application was running and it indeed showed up as using my original connection.

So, it works. The WebBrowser components are using their assigned proxy's while the browser on my pc remains unaffected (isn't using either of the proxy's)

Tested this using Rad Studio 10.2 Tokyo just now. Good luck :)

UPDATE

As highlighted in the comments, a way to set the proxy that will be used to navigate, without setting it at design time or in the button you use to Navigate is by using a TStringList and loading it from a file (.txt, for example). This can be used in the TWebBrowser OnBeforeNavigate2 event.

procedure TForm1.WebBrowser1BeforeNavigate2(ASender: TObject; const pDisp: IDispatch; var URL, Flags, TargetFrameName, PostData, Headers: OleVariant; var Cancel: WordBool);

var
proxylist: TStringList;

begin
proxylist:= TStringList.Create;
proxylist.LoadFromFile('proxylist.txt');
SetProxy(proxylist.Strings[0]); //adds the proxy from the 1st line in the txt
proxylist.Free;
end;

Create a .txt file named proxylist in your application folder and write the proxy there.

Now you'll have a proxy set for your TWebBrowser before you begin to navigate. Either way, I'm sure there a lot of ways to expand this so use your imagination.

t1f
  • 3,021
  • 3
  • 31
  • 61
  • 1
    What happens if you add a third button which calls `Navigate()` on both browser controls without setting the proxy first? I didn't test but assume that this will prove that the two browser instances do not in fact use independent proxies but just the last one that was set. – mghie Aug 14 '17 at 04:20
  • @mghie The question was how do you set a different proxy for each `TWebBrowser` without changing the global setting on the system or each other. You can set the proxy in the `TWebBrowser` `OnBeforeNavigate2` event, either at design time or by using a TStringList and loading a proxy from a .txt/.ini list in the program folder, indicating which line to load, looping them and so forth. I've just tested that and I can confirm this approach also works and saves you the trouble, you can navigate freely once its set using the event. – t1f Aug 14 '17 at 04:46