资源描述
C#Webbrowser中屏蔽弹出窗口及脚本错误提示
当IE浏览器遇到脚本错误时浏览器,左下角会出现一个黄色图标,点击可以查看脚本错误的详细信息,并不会有弹出的错误信息框。当我们使用WebBrowser控件时有错误信息框弹出,这样程序显的很不友好,而且会让一些自动执行的程序暂停。我看到有人采取的解决方案是做一个窗体杀手程序来关闭弹出的窗体。今天探讨的方法是从控件解决问题。
1、SHDocVw.dll
在COM时代我们使用的WebBrowser控件是SHDocVw.dll。屏蔽错误信息的方法很简单使用下面的一句就可以搞定。
[c-sharp] view plaincopyprint?
1. WebBrowser1.Silent = true;
2、.Net中
在.Net中提供了托管的WebBrowser可供我们使用,当然我们仍然可以在.Net中使用COM组建SHDocVw.dll,如果使用SHDocVw.dll
处理错误方式和上面的方法一样。但如果我们是使用.Net组件如何解决这个问题呢?
在.Net中提供了托管的WebBrowser可供我们使用,当然我们仍然可以在.Net中使用COM组建SHDocVw.dll,如果使用SHDocVw.dll
处理错误方式和上面的方法一样。但如果我们是使用.Net组件如何解决这个问题呢?
[c-sharp] view plaincopyprint?
1. webBrowser1.ScriptErrorsSuppressed = true;
(据说在.net framework2.0以前是这样,我没有使用过)
那么在.net framework2.0中如何解决这个问题呢?
有一种方法不能彻底解决,可以部分解决问题这里也介绍给大家。
[c-sharp] view plaincopyprint?
1. //捕获控件的错误
2. this.WebBrowser.Document.Window.Error += new HtmlElementErrorEventHandler(Window_Error);
3. //对错误进行处理
4. void Window_Error(object sender, HtmlElementErrorEventArgs e)
5. {
6. // 自己的处理代码
7. e.Handled = true;
8. }
3、上面的方法对于多个框架嵌套等等的情形还是不能很好的解决。
为了彻底解决这个问题,我们借助AxWebBrowser来解决WebBrowser的问题。
我们定义一个自己的类,他的父类是WebBrowser,以后使用这个类就可以了。在这个类的定义中需要引用SHDocVw。
[c-sharp] view plaincopyprint?
1. class EWebBrowser : System.Windows.Forms.WebBrowser
2. {
3. SHDocVw.IWebBrowser2 Iwb2;
4.
5. protected override void AttachInterfaces(object nativeActiveXObject)
6. {
7. Iwb2 = (SHDocVw.IWebBrowser2) nativeActiveXObject;
8. Iwb2.Silent = true;
9. base.AttachInterfaces(nativeActiveXObject);
10. }
11.
12. protected override void DetachInterfaces()
13. {
14. Iwb2 = null;
15. base.DetachInterfaces();
16. }
17. }
18.
19.
20.
21. //项目中添加Micrsoft.mshtml引用
22. using mshtml;
23.
24. private void webBrowser1_Navigated(object sender, WebBrowserNavigatedEventArgs e)
25. {
26. IHTMLDocument2 vDocument = (IHTMLDocument2)webBrowser1.Document.DomDocument;
27. vDocument.parentWindow.execScript(
28. "function alert(str){if(str=='zswang')confirm(str);}", "javaScript");
29. }
30.
31. //frame结构
32.
33. private void webBrowser1_Navigated(object sender, WebBrowserNavigatedEventArgs e)
34. {
35. IHTMLDocument2 vDocument = (IHTMLDocument2)webBrowser1.Document.DomDocument;
36. foreach (IHTMLElement vElement in vDocument.all)
37. if (vElement.tagName.ToUpper() == "FRAME")
38. {
39. IHTMLFrameBase2 vFrameBase2 = vElement as IHTMLFrameBase2;
40. vFrameBase2.contentWindow.execScript(
41. "function alert(str){confirm('[' + str + ']');}", "javaScript");
42. }
43. }
4、屏蔽其它窗口
[c-sharp] view plaincopyprint?
1. (wb.ActiveXInstance as SHDocVw.WebBrowser).NavigateComplete2 += new DWebBrowserEvents2_NavigateComplete2EventHandler(wb_NavigateComplete2);//wb是一个Webbrowser控件
2.
3. //屏蔽一些弹出窗口
4. void wb_NavigateComplete2(object pDisp, ref object URL)
5. {
6. mshtml.IHTMLDocument2 doc = (wb.ActiveXInstance as SHDocVw.WebBrowser).Document as mshtml.IHTMLDocument2;
7. doc.parentWindow.execScript("window.alert=null", "javascript");
8. doc.parentWindow.execScript("window.confirm=null", "javascript");
9. doc.parentWindow.execScript("window.open=null", "javascript");
10. doc.parentWindow.execScript("window.showModalDialog=null", "javascript");
11. doc.parentWindow.execScript("window.close=null", "javascript");
5、自动确定弹出对话框
Q:winform中如何实现自动点击webbrowser弹出对话框中的确定按钮
A:
[c-sharp] view plaincopyprint?
1. //using mshtml;
2. //using SHDocVw;
3. private void Form1_Load(object sender, EventArgs e)
4. {
5. this.webBrowser1.Navigate("http://localhost:28512/WebSite2/Default.aspx");
6. SHDocVw.WebBrowser wb = this.webBrowser1.ActiveXInstance as SHDocVw.WebBrowser;
7. wb.NavigateComplete2 += new SHDocVw.DWebBrowserEvents2_NavigateComplete2EventHandler(wb_NavigateComplete2);
8.
9. }
10.
11. void wb_NavigateComplete2(object pDisp, ref object URL)
12. ...{
13. mshtml.IHTMLDocument2 doc = (this.webBrowser1.ActiveXInstance as SHDocVw.WebBrowser).Document as mshtml.IHTMLDocument2;
14. doc.parentWindow.execScript("function alert(str){return ''}", "javascript");
15. }
6、C#集成的WebBrowser解决方案。
将WebBrowser控件ScriptErrorsSuppressed 设置为True,可禁止弹出脚本错误对话框,ScriptErrorsSuppressed属性是对其基础COM控件的Silent属性的封装,因此设置ScriptErrorsSuppressed属性和设置其基础COM控件的Slient属性是效果一样的,这一点通过反编译System.Windows.Forms程序集可以证实。
为了解决这个问题,有的人专门从WebBrowser派生出一个新类,然后重写了AttachInterfaces方法,其实也是没有必要的,效果和直接设置ScriptErrorsSuppressed属性相同。
不过要注意的是:
ScriptErrorsSuppressed 设置为True会禁用所有的对话框,比如提示Activex下载、执行以及安全登录等对话框。
如果不想禁止除脚本错误之外的对话框,请使用MSDN上的代码示例:
[c-sharp] view plaincopyprint?
1. private void browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
2. {
3. ((WebBrowser)sender).Document.Window.Error += new HtmlElementErrorEventHandler(Window_Error);
4. }
5.
6. private void Window_Error(object sender, HtmlElementErrorEventArgs e)
7. {
8. // Ignore the error and suppress the error dialog box.
9. e.Handled = true;
10. }
对ExtendedWebBrowser的再扩展
<=======================
原创文章,转载请注明出处!
作者: 谭剑
博客:
关键字:C#,.NET,WebBrowser,ExtendedWebBrowser,浏览器,完全载入,新窗口,脚本
=======================>
.NET 2.0 提供了一个新的WebBrowser控件.该WebBrowser控件为我们带来了许多非常实用的新特性.举个简单的例子:
HtmlDocument htmlDoc = webBrowser.Document;
HtmlElement btnElement = htmlDoc.All["btnClose"];
if (btnElement != null)
{
btnElement.click += new HtmlElementEventHandler(HtmlBtnClose_Click);
}
仅需类似这样简单易懂的几行代码,便可实现Windows Forms对Web页面各个HTML元素各种事件的响应.
在Windows Forms与Web页面交互这方面,在功能与易用性上,该WebBrowser控件达到了一个前所未有的高度.这样的特性,就已经为我们在进行相关的Windows Forms程序开发时选用它提供了足够的理由.
很显然,WebBrowser控件是对SHDocVw的AxWebBrowser这个非托管的ActiveX控件进行了封装.但是在实用中,我们很快可以发现,其在提供新特性的同时,并没有全部暴露出AxWebBrowser原有的属性和方法,在很多情况下,这样就使得它显得有点捉襟见肘了.
jlandheer对这个WebBrowser控件进行了扩展(见Extended .NET 2.0 WebBrowser Control).但是该ExtendedWebBrowser也仅仅是提供了一个结构和思路,真正实现的扩展也比较有限.
根据实际的需要,我又对ExtendedWebBrowser进行了再扩展.
判断页面是否完全载入:
1.新增DocumentCompleted事件:
在类ExtendedWebBrowser里面事件部分的末尾添加如下代码:
public new event EventHandler<BrowserExtendedNavigatingEventArgs> DocumentCompleted;
protected void OnDocumentCompleted(BrowserExtendedNavigatingEventArgs e)
{
if (e == null)
throw new ArgumentNullException("e");
if (this.DocumentCompleted != null)
this.DocumentCompleted(this, e);
}
2.实现public void DocumentComplete(object pDisp, ref object URL)方法:
在文件ExtendedWebBrowser.cs class WebBrowserExtendedEvents : UnsafeNativeMethods.DWebBrowserEvents2 的 Unused events区域里面可以找到未实现的方法:
public void DocumentComplete(object pDisp, ref object URL)
{
}
将其剪贴到已实现的方法部分的末尾,并修改为:
public void DocumentComplete(object pDisp, ref object URL)
{
BrowserExtendedNavigatingEventArgs args = new BrowserExtendedNavigatingEventArgs(pDisp, new Uri(URL.ToString()), null, UrlContext.None);
_Browser.OnDocumentCompleted(args);
}
3.修改原有DocumentCompleted事件的响应:
由于上面重写了DocumentCompleted事件,所以需要修改原有的DocumentCompleted事件响应:
修改类BrowserControl中
_browser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(_browser_DocumentCompleted);
为:
_browser.DocumentCompleted += new EventHandler<BrowserExtendedNavigatingEventArgs>(_browser_DocumentCompleted);
修改
void _browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
为:
void _browser_DocumentCompleted(object sender, BrowserExtendedNavigatingEventArgs e)
其它相应的地方进行同样的修改.
4.发送DocumentCompleted事件到最外层:
该ExtendedWebBrowser演示程序通过类WindowManager管理了一个标签浏览器,如果需要,我们可以将事件发送到最外层,提供给MainForm使用.
将WindowManager中的代码
void WebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
CheckCommandState();
}
改成:
void WebBrowser_DocumentCompleted(object sender, BrowserExtendedNavigatingEventArgs e)
{
OnDocumentCompleted(sender, e);
CheckCommandState();
}
public event EventHandler<BrowserExtendedNavigatingEventArgs> DocumentCompleted;
/// <summary>
/// Raises the DocumentCompleted event
/// </summary>
/// <param name="e"></param>
protected virtual void OnDocumentCompleted(object sender, BrowserExtendedNavigatingEventArgs e)
{
if (DocumentCompleted != null)
DocumentCompleted(sender, e);
}
5.在需要的地方响应DocumentCompleted事件:
如:
_windowManager.DocumentCompleted += new EventHandler<BrowserExtendedNavigatingEventArgs>(_windowManager_DocumentCompleted);
.
.
.
void _windowManager_DocumentCompleted(object sender, BrowserExtendedNavigatingEventArgs e)
{
// 页面完全载入
if (e.AutomationObject == ((ExtendedWebBrowser)sender).Application)
{
MessageBox.Show("DocumentCompleted:" + e.Url.ToString());
}
}
注意:必须e.AutomationObject == ((ExtendedWebBrowser)sender).Application才说明页面已经完全载入.由于Web页面可能为多个框架嵌套的(可能还有其它的情况,尚未深究),那么载入过程中对应会有多个DocumentCompleted事件,而只有页面完全载入了,才会e.AutomationObject == ((ExtendedWebBrowser)sender).Application.这就是为什么要费尽千辛万苦把pDisp传递出来的原因.
不弹出页面,仍在当前浏览器浏览:
ExtendedWebBrowser中的StartNewWindow事件在弹出新页面的时候触发.其扩展的事件数据BrowserExtendedNavigatingEventArgs中已经提供了上下文,新页面的URL,ppDisp等所需的数据.所以我们只需改动类BrowserControl中的方法
void _browser_StartNewWindow(object sender, BrowserExtendedNavigatingEventArgs e)
为:
void _browser_StartNewWindow(object sender, BrowserExtendedNavigatingEventArgs e)
{
// Here we do the pop-up blocker work
// 这些弹出窗口过滤的代码如果不需要,就全部删除掉
if (allowPopup)
{
// Check wheter it's a HTML dialog box. If so, allow the popup but do not open a new tab
if (!((e.NavigationContext & UrlContext.HtmlDialog) == UrlContext.HtmlDialog))
{
ExtendedWebBrowser ewb = mf.WindowManager.New(false);
// The (in)famous application object
e.AutomationObject = ewb.Application;
}
}
//在这里使用: e.AutomationObject = _browser.Application;似乎没有作用,
//但是他原来的代码e.AutomationObject = ewb.Application;是有用的(见上面注释)
//不知道是什么原因,只好暂时采用这个办法
_browser.Navigate(e.Url);
e.Cancel = true;
}
这里如果使用e.AutomationObject = _browser.Application的话,似乎同他原来的代码e.AutomationObject = ewb.Application唯一的区别就是一个browser是浏览过页面了的,一个browser.是新建的,难道会同这个有关?哪位如果知道原因,还请不吝赐教!
不弹出脚本错误提示框:
ExtendedWebBrowser通过响应事件WebBrowser.Document.Window.Error来捕获脚本错误提示框弹出的消息:
void _browser_DownloadComplete(object sender, EventArgs e)
{
// Check wheter the document is available (it should be)
if (this.WebBrowser.Document != null)
{
// Subscribe to the Error event
this.WebBrowser.Document.Window.Error += new HtmlElementErrorEventHandler(Window_Error);
.
.
.
void Window_Error(object sender, HtmlElementErrorEventArgs e)
{
// We got a script error, record it
ScriptErrorManager.Instance.RegisterScriptError(e.Url, e.Description, e.LineNumber);
// Let the browser know we handled this error.
e.Handled = true;
}
但是似乎还是由于前面提到的Web页面存在多个框架嵌套的原因,其能够捕获到的消息比较有限,有很大一部分脚本错误提示消息仍然会捕获不到.这样一个问题困扰了我几天.后来突然发现ExtendedWebBrowser里面有如下的代码:
/// <summary>
/// This method supports the .NET Framework infrastructure and is not intended to be used directly from your code.
/// Called by the control when the underlying ActiveX control is created.
/// </summary>
/// <param name="nativeActiveXObject"></param>
[PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
protected override void AttachInterfaces(object nativeActiveXObject)
{
this.axIWebBrowser2 = (UnsafeNativeMethods.IWebBrowser2)nativeActiveXObject;
base.AttachInterfaces(nativeActiveXObject);
}
原来AxWebBrowser在这里!于是简单的设置了axIWebBrowser2.Silent属性:
protected override void AttachInterfaces(object nativeActiveXObject)
{
this.axIWebBrowser2 = (UnsafeNativeMethods.IWebBrowser2)nativeActiveXObject;
this.axIWebBrowser2.Silent = true;//不弹脚本错误框
base.AttachInterfaces(nativeActiveXObject);
}
不再弹出任何提示框,Silent属性真的是恰如其名,整个世界清静了...*^_^*
从上面的内容可以看出,ExtendedWebBrowser截取了AxWebBrowser接口.那么,不难想象,虽然我的"再扩展"只扩展了如上三项功能,其实我们现在可以做我们任何想做的!
<=======================
原创文章,转载请注明出处!
作者: 谭剑
博客:
对ExtendedWebBrowser的再扩展(续)
《对ExtendedWebBrowser的再扩展》(续)
<=======================
原创文章,转载请注明出处!
作者: 谭剑
博客:
关键字:C#,.NET,WebBrowser,alert,ExtendedWebBrowser,浏览器,对话框
=======================>
截获"浏览器的信息对话框"弹出消息:
基于某些特殊需求的需要,程序需要知道浏览器控件的信息对话框何时弹出了,消息的内容是什么,以及其它相关的信息.
思路一:
向浏览的页面中添加如下代码(为避免与页面中原有的元素相冲突,可以将下面代码内的方法名,元素名等替换成不同的guid)
<script language="JavaScrip\">
window.alert=myFunction; //替换alert
function myFunction(u1) //在自定义的方法中将alert内容赋值给自己添加的button,并click该button
{
document.myForm.myButton.value = u1;
document.myForm.myButton.click();
}
</script>
<form method="get" name="myForm">
<input type="button" name = "myButton" value=""/> <!--自己添加button-->
</form>
并在宿主程序中响应该button的click事件消息:
((ExtendedWebBrowser)sender).Document.All["myButton"].Click +=
new HtmlElementEventHandler(myAlertElement_Click);
这样一来,便可以一种迂回的方式巧妙获取到alert消息框弹出事件.
但是通过使用HtmlElement.AppendChild(..) / HtmlDocument.Write(..) 以及 HTMLWindow2.execScript(...) 等方法向载入的页面中添加上述代码,均未能得到理想的结果,遂暂时放弃(哪位知道该怎么弄的话,请不吝赐教!!!)
思路二:
额外开一监视线程,实时枚举所有子窗口.以达到获取该消息框弹出事件的目的.
可以预计,该方法会影响到整个系统的性能,会影响到程序的稳定性,同时其可靠性也不高(不能保证每次弹出消息框时刚好能够枚举到).
所以这只能作为备用方法,在没有找到其它更好方法的情况下,勉强用用.
思路三:
再一次扩展浏览器控件.
查询MSDN,可以找到对WebBrowser.CreateWebBrowserSiteBase 方法的描述:
『返回对非托管 WebBrowser ActiveX 控件站点的引用,扩展该站点可以对托管 WebBrowser 控件进行自定义。
若要使用此功能,请实现从 WebBrowser 和 WebBrowser.WebBrowserSite 类继承的类。非托管 WebBrowser ActiveX 控件使用受保护的 CreateWebBrowserSiteBase 方法检索由 WebBrowser.WebBrowserSite 类实现的扩展性接口。重写 CreateWebBrowserSiteBase 方法以返回自己的从 WebBrowser.WebBrowserSite 类继承的类的实例。WebBrowser.WebBrowserSite 类提供 OLE IDocHostUIHandler 的默认
展开阅读全文