66

I found a similar question here:

How do I suppress script errors when using the WPF WebBrowser control?

But non of those solutions work for me. I need to stop the popups from appearing as i am using the WebBrowser to automate admin tasks on a website.

SuppressScriptErrors does not appear to be an available attribute on my WebControl :(

2
  • 1
    WinForms, WPF or Compact Framework? Commented May 26, 2011 at 12:08
  • Sorry forgot to add that - it's WPF Commented May 26, 2011 at 12:39

10 Answers 10

126
+50

Here is a C# routine that is capable of putting WPF's WebBrowser in silent mode. You can't call it at WebBrowser initialization as it 's too early, but instead after navigation occured. Here is a WPF sample app with a wbMain WebBrowser component:

public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
        wbMain.Navigated += new NavigatedEventHandler(wbMain_Navigated);
    }

    void wbMain_Navigated(object sender, NavigationEventArgs e)
    {
        SetSilent(wbMain, true); // make it silent
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        wbMain.Navigate(new Uri("... some url..."));
    }
}


public static void SetSilent(WebBrowser browser, bool silent)
{
    if (browser == null)
        throw new ArgumentNullException("browser");

    // get an IWebBrowser2 from the document
    IOleServiceProvider sp = browser.Document as IOleServiceProvider;
    if (sp != null)
    {
        Guid IID_IWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046");
        Guid IID_IWebBrowser2 = new Guid("D30C1661-CDAF-11d0-8A3E-00C04FC9E26E");

        object webBrowser;
        sp.QueryService(ref IID_IWebBrowserApp, ref IID_IWebBrowser2, out webBrowser);
        if (webBrowser != null)
        {
            webBrowser.GetType().InvokeMember("Silent", BindingFlags.Instance | BindingFlags.Public | BindingFlags.PutDispProperty, null, webBrowser, new object[] { silent });
        }
    }
}


[ComImport, Guid("6D5140C1-7436-11CE-8034-00AA006009FA"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IOleServiceProvider
{
  [PreserveSig]
  int QueryService([In] ref Guid guidService, [In] ref Guid riid, [MarshalAs(UnmanagedType.IDispatch)] out object ppvObject);
}
Sign up to request clarification or add additional context in comments.

8 Comments

Thankyou Simon. What the heck is going off with that code? It works a charm, but I cannot read it that well.
@DrLazer - Thanks. It uses ancient COM/IE knowledge :-)
This is great, i've been looking for this since long time! Thank you very much!!
@DrLazer There used to be a property on the old IE COM control called Silent. If you set Silent to true, it would prevent the control from creating any windows. MS didn't port all the properties to WPF (WinForms has it much better), so you have to resort to hacks like these to actually set the property in late binding.
works great, but I had to change this line: IOleServiceProvider sp = browser.Document.DomDocument as IOleServiceProvider;
|
61

Thought it'd be relevant to add here. There is another option to get to the WPF WebBrowser's underlying WebBorwser ActiveX Control and its otherwise inaccessible methods and events. I just discovered it a few days ago. It's very simple and doesn't require initial navigation on WB:

dynamic activeX = this.WB.GetType().InvokeMember("ActiveXInstance",
                    BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
                    null, this.WB, new object[] { });

activeX.Silent = true;

Of course, there's a chance this method may not work in future version of the Framework, but so is true about any other undocumented method. So far, it's been there since .NET 3.0. More details with a working code sample here.

5 Comments

This worked like a charm, and is really elegant. Thanks.
@Noseratio Yea! Finally a two liner.... I still don't understand why Microsoft doesn't make this a public method named Silence or something like that. Imagine this: XWB.Silent = true;
All the other solutions did not work for me !!! Except that solution with ActiveXInstance ! It works really well. Thanks a lo. I broke my nerves on that issue for long. Caution :: to place the code into the MainWindow constructor.
This woks great!
I use this right after initiating the WebBrowser, it works for my WPF app.
16

Thanks to Simon Mourier for elegant way to solve this problem. I made a little improvement and encapsulated Simon's solution into attached property.

In my application I use WebBrowser control databounded to viewmodel, the webbrowser might be hidden on inactive TabItem, so I have to check that it has been Loaded and Navigated before setting javascript errors silent. And of cource this setting should be done just once, so after setting I release hooked events.

XAML Code:

<TabControl xmlns:b="clr-namespace:MyApplication.Behaviors">
  <TabItem Header="foo">...</TabItem>
  <TabItem Header="Google map">
    <WebBrowser b:BindableSource="{Binding Path=MapUrl}"
                b:DisableJavascriptErrors="True" />
  </TabItem>
</TabControl>

Behavior code:

using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;

namespace MyApplication.Behaviors
{
    public class WebBrowserBehavior
    {
        private static readonly Type OwnerType = typeof (WebBrowserBehavior);

        #region BindableSource

        public static readonly DependencyProperty BindableSourceProperty =
            DependencyProperty.RegisterAttached(
                "BindableSource", 
                typeof(string), 
                OwnerType, 
                new UIPropertyMetadata(OnBindableSourcePropertyChanged));

        [AttachedPropertyBrowsableForType(typeof(WebBrowser))]
        public static string GetBindableSource(DependencyObject obj)
        {
            return (string)obj.GetValue(BindableSourceProperty);
        }

        [AttachedPropertyBrowsableForType(typeof(WebBrowser))]
        public static void SetBindableSource(DependencyObject obj, string value)
        {
            obj.SetValue(BindableSourceProperty, value);
        }

        public static void OnBindableSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var browser = d as WebBrowser;
            if (browser == null) return;

            browser.Source = (e.NewValue != null) ? new Uri(e.NewValue.ToString()) : null;
        }

        #endregion

        #region DisableJavascriptErrors

        #region SilentJavascriptErrorsContext (private DP)

        private static readonly DependencyPropertyKey SilentJavascriptErrorsContextKey =
            DependencyProperty.RegisterAttachedReadOnly(
                "SilentJavascriptErrorsContext",
                typeof (SilentJavascriptErrorsContext),
                OwnerType,
                new FrameworkPropertyMetadata(null));

        private static void SetSilentJavascriptErrorsContext(DependencyObject depObj, SilentJavascriptErrorsContext value)
        {
            depObj.SetValue(SilentJavascriptErrorsContextKey, value);
        }

        private static SilentJavascriptErrorsContext GetSilentJavascriptErrorsContext(DependencyObject depObj)
        {
            return (SilentJavascriptErrorsContext) depObj.GetValue(SilentJavascriptErrorsContextKey.DependencyProperty);
        }

        #endregion

        public static readonly DependencyProperty DisableJavascriptErrorsProperty =
            DependencyProperty.RegisterAttached(
                "DisableJavascriptErrors",
                typeof (bool),
                OwnerType,
                new FrameworkPropertyMetadata(OnDisableJavascriptErrorsChangedCallback));

        [AttachedPropertyBrowsableForType(typeof(WebBrowser))]
        public static void SetDisableJavascriptErrors(DependencyObject depObj, bool value)
        {
            depObj.SetValue(DisableJavascriptErrorsProperty, value);
        }

        [AttachedPropertyBrowsableForType(typeof(WebBrowser))]
        public static bool GetDisableJavascriptErrors(DependencyObject depObj)
        {
            return (bool)depObj.GetValue(DisableJavascriptErrorsProperty);
        }

        private static void OnDisableJavascriptErrorsChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var webBrowser = d as WebBrowser;
            if (webBrowser == null) return;
            if (Equals(e.OldValue, e.NewValue)) return;

            var context = GetSilentJavascriptErrorsContext(webBrowser);
            if (context != null) {
                context.Dispose();
            }

            if (e.NewValue != null) {
                context = new SilentJavascriptErrorsContext(webBrowser);
                SetSilentJavascriptErrorsContext(webBrowser, context);
            }
            else {
                SetSilentJavascriptErrorsContext(webBrowser, null);
            }
        }

        private class SilentJavascriptErrorsContext : IDisposable
        {
            private bool? _silent; 
            private readonly WebBrowser _webBrowser;


            public SilentJavascriptErrorsContext(WebBrowser webBrowser)
            {
                _silent = new bool?();

                _webBrowser = webBrowser;
                _webBrowser.Loaded += OnWebBrowserLoaded;
                _webBrowser.Navigated += OnWebBrowserNavigated;
            }

            private void OnWebBrowserLoaded(object sender, RoutedEventArgs e)
            {
                if (!_silent.HasValue) return;

                SetSilent();
            }

            private void OnWebBrowserNavigated(object sender, NavigationEventArgs e)
            {
                var webBrowser = (WebBrowser)sender;

                if (!_silent.HasValue) {
                    _silent = GetDisableJavascriptErrors(webBrowser);
                }

                if (!webBrowser.IsLoaded) return;

                SetSilent();
            }

            /// <summary>
            /// Solution by Simon Mourier on StackOverflow
            /// http://stackoverflow.com/a/6198700/741414
            /// </summary>
            private void SetSilent()
            {
                _webBrowser.Loaded -= OnWebBrowserLoaded;
                _webBrowser.Navigated -= OnWebBrowserNavigated;

                // get an IWebBrowser2 from the document
                var sp = _webBrowser.Document as IOleServiceProvider;
                if (sp != null)
                {
                    var IID_IWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046");
                    var IID_IWebBrowser2 = new Guid("D30C1661-CDAF-11d0-8A3E-00C04FC9E26E");

                    object webBrowser2;
                    sp.QueryService(ref IID_IWebBrowserApp, ref IID_IWebBrowser2, out webBrowser2);
                    if (webBrowser2 != null)
                    {
                        webBrowser2.GetType().InvokeMember(
                            "Silent",
                            BindingFlags.Instance | BindingFlags.Public | BindingFlags.PutDispProperty,
                            null,
                            webBrowser2,
                            new object[] { _silent });
                    }
                }
            }

            [ComImport, Guid("6D5140C1-7436-11CE-8034-00AA006009FA"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
            private interface IOleServiceProvider
            {
                [PreserveSig]
                int QueryService([In] ref Guid guidService, [In] ref Guid riid, [MarshalAs(UnmanagedType.IDispatch)] out object ppvObject);
            }

            public void Dispose()
            {
                if (_webBrowser != null) {
                    _webBrowser.Loaded -= OnWebBrowserLoaded;
                    _webBrowser.Navigated -= OnWebBrowserNavigated;
                }
            }
        }

        #endregion

    }
}

2 Comments

I'm still a little shaky on bindings, so what does the MapUrl in your XAML binding refer to. I implemented this exactly as you have here, including the MapUrl binding, and everything works. But I don't have a MapUrl variable/object anywhere, so I'd kind of like to know how exactly this is working. :)
Has something changed in the latest .net version??.this stopped working for me now :( used to work before!
14

The answer by @SimonMourier didn't work for me, but this did:

public void HideScriptErrors(WebBrowser wb, bool Hide)
{
    FieldInfo fiComWebBrowser = typeof(WebBrowser)
        .GetField("_axIWebBrowser2", 
                  BindingFlags.Instance | BindingFlags.NonPublic);
    if (fiComWebBrowser == null) return;
    object objComWebBrowser = fiComWebBrowser.GetValue(wb);
    if (objComWebBrowser == null) return;
    objComWebBrowser.GetType().InvokeMember(
        "Silent", BindingFlags.SetProperty, null, objComWebBrowser, 
        new object[] { Hide });
}

Note that I got it from here.

1 Comment

Great. Works for me
8

I've also found an interesting way to disable JavaScript errors. But you need to use at least .Net Framework 4.0 because of using elegant dynamic type.

You need to subscribe to the LoadCompleted event of the WebBrowser element:

<WebBrowser x:Name="Browser" 
            LoadCompleted="Browser_OnLoadCompleted" />

After that you need to write an event handler that looks like below:

    void Browser_OnLoadCompleted(object sender, NavigationEventArgs e)
    {
        var browser = sender as WebBrowser;

        if (browser == null || browser.Document == null)
            return;

        dynamic document = browser.Document;

        if (document.readyState != "complete")
            return;

        dynamic script = document.createElement("script");
        script.type = @"text/javascript";
        script.text = @"window.onerror = function(msg,url,line){return true;}";
        document.head.appendChild(script);
    }

Comments

1

Well if it was necessary i would have gone for WinformHost and added WebBrowser Control to it and used it.

You can easily do those tasks here in WinformHost also because i have made whole applications that does bundle of things

3 Comments

thanks but no thanks for downvote but i do not see any reason to down vote.I gave what is possible solution.
clicked by mistake. my appologies
ahhh wont let me undo it. :(
1

Here is an example of how to do this without using reflection.

    /// <summary>
    /// Gets an interop web browser.
    /// </summary>
    /// <param name="browser"></param>
    /// <returns></returns>
    public static SHDocVw.WebBrowser GetInteropWebBrowser(this WebBrowser browser)
    {
        Guid serviceGuid = new Guid("0002DF05-0000-0000-C000-000000000046");
        Guid iid = typeof(SHDocVw.IWebBrowser2).GUID;
        Interop.IServiceProvider serviceProvider = (Interop.IServiceProvider)browser.Document;
        SHDocVw.IWebBrowser2 browser2 = (SHDocVw.IWebBrowser2)serviceProvider.QueryService(ref serviceGuid, ref iid);
        SHDocVw.WebBrowser wb = (SHDocVw.WebBrowser)browser2;

        return wb;
    }

    /// <summary>
    /// Disables script errors for the browser.
    /// </summary>
    /// <param name="browser"></param>
    /// <param name="silent"></param>
    public static void SetSilent(this WebBrowser browser, bool silent)
    {
        SHDocVw.WebBrowser browser2 = browser.GetInteropWebBrowser();
        if (browser2 != null)
            browser2.Silent = silent;
    }

/// <summary>
/// Provides the COM interface for the IServiceProvider.
/// </summary>
[ComImport, Guid("6D5140C1-7436-11CE-8034-00AA006009FA"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IServiceProvider
{
    /// <summary>
    /// Queries the service.
    /// </summary>
    /// <param name="serviceGuid"></param>
    /// <param name="riid"></param>
    /// <returns></returns>
    [return: MarshalAs(UnmanagedType.IUnknown)]
    object QueryService(ref Guid serviceGuid, ref Guid riid);
}

Then in the constructor for the view that hosts the Browser control you have:

            Browser.Navigated += (s, e) =>
            {
                Browser.SetSilent(true);
            };

Comments

0

I wanted to add that I tried all the above solutions to try and stop the long running script error (which they don't claim to do so, but this was the closest question I could find to my issue). Posting in case anyone else has the same "a script on this page is causing your browser to run slowly" issue.

The only thing I found to work was setting the registry key which must be set before the browser is created

        var keyName = "HKEY_CURRENT_USER\\Software\\Microsoft\\Internet Explorer\\styles";
        if(Registry.GetValue(keyName, "MaxScriptStatements", null) == null)
        {
            Registry.SetValue(keyName, "MaxScriptStatements", unchecked((int)0xffffffff), RegistryValueKind.DWord);
        }

enter image description here

Comments

0
        wbSample.Navigating += (s, e) =>
            {
                var fiComWebBrowser = typeof(WebBrowser).GetField("_axIWebBrowser2", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
                if (fiComWebBrowser == null)
                    return;

                object objComWebBrowser = fiComWebBrowser.GetValue(wbSample);
                if (objComWebBrowser == null)
                    return;

                objComWebBrowser.GetType().InvokeMember("Silent", System.Reflection.BindingFlags.SetProperty, null, objComWebBrowser, new object[] { true });
            };


this code work for me. add this at constructor.

reference: https://social.msdn.microsoft.com/Forums/lync/en-US/8a62fed2-24c8-4765-a6ab-aa245fa7f8d5/wpf-web-browser-script-error?forum=wpf

Comments

-3

Really very simple, thank you for your solution.

http://social.msdn.microsoft.com/Forums/en-US/6996b0c5-b44d-4040-9dbe-6206b1d9185e/webbrowser-script-error-when-using-google-maps?forum=wpf&prof=required


Dim sb As New StringBuilder
sb.Append("<html>")
sb.Append("<head>")
sb.Append("</head")
sb.Append("<body>")

sb.Append("<iframe src ='" + url + "' height='" + webBrowser1.Height + "' width='" + webBrowser1.Width + "'></iframe>")

sb.Append("</body")
sb.Append("</html>")

WebBrowser1.DocumentText = sb.ToString

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.