Click here to Skip to main content
15,885,546 members
Articles / Programming Languages / C#

How to easily capture the NewWindow3 event and detect a JavaScript window.close() call with System.Windows.Forms.WebBrowser

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
8 Apr 2010CPOL3 min read 71K   13   4
This article describes a simple method of capturing a NewWindow event for the Windows Forms WebBrowser control, and also how to detect (and potentially cancel) a JavaScript window.close() call.

Introduction

The purpose of this article is to explain a simple way of capturing a NewWindow event for the Windows Forms WebBrowser control, and a (slightly) less simple way of detecting and acting upon a JavaScript window.close() call. A solution to both of these problems is particularly useful when developing a Windows Forms app with tabbed browsing.

Background

I ran across the above problems while creating a tabbed browsing interface within a desktop application that was going to be used to view two web applications used within my company. The purpose of this app was mainly to allow a modified copy and paste between two web pages. This would have been simple enough if not for the frequent opening of new windows and JavaScript window.close() calls!

There are numerous articles around (mainly to do with the NewWindow event), but they all seem to take an overly complicated approach, extending the WebBrowser control and implementing interfaces, which is really not needed. I realised there was a simpler way, that's why I am writing this article.

NewWindow Event

Problem

After creating the tabbed browsing interface, I found that when a new window was being opened from the page, a completely new window would be opened. The main issue with this was the fact that the site being browsed required a username and password login, which meant that when an instance of IE was being opened up, the user had to log in again as IE was executing from a different thread (which messes up cookies relating to the username/passwordd I assume).

Easy I thought, simply use the WebBrowser's NewWindow event, capture the URL, and pop open a new tab, directing it to the URL. However, this is where problem number one reared its ugly head...the WebBrowser's NewWindow event provides us with CancelEventArgs which allows us to stop the new window from opening by setting e.Cancel to true, but it doesn't provide us with any more useful info such as the URL etc.

Solution

The main solution that people seemed to be using after a bit of browsing the web was like the solution offered here on CodeProject which consists of extending the WebBrowser control to implement IWebBrowser2 and DWebBrowserEvents2. However, although this does work, there is a much simpler way to get access to a wider range of events.

Firstly, you need to add a COM reference to your project 'Microsoft Internet Controls':

Image 1

You then need to add using SHDocVw; to your code file. This namespace gives you access to SHDocVw.WebBrowser, which is the class we need. Now comes the easy bit.

The System.Windows.Forms.WebBrowser control has a property called ActiveXInstance of type object. All you have to do is cast the ActiveXInstance property to SHDocVw.WebBrowser and you have access to the full range of events that the ActiveX browser offers, including NewWindow3 which offers many more event arguments including the URL. Look at the code below to see an example of assigning an event handler to the NewWindow3 event:

C#
System.Windows.Forms.WebBrowser webBrowser = new System.Windows.Forms.WebBrowser();
SHDocVw.WebBrowser axBrowser = (SHDocVw.WebBrowser)webBrowser.ActiveXInstance;

axBrowser.NewWindow3 += new DWebBrowserEvents2_NewWindow3EventHandler(Browser_NewWindow3);

window.close() from JavaScript

Problem

After discovering the solution to the new window problem, I quickly came upon a second problem. When a window was being closed via JavaScript, the WebBrowser control was hanging. Easy this time, I thought. I have access to loads of events now through the ActiveX browser, all I need to do is find some sort of window closing/closed event and do whatever I need in there.

However, even though there is a WindowClosing event, it is not fired when window.close() is called from JavaScript. I have no idea why, and neither does anyone else I found who has discussed this problem online. Despite this, all is not lost!

Solution

I found this guy's blog where he describes a way overcoming the problem by overriding WndProc, intercepting the destroy message, and then acting upon it however we wish. The code to achieve this can bee seen below (majority of it nicked off the aforementioned site).

C#
protected override void WndProc(ref Message m)
{
    switch (m.Msg)
    {
        case WM_PARENTNOTIFY:
            if (!DesignMode)
            {
                if (m.WParam.ToInt32() == WM_DESTROY)
                {
                    Message newMsg = new Message();
                    newMsg.Msg = WM_DESTROY;

                    // Check for a parent tab
                    TabPage parentTab = this.Parent as TabPage;

                    // If parent tab found then remove it
                    if (parentTab != null)
                    {
                        TabControl browserTabs = parentTab.Parent as TabControl;

                        if (browserTabs != null)
                        {
                            browserTabs.TabPages.Remove(parentTab);
                        }
                    }
                }
            }
            DefWndProc(ref m);
            break;
        default:
            base.WndProc(ref m);
            break;
    }
}

Below is the full code for a class that extends the functionality of System.Windows.Forms.WebBrowser by implementing the two solutions above:

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace GoldMedal.TravelinkViewer.UI.User_Controls
{
    /// Extends the functionality of System.Windows.Forms.WebBrowser
    public class ExtendedWebBrowser : WebBrowser
    {
        #region Private Fields

        private const int WM_PARENTNOTIFY = 0x210;
        private const int WM_DESTROY = 2;

        #endregion

        /// Gets the underlying ActiveXBrowser instance and casts it as SHDocVw.WebBrowser
        /// type to give access to greater functionality
        public SHDocVw.WebBrowser ActiveXBrowser
        {
            get
            {
                return (SHDocVw.WebBrowser)ActiveXInstance;
            }
        }

        /// Overrides WndProc to close parent tab
        /// or form if WM_DESTORY message recieved from 
        /// javascript window.close method call.
        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case WM_PARENTNOTIFY:
                    if (!DesignMode)
                    {
                        if (m.WParam.ToInt32() == WM_DESTROY)
                        {
                            Message newMsg = new Message();
                            newMsg.Msg = WM_DESTROY;

                            // Check for a parent tab
                            TabPage parentTab = this.Parent as TabPage;

                            // If parent tab found then remove it
                            if (parentTab != null)
                            {
                                TabControl browserTabs = parentTab.Parent as TabControl;

                                if (browserTabs != null)
                                {
                                    browserTabs.TabPages.Remove(parentTab);
                                }
                            }
                        }
                    }
                    DefWndProc(ref m);
                    break;
                default:
                    base.WndProc(ref m);
                    break;
            }
        }
    }
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Gold Medal Travel
United Kingdom United Kingdom
"What is best in life: Crush your enemies, see them driven before you, and to hear the lamentation of the women!"

Comments and Discussions

 
QuestionGreat idea but... Pin
grady.imel11-Jan-13 7:54
grady.imel11-Jan-13 7:54 
GeneralMy vote of 5 Pin
J. Merrill19-Sep-12 12:08
J. Merrill19-Sep-12 12:08 
GeneralNewWindow3 event never fire Pin
killix16-Apr-11 15:59
killix16-Apr-11 15:59 
AnswerRe: NewWindow3 event never fire Pin
urinspiration28-Mar-13 4:31
urinspiration28-Mar-13 4:31 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.