nuits.jp blog

C#, Xamarin, WPFを中心に書いています。Microsoft MVP for Development Technologies。

WPFのWebBrowserでWindow Openイベントをインターセプトする

WebBrowserコントロールを利用している際に、JavaScriptでopenメソッドを呼ばれるなどで新しいWindowを開かれるとポップアップでIEが開かれてしまい、制御がプログラムから外れてしまいます。
本エントリーでは新しいWindowが開かれる前にイベントをインターセプトする方法を記載します。

MSHTMLインターフェースのDWebBrowserEventsを利用することでハンドルします。
まずは「Microsoft Internet Controls」のCOMの参照を追加します。

f:id:nuitsjp:20160625192321p:plain

で、以下のようにWebBrowserのLoadCompleteイベントでDWebBrowserEventsのNewWindowイベントにイベントハンドラを追加します。

        private bool isInitialized = false;
        private void WebBrowser_LoadCompleted(object sender, NavigationEventArgs e)
        {
            if(!isInitialized)
            {
                IServiceProvider serviceProvider = (IServiceProvider)webBrowser.Document;
                Guid serviceGuid = new Guid("0002DF05-0000-0000-C000-000000000046");
                Guid iid = typeof(SHDocVw.IWebBrowser2).GUID;
                SHDocVw.DWebBrowserEvents_Event wbEvents = (SHDocVw.DWebBrowserEvents_Event)serviceProvider.QueryService(ref serviceGuid, ref iid);
                wbEvents.NewWindow += OnNewWindow;
                isInitialized = true;
            }
        }

        [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        [Guid("6d5140c1-7436-11ce-8034-00aa006009fa")]
        private interface IServiceProvider
        {
            [return: MarshalAs(UnmanagedType.IUnknown)]
            object QueryService(ref Guid guidService, ref Guid riid);
        }

上記のサンプルでは、OnNewWindowというメソッドをハンドラとして追加しています。
あとはイベントを受け取ったら好きなように処理すればOKです。

以下にイベントを受ける際のサンプルも一応載せておきます。

        private void OnNewWindow(string URL, int Flags, string TargetFrameName, ref object PostData, string Headers, ref bool Processed)
        {
            Processed = true;
            webBrowser.Navigate(URL);
        }

上の例では、Processedにtrueを設定することで、ブラウザのイベントをキャンセルし、ポップアップで開くよう指定されたURIに画面を遷移させています。
他にはタブブラウザ的にアプリ内で別のWebBrowserを開いてそちらで開くとかが、動作としてはありそうなパターンですね。

一応動くコードをGithubに上げておきます。

github.com

WebBrowserSampleソリューションのHandleNewWindowBrowserプロジェクトを参照してください。

という事で以上です。
それではまた!