55

I have a WPF application that uses the WPF WebBrowser control to display interesting web pages to our developers on a flatscreen display (like a news feed).

The trouble is that I occasionally get a HTML script error that pops up a nasty IE error message asking if I would like to "stop running scripts on this page". Is there a way to suppress this error checking?

NOTE: I have disabled script debugging in IE settings already.

willem
  • 25,977
  • 22
  • 75
  • 115

9 Answers9

140

Here is a solution i just made with reflection. Solves the issue :) I run it at the Navigated event, as it seems the activeX object is not available until then.

What it does is set the .Silent property on the underlying activeX object. Which is the same as the .ScriptErrorsSuppressed property which is the Windows forms equivalent.

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

A better version that can be run anytime and not after the .Navigated event:

public void HideScriptErrors(WebBrowser wb, bool hide) {
    var fiComWebBrowser = typeof(WebBrowser).GetField("_axIWebBrowser2", BindingFlags.Instance | BindingFlags.NonPublic);
    if (fiComWebBrowser == null) return;
    var objComWebBrowser = fiComWebBrowser.GetValue(wb);
    if (objComWebBrowser == null) {
        wb.Loaded += (o, s) => HideScriptErrors(wb, hide); //In case we are to early
        return;
    }
    objComWebBrowser.GetType().InvokeMember("Silent", BindingFlags.SetProperty, null, objComWebBrowser, new object[] { hide });
}

If any issues with the second sample, try swapping wb.Loaded with wb.Navigated.

Wolf5
  • 16,600
  • 12
  • 59
  • 58
17

Just found from another question, this is elegant and works great.

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

activeX.Silent = true;
Community
  • 1
  • 1
Carol
  • 1,852
  • 26
  • 29
10

The problem here is that the WPF WebBrowser did not implement this property as in the 2.0 control.

Your best bet is to use a WindowsFormsHost in your WPF application and use the 2.0's WebBrowser property: SuppressScriptErrors. Even then, you will need the application to be full trust in order to do this.

Not what one would call ideal, but it's pretty much the only option currently.

Kyle Rosendo
  • 25,001
  • 7
  • 80
  • 118
  • Now there is one more argument for me against this winforms-haters. There are just too many `not-possible`'s – C4d Jun 14 '16 at 19:51
7

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);
    }
  • In my case the code I had to fix is creating the complete markup as a MemoeryStream and passing it to the browser with NavigateToStream. So the solution was simply to add a window.onerror function that silently handles the error. Thank you @Ashot Muradian – pasx Apr 12 '16 at 21:48
  • In 99% of the cases, the trick with ActiveX was enough and working but I had one case and one case only when this was the only option of hiding the JS errors. THANK YOU! – Edi Oct 24 '19 at 14:12
6

I wanted to add this as a comment to @Alkampfer answer, but I don't have enough reputation. This works for me (Windows 8.1, NET 4.5):

 window.Browser.LoadCompleted.Add(fun _ -> 
    window.Browser.Source <- new System.Uri("javascript:window.onerror=function(msg,url,line){return true;};void(0);"))

This code sample is written in F#, but it's pretty clear what it does.

alexb
  • 880
  • 11
  • 16
3

Check the below code for suppressing script errors for WPF browser control..

    public MainWindow
    {
    InitializeComponent();
    WebBrowserControlView.Navigate(new Uri("https://www.hotmail.com"));
                        //The below checks for script errors.
    ViewerWebBrowserControlView.Navigated += ViewerWebBrowserControlView_Navigated;
    }

void ViewerWebBrowserControlView_Navigated(object sender, NavigationEventArgs e)
            {
    BrowserHandler.SetSilent(ViewerWebBrowserControlView, true); // make it silent
            }

public static class BrowserHandler
{
    private const string IWebBrowserAppGUID = "0002DF05-0000-0000-C000-000000000046";
    private const string IWebBrowser2GUID = "D30C1661-CDAF-11d0-8A3E-00C04FC9E26E";

    public static void SetSilent(System.Windows.Controls.WebBrowser browser, bool silent)
    {
        if (browser == null)
            MessageBox.Show("No Internet Connection");

        // get an IWebBrowser2 from the document
        IOleServiceProvider sp = browser.Document as IOleServiceProvider;
        if (sp != null)
        {
            Guid IID_IWebBrowserApp = new Guid(IWebBrowserAppGUID);
            Guid IID_IWebBrowser2 = new Guid(IWebBrowser2GUID);

            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)]
public interface IOleServiceProvider
{
    [PreserveSig]
    int QueryService([In] ref Guid guidService, [In] ref Guid riid, [MarshalAs(UnmanagedType.IDispatch)] out object ppvObject);


   }

Whereas, If you are using Winforms Web browser with winforms host.. you have a property "SuppressScriptErrors" set it to true

    <WindowsFormsHost Name="WinformsHost" Grid.Row="1">
    <winForms:WebBrowser x:Name="WebBrowserControlView" ScriptErrorsSuppressed="True" AllowWebBrowserDrop="False"></winForms:WebBrowser>
</WindowsFormsHost>
Darey
  • 497
  • 4
  • 24
  • 5
    You should refer to the **[original post](http://stackoverflow.com/a/6198700/1768303)** when you copy existing code. – noseratio Nov 06 '13 at 21:10
2

I've this problem in the past and finally resolved it with an injection of a Javascript script that suppress error handling. Hope this could help you too.

Disable Javascript errors in WEbBrowsercontrol

Alkampfer
  • 1,359
  • 12
  • 27
  • Actually I have it working with 8.1 and 4.5 in production program, but the code is probably changed from that example. If you are interested I can try to verify new code and do an updated post. – Alkampfer Aug 23 '14 at 16:03
1

you can use this trick

vb.net

Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long

Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
Private Const WM_CLOSE As Short = &H10s

and call last lib :

 dim hwnd 
    dim vreturnvalue
    hwnd = FindWindow(vbNullString,"script error")
    if hwnd<>0 then vreturnvalue = SendMessage(hwnd, WM_CLOSE,  &O0s, &O0s)
ASR
  • 1,801
  • 5
  • 25
  • 33
1

Wolf5's answer is good but if (objComWebBrowser == null) doesn't seem to work. Instead I check the WebBrowser instance for IsLoaded:

public void HideScriptErrors(WebBrowser webBrowser)
{
    if (!webBrowser.IsLoaded)
    {
        webBrowser.Loaded += WebBrowser_Loaded; // in case we are too early
        return;
    }

    var objComWebBrowser = typeof(WebBrowser).GetField("_axIWebBrowser2", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(webBrowser);
    if (objComWebBrowser == null)
    {
        return;
    }

    objComWebBrowser.GetType().InvokeMember("Silent", BindingFlags.SetProperty, null, objComWebBrowser, new object[] { true });
}
private void WebBrowser_Loaded(object sender, RoutedEventArgs e)
{
    var webBrowser = sender as WebBrowser;
    webBrowser.Loaded -= WebBrowser_Loaded;
    HideScriptErrors(webBrowser);
}

It is also necessary to remove the Loaded event handler after the first time, as the control may be unloaded and loaded again several times when making it invisible by switching to a different tab. Also the if (!wb.Loaded)) fallback is still important when the WebBrowser is not visible yet on its first navigation, e.g. if it is on a different tab that is not visible on application startup.

Kim Homann
  • 3,042
  • 1
  • 17
  • 20