1、CWebbrowser 中屏蔽弹出窗口及脚本错误提示当 IE 浏览器遇到脚本错误时浏览器,左下角会出现一个黄色图标,点击可以查看脚本错误的详细信息,并不会有弹出的错误信息框。当我们使用 WebBrowser 控件时有错误信息框弹出,这样程序显的很不友好,而且会让一些自动执行的程序暂停。我看到有人采取的解决方案是做一个窗体杀手程序来关闭弹出的窗体。今天探讨的方法是从控件解决问题。 1、SHDocVw.dll 在 COM 时代我们使用的 WebBrowser 控件是 SHDocVw.dll。屏蔽错误信息的方法很简单使用下面的一句就可以搞定。c-sharp view plaincopyprint?1
2、. WebBrowser1.Silent = true; WebBrowser1.Silent = true;2、.Net 中 在.Net 中提供了托管的 WebBrowser 可供我们使用,当然我们仍然可以在 .Net 中使用COM 组建 SHDocVw.dll,如果使用 SHDocVw.dll 处理错误方式和上面的方法一样。但如果我们是使用.Net 组件如何解决这个问题呢? 在.Net 中提供了托管的 WebBrowser 可供我们使用,当然我们仍然可以在 .Net 中使用COM 组建 SHDocVw.dll,如果使用 SHDocVw.dll 处理错误方式和上面的方法一样。但如果我们是使用
3、.Net 组件如何解决这个问题呢? c-sharp view plaincopyprint?1. webBrowser1.ScriptErrorsSuppressed = true; webBrowser1.ScriptErrorsSuppressed = true;(据说在.net framework2.0 以前是这样,我没有使用过) 那么在.net framework2.0 中如何解决这个问题呢? 有一种方法不能彻底解决,可以部分解决问题这里也介绍给大家。 c-sharp view plaincopyprint?1. /捕获控件的错误 2. this.WebBrowser.Document
4、.Window.Error += new HtmlElementErrorEventHandler(Window_Error); 3. /对错误进行处理 4. void Window_Error(object sender, HtmlElementErrorEventArgs e) 5. 6. / 自己的处理代码 7. e.Handled = true; 8. /捕 获 控 件 的 错 误this.WebBrowser.Document.Window.Error += new HtmlEl/对 错 误 进 行 处 理void Window_Error(object sender, HtmlEl
5、ementErrorEv / 自 己 的 处 理 代 码e.Handled = true;3、上面的方法对于多个框架嵌套等等的情形还是不能很好的解决。为了彻底解决这个问题,我们借助 AxWebBrowser 来解决 WebBrowser 的问题。我们定义一个自己的类,他的父类是 WebBrowser,以后使用这个类就可以了。在这个类的定义中需要引用 SHDocVw。 c-sharp view plaincopyprint?1. class EWebBrowser : System.Windows.Forms.WebBrowser 2. 3. SHDocVw.IWebBrowser2 Iwb2;
6、 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.DetachInterf
7、aces(); 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. “funct
8、ion 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 vDocum
9、ent.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. class EWebBrowser : System.Windows.Forms.WebBrowserSHDocVw.IWebBrow
10、ser2 Iwb2;protected override void AttachInterfaces(object Iwb2 = (SHDocVw.IWebBrowser2) nativeActiveX Iwb2.Silent = true;base.AttachInterfaces(nativeActiveXObject); protected override void DetachInterfaces() Iwb2 = null; base.DetachInterfaces();4、屏蔽其它窗口c-sharp view plaincopyprint?1. (wb.ActiveXInsta
11、nce 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).Doc
12、ument 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“, “ja
13、vascript“); 11. doc.parentWindow.execScript(“window.close=null“, “javascript“); (wb.ActiveXInstance as SHDocVw.WebBrows/屏 蔽 一 些 弹 出 窗 口 void wb_NavigateComplete2(object pDisp, ref mshtml.IHTMLDocument2 doc = (wb.ActiveXdoc.parentWindow.execScript(“window.ale doc.parentWindow.execScript(“window.condo
14、c.parentWindow.execScript(“window.ope doc.parentWindow.execScript(“window.shodoc.parentWindow.execScript(“window.clo5、自动确定弹出对话框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. thi
15、s.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_NavigateCompl
16、ete2(object pDisp, ref object URL) 12. . 13. mshtml.IHTMLDocument2 doc = (this.webBrowser1.ActiveXInstance asSHDocVw.WebBrowser).Document as mshtml.IHTMLDocument2; 14. doc.parentWindow.execScript(“function alert(str)return “, “javascript“); 15. /using mshtml; /using SHDocVw;private void Form1_Load(o
17、bject sender, Even this.webBrowser1.Navigate(“http:/local SHDocVw.WebBrowser wb = this.webBrowserwb.NavigateComplete2 += new SHDocVw.DWe void wb_NavigateComplete2(object pDisp, ref .mshtml.IHTMLDocument2 doc = (this.webBr doc.parentWindow.execScript(“function a6、C# 集成的 WebBrowser 解决方案。将 WebBrowser 控
18、件 ScriptErrorsSuppressed 设置为 True,可禁止弹出脚本错误对话框,ScriptErrorsSuppressed 属性是对其基础 COM 控件的 Silent 属性的封装,因此设置ScriptErrorsSuppressed 属性和设置其基础 COM 控件的 Slient 属性是效果一样的,这一点通过反编译 System.Windows.Forms 程序集可以证实。为了解决这个问题,有的人专门从 WebBrowser 派生出一个新类,然后重写了AttachInterfaces 方法,其实也是没有必要的,效果和直接设置 ScriptErrorsSuppressed属性相
19、同。不过要注意的是: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 HtmlE
20、lementErrorEventHandler(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 的再扩展.NET 2.0 提供了一个新的 WebBrowser 控件.该 WebBrowser 控件为我们带来了许多非常实用的新特性.举个简单的例子:H
21、tmlDocument 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 控件达到了一个前
22、所未有的高度.这样的特性,就已经为我们在进行相关的Windows Forms 程序开发时选用它提供了足够的理由.很显然,WebBrowser 控件是对 SHDocVw 的 AxWebBrowser 这个非托管的 ActiveX控件进行了封装.但是在实用中,我们很快可以发现,其在提供新特性的同时,并没有全部暴露出 AxWebBrowser 原有的属性和方法,在很多情况下,这样就使得它显得有点捉襟见肘了.jlandheer 对这个 WebBrowser 控件进行了扩展( 见 Extended .NET 2.0 WebBrowser Control).但是该 ExtendedWebBrowser 也
23、仅仅是提供了一个结构和思路,真正实现的扩展也比较有限.根据实际的需要,我又对 ExtendedWebBrowser 进行了再扩展.判断页面是否完全载入:1.新增 DocumentCompleted 事件:在类 ExtendedWebBrowser 里面事件部分的末尾添加如下代码:public new event EventHandler DocumentCompleted;protected void OnDocumentCompleted(BrowserExtendedNavigatingEventArgs e)if (e = null)throw new ArgumentNullExcep
24、tion(“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
25、(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.修改原有 DocumentCompl
26、eted 事件的响应:由于上面重写了 DocumentCompleted 事件,所以需要修改原有的DocumentCompleted 事件响应:修改类 BrowserControl 中_browser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(_browser_DocumentCompleted);为:_browser.DocumentCompleted += new EventHandler(_browser_DocumentCompleted);修改void _browser_DocumentCompl
27、eted(object sender, WebBrowserDocumentCompletedEventArgs e)为:void _browser_DocumentCompleted(object sender, BrowserExtendedNavigatingEventArgs e)其它相应的地方进行同样的修改.4.发送 DocumentCompleted 事件到最外层:该 ExtendedWebBrowser 演示程序通过类 WindowManager 管理了一个标签浏览器,如果需要,我们可以将事件发送到最外层,提供给 MainForm 使用.将 WindowManager 中的代码v
28、oid WebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)CheckCommandState();改成:void WebBrowser_DocumentCompleted(object sender, BrowserExtendedNavigatingEventArgs e)OnDocumentCompleted(sender, e);CheckCommandState();public event EventHandler DocumentCompleted;/ / Raise
29、s the DocumentCompleted event/ / protected virtual void OnDocumentCompleted(object sender, BrowserExtendedNavigatingEventArgs e)if (DocumentCompleted != null)DocumentCompleted(sender, e);5.在需要的地方响应 DocumentCompleted 事件:如:_windowManager.DocumentCompleted += new EventHandler(_windowManager_DocumentCom
30、pleted);.void _windowManager_DocumentCompleted(object sender, BrowserExtendedNavigatingEventArgs e)/ 页面完全载入if (e.AutomationObject = (ExtendedWebBrowser)sender).Application)MessageBox.Show(“DocumentCompleted:“ + e.Url.ToString();注意:必须 e.AutomationObject = (ExtendedWebBrowser)sender).Application 才说明页面
31、已经完全载入.由于 Web 页面可能为多个框架嵌套的(可能还有其它的情况,尚未深究),那么载入过程中对应会有多个DocumentCompleted 事件,而只有页面完全载入了,才会 e.AutomationObject = (ExtendedWebBrowser)sender).Application.这就是为什么要费尽千辛万苦把pDisp 传递出来的原因.不弹出页面,仍在当前浏览器浏览:ExtendedWebBrowser 中的 StartNewWindow 事件在弹出新页面的时候触发.其扩展的事件数据 BrowserExtendedNavigatingEventArgs 中已经提供了上下文
32、,新页面的 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
33、 wheter its a HTML dialog box. If so, allow the popup but do not open a new tabif (!(e.NavigationContext / The (in)famous application objecte.AutomationObject = ewb.Application;/在这里使用: e.AutomationObject = _browser.Application;似乎没有作用,/但是他原来的代码 e.AutomationObject = ewb.Application;是有用的(见上面注释)/不知道是什么原
34、因,只好暂时采用这个办法_browser.Navigate(e.Url);e.Cancel = true;这里如果使用 e.AutomationObject = _browser.Application 的话,似乎同他原来的代码 e.AutomationObject = ewb.Application 唯一的区别就是一个browser 是浏览过页面了的,一个 browser.是新建的,难道会同这个有关?哪位如果知道原因,还请不吝赐教!不弹出脚本错误提示框:ExtendedWebBrowser 通过响应事件 WebBrowser.Document.Window.Error 来捕获脚本错误提示框弹
35、出的消息: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 eventthis.WebBrowser.Document.Window.Error += new HtmlElementErrorEventHandler(Window_Error);.void Window_Error(object s
36、ender, HtmlElementErrorEventArgs e)/ We got a script error, record itScriptErrorManager.Instance.RegisterScriptError(e.Url, e.Description, e.LineNumber);/ Let the browser know we handled this error.e.Handled = true;但是似乎还是由于前面提到的 Web 页面存在多个框架嵌套的原因,其能够捕获到的消息比较有限,有很大一部分脚本错误提示消息仍然会捕获不到.这样一个问题困扰了我几天.后来突然
37、发现 ExtendedWebBrowser 里面有如下的代码:/ / 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. / / PermissionSet(SecurityAction.LinkDemand, Name = “FullTrust“)protected override
38、 void AttachInterfaces(object nativeActiveXObject)this.axIWebBrowser2 = (UnsafeNativeMethods.IWebBrowser2)nativeActiveXObject;base.AttachInterfaces(nativeActiveXObject);原来 AxWebBrowser 在这里!于是简单的设置了 axIWebBrowser2.Silent 属性:protected override void AttachInterfaces(object nativeActiveXObject)this.axIW
39、ebBrowser2 = (UnsafeNativeMethods.IWebBrowser2)nativeActiveXObject;this.axIWebBrowser2.Silent = true;/不弹脚本错误框base.AttachInterfaces(nativeActiveXObject);不再弹出任何提示框,Silent 属性真的是恰如其名,整个世界清静了.*_*从上面的内容可以看出,ExtendedWebBrowser 截取了 AxWebBrowser 接口.那么,不难想象,虽然我的“再扩展“只扩展了如上三项功能,其实我们现在可以做我们任何想做的!截获“浏览器的信息对话框“弹出
40、消息:基于某些特殊需求的需要 ,程序需要知道浏览器控件的信息对话框何时弹出了,消息的内容是什么,以及其它相关的信息.思路一 :向浏览的页面中添加如下代码(为避免与页面中原有的元素相冲突,可以将下面代码内的方法名, 元素名等替换成不同的 guid)window.alert=myFunction; /替换 alertfunction myFunction(u1) /在自定义的方法中将 alert 内容赋值给自己添加的 button,并 click 该 buttondocument.myForm.myButton.value = u1;document.myForm.myButton.click()
41、;并在宿主程序中响应该 button 的 click 事件消息:(ExtendedWebBrowser)sender).Document.All“myButton“.Click +=new HtmlElementEventHandler(myAlertElement_Click);这样一来,便可以一种迂回的方式巧妙获取到 alert 消息框弹出事件.但是通过使用 HtmlElement.AppendChild() / HtmlDocument.Write() 以及 HTMLWindow2.execScript(.) 等方法向载入的页面中添加上述代码,均未能得到理想的结果,遂暂时放弃(哪位知道该
42、怎么弄的话,请不吝赐教!)思路二 :额外开一监视线程 ,实时枚举所有子窗口.以达到获取该消息框弹出事件的目的.可以预计,该方法会影响到整个系统的性能,会影响到程序的稳定性,同时其可靠性也不高(不能保证每次弹出消息框时刚好能够枚举到).所以这只能作为备用方法 ,在没有找到其它更好方法的情况下,勉强用用.思路三 :再一次扩展浏览器控件 .查询 MSDN,可以找到对 WebBrowser.CreateWebBrowserSiteBase 方法的描述:返回对非托管 WebBrowser ActiveX 控件站点的引用,扩展该站点可以对托管 WebBrowser 控件进行自定义。 若要使用此功能,请实现
43、从 WebBrowser 和 WebBrowser.WebBrowserSite 类继承的类。非托管 WebBrowser ActiveX 控件使用受保护的 CreateWebBrowserSiteBase 方法检索由 WebBrowser.WebBrowserSite 类实现的扩展性接口。重写 CreateWebBrowserSiteBase 方法以返回自己的从 WebBrowser.WebBrowserSite 类继承的类的实例。WebBrowser.WebBrowserSite 类提供 OLE IDocHostUIHandler 的默认实现。您可以为此接口提供自己的实现,或者实现任何其他
44、 WebBrowser ActiveX 控件接口,从而对控件行为进行自定义。 可以看出,我们只需重写 CreateWebBrowserSiteBase 方法,扩展 WebBrowserSite ,便可实现对浏览器控件的扩展。我们知道, IDocHostUIHandler ,IDocHostUIHandler2 和 IDocHostShowUI 这三个接口是浏览器控件用户界面的自定义的核心。当一个容器提供对 ActiveX 控件支持的时候 , 当浏览器控件被实例化时,如果可能的话,它尝试找来自宿主的 IDocHostUIHandler , IDocHostUIHandler2 和 IDocHos
45、tShowUI 实现。当我们修改浏览器控件的时候 , 这些是我们应该在程序中实现的接口。在这里,我们需要的仅仅是截获“浏览器的信息对话框“弹出消息,所以我们也没有必要把所有这些接口全部实现一遍。IDocHostShowUI 这个接口提供给我们对浏览器控件显示的信息对话框和帮助的控制。我们实现它,这样在浏览器控件显示它自己的任何的信息或帮助之前 ,能调用我们定义的 IDocHostShowUI 的方法。这样我们便有一个机会捕获该信息对话框弹出的消息。 IDocHostShowUI 有两个方法,IDocHostShowUI:ShowMessage 和 IDocHostShowUI:ShowHelp
46、。已经准备得很充分了。现在开工!在文件 UnsafeNativeMethods.cs 的 public class UnsafeNativeMethods 里面添加如下代码:#region IDocHostShowUIStructLayout(LayoutKind.Explicit, Pack = 4)public struct _MIDL_IWinTypes_0009/ FieldsFieldOffset(0)public int hInproc;FieldOffset(0)public int hRemote;StructLayout(LayoutKind.Sequential, Pack
47、 = 4)public struct _RemotableHandlepublic int fContext;public _MIDL_IWinTypes_0009 u;StructLayout(LayoutKind.Sequential, Pack = 4)public struct tagPOINTpublic int x;public int y;ComImport, Guid(“C4D244B0-D43E-11CF-893B-00AA00BDCE1A“), InterfaceType(short)1)public interface IDocHostShowUIMethodImpl(M
48、ethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)void ShowMessage(In, ComAliasName(“ExtendedWebBrowser2.UnsafeNativeMethods.wireHWND“) ref _RemotableHandle hwnd, In, MarshalAs(UnmanagedType.LPWStr) string lpstrText, In, MarshalAs(UnmanagedType.LPWStr) string lpstrCaption, In uint dwType, In, MarshalAs(UnmanagedType.LPWStr) string lpstrHelpFile, In uint dwHelpContext,