4

I am trying to use the WebBrowser control to launch a new form for popups instead of it opening in IE. I have tried to use the AxWebBrowser instead to get the popups which works with NewWindow3 event and just doing e.ppDisp = AxWebBrowser.Application, but there are many limitations that come with AxWebBrowser. So instead I am trying to Extend the normal WebBrowser to include the NewWindow3 event like the AxWebBrowser but running into problems. With e.ppDisp = AxWebBrowser.Application I am getting errors: "InvalidVariant was detected" followed by "Specified OLE variant is invalid" if I continue.

Note: This is my first time extending a class so I could be over looking something simple. If I try just navigating to the new URL in the new window, I get java script errors from the site.

I have updated the code base on comments. Have removed the ExtendedWebBrowser class for a munch smaller and nicer version. Here is the New Code:

From the main form and a very similar BrowserPopup form -

Protected Overrides Sub OnLoad(ByVal e As EventArgs)
    MyBase.OnLoad(e)
    nativeBrowser = DirectCast(ExtendedWebBrowser1.ActiveXInstance, SHDocVw.WebBrowser)
    AddHandler nativeBrowser.NewWindow3, AddressOf nativeBrowser_NewWindow3
    AddHandler nativeBrowser.WindowClosing, AddressOf nativeBrowser_WindowClosing
End Sub

Private Sub nativeBrowser_NewWindow3(ByRef ppDisp As Object, ByRef Cancel As Boolean, ByVal dwflags As UInteger, ByVal bStrUrlContext As String, ByVal bstrUrl As String)
    Dim popup = New BrowserPopup()
    popup.Show(Me)
    popup.browserPop.DocumentText = bStrUrlContext
    ppDisp = popup.browserPop.ActiveXInstance
End Sub

Private Sub nativeBrowser_WindowClosing(ByVal IsChildWindow As Boolean, ByRef Cancel As Boolean)
    MsgBox("working?") '<<<Doesn't Trigger>>>
End Sub

Protected Overrides Sub OnFormClosing(ByVal e As FormClosingEventArgs)
    MyBase.OnFormClosing(e)
End Sub

Also, if it helps, here is the scripting from the page that should be able to close the popup form but just seems to deactivate the WebBrowser instead.

<table isListBtn="false" cellpadding="0" enabled="true" class="buttonBorderBlue"
cellspacing="0" border="0" onClick="if (typeof(workpaneMediator_toolbar)!='undefined')
workpaneMediator_toolbar.onSelect('CANCEL_ACTION', this)"
actionType="CLOSE_WINDOW_TYPE" id="workpaneMediator_toolbar_CANCEL_ACTIONWrapper"
nowrap><tr><td class="buttonBlueTD">
Congree
  • 73
  • 1
  • 7
  • Answered [here](http://stackoverflow.com/a/6473442/1768303) for C#, should not be a problem to translate to VB. – noseratio Oct 28 '13 at 01:41
  • Thank you for the response! I was able to convert the code and implement it into my own. It now pops up with no errors and does run scripts correctly for the most part. But when clicking the java script buttons to submit/cancel the popup, the Web Browser does stop functioning (as it should) but the popup form doesn't go away. I am researching and seeing if I can find anything for it. – Congree Oct 28 '13 at 19:53
  • For JavaScript links, check [this one](http://stackoverflow.com/a/18822779/1768303). – noseratio Oct 28 '13 at 19:58
  • The link you provided for JavaScripts doesn't seem to do much for me. Just to be clear, I have removed the WebBrowserEx Class for now, picking up the item you first posted. This successfully opens the popup in the new form with no errors. However when trying to click on submit/close on the new form, the WebBrowser seems to deactivate like it's been told to close. But the Form itself is not closing automatically. I tried checking for various events from the WebBrowser but can't seem to find any events if any being called. – Congree Oct 29 '13 at 20:06
  • Handling closing of the form with `WebBrowser` from JavaScript is a different matter. Have you looked at [WindowClosing](http://msdn.microsoft.com/en-us/library/aa768352(v=vs.85).aspx) event of the underlying `WebBrowser` ActiveX control? – noseratio Oct 29 '13 at 20:48
  • 1
    `WindowClosing` doesn't seem to be catching either. Going to update the code in my original post to reflect recent changes. – Congree Oct 29 '13 at 21:52

1 Answers1

5

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
noseratio
  • 59,932
  • 34
  • 208
  • 486
  • The link provided for the workaround shows the ParentNotify event occuring on a WM_LBUTTONDOWN. The WM_DESTROY doesn't seem to be called. I think I may need to learn C# because all the solutions for my issue are available in C# and they never seem to work right when converting to VB.Net. I can confirm your solution works for C# without issue. But I can't seem to get the code converted into VB.Net correctly. Sites like http://www.developerfusion.com/ are converting it incorrectly. Specifically it doesn't like converting `ax.NewWindow2 += (ref object ppDisp, ref bool Cancel) =>...` – Congree Oct 30 '13 at 19:36
  • @Congree, I've posted a working VB.NET sample. This is as much as I can help with this question. – noseratio Oct 31 '13 at 02:08
  • 1
    Thank you so much for your all of your help! I have verified it is working correctly in VB.Net and is exactly what I needed. Thanks again! I'll be up voting as well as soon as I have enough rep and the site allows me. – Congree Nov 01 '13 at 06:27
  • Glad it helped. +1 for reporting the issue with `WindowClosing`. – noseratio Nov 01 '13 at 07:09