Setting a proxy server for the WebBrowser control is not a straight forward affair. There are plenty of resources out there on the web that will show you how to do this. However, what is lacking is any solutions that show how to authenticate a proxy server, at least any solutions that would work for me. So in this post I am not only going to show you how to set a proxy for the WebBrowser control, I will also share with you the only solution I know of that successfully authenticates with a proxy.
To set the proxy server we will make a call to the Win32 API, the InternetSetOption function found in wininet.dll. To use this function in C# we need to declare an external function like so.
- [DllImport("wininet.dll", SetLastError = true)]
- private static extern bool InternetSetOption(IntPtr hInternet, int dwOption,
- IntPtr lpBuffer, int lpdwBufferLength);
To use this function we are also going to have to declare a struct as one of the parameters required is a pointer to this struct. Here it is.
- public struct INTERNET_PROXY_INFO
- {
- public int dwAccessType;
- public IntPtr proxy;
- public IntPtr proxyBypass;
- }
Next I have created a SetProxyServer method. It takes one string parameter, the IP address and port of the proxy server in the format "1.2.3.4:1234". In this method we create our INTERNET_PROXY_INFO struct and populate the values, we use some of the static methods of the Marshall class to copy the values into unmanaged memory and then we call the external function.
- private void SetProxyServer(string proxy)
- {
- //Create structure
- INTERNET_PROXY_INFO proxyInfo = new INTERNET_PROXY_INFO();
- if (proxy == null)
- {
- proxyInfo.dwAccessType = INTERNET_OPEN_TYPE_DIRECT;
- }
- else
- {
- proxyInfo.dwAccessType = INTERNET_OPEN_TYPE_PROXY;
- proxyInfo.proxy = Marshal.StringToHGlobalAnsi(proxy);
- proxyInfo.proxyBypass = Marshal.StringToHGlobalAnsi("local");
- }
- // Allocate memory
- IntPtr proxyInfoPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(proxyInfo));
- // Convert structure to IntPtr
- Marshal.StructureToPtr(proxyInfo, proxyInfoPtr, true);
- bool returnValue = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_PROXY,
- proxyInfoPtr, Marshal.SizeOf(proxyInfo));
- }
If your proxy servers have IP authentication or no authentication at all then you don not need to do anymore. However, if you need to provide username and passwords then some more steps are required.
If we register our form as a client site object for the underlying instance of IE within the control and implements the IServiceProvider interface, the underlying IE instance will query our form when authentication is required thus allowing us to provide the required credentials.
To make all that work our form needs to implement three interfaces IOleClientSite, IServiceProvider and IAuthenticate. IOleClientSite has six methods but we only need to implement one of these, GetContainer. All we need to do here is set the incoming object parameter to the instance of our WinForm.
- #region IOleClientSite Members
- public void SaveObject()
- {
- // TODO: Add Form1.SaveObject implementation
- }
- public void GetMoniker(uint dwAssign, uint dwWhichMoniker, object ppmk)
- {
- // TODO: Add Form1.GetMoniker implementation
- }
- public void GetContainer(object ppContainer)
- {
- ppContainer = this;
- }
- public void ShowObject()
- {
- // TODO: Add Form1.ShowObject implementation
- }
- public void OnShowWindow(bool fShow)
- {
- // TODO: Add Form1.OnShowWindow implementation
- }
- public void RequestNewObjectLayout()
- {
- // TODO: Add Form1.RequestNewObjectLayout implementation
- }
- #endregion
Next we implement IServiceProvider which has only one method, QueryService. In this method we check the service and interface being requested. If the request is for authentication we return a pointer to the implementation of IAuthenticate in our form.
- #region IServiceProvider Members
- public int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject)
- {
- int nRet = guidService.CompareTo(IID_IAuthenticate);
- if (nRet == 0)
- {
- nRet = riid.CompareTo(IID_IAuthenticate);
- if (nRet == 0)
- {
- ppvObject = Marshal.GetComInterfaceForObject(this, typeof(IAuthenticate));
- return S_OK;
- }
- }
- ppvObject = new IntPtr();
- return INET_E_DEFAULT_ACTION;
- }
- #endregion
IAuthenticate also has only one method, Authenticate. Here all we need to do is create pointers to the required username and password.
- #region IAuthenticate Members
- public int Authenticate(ref IntPtr phwnd, ref IntPtr pszUsername, ref IntPtr pszPassword)
- {
- IntPtr sUser = Marshal.StringToCoTaskMemAuto(_currentUsername);
- IntPtr sPassword = Marshal.StringToCoTaskMemAuto(_currentPassword);
- pszUsername = sUser;
- pszPassword = sPassword;
- return S_OK;
- }
- #endregion
Our three interfaces IOleClientSite, IServiceProvider and IAuthenticate are COM interfaces so we need to declare them, along with IOleObject. Here is the full code tying everything together.
- using System;
- using System.Runtime.InteropServices;
- using System.Windows.Forms;
- using System.Collections.Generic;
- namespace WebBrowserProxyAuthentication
- {
- public partial class Form1 : Form, IOleClientSite, IServiceProvider, IAuthenticate
- {
- [DllImport("wininet.dll", SetLastError = true)]
- private static extern bool InternetSetOption(IntPtr hInternet, int dwOption,
- IntPtr lpBuffer, int lpdwBufferLength);
- private Guid IID_IAuthenticate = new Guid("79eac9d0-baf9-11ce-8c82-00aa004ba90b");
- private const int INET_E_DEFAULT_ACTION = unchecked((int)0x800C0011);
- private const int S_OK = unchecked((int)0x00000000);
- private const int INTERNET_OPTION_PROXY = 38;
- private const int INTERNET_OPEN_TYPE_DIRECT = 1;
- private const int INTERNET_OPEN_TYPE_PROXY = 3;
- private string _currentUsername;
- private string _currentPassword;
- public Form1()
- {
- InitializeComponent();
- }
- private void Form1_Load(object sender, EventArgs e)
- {
- webBrowser1.Navigate("about:blank");
- object obj = webBrowser1.ActiveXInstance;
- IOleObject oc = obj as IOleObject;
- oc.SetClientSite(this as IOleClientSite);
- List<Tuple<string, string, string>> proxies = new List<Tuple<string, string, string>>
- {
- new Tuple<string, string, string>("{proxy_ip_here}:{proxy_port_here}",
- "username", "password")
- };
- foreach (Tuple<string, string, string> proxy in proxies)
- {
- _currentUsername = proxy.Item2;
- _currentPassword = proxy.Item3;
- SetProxyServer(proxy.Item1);
- webBrowser1.Navigate("about:blank");
- Application.DoEvents();
- webBrowser1.Navigate("http://www.showmyip.co.uk/");
- Application.DoEvents();
- while (webBrowser1.StatusText != "Done" || webBrowser1.Document.Body.InnerText == null)
- {
- Application.DoEvents();
- }
- MessageBox.Show(webBrowser1.Document.Body.InnerText.Trim());
- }
- }
- private void SetProxyServer(string proxy)
- {
- //Create structure
- INTERNET_PROXY_INFO proxyInfo = new INTERNET_PROXY_INFO();
- if (proxy == null)
- {
- proxyInfo.dwAccessType = INTERNET_OPEN_TYPE_DIRECT;
- }
- else
- {
- proxyInfo.dwAccessType = INTERNET_OPEN_TYPE_PROXY;
- proxyInfo.proxy = Marshal.StringToHGlobalAnsi(proxy);
- proxyInfo.proxyBypass = Marshal.StringToHGlobalAnsi("local");
- }
- // Allocate memory
- IntPtr proxyInfoPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(proxyInfo));
- // Convert structure to IntPtr
- Marshal.StructureToPtr(proxyInfo, proxyInfoPtr, true);
- bool returnValue = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_PROXY,
- proxyInfoPtr, Marshal.SizeOf(proxyInfo));
- }
- #region IOleClientSite Members
- public void SaveObject()
- {
- // TODO: Add Form1.SaveObject implementation
- }
- public void GetMoniker(uint dwAssign, uint dwWhichMoniker, object ppmk)
- {
- // TODO: Add Form1.GetMoniker implementation
- }
- public void GetContainer(object ppContainer)
- {
- ppContainer = this;
- }
- public void ShowObject()
- {
- // TODO: Add Form1.ShowObject implementation
- }
- public void OnShowWindow(bool fShow)
- {
- // TODO: Add Form1.OnShowWindow implementation
- }
- public void RequestNewObjectLayout()
- {
- // TODO: Add Form1.RequestNewObjectLayout implementation
- }
- #endregion
- #region IServiceProvider Members
- public int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject)
- {
- int nRet = guidService.CompareTo(IID_IAuthenticate);
- if (nRet == 0)
- {
- nRet = riid.CompareTo(IID_IAuthenticate);
- if (nRet == 0)
- {
- ppvObject = Marshal.GetComInterfaceForObject(this, typeof(IAuthenticate));
- return S_OK;
- }
- }
- ppvObject = new IntPtr();
- return INET_E_DEFAULT_ACTION;
- }
- #endregion
- #region IAuthenticate Members
- public int Authenticate(ref IntPtr phwnd, ref IntPtr pszUsername, ref IntPtr pszPassword)
- {
- IntPtr sUser = Marshal.StringToCoTaskMemAuto(_currentUsername);
- IntPtr sPassword = Marshal.StringToCoTaskMemAuto(_currentPassword);
- pszUsername = sUser;
- pszPassword = sPassword;
- return S_OK;
- }
- #endregion
- }
- public struct INTERNET_PROXY_INFO
- {
- public int dwAccessType;
- public IntPtr proxy;
- public IntPtr proxyBypass;
- }
- #region COM Interfaces
- [ComImport, Guid("00000112-0000-0000-C000-000000000046"),
- InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
- public interface IOleObject
- {
- void SetClientSite(IOleClientSite pClientSite);
- void GetClientSite(IOleClientSite ppClientSite);
- void SetHostNames(object szContainerApp, object szContainerObj);
- void Close(uint dwSaveOption);
- void SetMoniker(uint dwWhichMoniker, object pmk);
- void GetMoniker(uint dwAssign, uint dwWhichMoniker, object ppmk);
- void InitFromData(IDataObject pDataObject, bool
- fCreation, uint dwReserved);
- void GetClipboardData(uint dwReserved, IDataObject ppDataObject);
- void DoVerb(uint iVerb, uint lpmsg, object pActiveSite,
- uint lindex, uint hwndParent, uint lprcPosRect);
- void EnumVerbs(object ppEnumOleVerb);
- void Update();
- void IsUpToDate();
- void GetUserClassID(uint pClsid);
- void GetUserType(uint dwFormOfType, uint pszUserType);
- void SetExtent(uint dwDrawAspect, uint psizel);
- void GetExtent(uint dwDrawAspect, uint psizel);
- void Advise(object pAdvSink, uint pdwConnection);
- void Unadvise(uint dwConnection);
- void EnumAdvise(object ppenumAdvise);
- void GetMiscStatus(uint dwAspect, uint pdwStatus);
- void SetColorScheme(object pLogpal);
- }
- [ComImport, Guid("00000118-0000-0000-C000-000000000046"),
- InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
- public interface IOleClientSite
- {
- void SaveObject();
- void GetMoniker(uint dwAssign, uint dwWhichMoniker, object ppmk);
- void GetContainer(object ppContainer);
- void ShowObject();
- void OnShowWindow(bool fShow);
- void RequestNewObjectLayout();
- }
- [ComImport, GuidAttribute("6d5140c1-7436-11ce-8034-00aa006009fa"),
- InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown),
- ComVisible(false)]
- public interface IServiceProvider
- {
- [return: MarshalAs(UnmanagedType.I4)]
- [PreserveSig]
- int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject);
- }
- [ComImport, GuidAttribute("79EAC9D0-BAF9-11CE-8C82-00AA004BA90B"),
- InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown),
- ComVisible(false)]
- public interface IAuthenticate
- {
- [return: MarshalAs(UnmanagedType.I4)]
- [PreserveSig]
- int Authenticate(ref IntPtr phwnd, ref IntPtr pszUsername, ref IntPtr pszPassword);
- }
- #endregion
- }
No comments:
Post a Comment