Changing the user agent of the WebBrowser control
Asked Answered
B

4

50

I am trying to change the UserAgent of the WebBrowser control in a Winforms application.

I have successfully achieved this by using the following code:

[DllImport("urlmon.dll", CharSet = CharSet.Ansi)]
private static extern int UrlMkSetSessionOption(
    int dwOption, string pBuffer, int dwBufferLength, int dwReserved);

const int URLMON_OPTION_USERAGENT = 0x10000001;

public void ChangeUserAgent()
{
    List<string> userAgent = new List<string>();
    string ua = "Googlebot/2.1 (+http://www.google.com/bot.html)";

    UrlMkSetSessionOption(URLMON_OPTION_USERAGENT, ua, ua.Length, 0);
}

The only problem is that this only works once. When I try to run the ChangeUserAgent() method for the second time it doesn't work. It stays set to the first changed value. This is quite annoying and I've tried everything but it just won't change more than once.

Does anyone know of a different, more flexible approach?

Thanks

Bordiuk answered 2/6, 2009 at 1:27 Comment(1)
I tried the method above, but it didn't work for WPF (System.Windows.Controls.WebBrowser)Oaxaca
P
37

I'm not sure whether I should just copy/paste from a website, but I'd rather leave the answer here, instead of a link. If anyone can clarify in comments, I'll be much obliged.

Basically, you have to extend the WebBrowser class.

public class ExtendedWebBrowser : WebBrowser
{
    bool renavigating = false;

    public string UserAgent { get; set; }

    public ExtendedWebBrowser()
    {
        DocumentCompleted += SetupBrowser;

        //this will cause SetupBrowser to run (we need a document object)
        Navigate("about:blank");
    }

    void SetupBrowser(object sender, WebBrowserDocumentCompletedEventArgs e)
    {
        DocumentCompleted -= SetupBrowser;
        SHDocVw.WebBrowser xBrowser = (SHDocVw.WebBrowser)ActiveXInstance;
        xBrowser.BeforeNavigate2 += BeforeNavigate;
        DocumentCompleted += PageLoaded;
    }

    void PageLoaded(object sender, WebBrowserDocumentCompletedEventArgs e)
    {

    }

    void BeforeNavigate(object pDisp, ref object url, ref object flags, ref object targetFrameName,
        ref object postData, ref object headers, ref bool cancel)
    {
        if (!string.IsNullOrEmpty(UserAgent))
        {
            if (!renavigating)
            {
                headers += string.Format("User-Agent: {0}\r\n", UserAgent);
                renavigating = true;
                cancel = true;
                Navigate((string)url, (string)targetFrameName, (byte[])postData, (string)headers);
            }
            else
            {
                renavigating = false;
            }
        }
    }
}

Note: To use the method above you’ll need to add a COM reference to “Microsoft Internet Controls”.

He mentions your approach too, and states that the WebBrowser control seems to cache this user agent string, so it will not change the user agent without restarting the process.

Prove answered 2/6, 2009 at 2:2 Comment(10)
Is there a way to restart the process, maybe by using threading? I have limited experience with winforms.Bordiuk
I'm not so sure, I'd try it myself, but I think the approach I gave in my answer should work. It's less elegant, though. I also wonder if you could remove the control and make a new one at runtime but I guess that might be a bit expensive.Prove
I actually added that class to my project and it didn't work at all. So now I guess I have to try the restarting the process approach.Bordiuk
link is invalid now. So yes, nearly two years later, copying and pasting turned out to be the right thing to do :)Peralta
@zourtney, heh it paid off in the end!Prove
i've been doing this (different code to yours) for years, no need to restart, no need to use msinet.ocx (Ms Internet Controls)... if you still want the code, let me know and i can show you how to do it. in fact, i can even make it work with Visual Studio 6.0 :).Marcy
Is there still a way to do this? Apparently the WPF-Variant of WebBrowser is sealed and can't be used this way.Coff
BeforeNavigate2 does not fire if control is hosted in .net application support.microsoft.com/kb/325079Routine
What is this SHDocVw.WebBrowser xBrowser = (SHDocVw.WebBrowser)ActiveXInstance??Sumach
@Coff you can using System.Windows.Forms; instead using System.Windows.Controls;Crosby
M
66

The easiest way:

webBrowser.Navigate("http://localhost/run.php", null, null,
                    "User-Agent: Here Put The User Agent");
Martyrology answered 23/9, 2011 at 17:44 Comment(4)
you have to terminate the custom header with \r\nStylolite
If the webbrowser control navigate away from that URI (when clicking a link, or moving back/forward) the user agent is reset. Ideally it the solution should work for all requests the control does.Forrer
It only works for the original request passed to Navigate - all AJAX calls within the website will still use control's default UARoutine
@Martyrology The Webbrowser will open my default browser automatically with the url when i use this code on my project. I just want the webpage load into webbrowser but open extra browser. Did i miss something in my code?browser.Navigate(url, "User-Agent:Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Mobile Safari/537.36");Electromotive
P
37

I'm not sure whether I should just copy/paste from a website, but I'd rather leave the answer here, instead of a link. If anyone can clarify in comments, I'll be much obliged.

Basically, you have to extend the WebBrowser class.

public class ExtendedWebBrowser : WebBrowser
{
    bool renavigating = false;

    public string UserAgent { get; set; }

    public ExtendedWebBrowser()
    {
        DocumentCompleted += SetupBrowser;

        //this will cause SetupBrowser to run (we need a document object)
        Navigate("about:blank");
    }

    void SetupBrowser(object sender, WebBrowserDocumentCompletedEventArgs e)
    {
        DocumentCompleted -= SetupBrowser;
        SHDocVw.WebBrowser xBrowser = (SHDocVw.WebBrowser)ActiveXInstance;
        xBrowser.BeforeNavigate2 += BeforeNavigate;
        DocumentCompleted += PageLoaded;
    }

    void PageLoaded(object sender, WebBrowserDocumentCompletedEventArgs e)
    {

    }

    void BeforeNavigate(object pDisp, ref object url, ref object flags, ref object targetFrameName,
        ref object postData, ref object headers, ref bool cancel)
    {
        if (!string.IsNullOrEmpty(UserAgent))
        {
            if (!renavigating)
            {
                headers += string.Format("User-Agent: {0}\r\n", UserAgent);
                renavigating = true;
                cancel = true;
                Navigate((string)url, (string)targetFrameName, (byte[])postData, (string)headers);
            }
            else
            {
                renavigating = false;
            }
        }
    }
}

Note: To use the method above you’ll need to add a COM reference to “Microsoft Internet Controls”.

He mentions your approach too, and states that the WebBrowser control seems to cache this user agent string, so it will not change the user agent without restarting the process.

Prove answered 2/6, 2009 at 2:2 Comment(10)
Is there a way to restart the process, maybe by using threading? I have limited experience with winforms.Bordiuk
I'm not so sure, I'd try it myself, but I think the approach I gave in my answer should work. It's less elegant, though. I also wonder if you could remove the control and make a new one at runtime but I guess that might be a bit expensive.Prove
I actually added that class to my project and it didn't work at all. So now I guess I have to try the restarting the process approach.Bordiuk
link is invalid now. So yes, nearly two years later, copying and pasting turned out to be the right thing to do :)Peralta
@zourtney, heh it paid off in the end!Prove
i've been doing this (different code to yours) for years, no need to restart, no need to use msinet.ocx (Ms Internet Controls)... if you still want the code, let me know and i can show you how to do it. in fact, i can even make it work with Visual Studio 6.0 :).Marcy
Is there still a way to do this? Apparently the WPF-Variant of WebBrowser is sealed and can't be used this way.Coff
BeforeNavigate2 does not fire if control is hosted in .net application support.microsoft.com/kb/325079Routine
What is this SHDocVw.WebBrowser xBrowser = (SHDocVw.WebBrowser)ActiveXInstance??Sumach
@Coff you can using System.Windows.Forms; instead using System.Windows.Controls;Crosby
G
24

Also, there is a refresh option in the function (according to MSDN). It worked well for me (you should set it before any user agent change). Then the question code could be changed like this:

[DllImport("urlmon.dll", CharSet = CharSet.Ansi)]
private static extern int UrlMkSetSessionOption(
    int dwOption, string pBuffer, int dwBufferLength, int dwReserved);

const int URLMON_OPTION_USERAGENT = 0x10000001;
const int URLMON_OPTION_USERAGENT_REFRESH = 0x10000002;

public void ChangeUserAgent()
{
    string ua = "Googlebot/2.1 (+http://www.google.com/bot.html)";

    UrlMkSetSessionOption(URLMON_OPTION_USERAGENT_REFRESH, null, 0, 0);
    UrlMkSetSessionOption(URLMON_OPTION_USERAGENT, ua, ua.Length, 0);
}
Grasmere answered 6/8, 2013 at 12:55 Comment(8)
why are you not using the userAgent variable?Jaleesa
It's been extracted from my own code, shouldn't be there. Tks for pointing it out.Grasmere
The accepted answer won't work if you are, for example, logging into Facebook and need to get permissions approval from the user ("renavigate" causes problems). So create your embedded browser and use URLMON_OPTION_USERAGENT_REFRESH then URLMON_OPTION_USERAGENT to set your custom UA. As pointed out above repeat as needed or only set URLMON_OPTION_USERAGENT_REFRESH to go back to the default IE UA.Thereby
Looking back I must say I liked this answer, too bad it's 4 years late :)Bordiuk
So easy. Thank you! :)Pivot
just a note, if using forms, run before InitializeComponent();Midway
It works perfect on Windows 7 and 10 even with Guest account, tested. First call ChangeUserAgent() in your app, then you are ready to navigate with brand new UA. Repeat on every runtime. Be careful thoug - libraries like jquery could not work as expected because they use different methods for IE browsers.Crosby
I think this should be the accepted answer; it's simpler, cleaner and there were less "side-effects" such as opening the IE setup window. For me anyway; I needed to pop up an SSO auth browser windows from with a class library (thanks oAuth2!).Sturdivant
C
4

I'd like to add to @Jean Azzopardi's answer.

void BeforeNavigate(object pDisp, ref object url, ref object flags, ref object targetFrameName,
        ref object postData, ref object headers, ref bool cancel)
{
    // This alone is sufficient, because headers is a "Ref" parameters, and the browser seems to pick this back up.
    headers += string.Format("User-Agent: {0}\r\n", UserAgent);
}

This solution worked best for me. Using the renavigating caused other weird issues for me, like the browser content suddenly vanishing, and sometimes still getting Unsupported Browser. With this technique, all the requests in Fiddler had the correct User Agent.

Caterer answered 21/10, 2014 at 22:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.