16963


### 概要

・C#においてWebBrowserで特定のサイトにアクセスした際にボタンをクリックすると、IEが立ち上がってしまいました。そのため、新規ウィンドウを開こうとするときにNewWindow2イベントを拾ってWebBrowser内で立ち上げるためにWebBrowserを拡張してNewWindow2イベントを扱えるようにしようとしています。  
・主にこのWebページ（[新規ウィンドウを自前のForm（WebBrowser）で開きたい](http://dobon.net/vb/bbs/log3-45/26969.html)）を参考に下記のようなコードを足しました。

[code]

    public class ExtendedWebBrowser : WebBrowser
    {
        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.GetType().InvokeMember("Application", System.Reflection.BindingFlags.GetProperty, null, this.ActiveXInstance, null);
    
    
            }
        }
    
        [DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)]
        [DispIdAttribute(552)]
        public bool RegisterAsBrowser
        {
            get
            {
                if (this.ActiveXInstance == null)
                {
                    throw new AxHost.InvalidActiveXStateException("RegisterAsBrowser", AxHost.ActiveXInvokeKind.PropertyGet);
                }
                return (bool)this.ActiveXInstance.GetType().InvokeMember("RegisterAsBrowser", System.Reflection.BindingFlags.GetProperty, null, this.ActiveXInstance, null);
    
    
            }
            set
            {
                if (this.ActiveXInstance == null)
                {
                    throw new AxHost.InvalidActiveXStateException("RegisterAsBrowser", AxHost.ActiveXInvokeKind.PropertySet);
                }
                this.ActiveXInstance.GetType().InvokeMember("RegisterAsBrowser", System.Reflection.BindingFlags.SetProperty, null, this.ActiveXInstance, new object[] { 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 ExtendedWebBrowser parent;
    
            public WebBrowser2EventHelper(ExtendedWebBrowser 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;
            }
        }
    }
    
    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);
    }
    
[/code]

・これを使用するクラスは下記のWebBrowserを管理するクラス（抜粋）です。

[code]

    private void WebBrowser_NewWindow2(object sender, WebBrowserNewWindow2EventArgs e)
    {
            // 新しい WebBrowser の初期化
            WebBrowser = new ExtendedWebBrowser();
            WebBrowser.Dock = DockStyle.Fill;
    
    
            WebBrowser.NewWindow2 += WebBrowser_NewWindow2;
            // this.TabPage1 = new TabPage();
            // this.TabPage1.Controls.Add(WebBrowser);
            // this.TabControl.Controls.Add(TabPage1);
            // this.TabControl.SelectedTab = TabPage1;
    
            // 新しい WebBrowser に表示させる設定
            e.ppDisp = this.WebBrowser.Application;
            this.WebBrowser.RegisterAsBrowser = true;
        }
    
    public async Task WaitNextPage()
    {
     await this.WaitDocumentLoad();
     this.SwitchToRootFrame();
     WebBrowser.NewWindow2 += new WebBrowserNewWindow2EventHandler(WebBrowser_NewWindow2);
     this.SavePage();
    }
    
[/code]

・実行時にExtendedWebBrowserクラスの

[code]

    return this.ActiveXInstance.GetType().InvokeMember("Application", System.Reflection.BindingFlags.GetProperty, null, this.ActiveXInstance, null);
    
[/code]

で 'System.Windows.Forms.AxHost.InvalidActiveXStateException' の例外が発生してしまいます。

### 動作環境

・.NET Frame Work 4.5  
・Visual Studio2013

### 補足

・サイト遷移の様子はアプリ利用者に表示しないため、WebBrowserコントロールはFormに紐づけていません。

よろしくお願いします。


CC BY-SA 3.0
2015-09-26T11:59:23.400
16958
2015-09-27T22:49:18.693
12459
question
c# visual-studio
WebBrowserを拡張してWebBrowser2イベントを拾う際にInvalidActiveXStateExceptionが出てしまいます。


質問文にある`WebBrowser_NewWindow2`に

[code]

    Controls.Add(WebBrowser);
    
[/code]

などを追加すると例外は発生しないので、「補足」にある`WebBrowser`をフォームに配置せずに利用することが仕様上想定されていないのだと思います。

表示されない箇所に`WebBrowser`を配置するのが一番簡単だと思いますが、[WebBrowserBaseのソース](http://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/WebBrowserBase.cs)を調べて無理やり動かす手もあります。


CC BY-SA 3.0
2015-09-26T14:16:24.710
16963
2015-09-26T14:16:24.710
5750
16958
answer


> 実行時にExtendedWebBrowserクラスの  
>  return this.ActiveXInstance.GetType().InvokeMember("Application",
> System.Reflection.BindingFlags.GetProperty, null, this.ActiveXInstance,
> null);  
>  で 'System.Windows.Forms.AxHost.InvalidActiveXStateException' の例外が発生してしまいます。

と書かれていますが、`Type.InvokeMember()`で実行されるのはこの場合、COMの`IWebBrowser2.Application`です。つまりCOMコードですので.NET例外`InvalidActiveXStateException`が投げられることはないはずです。実際に例外が発生しているのは１つ上の行

[code]

    if (this.ActiveXInstance == null)
    {
        throw new AxHost.InvalidActiveXStateException("Application", AxHost.ActiveXInvokeKind.PropertyGet);
    }
    
[/code]

ではありませんか？ つまり`this.ActiveXInstance`が`null`なのでは？  
その原因についてはpgrhoさんも指摘されていますがフォームにロードされていないこと（ソースコードを見た感じではハンドルが作成されていないことかな？）でしょうか。

蛇足ですが、`DWebBrowserEvents2`インターフェイスに属性を付ける必要がありますが、`ExtendedWebBrowser`クラスにあまり意味のない属性が付けられています。

* * *

ところで`IWebBrowser2`は`IDispatch`のはずなのに呼び出せない場合があるので、私は`IUnknown`で呼び出すようにしています。何が原因なんだろう…？

* * *

> 新しいウィンドウで開く予定だったURL等取得できるようになりました！

`DWebBrowserEvents2.NewWindow2`の処理の仕方でなく、真の目的は開く予定のURLの取得方法だったということでしょうか？  
であれば、Windows XP SP2（IE6
SP2）以降に[DWebBrowserEvents2.NewWindow3イベント](https://msdn.microsoft.com/en-
us/library/aa768337\(v=vs.85\).aspx)が追加されています。こちらであれば`bstrUrl`でURLを得ることができます。

[code]

    [ComImport, Guid("34A715A0-6587-11D0-924A-0020AFC7AC4D"), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    public interface DWebBrowserEvents2 {
        [DispId(273)]
        void NewWindow3([MarshalAs(UnmanagedType.IDispatch)] ref object ppDisp, ref bool Cancel, int dwFlags, string bstrUrlContext, string bstrUrl);
    }
    
[/code]


CC BY-SA 3.0
2015-09-26T14:28:25.017
16965
2015-09-27T22:49:18.693
2015-09-27T22:49:18.693
4236
4236
16958
answer


上記の質問をしたものです。ゲスト投稿したものの、回答にコメントできずこちらに失礼します。

＞ sayuriさん

> this.ActiveXInstanceがnullなのでは？

この部分ご指摘の通りでした。ありがとうございます。

フォームにロードされていないというのは、やはりWebBrowserを表示しないしても何かしらひも付けて扱うべきというところでしょうか？

＞pgrhoさん  
ありがとうございます！  
`Controls.Add(WebBrowser);`を足すことでエラーも出なくなり、新しいウィンドウで開く予定だったURL等取得できるようになりました！


CC BY-SA 3.0
2015-09-27T08:47:19.490
16993
2015-09-27T08:47:19.490
12459
16958
answer