How To: Set the proxy for the WebBrowser control in .NET
I see some horrible solutions for this out on the web. Most involve setting the proxy for the entire machine and then toggling it back off. Here is a class that will allow you to set it ONLY FOR THE PROCESS that the control is hosted in. You could call it like this:
WinInetInterop.SetConnectionProxy(“localhost:8888”);
and then restore it to the default set in IE with this call:
// read the default settings for IE and restore these as the proxy
WinInetInterop.RestoreSystemProxy();
Let me know if you thought this was useful!
Listing:
Using System;
using System.Runtime.InteropServices;
namespace SetProxy
{
public static class WinInetInterop
{
public static string applicationName;
[DllImport("wininet.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr InternetOpen(
string lpszAgent, int dwAccessType, string lpszProxyName,
string lpszProxyBypass, int dwFlags);
[DllImport("wininet.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool InternetCloseHandle(IntPtr hInternet);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
private struct INTERNET_PER_CONN_OPTION_LIST
{
public int Size;
// The connection to be set. NULL means LAN.
public System.IntPtr Connection;
public int OptionCount;
public int OptionError;
// List of INTERNET_PER_CONN_OPTIONs.
public System.IntPtr pOptions;
}
private enum INTERNET_OPTION
{
// Sets or retrieves an INTERNET_PER_CONN_OPTION_LIST structure that specifies
// a list of options for a particular connection.
INTERNET_OPTION_PER_CONNECTION_OPTION = 75,
// Notify the system that the registry settings have been changed so that
// it verifies the settings on the next call to InternetConnect.
INTERNET_OPTION_SETTINGS_CHANGED = 39,
// Causes the proxy data to be reread from the registry for a handle.
INTERNET_OPTION_REFRESH = 37
}
private enum INTERNET_PER_CONN_OptionEnum
{
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,
INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL = 6,
INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS = 7,
INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME = 8,
INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_URL = 9,
INTERNET_PER_CONN_FLAGS_UI = 10
}
private const int INTERNET_OPEN_TYPE_DIRECT = 1; // direct to net
private const int INTERNET_OPEN_TYPE_PRECONFIG = 0; // read registry
/// <summary>
/// Constants used in INTERNET_PER_CONN_OPTON struct.
/// </summary>
private enum INTERNET_OPTION_PER_CONN_FLAGS
{
PROXY_TYPE_DIRECT = 0x00000001, // direct to net
PROXY_TYPE_PROXY = 0x00000002, // via named proxy
PROXY_TYPE_AUTO_PROXY_URL = 0x00000004, // autoproxy URL
PROXY_TYPE_AUTO_DETECT = 0x00000008 // use autoproxy detection
}
/// <summary>
/// Used in INTERNET_PER_CONN_OPTION.
/// When create a instance of OptionUnion, only one filed will be used.
/// The StructLayout and FieldOffset attributes could help to decrease the struct size.
/// </summary>
[StructLayout(LayoutKind.Explicit)]
private struct INTERNET_PER_CONN_OPTION_OptionUnion
{
// A value in INTERNET_OPTION_PER_CONN_FLAGS.
[FieldOffset(0)]
public int dwValue;
[FieldOffset(0)]
public System.IntPtr pszValue;
[FieldOffset(0)]
public System.Runtime.InteropServices.ComTypes.FILETIME ftValue;
}
[StructLayout(LayoutKind.Sequential)]
private struct INTERNET_PER_CONN_OPTION
{
// A value in INTERNET_PER_CONN_OptionEnum.
public int dwOption;
public INTERNET_PER_CONN_OPTION_OptionUnion Value;
}
/// <summary>
/// Sets an Internet option.
/// </summary>
[DllImport("wininet.dll", CharSet = CharSet.Ansi, SetLastError = true)]
private static extern bool InternetSetOption(
IntPtr hInternet,
INTERNET_OPTION dwOption,
IntPtr lpBuffer,
int lpdwBufferLength);
/// <summary>
/// Queries an Internet option on the specified handle. The Handle will be always 0.
/// </summary>
[DllImport("wininet.dll", CharSet = CharSet.Ansi, SetLastError = true,
EntryPoint = "InternetQueryOption")]
private extern static bool InternetQueryOptionList(
IntPtr Handle,
INTERNET_OPTION OptionFlag,
ref INTERNET_PER_CONN_OPTION_LIST OptionList,
ref int size);
/// <summary>
/// Set the proxy server for LAN connection.
/// </summary>
public static bool SetConnectionProxy(string proxyServer )
{
IntPtr hInternet = InternetOpen(applicationName,INTERNET_OPEN_TYPE_DIRECT, null, null, 0);
//// Create 3 options.
//INTERNET_PER_CONN_OPTION[] Options = new INTERNET_PER_CONN_OPTION[3];
// Create 2 options.
INTERNET_PER_CONN_OPTION[] Options = new INTERNET_PER_CONN_OPTION[2];
// Set PROXY flags.
Options[0] = new INTERNET_PER_CONN_OPTION();
Options[0].dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_FLAGS;
Options[0].Value.dwValue = (int)INTERNET_OPTION_PER_CONN_FLAGS.PROXY_TYPE_PROXY;
// Set proxy name.
Options[1] = new INTERNET_PER_CONN_OPTION();
Options[1].dwOption =
(int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_PROXY_SERVER;
Options[1].Value.pszValue = Marshal.StringToHGlobalAnsi(proxyServer);
//// Set proxy bypass.
//Options[2] = new INTERNET_PER_CONN_OPTION();
//Options[2].dwOption =
// (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_PROXY_BYPASS;
//Options[2].Value.pszValue = Marshal.StringToHGlobalAnsi("local");
//// Allocate a block of memory of the options.
//System.IntPtr buffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(Options[0])
// + Marshal.SizeOf(Options[1]) + Marshal.SizeOf(Options[2]));
// Allocate a block of memory of the options.
System.IntPtr buffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(Options[0])
+ Marshal.SizeOf(Options[1]));
System.IntPtr current = buffer;
// Marshal data from a managed object to an unmanaged block of memory.
for (int i = 0; i < Options.Length; i++)
{
Marshal.StructureToPtr(Options[i], current, false);
current = (System.IntPtr)((int)current + Marshal.SizeOf(Options[i]));
}
// Initialize a INTERNET_PER_CONN_OPTION_LIST instance.
INTERNET_PER_CONN_OPTION_LIST option_list = new INTERNET_PER_CONN_OPTION_LIST();
// Point to the allocated memory.
option_list.pOptions = buffer;
// Return the unmanaged size of an object in bytes.
option_list.Size = Marshal.SizeOf(option_list);
// IntPtr.Zero means LAN connection.
option_list.Connection = IntPtr.Zero;
option_list.OptionCount = Options.Length;
option_list.OptionError = 0;
int size = Marshal.SizeOf(option_list);
// Allocate memory for the INTERNET_PER_CONN_OPTION_LIST instance.
IntPtr intptrStruct = Marshal.AllocCoTaskMem(size);
// Marshal data from a managed object to an unmanaged block of memory.
Marshal.StructureToPtr(option_list, intptrStruct, true);
// Set internet settings.
bool bReturn = InternetSetOption(hInternet,
INTERNET_OPTION.INTERNET_OPTION_PER_CONNECTION_OPTION, intptrStruct, size);
// Free the allocated memory.
Marshal.FreeCoTaskMem(buffer);
Marshal.FreeCoTaskMem(intptrStruct);
InternetCloseHandle(hInternet);
// Throw an exception if this operation failed.
if (!bReturn)
{
throw new ApplicationException(" Set Internet Option Failed!");
}
return bReturn;
}
/// <summary>
/// Backup the current options for LAN connection.
/// Make sure free the memory after restoration.
/// </summary>
private static INTERNET_PER_CONN_OPTION_LIST GetSystemProxy()
{
// Query following options.
INTERNET_PER_CONN_OPTION[] Options = new INTERNET_PER_CONN_OPTION[3];
Options[0] = new INTERNET_PER_CONN_OPTION();
Options[0].dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_FLAGS;
Options[1] = new INTERNET_PER_CONN_OPTION();
Options[1].dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_PROXY_SERVER;
Options[2] = new INTERNET_PER_CONN_OPTION();
Options[2].dwOption = (int)INTERNET_PER_CONN_OptionEnum.INTERNET_PER_CONN_PROXY_BYPASS;
// Allocate a block of memory of the options.
System.IntPtr buffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(Options[0])
+ Marshal.SizeOf(Options[1]) + Marshal.SizeOf(Options[2]));
System.IntPtr current = (System.IntPtr)buffer;
// Marshal data from a managed object to an unmanaged block of memory.
for (int i = 0; i < Options.Length; i++)
{
Marshal.StructureToPtr(Options[i], current, false);
current = (System.IntPtr)((int)current + Marshal.SizeOf(Options[i]));
}
// Initialize a INTERNET_PER_CONN_OPTION_LIST instance.
INTERNET_PER_CONN_OPTION_LIST Request = new INTERNET_PER_CONN_OPTION_LIST();
// Point to the allocated memory.
Request.pOptions = buffer;
Request.Size = Marshal.SizeOf(Request);
// IntPtr.Zero means LAN connection.
Request.Connection = IntPtr.Zero;
Request.OptionCount = Options.Length;
Request.OptionError = 0;
int size = Marshal.SizeOf(Request);
// Query internet options.
bool result = InternetQueryOptionList(IntPtr.Zero,
INTERNET_OPTION.INTERNET_OPTION_PER_CONNECTION_OPTION,
ref Request, ref size);
if (!result)
{
throw new ApplicationException(" Set Internet Option Failed! ");
}
return Request;
}
/// <summary>
/// Restore the options for LAN connection.
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public static bool RestoreSystemProxy()
{
IntPtr hInternet = InternetOpen(applicationName, INTERNET_OPEN_TYPE_DIRECT, null, null, 0);
INTERNET_PER_CONN_OPTION_LIST request = GetSystemProxy();
int size = Marshal.SizeOf(request);
// Allocate memory.
IntPtr intptrStruct = Marshal.AllocCoTaskMem(size);
// Convert structure to IntPtr
Marshal.StructureToPtr(request, intptrStruct, true);
// Set internet options.
bool bReturn = InternetSetOption(hInternet,
INTERNET_OPTION.INTERNET_OPTION_PER_CONNECTION_OPTION,
intptrStruct, size);
// Free the allocated memory.
Marshal.FreeCoTaskMem(request.pOptions);
Marshal.FreeCoTaskMem(intptrStruct);
if (!bReturn)
{
throw new ApplicationException(" Set Internet Option Failed! ");
}
// Notify the system that the registry settings have been changed and cause
// the proxy data to be reread from the registry for a handle.
InternetSetOption(hInternet, INTERNET_OPTION.INTERNET_OPTION_SETTINGS_CHANGED,
IntPtr.Zero, 0);
InternetSetOption(hInternet, INTERNET_OPTION.INTERNET_OPTION_REFRESH,
IntPtr.Zero, 0);
InternetCloseHandle(hInternet);
return bReturn;
}
}
}
Comments
Anonymous
June 04, 2011
Great code!! thanks!Anonymous
July 07, 2011
Hi! Let me check this solution. If this work then this will be great!. I am searching for this solution for week,s and did not found a single solution!Anonymous
July 11, 2011
Thanks! It works.Will you please clarify it,s explanation(Comment the working of whole code in beginning the flow of whole code ). It works but it is not understandable. Thanks!Anonymous
July 19, 2011
The comment has been removedAnonymous
October 12, 2011
if you search on google you won't find this page . I found your code used at 1code.codeplex.com/.../62253 and it's working superb they have given credits to you!!! Many Many thinks!!Anonymous
October 12, 2011
Mahesh, I am glad the code helped! If you search with http://bing.com do you find this article :-). What are the search terms you used (so I can add it to this post)? -JeffAnonymous
October 17, 2011
Great post. Thanks http://gola.vn http://sachnghe.gola.vnAnonymous
November 15, 2011
jpsanders, thank you for your excellent article. From my understanding of your code, the proxy is set for the current process, right? Taking it further, perhaps you can answer these:
- Is it possible to launch multiple threads with each thread on a separate proxy server from the same application?
- is it possible to have multiple proxies running on the process but using multiple WebBrowser control instances? (e.g. a form has three browser controls with each control using a different proxy server) If so, I hope you can share some code. Thanks http://www.lifeinsuranceph.com
- Anonymous
November 16, 2011
Hi Life,
- No
- No The WebBrowser controls will all share WinINet.dll where all of this is controlled from. -Jeff
Anonymous
January 03, 2012
Hi, Thx for this. This is too good. How do I change your code to support accessing SSL sites. e.g https://mail.yahoo.com. Currently it gives a navigation cancelled error. Regards. KallolAnonymous
January 03, 2012
SSL sites should be no different. This sounds like you have a proxy problem. What happens when you set the proxy manually in IE with the same proxy value. Can you get to that URL then?Anonymous
March 07, 2012
I got "Set Internet Option Failed!" error. How can I find what the problem is?Anonymous
March 07, 2012
Hi ZAX, What OS are you running on and what version of IE. You are not trying to run this in a service or non-interactive account are you? -JeffAnonymous
March 08, 2012
Hi Jeff! I'm running a recently installed Win 7 SP1 with the default IE 9 in it - I use Chrome otherwise so never updated anything in IE. I see that this bool bReturn = InternetSetOption(hInternet, INTERNET_OPTION.INTERNET_OPTION_PER_CONNECTION_OPTION, intptrStruct, size); generates the exception but I don't know how to troubleshoot the problem further cause I don't really understand working with wininet.dll. I tried to test with a private proxy with this command: WinInetInterop.SetConnectionProxy("proxyuser:proxypass@ip:port"); my aim is to be able to change the proxy every few minutes for the browser control of my WinForms app in C# thx for Your attention ZAXAnonymous
March 08, 2012
Hi ZAX, You will want to get the last error when this fails. Use this function: msdn.microsoft.com/.../system.runtime.interopservices.marshal.getlastwin32error.aspx What is the error you get from this?Anonymous
March 11, 2012
Hi Jeff! I posted back on Friday already but maybe i had misclicked sg as it never appeared so I try again: I got back the 87 "wrong parameter error" from Marshal.GetLastWin32Error. Immediately after that I tried the code using a public proxy in a simple format of "ip:port". and it worked! So the only question is if this code can handle private proxy credentials too? And if yes, what is the exact format of the user/pass/ip/port that I have to feed in? (so far I used user:pass@ip:port but this always brings up the wrong parameter error) I think it would be useful for all to have this info. thx ZAXAnonymous
March 12, 2012
Hi ZAX, What type of authentication does your proxy provide? You could always use straight WinINet functions to do proxy auth once you get the 407 response from the proxy. Here is an article on that (no I do not have a .NET sample but you could write one I am sure): msdn.microsoft.com/.../aa384220(v=vs.85).aspx -JeffAnonymous
May 23, 2012
I was looking for such a solution for one of my ClickOnce application and your code just did the trick! Just wanted to say a big thank you to you for posting this. Keep it up!Anonymous
November 20, 2012
Hi, I have a question regarding the usage of your "WinInetInterop" class. I want to set the proxy settings of my Windows form application as settings for IE, the method you wrote and which i can use if RestoreProxySettings(), I am a beginner but need this application to work, could you please tell me where should I call this method, I mean in the Onload_form method or in Contructor and whether to take some extra steps to achieve this task. A quick reply will be appreciated.Anonymous
November 20, 2012
Hi Arif, You cannot set the proxy for your WinForms application. You can however set the proxy for the Internet Explorer web browser control. Is that what you are trying to do? -JeffAnonymous
November 20, 2012
Let me be more in detail. I have some application which uses Trident (the web engine for IE). And now I have some styling issues with html pages, and this web engine is not enough. So I want to introduce a different web engine like webkit (the web engine for Chrome) because the displaying problems are solved by webkit engine. In order to do this I have to test Webkit with my application (Windows Form application). And So I want to Copy the proxy settings for IE, and than use it as proxy setting for my application in order to check that the new web engine works fine and than embed it permanently in my application. I hope I have made it clear what I mean. I am stuck with this problem since days and your method could solve this if used property. Thanks in advance ,Anonymous
November 20, 2012
Hi Arif, This will not do what you want. You need to first discover how your web engine uses/gets the proxy. This solution is for WinINet based solutions only and only if you want to temporarily set a proxy DIFFERENT from the default proxy. You should engage WebKit support or forums to see how this is done. I am sure that it can already read the default IE proxy settings some how! -JeffAnonymous
May 07, 2015
thanks for your codeAnonymous
July 26, 2015
This is fantastic! Thanks so much for making this awesome contribution to the community. I, and many others, very much appreciate it.Anonymous
October 10, 2015
Can I ask the variable string applicationName; is the name of the application that we want to change the web browser control proxy. For example, my application is "SomeName" then I may be set applicationName = SomeName? ThanksAnonymous
October 12, 2015
Hi Hill, Take a look at the documentation for the InternetOpen function (they describe it adequately) : msdn.microsoft.com/.../aa385096(v=vs.85).aspx JeffAnonymous
October 14, 2015
Hi Jeff, Thanks so much, I understood.Anonymous
January 20, 2016
thankyou very much your a heroAnonymous
July 23, 2016
Great Post..Anonymous
September 11, 2016
I have a website that switched to TLS 1.2 and now this code no longer works. I am running in c# .net 4.0 have had 0 issues in the past. Any ideas what would have to be changed ???- Anonymous
September 30, 2016
NO sorry!
- Anonymous
Anonymous
March 01, 2017
The comment has been removedAnonymous
March 01, 2017
Thanks for your code btw.