我用vs2010里的vb语言编程,用WebBrowser控件打开一般新窗口时是没问题的,但某些新窗口就不能正常显示
忘记说了,GetFileCopyExCallBackPtr获取类模块函数地址指针的方法改进自PctGL的无崩溃回调函数,有相似也有不同,PctGL大神勿怪!
因为是通过 window.open() 打开的,所以取不到 href 参数。
比较直接的方法是取 WebBrowser1.Document.ActiveElement.OuterHtml,从里面解析出 window.open() 的地址。
1. 对于新打开的窗口,在打开时会触发WebBrowser的NewWindow3事件,触发该事件有以下几种操作:
1) 按住SHIFT或CTRL键时点击鼠标;
2) 在链接的右键菜单中选择“在新窗口中打开”或“在新标签中打工”;
3) 链接的目标窗口不存在或者为“_blank“;
4) Javascript的windows.open函数调用;
5) 在调用Navigate 或 Navigate2 时,设置了navOpenInNewWindow标志位;
在自定义的窗口中使用WebBrowser控件时,可以捕捉该事件,然后创建新的窗口,在窗口中打开指定的链接;但.NET实现的WebBrowser控件没有给出该事件的接口,我们需要扩展该控件。
STEP 1:定义扩展的WebBrowser控件
public class ExWebBrowser : System.Windows.Forms.WebBrowser
{ // ……
}
STEP 2: 定义浏览器窗口类:
窗口中有一个ExtWebBrowser控件browser,然后一个地址栏输入框txtURL,一个用于打开页面的按钮btnGo。
public partial class ExWebBrowserForm : Form
{
public ExWebBrowserForm( )
{
InitializeComponent( );
}
public ExWebBrowser Browser
{
get { return null; }
}
private void btnGo_Click(object sender, EventArgs e)
{
try {
_browser.Navigate(txtURL.Text);
} catch (Exception ex) {
MessageBox.Show(ex.ToString( ), ex.Message);
}
}
}
STEP 3:定义要实现的事件接口
还有其它事件,可以在此处定义,但我们目前只关注NewWindow3一个事件,必要时在该接口中增加即可。
[ComImport, TypeLibType((short)0x1010), InterfaceType((short)2), Guid("34A715A0-6587-11D0-924A-0020AFC7AC4D")]
public interface IWebBrowserEvents2
{
[PreserveSig, MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x111)]
void NewWindow3([In, Out, MarshalAs(UnmanagedType.IDispatch)] ref object ppDisp, [In, Out] ref bool Cancel, [In] uint dwFlags, [In, MarshalAs(UnmanagedType.BStr)] string bstrUrlContext, [In, MarshalAs(UnmanagedType.BStr)] string bstrUrl);
}
STEP 4:实现事件接口
在捕捉到NewWindow3事件后创建一个新的窗口,然后在新窗口的ExWebBrowser控件中打开指定的页面。
class WebBrowserExtendedEvents : IWebBrowserEvents2
{
private ExWebBrowser _browser = null;
public WebBrowserExtendedEvents(ExWebBrowser browser) { _browser = browser; }
private object PopupWindow( )
{
ExWebBrowserForm form = new ExWebBrowserForm( );
form.Text += " -- " + form.Browser.Url ?? string.Empty;
form.Visible = true;
form.Show( );
return form.Browser.ApplicationObject;
}
// NewWindow3 event, used on Windows XP SP2 and higher
public void NewWindow3(ref object ppDisp, ref bool Cancel, uint dwFlags, string bstrUrlContext, string bstrUrl)
{
Cancel = _browser.DisablePopupWindow;
if (!Cancel)
ppDisp = PopupWindow( ) ;
}
}
STEP 5:为ExWebBrowser附件实现的IWebBrowserEvents2接口
此处增加了一个属性DisablePopupWindow,该属性用于控制是否禁止弹出窗口。
public class ExWebBrowser : System.Windows.Forms.WebBrowser
{
private IWebBrowser2 axIWebBrowser2;
private bool _diablePopupWindow = false;
private WebBrowserExtendedEvents events = null;
private System.Windows.Forms.AxHost.ConnectionPointCookie cookie;
public bool DisablePopupWindow
{
get { return _diablePopupWindow; }
set { _diablePopupWindow = value; }
}
// 该方法由系统自动调用,从该函数的调用中截获到IWebBrowser2接口
[PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
protected override void AttachInterfaces(object nativeActiveXObject)
{
this.axIWebBrowser2 = (IWebBrowser2)nativeActiveXObject;
base.AttachInterfaces(nativeActiveXObject);
}
[PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
protected override void DetachInterfaces( )
{
this.axIWebBrowser2 = null;
base.DetachInterfaces( );
}
// 返回WebBrowser的自动化对象
public object ApplicationObject
{
get { return axIWebBrowser2.Application; }
}
// 此方法增加自定义的事件对象
[PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
protected override void CreateSink( )
{
// 一定在此调用基类的方法,否则WebBrowser自己实现的事件就不能触发了
base.CreateSink( );
events = new WebBrowserExtendedEvents(this);
cookie = new AxHost.ConnectionPointCookie(this.ActiveXInstance, events, typeof(IWebBrowserEvents2));
}
[PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
protected override void DetachSink( )
{
if (null != cookie) {
cookie.Disconnect( );
cookie = null;
}
}
}
STEP 6:主程序
主程序很简单,就是创建一个浏览器窗口。由于我是在现有的一个工程中写的主函数,基于控制台的,如果创建windows程序在主程序中使用Application.Run(new ExWebBrowserForm() )就可以了。
class Program
{
[STAThread]
static int Main(string[] args)
{
ExWebBrowserForm browser = new ExWebBrowserForm( );
browser.ShowDialog( );
}
}
其实,原理很简单,因为.NET Framework中实现WebBrowser时,很多IE的事件或方法都没有定义出来,需要时只能通过AttachInterfaces把相应的接口附上,通过这个方法,我们就可以有选择性地对我们关心的接口进行实现。
我们一旦获取了一个包含子窗口的WebBrowser控件,就可以在程序中通过该控件进行任何自动化的操作了。
但对于showModalDialog( )和showModelessDialog( )弹出是就没有NewWindow3事件了,下一篇中再讨论这两个窗口的弹出问题。