How to Display a Popup from a Webbrowser in Another Window I Created

How do I display a popup from a WebBrowser in another window I created?

The web browser control supports the NewWindow event to get notified about a popup window. The Winforms wrapper however does not let you do much with it, you can only cancel the popup. The native COM wrapper permits passing back a new instance of the web browser, that instance will then be used to display the popup.

Taking advantage of this requires some work. For starters, use Project + Add Reference, Browse tab and select c:\windows\system32\shdocvw.dll. That adds a reference to the native COM interface.

Create a form that acts as the popup form. Drop a WebBrowser on it and make its code look similar to this:

public partial class Form2 : Form {
public Form2() {
InitializeComponent();
}
public WebBrowser Browser {
get { return webBrowser1; }
}
}

The Browser property gives access to the browser that will be used to display the web page in the popup window.

Now back to the main form. Drop a WebBrowser on it and make its code look like this:

public partial class Form1 : Form {
public Form1() {
InitializeComponent();
webBrowser1.Url = new Uri("http://google.com");
}
SHDocVw.WebBrowser nativeBrowser;
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
nativeBrowser = (SHDocVw.WebBrowser)webBrowser1.ActiveXInstance;
nativeBrowser.NewWindow2 += nativeBrowser_NewWindow2;
}
protected override void OnFormClosing(FormClosingEventArgs e) {
nativeBrowser.NewWindow2 -= nativeBrowser_NewWindow2;
base.OnFormClosing(e);
}

void nativeBrowser_NewWindow2(ref object ppDisp, ref bool Cancel) {
var popup = new Form2();
popup.Show(this);
ppDisp = popup.Browser.ActiveXInstance;
}
}

The OnLoad method obtains a reference to the native COM interface, then subscribes an event handler to the NewWindow2 event. I made sure to unsubscribe that event in the FormClosing event handler, not 100% sure if that's necessary. Better safe then sorry.

The NewWindow2 event handler is the crux, note that the first argument allows passing back an untyped reference. That should be the native browser in the popup window. So I create an instance of Form2 and Show() it. Note the argument to Show(), that ensures that the popup is an owned window. Substitute this as necessary for your app, I assume you'd want to create an MDI child window in your case.

Do beware that this event doesn't fire for the window displayed when Javascript uses alert(). The browser doesn't treat that window as an HTML popup and doesn't use a browser window to display it so you cannot intercept or replace it.

How do I display a popup from a WebBrowser in another window I created?

The web browser control supports the NewWindow event to get notified about a popup window. The Winforms wrapper however does not let you do much with it, you can only cancel the popup. The native COM wrapper permits passing back a new instance of the web browser, that instance will then be used to display the popup.

Taking advantage of this requires some work. For starters, use Project + Add Reference, Browse tab and select c:\windows\system32\shdocvw.dll. That adds a reference to the native COM interface.

Create a form that acts as the popup form. Drop a WebBrowser on it and make its code look similar to this:

public partial class Form2 : Form {
public Form2() {
InitializeComponent();
}
public WebBrowser Browser {
get { return webBrowser1; }
}
}

The Browser property gives access to the browser that will be used to display the web page in the popup window.

Now back to the main form. Drop a WebBrowser on it and make its code look like this:

public partial class Form1 : Form {
public Form1() {
InitializeComponent();
webBrowser1.Url = new Uri("http://google.com");
}
SHDocVw.WebBrowser nativeBrowser;
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
nativeBrowser = (SHDocVw.WebBrowser)webBrowser1.ActiveXInstance;
nativeBrowser.NewWindow2 += nativeBrowser_NewWindow2;
}
protected override void OnFormClosing(FormClosingEventArgs e) {
nativeBrowser.NewWindow2 -= nativeBrowser_NewWindow2;
base.OnFormClosing(e);
}

void nativeBrowser_NewWindow2(ref object ppDisp, ref bool Cancel) {
var popup = new Form2();
popup.Show(this);
ppDisp = popup.Browser.ActiveXInstance;
}
}

The OnLoad method obtains a reference to the native COM interface, then subscribes an event handler to the NewWindow2 event. I made sure to unsubscribe that event in the FormClosing event handler, not 100% sure if that's necessary. Better safe then sorry.

The NewWindow2 event handler is the crux, note that the first argument allows passing back an untyped reference. That should be the native browser in the popup window. So I create an instance of Form2 and Show() it. Note the argument to Show(), that ensures that the popup is an owned window. Substitute this as necessary for your app, I assume you'd want to create an MDI child window in your case.

Do beware that this event doesn't fire for the window displayed when Javascript uses alert(). The browser doesn't treat that window as an HTML popup and doesn't use a browser window to display it so you cannot intercept or replace it.

Web Browser to handle pop ups within the application

You're right that WindowClosing doesn't get fired for Winforms WebBrowser Control, I confirm that. It appears to be a long-time bug in .NET WebBrowser ActiveX hosting code, which has never been addressed. Check this post for more details and a possible workaround.

Another possible workaround may be to host WebBrowser ActiveX Control directly via AxHost class, in which case WindowClosing gets fire correctly. Example:

C#:

using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WebBrowserApp
{
// MainForm

public partial class MainForm : Form
{
WebBrowser webBrowser;

public MainForm()
{
InitializeComponent();
InitBrowser();

if (this.webBrowser.Document == null && this.webBrowser.ActiveXInstance == null)
throw new ApplicationException ("Unable to initialize WebBrowser ActiveX control.");

var ax = (SHDocVw.WebBrowser)this.webBrowser.ActiveXInstance;
ax.NewWindow2 += (ref object ppDisp, ref bool Cancel) =>
{
var popup = new RawBrowserPopup();
popup.Visible = true;
ppDisp = popup.WebBrowser.ActiveXInstance;
};

this.Load += (s, e) =>
{
this.webBrowser.DocumentText = "<a target=\"_blank\" href=\"javascript:'<button onclick=\\'window.close()\\'>Close</button>'\">Go</a>";
};
}

// create a WebBrowser instance
void InitBrowser()
{
this.webBrowser = new WebBrowser();
this.webBrowser.Dock = DockStyle.Fill;
this.Controls.Add(this.webBrowser);
this.webBrowser.Visible = true;
}
}

// RawWebBrowser

public class RawWebBrowser : AxHost
{
public RawWebBrowser()
: base("8856f961-340a-11d0-a96b-00c04fd705a2")
{
}

public event EventHandler Initialized;

protected override void AttachInterfaces()
{
if (this.Initialized != null)
this.Initialized(this, new EventArgs());
}

public object ActiveXInstance
{
get
{
return base.GetOcx();
}
}
}

// RawBrowserPopup

public class RawBrowserPopup : Form
{
RawWebBrowser webBrowser;

public RawWebBrowser WebBrowser
{
get { return this.webBrowser; }
}

public RawBrowserPopup()
{
this.webBrowser = new RawWebBrowser();

this.webBrowser.Initialized += (s, e) =>
{
var ax = (SHDocVw.WebBrowser)this.webBrowser.ActiveXInstance;
ax.NewWindow2 += (ref object ppDisp, ref bool Cancel) =>
{
var popup = new RawBrowserPopup();
popup.Visible = true;
ppDisp = popup.WebBrowser.ActiveXInstance;
};

ax.WindowClosing += (bool IsChildWindow, ref bool Cancel) =>
{
Cancel = true;
this.Close();
};
};

this.webBrowser.Dock = DockStyle.Fill;
this.Controls.Add(this.webBrowser);
this.webBrowser.Visible = true;
}
}
}

VB.NET:

Public Class Form1
Dim webBrowser As WebBrowser = New WebBrowser()

Sub New()
MyBase.New()
Me.InitializeComponent()
webBrowser.Dock = DockStyle.Fill
Me.Controls.Add(webBrowser)
webBrowser.Visible = True
End Sub

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.webBrowser.DocumentText = "<a target='_blank' href='javascript:""<button onclick=\""window.close()\"">Close</button>""'>Go</a>"

Dim ActiveX As SHDocVw.WebBrowser = Me.webBrowser.ActiveXInstance
AddHandler ActiveX.NewWindow2, AddressOf WebBrowser_ActiveX_NewWindow2
End Sub

Private Sub WebBrowser_ActiveX_NewWindow2(ByRef ppDisp As Object, ByRef Cancel As Boolean)
Dim popup As RawBrowserPopup = New RawBrowserPopup()
popup.Visible = True
ppDisp = popup.WebBrowser.ActiveXInstance
End Sub
End Class

Public Class RawWebBrowser
Inherits System.Windows.Forms.AxHost

Sub New()
MyBase.New("8856f961-340a-11d0-a96b-00c04fd705a2")
End Sub

Event Initialized(sender As Object, e As EventArgs)

Protected Overrides Sub AttachInterfaces()
RaiseEvent Initialized(Me, New EventArgs())
End Sub

Public ReadOnly Property ActiveXInstance() As Object
Get
Return MyBase.GetOcx()
End Get
End Property
End Class

Public Class RawBrowserPopup
Inherits System.Windows.Forms.Form

Dim WithEvents rawBrowser As RawWebBrowser = New RawWebBrowser()

Sub New()
MyBase.New()
rawBrowser.Dock = DockStyle.Fill
Me.Controls.Add(rawBrowser)
rawBrowser.Visible = True
End Sub

Public ReadOnly Property WebBrowser() As Object
Get
Return rawBrowser
End Get
End Property

Private Sub rawBrowser_Initialized(sender As Object, e As EventArgs) Handles rawBrowser.Initialized
Dim activeX As SHDocVw.WebBrowser = rawBrowser.ActiveXInstance
AddHandler activeX.NewWindow2, AddressOf activeX_NewWindow2
AddHandler activeX.WindowClosing, AddressOf activeX_WindowClosing
End Sub

Private Sub activeX_NewWindow2(ByRef ppDisp As Object, ByRef Cancel As Boolean)
Dim popup As RawBrowserPopup = New RawBrowserPopup()
popup.Visible = True
ppDisp = popup.WebBrowser.ActiveXInstance
End Sub

Private Sub activeX_WindowClosing(IsChildWindow As Boolean, ByRef Cancel As Boolean)
Cancel = True
Me.Close()
End Sub

End Class

Is it possible to force a WebBrowser to, instead of opening in a new window, replace the currently opened window?

there are a few ways you can do this, one way is to loop through the DOM (Document Object Model) and find the link which opens in a new window, and change its "target=" attribute value to "target=_top" this way it will open in current top-level page of your current WB Control container.

Otherwise, there is a NewWindow2 event which you can intercept, write the following code inside that event (where WB1 is you WebBrowser Controls name):

Processed = True
WB1.Navigate2 URL

This will tell your WB Control that the request has been processed (tricking it into believing that it has been processed), and if you just did this, nothing would happen, so after the first line you write the second line which tells it to open the URL that it just tried to open in the new window, in the current window (WB1), so really you are just reissuing the request but for the same container/WB Control where the link was clicked.

I've written the code in VB, however I'm sure it's not a problem to understand and transfer to c#.

Let me know how you get along and if there is anything else i can do to help.

C# - Getting control of popup window

Okay. I found an answer. COMException (0x80004005): Error HRESULT E_FAIL was occurred because I tried to access main thread object from COM thread. Below is what I did.

public partial class Form1 : Form
{
WebBrowser browser;
SHDocVw.WebBrowser_V1 browserV1AceCounter;

byte[] bPostData;
string sHeader;
string sURL;

public Form1()
{
InitializeComponent();

browser = new WebBrowser();

browser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(browserLoaded);
browser.NewWindow += new CancelEventHandler(WebBrowserNewWindow);
}

private void WebBrowserNewWindow(Object sender, CancelEventArgs e)
{
browserV1AceCounter = (SHDocVw.WebBrowser_V1)browser.ActiveXInstance;
browserV1AceCounter.NewWindow += Web_V1_NewWindow;
}

private void Web_V1_NewWindow(string URL, int Flags, string TargetFrameName, ref object PostData, string Headers, ref bool Processed)
{
try
{
Processed = true; //Stop event from being processed

// Copy necessary info to use in main thread
sURL = URL;
bPostData = (byte[])PostData;
sHeader = Headers;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}

private void browserLoaded(object sender, WebBrowserDocumentCompletedEventArgs e)
{
try
{
if (e.Url.ToString().Contains("loginURL.com"))
{
this.browser.Navigate(sURL, null, bPostData, sHeader);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}

You need to make sure the sequence is alright and fill in the rest part but, in case of you need to go through popup window with encrypted post data, above code snippet should work.

vb.net how to catch new window from dynamic webbrowser?

You need to add the line (after creating the control):

AddHandler brws.NewWindow, AddressOf WebBrowserNewWindow

for it to handle that event, see http://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser.newwindow(v=vs.110).aspx



Related Topics



Leave a reply



Submit