ActiveX の WebBrowser をラップしている System.Windows.Forms.WebBrowser コントロール。非常に便利なのだが、target="_blank" や JavaScript で新しいウィンドウを開く動作をされると、IE が開いてしまう。
個人的には新しいウィンドウを開くかどうかはユーザーに委ねるべきで、target="_blank" などはなくなればいいと思っているのだが、利用しているサイトがあるのだから致し方ない。
まぁ、IE が新しく開いても問題ない場合も多いのだろうが、クッキーが維持されないし、開いた先のウィンドウをコントロールするのが面倒なので、どうせならアプリ内で完結したい。
さて、対策はと言うと、概ね下記のようなものである。
というわけである。
Web で情報をかき集めるものの、断片的でなぜか VB.NET のコードが多い。 やっとこさ、あちこちから集めたソースで動くようになったので、記録しておく。 なお、各要素のこまかい説明に関しては参考サイトを参照されたい。
WebBrowser クラスを継承したクラス。名前は適当に変えましょう。
public class WebBrowserEx : WebBrowser
#region NewWindow2 イベント関連
private AxHost.ConnectionPointCookie cookie;
private WebBrowser2EventHelper helper;
[DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)]
[DispIdAttribute(200)]
public object Application
{
get
{
if (this.ActiveXInstance == null)
{
throw new AxHost.InvalidActiveXStateException("Application", AxHost.ActiveXInvokeKind.PropertyGet);
}
return (this.ActiveXInstance as IWebBrowser2).Application;
}
}
[DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)]
[DispIdAttribute(552)]
public bool RegisterAsBrowser
{
get
{
if (this.ActiveXInstance == null)
{
throw new AxHost.InvalidActiveXStateException("RegisterAsBrowser", AxHost.ActiveXInvokeKind.PropertyGet);
}
return (this.ActiveXInstance as IWebBrowser2).RegisterAsBrowser;
}
set
{
if (this.ActiveXInstance == null)
{
throw new AxHost.InvalidActiveXStateException("RegisterAsBrowser", AxHost.ActiveXInvokeKind.PropertyGet);
}
(this.ActiveXInstance as IWebBrowser2).RegisterAsBrowser = value;
}
}
[PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")]
protected override void CreateSink()
{
base.CreateSink();
helper = new WebBrowser2EventHelper(this);
cookie = new AxHost.ConnectionPointCookie(this.ActiveXInstance, helper, typeof(DWebBrowserEvents2));
}
[PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")]
protected override void DetachSink()
{
if (cookie != null)
{
cookie.Disconnect();
cookie = null;
}
base.DetachSink();
}
public event WebBrowserNewWindow2EventHandler NewWindow2 = (o, e) => { };
protected virtual void OnNewWindow2(WebBrowserNewWindow2EventArgs e)
{
NewWindow2(this, e);
}
private class WebBrowser2EventHelper : StandardOleMarshalObject, DWebBrowserEvents2
{
private WebBrowserEx parent;
public WebBrowser2EventHelper(WebBrowserEx parent)
{
this.parent = parent;
}
public void NewWindow2(ref object ppDisp, ref bool cancel)
{
var e = new WebBrowserNewWindow2EventArgs(ppDisp);
this.parent.OnNewWindow2(e);
ppDisp = e.ppDisp;
cancel = e.Cancel;
}
}
#endregion
}
public delegate void WebBrowserNewWindow2EventHandler(object sender, WebBrowserNewWindow2EventArgs e);
public class WebBrowserNewWindow2EventArgs : CancelEventArgs
{
public object ppDisp { get; set; }
public WebBrowserNewWindow2EventArgs(object ppDisp)
{
this.ppDisp = ppDisp;
}
}
[ComImport, Guid("34A715A0-6587-11D0-924A-0020AFC7AC4D")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[TypeLibType(TypeLibTypeFlags.FHidden)]
public interface DWebBrowserEvents2
{
[DispId(251)]
void NewWindow2(
[InAttribute(), OutAttribute(), MarshalAs(UnmanagedType.IDispatch)] ref object ppDisp,
[InAttribute(), OutAttribute()] ref bool cancel);
}
[ComImport, Guid("D30C1661-CDAF-11D0-8A3E-00C04FC9E26E")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IWebBrowser2
{
object Application { get; }
bool RegisterAsBrowser { get; set; }
}
Form の Load イベントなどで下記のようにイベントハンドラを関連づけておく。
webBrowser.NewWindow2 += new WebBrowserNewWindow2EventHandler(webBrowser_NewWindow2);
イベントハンドラの中身は下記のようなもの。newBrowser が新しい WebBrowser コントロールなので、表示したい親フォームの Controls に Add してやればよい。
// 新しくウィンドウを開かれようとするときに発生する
void webBrowser_NewWindow2(object sender, WebBrowserNewWindow2EventArgs e)
{
// 新しい WebBrowser の初期化
var newBrowser = new WebBrowserEx();
newBrowser.Dock = DockStyle.Fill;
// 新しい WebBrowser のコンテナ(下記はタブの場合)
//var tabPage = new TabPage();
//tabPage.Controls.Add(newBrowser);
//tabControl1.TabPages.Add(tabPage);
// 新しい WebBrowser に表示させる設定
e.ppDisp = newBrowser.AxApplication;
newBrowser.RegisterAsBrowser = true;
// 新しい WebBrowser からさらにウィンドウを開かれるときも同じようにする
newBrowser.NewWindow2 += webBrowser_NewWindow2;
}
Kenz Yamada(山田研二)。1984年生。大阪。ちょっとずつ好きなプログラム作ってます。
好きなものはカメラと旅行。ガジェットや身の回り、ちょっとこだわります。
詳しくは Web mixi で。