WPF WebBrowser control - how to suppress script errors?

C#.NetWpfWebbrowser Control

C# Problem Overview


I found a similar question here:

https://stackoverflow.com/questions/1298255/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 :(

C# Solutions


Solution 1 - C#

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);
}

Solution 2 - C#

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.

Solution 3 - C#

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

    }
}

Solution 4 - C#

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.

Solution 5 - C#

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);
    }

Solution 6 - C#

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

Solution 7 - C#

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);
            };

Solution 8 - C#

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

Solution 9 - C#

        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

Solution 10 - C#

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDrLazerView Question on Stackoverflow
Solution 1 - C#Simon MourierView Answer on Stackoverflow
Solution 2 - C#noseratioView Answer on Stackoverflow
Solution 3 - C#OndrejView Answer on Stackoverflow
Solution 4 - C#Scott WhitlockView Answer on Stackoverflow
Solution 5 - C#user1826289View Answer on Stackoverflow
Solution 6 - C#Afnan BashirView Answer on Stackoverflow
Solution 7 - C#Icons of IndustryView Answer on Stackoverflow
Solution 8 - C#David WiltonView Answer on Stackoverflow
Solution 9 - C#Shah Jafar Ulla HamidiView Answer on Stackoverflow
Solution 10 - C#user2942918View Answer on Stackoverflow