Freigeben über


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 removed

  • Anonymous
    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)? -Jeff

  • Anonymous
    October 17, 2011
    Great post. Thanks http://gola.vn http://sachnghe.gola.vn

  • Anonymous
    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:

  1. Is it possible to launch multiple threads with each thread on a separate proxy server from the same application?
  2. 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,
  1. No
  2. 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. Kallol

  • Anonymous
    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? -Jeff

  • Anonymous
    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 ZAX

  • Anonymous
    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 ZAX

  • Anonymous
    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 -Jeff

  • Anonymous
    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? -Jeff

  • Anonymous
    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! -Jeff

  • Anonymous
    May 07, 2015
    thanks for your code

  • Anonymous
    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? Thanks

  • Anonymous
    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 Jeff

  • Anonymous
    October 14, 2015
    Hi Jeff, Thanks so much, I understood.

  • Anonymous
    January 20, 2016
    thankyou very much your a hero

  • Anonymous
    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
    March 01, 2017
    The comment has been removed

  • Anonymous
    March 01, 2017
    Thanks for your code btw.