阻止 .NET WebBrowser 控件中的对话框

发布于 2024-07-05 12:54:32 字数 778 浏览 7 评论 0原文

我有一个 .NET 2.0 WebBrowser 控件,用于在没有用户交互的情况下导航某些页面(不要问......长话短说)。 由于该应用程序的无用户性质,我已将 WebBrowser 控件的 ScriptErrorsSuppressed 属性设置为 true,VS 2005 附带的文档指出该属性将 [...]“隐藏源自底层 ActiveX 控件的所有对话框,不仅仅是脚本错误。” MSDN 文章 但是没有提到这一点。 我已设法取消 NewWindow 事件,该事件可防止弹出窗口,因此已解决。

有人有使用其中之一并成功阻止所有对话框、脚本错误等的经验吗?

编辑

这不是 IE 的独立实例,而是 Windows 窗体应用程序上的 WebBrowser 控件的实例。 有人对这个控件或底层控件AxSHDocVW有任何经验吗?

再次编辑

抱歉,我忘了提及这一点...我正在尝试仅使用“确定”按钮来阻止JavaScript警报()。 也许我可以转换为 IHTMLDocument2 对象并以这种方式访问​​脚本,我使用过一点 MSHTML,有人知道吗?

I have a .NET 2.0 WebBrowser control used to navigate some pages with no user interaction (don't ask...long story). Because of the user-less nature of this application, I have set the WebBrowser control's ScriptErrorsSuppressed property to true, which the documentation included with VS 2005 states will [...]"hide all its dialog boxes that originate from the underlying ActiveX control, not just script errors." The MSDN article doesn't mention this, however.
I have managed to cancel the NewWindow event, which prevents popups, so that's taken care of.

Anyone have any experience using one of these and successfully blocking all dialogs, script errors, etc?

EDIT

This isn't a standalone instance of IE, but an instance of a WebBrowser control living on a Windows Form application. Anyone have any experience with this control, or the underlying one, AxSHDocVW?

EDIT again

Sorry I forgot to mention this... I'm trying to block a JavaScript alert(), with just an OK button. Maybe I can cast into an IHTMLDocument2 object and access the scripts that way, I've used MSHTML a little bit, anyone know?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

花桑 2024-07-12 12:54:32

要了解注入 javascript 神奇行的简单方法,请阅读 如何将 javascript 注入网络浏览器控件

或者直接使用这个完整的代码:

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

And for an easy way to inject that magic line of javascript, read how to inject javascript into webbrowser control.

Or just use this complete code:

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);
}
如此安好 2024-07-12 12:54:32

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

这是我所知道的最简单的方法。 您需要注入 JavaScript 来覆盖警报函数...与注入此 JavaScript 函数类似:

window.alert = function () { }

有很多方法可以做到这一点,但很有可能做到。 一种可能性是挂钩 DWebBrowserEvents2 接口的实现。 完成此操作后,您可以插入 NavigateComplete、DownloadComplete 或 DocumentComplete(或者像我们一样,使用它们的某些变体),然后调用您已实现的 InjectJavaScript 方法来执行 window.alert 的重写方法。

就像我说的,hacky,但它有效:)

如果需要的话我可以进入更多细节。

This is most definitely hacky, but if you do any work with the WebBrowser control, you'll find yourself doing a lot of hacky stuff.

This is the easiest way that I know of to do this. You need to inject JavaScript to override the alert function... something along the lines of injecting this JavaScript function:

window.alert = function () { }

There are many ways to do this, but it is very possible to do. One possibility is to hook an implementation of the DWebBrowserEvents2 interface. Once this is done, you can then plug into the NavigateComplete, the DownloadComplete, or the DocumentComplete (or, as we do, some variation thereof) and then call an InjectJavaScript method that you've implemented that performs this overriding of the window.alert method.

Like I said, hacky, but it works :)

I can go into more details if I need to.

听风念你 2024-07-12 12:54:32

Bulletproof 警报拦截器:

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 引用、“using mshtml;”,并且浏览器是您的 >WebBrowser 实例。

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

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

Bulletproof alert blocker:

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

This sample assumes you have Microsoft.mshtml reference added, "using mshtml;" in your namespaces and Browser is your WebBrowser instance.

Why is it bulletproof? First, it handles scripts inside frames. Then, it doesn't crash when a special "killer frame" exists in document. A "killer frame" is a frame which raises an exception on attempt to use it as HtmlWindow object. Any "foreach" used on Document.Window.Frames would cause an exception, so safer "for" loop must be used with try / catch block.

Maybe it's not the most readable piece of code, but it works with real life, ill-formed pages.

饭团 2024-07-12 12:54:32

您可能需要自定义一些东西,看看IDocHostUIHandler,然后查看一些其他相关接口。 您可以拥有相当多的控制权,甚至可以自定义对话框显示/ui(我不记得是哪个界面执行此操作)。 我很确定您可以做您想做的事情,但它确实需要在 MSHTML 内部进行修改,并能够实现各种 COM 接口。

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

IHostDialogHelper
IDocHostShowUI

这些可能是您正在考虑实现的内容。

You may have to customize some things, take a look at IDocHostUIHandler, and then check out some of the other related interfaces. You can have a fair amount of control, even to the point of customizing dialog display/ui (I can't recall which interface does this). I'm pretty sure you can do what you want, but it does require mucking around in the internals of MSHTML and being able to implement the various COM interfaces.

Some other ideas:
http://msdn.microsoft.com/en-us/library/aa770041.aspx

IHostDialogHelper
IDocHostShowUI

These may be the things you're looking at implementing.

情深缘浅 2024-07-12 12:54:32

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

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

window.showModelessDialog and window.showModalDialog can be blocked by implementing INewWindowManager interface, additionally code below show how to block alert dialogs by implementing IDocHostShowUI

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;
    }
}
记忆之渊 2024-07-12 12:54:32
webBrowser1.ScriptErrorsSuppressed = true;

只需将其添加到您的入门级函数中即可。 经过大量研究后,我发现了这种方法,并接触木头,直到现在它才有效。 干杯!!

webBrowser1.ScriptErrorsSuppressed = true;

Just add that to your entry level function. After alot of research is when I came across this method, and touch wood till now its worked. Cheers!!

°如果伤别离去 2024-07-12 12:54:32

InjectAlertBlocker 绝对正确
代码是

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

需要添加的引用是

  1. 添加对 MSHTML 的引用,该引用可能在 COMMicrosoft HTML Object Library” > 引用。

  2. using mshtml; 添加到您的命名空间。

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

然后您可以使用 Naviged 事件为:

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

The InjectAlertBlocker is absolutely correct
code is

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

References needed to be added is

  1. Add a reference to MSHTML, which will probalby be called "Microsoft HTML Object Library" under COM references.

  2. Add using mshtml; to your namespaces.

  3. Get a reference to your script element's IHTMLElement:

Then you can use the Navigated event of webbrowser as:

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();
}
甲如呢乙后呢 2024-07-12 12:54:32

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

Are you trying to implement a web robot? I have little experience in using the hosted IE control but I did completed a few Win32 projects tried to use the IE control. Disabling the popups should be done via the event handlers of the control as you already did, but I found that you also need to change the 'Disable script debugging xxxx' in the IE options (or you could modify the registry in your codes) as cjheath already pointed out. However I also found that extra steps needed to be done on checking the navigating url for any downloadable contents to prevent those open/save dialogs. But I do not know how to deal with streaming files since I cannot skip them by looking at the urls alone and in the end I turned to the Indy library saving me all the troubles in dealing with IE. Finally, I remember Microsoft did mention something online that IE is not designed to be used as an OLE control. According to my own experience, every time the control navigates to a new page did introduce memory leaks for the programs!

薄荷梦 2024-07-12 12:54:32

我遇到了更大的问题:加载一个用于打印的网页,它显示恼人的打印对话框。 InjectBlocker 是唯一有效的方法,但相当不可靠。 在某些条件下(我认为这是由于 WebBrowser 控件使用 IE 引擎,这取决于安装的 IE 版本),打印对话框仍然会出现。 这是一个主要问题,该解决方案适用于安装了 IE9 的 Win7,但是安装了 IE8 的 WinXP 无论如何都会显示该对话框。

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

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

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

I had bigger problems with this: loading a webpage that is meant for printing and it displays annoying Print dialog. The InjectBlocker was the only way that worked, but fairly unreliable. Under certain conditions (I am considering it's due that WebBrowser control uses IE engine and this depends on installed IE version) the print dialog still appears. This is a major problem, the solution works on Win7 with IE9 installed, but WinXP with IE8 displays the dialog, no matter what.

I believe the solution is in modifying source code and removing the print javascript, before control renders the page. However I tried that with: DocumentText property of the webbrowser control and it is not working. The property is not read only, but it has no effect, when I modify the source.

The solution I found for my problem is the Exec script:

string alertBlocker = "window.print = function emptyMethod() { }; window.alert = function emptyMethod() { }; window.open = function emptyMethod() { };";    
this.Document.InvokeScript("execScript", new Object[] { alertBlocker, "JavaScript" });
薄凉少年不暖心 2024-07-12 12:54:32

我设法通过创建扩展的 WebBroswer 类并重写 OnNaviged 方法来注入上面的代码。

这看起来效果很好:

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

I managed to inject the code above by creating an extended WebBroswer class and overriding the OnNavigated method.

This seemed to work quite well:

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 );
  }
}
鸢与 2024-07-12 12:54:32

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

BeforeScriptExecute的参数是pdispwindow

添加以下内容:

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

以这种方式在任何页面窗口警报上的脚本执行将被注入的代码抑制。

The easiest way to do this is :
In the : Webbrowser Control you have the procedure ( standard ) BeforeScriptExecute

( The parameter for BeforeScriptExecute is pdispwindow )

Add this :

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

In this way before any script execution on the page window alert will be suppressed by injected code.

深爱成瘾 2024-07-12 12:54:32

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

Simply from the browser control properties: scriptErrorSupressed=true

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文