关于c#.NET WebBrowser控件中的阻止对话框

关于c#.NET WebBrowser控件中的阻止对话框

Blocking dialogs in .NET WebBrowser control

我有一个.NET 2.0 WebBrowser控件,该控件用于在没有用户交互的情况下导航某些页面(不要问...长话短说)。由于此应用程序的用户较少,因此我将WebBrowser控件的ScriptErrorsSuppressed属性设置为true,VS 2005状态随附的文档将隐藏所有来自基础ActiveX控件的对话框,不只是脚本错误。"但是,MSDN文章没有提到这一点。
我设法取消了NewWindow事件,该事件可以防止弹出窗口,因此已经解决了这个问题。

任何人都有使用其中一种方法并成功阻止所有对话框,脚本错误等的经验吗?

编辑

这不是IE的独立实例,而是Windows Form应用程序上的WebBrowser控件的实例。任何人都对此控件或基础控件AxSHDocVW有经验吗?

再次编辑

抱歉,我忘了提及这一点...我试图仅使用OK按钮来阻止JavaScript alert()。也许我可以转换为IHTMLDocument2对象并以这种方式访问?疟荆乙丫褂昧薓SHTML一点,有人知道吗?


为了方便地注入神奇的javascript代码,请阅读如何将javascript注入到webbrowser控件中。

或者只使用下面的完整代码:

1
2
3
4
5
6
7
private void InjectAlertBlocker() {
    HtmlElement head = webBrowser1.Document.GetElementsByTagName("head")[0];
    HtmlElement scriptEl = webBrowser1.Document.CreateElement("script");
    string alertBlocker ="window.alert = function () { }";
    scriptEl.SetAttribute("text", alertBlocker);
    head.AppendChild(scriptEl);
}

这绝对是很棘手的,但是如果您使用WebBrowser控件进行任何工作,您都会发现自己在做很多棘手的事情。

这是我所知道的最简单的方法。您需要注入JavaScript以覆盖警报功能...注入此JavaScript函数的过程如下:

1
window.alert = function () { }

有很多方法可以做到这一点,但这是很有可能的。一种可能性是挂钩DWebBrowserEvents2接口的实现。完成此操作后,您可以将其插入NavigateComplete,DownloadComplete或DocumentComplete(或我们的一些变体)中,然后调用已实现的InjectJavaScript方法来执行对窗口的覆盖。方法。

就像我说的,hacky,但是它可以用:)

如果需要,我可以详细介绍。


您可能必须自定义一些内容,看看IDocHostUIHandler,然后查看其他一些相关的接口。您甚至可以自定义对话框显示/用户界面(我想不起来是哪个界面执行的),您可以拥有相当多的控制权。我很确定您可以做您想做的事,但这确实需要对MSHTML的内部进行处理,并能够实现各种COM接口。

其他一些想法:
http://msdn.microsoft.com/en-us/library/aa770041.aspx

1
2
IHostDialogHelper
IDocHostShowUI

这些可能就是您要实现的东西。


防弹警报拦截器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Browser.Navigated +=
    new WebBrowserNavigatedEventHandler(
        (object sender, WebBrowserNavigatedEventArgs args) => {
            Action<HtmlDocument> blockAlerts = (HtmlDocument d) => {
                HtmlElement h = d.GetElementsByTagName("head")[0];
                HtmlElement s = d.CreateElement("script");
                IHTMLScriptElement e = (IHTMLScriptElement)s.DomElement;
                e.text ="window.alert=function(){};";
                h.AppendChild(s);
            };
            WebBrowser b = sender as WebBrowser;
            blockAlerts(b.Document);
            for (int i = 0; i < b.Document.Window.Frames.Count; i++)
                try { blockAlerts(b.Document.Window.Frames[i].Document); }
                catch (Exception) { };
        }
    );

本示例假定您已添加Microsoft.mshtml参考,"使用mshtml;"。在名称空间中,浏览器是WebBrowser实例。

为什么防弹呢?首先,它处理框架内的脚本。这样,当文档中存在特殊的"杀手frame"时,它就不会崩溃。"杀手框架"是在尝试将其用作HtmlWindow对象时引发异常的框架。 Document.Window.Frames上使用的任何" foreach"都将导致异常,因此必须将更安全的" for"循环与try / catch块一起使用。

也许这不是最易读的代码段,但它适用于现实生活中格式错误的页面。


可以通过实现INewWindowManager接口来阻止window.showModelessDialog和window.showModalDialog,下面的代码另外显示了如何通过实现IDocHostShowUI来阻止警报对话框

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public class MyBrowser : WebBrowser
{

    [PermissionSetAttribute(SecurityAction.LinkDemand, Name ="FullTrust")]
    public MyBrowser()
    {
    }

    protected override WebBrowserSiteBase CreateWebBrowserSiteBase()
    {
        var manager = new NewWindowManagerWebBrowserSite(this);
        return manager;
    }

    protected class NewWindowManagerWebBrowserSite : WebBrowserSite, IServiceProvider, IDocHostShowUI
    {
        private readonly NewWindowManager _manager;

        public NewWindowManagerWebBrowserSite(WebBrowser host)
            : base(host)
        {
            _manager = new NewWindowManager();
        }

        public int ShowMessage(IntPtr hwnd, string lpstrText, string lpstrCaption, int dwType, string lpstrHelpFile, int dwHelpContext, out int lpResult)
        {
            lpResult = 0;
            return Constants.S_OK; //  S_OK Host displayed its UI. MSHTML does not display its message box.
        }

        // Only files of types .chm and .htm are supported as help files.
        public int ShowHelp(IntPtr hwnd, string pszHelpFile, uint uCommand, uint dwData, POINT ptMouse, object pDispatchObjectHit)
        {
            return Constants.S_OK; //  S_OK Host displayed its UI. MSHTML does not display its message box.
        }

        #region Implementation of IServiceProvider

        public int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject)
        {
            if ((guidService == Constants.IID_INewWindowManager && riid == Constants.IID_INewWindowManager))
            {
                ppvObject = Marshal.GetComInterfaceForObject(_manager, typeof(INewWindowManager));
                if (ppvObject != IntPtr.Zero)
                {
                    return Constants.S_OK;
                }
            }
            ppvObject = IntPtr.Zero;
            return Constants.E_NOINTERFACE;
        }

        #endregion
    }
 }

[ComVisible(true)]
[Guid("01AFBFE2-CA97-4F72-A0BF-E157038E4118")]
public class NewWindowManager : INewWindowManager
{
    public int EvaluateNewWindow(string pszUrl, string pszName,
        string pszUrlContext, string pszFeatures, bool fReplace, uint dwFlags, uint dwUserActionTime)
    {

        // use E_FAIL to be the same as CoInternetSetFeatureEnabled with FEATURE_WEBOC_POPUPMANAGEMENT
        //int hr = MyBrowser.Constants.E_FAIL;
        int hr = MyBrowser.Constants.S_FALSE; //Block
        //int hr = MyBrowser.Constants.S_OK; //Allow all
        return hr;
    }
}

1
webBrowser1.ScriptErrorsSuppressed = true;

只需将其添加到您的入门级功能即可。经过大量研究后,我遇到了这种方法,并且一直接触到木材。干杯!!


InjectAlertBlocker是绝对正确的
代码是

1
2
3
4
5
6
7
8
private void InjectAlertBlocker() {
    HtmlElement head = webBrowser1.Document.GetElementsByTagName("head")[0];
    HtmlElement scriptEl = webBrowser1.Document.CreateElement("script");
    IHTMLScriptElement element = (IHTMLScriptElement)scriptEl.DomElement;
    string alertBlocker ="window.alert = function () { }";
    element.text = alertBlocker;
    head.AppendChild(scriptEl);
}

需要添加的参考是

  • 添加对MSHTML的引用,该引用在COM引用下将被称为" Microsoft HTML对象库"。

  • using mshtml;添加到您的名称空间。

  • 获取对脚本元素的IHTMLElement的引用:

  • 然后,可以将webbrowser的Navigated事件用作:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    private void InjectAlertBlocker()
    {
        HtmlElement head = webBrowser1.Document.GetElementsByTagName("head")[0];
        HtmlElement scriptEl = webBrowser1.Document.CreateElement("script");
        IHTMLScriptElement element = (IHTMLScriptElement)scriptEl.DomElement;
        string alertBlocker ="window.alert = function () { }";
        element.text = alertBlocker;
        head.AppendChild(scriptEl);
    }

    private void webDest_Navigated(object sender, WebBrowserNavigatedEventArgs e)
    {
        InjectAlertBlocker();
    }

    我刚刚在Code Project上发表了一篇文章,可能会对您有所帮助。

    请参阅-http://www.codeproject.com/KB/shell/WebBrowserControlDialogs.aspx

    希望这可以帮助。


    最简单的方法是:
    在:Webbrowser Control中,您具有步骤(标准)BeforeScriptExecute

    (BeforeScriptExecute的参数是pdispwindow)

    添加:

    1
    pdispwindow.execscript("window.alert = function () { }")

    这样,在页面窗口警报上执行任何脚本之前,都将被注入的代码抑制。


    只需从浏览器控件属性即可:scriptErrorSupressed = true


    我对此有更大的问题:加载一个用于打印的网页,它会显示令人讨厌的"打印"对话框。 InjectBlocker是唯一可行的方法,但相当不可靠。在某些情况下(我正在考虑由于WebBrowser控件使用IE引擎,而这取决于已安装的IE版本),仍然会出现打印对话框。这是一个主要问题,该解决方案适用于安装了IE9的Win7,但是无论如何,带IE8的WinXP都会显示该对话框。

    我认为解决方案是在控件呈现页面之前修改源代码并删除打印javascript。但是,我尝试使用:webbrowser控件的DocumentText属性,它不起作用。当我修改源时,该属性不是只读的,但是没有任何作用。

    我为问题找到的解决方案是Exec脚本:

    1
    2
    string alertBlocker ="window.print = function emptyMethod() { }; window.alert = function emptyMethod() { }; window.open = function emptyMethod() { };";    
    this.Document.InvokeScript("execScript", new Object[] { alertBlocker,"JavaScript" });


    通过创建扩展的WebBroswer类并覆盖OnNavigated方法,我设法注入了上面的代码。

    这似乎工作得很好:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    class WebBrowserEx : WebBrowser
    {
      public WebBrowserEx ()
      {
      }

      protected override void OnNavigated( WebBrowserNavigatedEventArgs e )
      {
           HtmlElement he = this.Document.GetElementsByTagName("head" )[0];
           HtmlElement se = this.Document.CreateElement("script" );
           mshtml.IHTMLScriptElement element = (mshtml.IHTMLScriptElement)se.DomElement;
           string alertBlocker ="window.alert = function () { }";
           element.text = alertBlocker;
           he.AppendChild( se );
           base.OnNavigated( e );
      }
    }

    您是否要实施网络机器人?我在使用托管IE控件方面经验很少,但是我确实完成了一些尝试使用IE控件的Win32项目。禁用弹出窗口应通过控件的事件处理程序完成,就像我已经做过的一样,但是我发现您还需要在IE选项中更改"禁用脚本调试xxxx"(或者您可以在代码中修改注册表),如下所示: cjheath已经指出。但是,我还发现,需要检查导航URL中是否有任何可下载的内容,以防止那些打开/保存对话框的出现,需要执行额外的步骤。但是我不知道如何处理流文件,因为我不能仅通过查看URL来跳过它们,最后我转向Indy库,省去了处理IE的所有麻烦。最后,我记得Microsoft确实在网上提到了IE并非旨在用作OLE控件的内容。根据我自己的经验,每次控件导航到新页面时,确实会引入程序的内存泄漏!


    推荐阅读