使用 WPF WebBrowser 控件时如何抑制脚本错误?

Posted

技术标签:

【中文标题】使用 WPF WebBrowser 控件时如何抑制脚本错误?【英文标题】:How do I suppress script errors when using the WPF WebBrowser control? 【发布时间】:2010-11-20 20:38:28 【问题描述】:

我有一个 WPF 应用程序,它使用 WPF WebBrowser 控件在平面显示器(如新闻提要)上向我们的开发人员显示有趣的网页。

问题是我偶尔会收到一个 html 脚本错误,弹出一个讨厌的 IE 错误消息,询问我是否想“停止在此页面上运行脚本”。有没有办法抑制这种错误检查?

注意:我已经在 IE 设置中禁用了脚本调试。

【问题讨论】:

这里还有另一个两行解决方案:***.com/a/18289217/1768303 【参考方案1】:

Wolf5 的回答很好,但if (objComWebBrowser == null) 似乎不起作用。相反,我检查 WebBrowser 实例中的 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);

第一次之后还需要删除Loaded 事件处理程序,因为当通过切换到不同的选项卡使其不可见时,控件可能会被卸载并再次加载几次。此外,当WebBrowser 在第一次导航时不可见时,if (!wb.Loaded)) 后备仍然很重要,例如如果它位于应用程序启动时不可见的其他选项卡上。

【讨论】:

【参考方案2】:

刚刚从another question 找到,这很优雅,效果很好。

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

activeX.Silent = true;

【讨论】:

我把它放在WebBrowser_OnNavigating 事件下并且它有效! +1【参考方案3】:

我想将此作为评论添加到@Alkampfer 答案,但我没有足够的声誉。这对我有用(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);"))

此代码示例是用 F# 编写的,但它的作用非常清楚。

【讨论】:

【参考方案4】:

我还发现了一种有趣的方法来禁用 JavaScript 错误。但是由于使用了优雅的动态类型,您至少需要使用 .Net Framework 4.0。

您需要订阅 WebBrowser 元素的 LoadCompleted 事件:

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

之后,您需要编写如下所示的事件处理程序:

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

【讨论】:

在我的例子中,我必须修复的代码是将完整的标记创建为 MemoeryStream 并使用 NavigateToStream 将其传递给浏览器。所以解决方案是简单地添加一个 window.onerror 函数来静默处理错误。谢谢@Ashot Muradian 在 99% 的情况下,使用 ActiveX 的技巧已经足够并且有效,但我有一种情况,只有一种情况是当这是隐藏 JS 错误的唯一选项时。谢谢!【参考方案5】:

检查以下代码以抑制 WPF 浏览器控件的脚本错误..

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


   

然而,如果您使用带有 winforms 主机的 Winforms Web 浏览器......您有一个属性“SuppressScriptErrors”将其设置为 true

    <WindowsFormsHost Name="WinformsHost" Grid.Row="1">
    <winForms:WebBrowser x:Name="WebBrowserControlView" ScriptErrorsSuppressed="True" AllowWebBrowserDrop="False"></winForms:WebBrowser>
</WindowsFormsHost>

【讨论】:

复制现有代码时应参考original post【参考方案6】:

这是我刚刚通过反射提出的解决方案。解决问题:) 我在 Navigated 事件中运行它,因为在此之前似乎 activeX 对象不可用。

它的作用是在底层的 activeX 对象上设置 .Silent 属性。这与 Windows 窗体等效的 .ScriptErrorsSuppressed 属性相同。

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

一个更好的版本,可以随时运行,而不是在 .Navigated 事件之后:

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

如果第二个示例有任何问题,请尝试将 wb.Loaded 替换为 wb.Navigated。

【讨论】:

+1 谢谢你 - 我真的不喜欢使用“WindowsFormsHost”来获得这个功能的开销,你的代码似乎做得很好。 如何将它添加到 webbrowser 对象中? var wb = new WebBrowser(); wb.Navigated += (a,b)=> HideScriptErrors(wb, true); ;只需要运行一次,但你明白了。在触发 Navigated 事件之前,您无法设置该属性。 创新!谢谢! 太棒了!你怎么能弄出来的:)【参考方案7】:

你可以使用这个技巧

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

并调用最后一个库:

 dim hwnd 
    dim vreturnvalue
    hwnd = FindWindow(vbNullString,"script error")
    if hwnd<>0 then vreturnvalue = SendMessage(hwnd, WM_CLOSE,  &O0s, &O0s)

【讨论】:

【参考方案8】:

我过去遇到过这个问题,最后通过注入抑制错误处理的 Javascript 脚本解决了这个问题。希望这对您也有帮助。

Disable Javascript errors in WEbBrowsercontrol

【讨论】:

实际上我在生产程序中使用了 8.1 和 4.5,但代码可能与该示例不同。如果您有兴趣,我可以尝试验证新代码并更新帖子。【参考方案9】:

这里的问题是 WPF WebBrowser 没有像在 2.0 控件中那样实现这个属性。

最好的办法是在 WPF 应用程序中使用 WindowsFormsHost 并使用 2.0 的 WebBrowser 属性:SuppressScriptErrors。即使这样,您也需要应用程序完全信任才能执行此操作。

不是人们所说的理想,但它几乎是目前唯一的选择。

【讨论】:

现在我还有一个反对这个 winforms-haters 的论据。 not-possible的太多了

以上是关于使用 WPF WebBrowser 控件时如何抑制脚本错误?的主要内容,如果未能解决你的问题,请参考以下文章

WPF下抑制WebBrowser不停弹出各种脚本错误

抑制 WebBrowser 控件中的保存/打开对话框

wpf中我想在WebBrowser控件上放置一个Border控件

在多个窗口中使用 WPF WebBrowser 控件时发生内存泄漏

如何通过 MVVM 在 WPF WebBrowser 控件上使用 Javascript

WebBrowser 控件和 JavaScript 错误