How to: Webbrowser NewWindow and Navigating equivalent to axWebbrowser
At first, I enjoyed the new webbrowser control but then I noticed that the args provided by the events NewWindow3 and BeforeNavigate of the axWebBrowser had not been implemented in the new control. Arg.
Good news, the guys from Microsoft gave us the a workaround recently in C# and said they will publish a sample soon on MSDN.
In the mean time, here is someVB.net code inspired from Microsoft's C# that will give you 2 new events and the args people like me were crying for.
NavigatingExtendedgives you the following args:
-Url as string
-Frame as string
-Headers as string
-Postdata as string
-PostdataByte() as byte
-Cancel as boolean (to cancel navigation)
NewWindowExtendedgives you the following args:
-Url as string
-UrlContext as string
-Flags as NWMF (see NewWindow3 on MSDN for definition)
-Cancel as boolean (to cancel navigation to new window)
Ok let's go.
1. Create a new Windows form project.
2. Add a new Module and Copy/Paste the following:
Imports System Imports System.Collections.Generic Imports System.Text Imports System.ComponentModel Imports System.Runtime.InteropServices Module Module1 PublicEnum NWMF NWMF_UNLOADING = &H1& NWMF_USERINITED = &H2& NWMF_FIRST_USERINITED = &H4& NWMF_OVERRIDEKEY = &H8& NWMF_SHOWHELP = &H10& NWMF_HTMLDIALOG = &H20& NWMF_FROMPROXY = &H40& EndEnum 'First define a new EventArgs class to contain the newly exposed data PublicClass WebBrowserNavigatingExtendedEventArgs Inherits CancelEventArgs Private m_UrlAsString Private m_FrameAsString Private m_Postdata()AsByte Private m_HeadersAsString PublicReadOnlyProperty Url()AsString Get Return m_Url EndGet EndProperty PublicReadOnlyProperty Frame()AsString Get Return m_Frame EndGet EndProperty PublicReadOnlyProperty Headers()AsString Get Return m_Headers EndGet EndProperty PublicReadOnlyProperty Postdata()AsString Get Return PostdataToString(m_Postdata) EndGet EndProperty PublicReadOnlyProperty PostdataByte()AsByte() Get Return m_Postdata EndGet EndProperty PublicSubNew(ByVal urlAsString,ByVal frameAsString,ByVal postdataAsByte(),ByVal headersAsString) m_Url = url m_Frame = frame m_Postdata = postdata m_Headers = headers EndSub PrivateFunction PostdataToString(ByVal p()AsByte)AsString 'not sexy but it works... Dim tabpd()AsByte, bstopAsBoolean =False, stmpAsString = "", iAsInteger = 0 tabpd = p If tabpdIsNothingOrElse tabpd.Length = 0Then Return "" Else For i = 0To tabpd.Length - 1 stmp += ChrW(tabpd(i)) Next stmp = Replace(stmp, ChrW(13), "") stmp = Replace(stmp, ChrW(10), "") stmp = Replace(stmp, ChrW(0), "") EndIf If stmp =NothingThen Return "" Else Return stmp EndIf EndFunction EndClass PublicClass WebBrowserNewWindowExtendedEventArgs Inherits CancelEventArgs Private m_UrlAsString Private m_UrlContextAsString Private m_FlagsAs NWMF PublicReadOnlyProperty Url()AsString Get Return m_Url EndGet EndProperty PublicReadOnlyProperty UrlContext()AsString Get Return m_UrlContext EndGet EndProperty PublicReadOnlyProperty Flags()As NWMF Get Return m_Flags EndGet EndProperty PublicSubNew(ByVal urlAsString,ByVal urlcontextAsString,ByVal flagsAs NWMF) m_Url = url m_UrlContext = urlcontext m_Flags = flags EndSub EndClass PublicClass ExtendedWebBrowser Inherits WebBrowser Private cookieAs AxHost.ConnectionPointCookie Private weventsAs WebBrowserExtendedEvents 'This method will be called to give you a chance to create your own event sink ProtectedOverridesSub CreateSink() 'MAKE SURE TO CALL THE BASE or the normal events won't fire MyBase.CreateSink() wevents =New WebBrowserExtendedEvents(Me) cookie =New AxHost.ConnectionPointCookie(Me.ActiveXInstance, wevents,GetType(DWebBrowserEvents2)) EndSub ProtectedOverridesSub DetachSink() IfNot cookieIsNothingThen cookie.Disconnect() cookie =Nothing EndIf MyBase.DetachSink() EndSub 'This new event will fire when the page is navigating PublicDelegateSub WebBrowserNavigatingExtendedEventHandler(ByVal senderAsObject,ByVal eAs WebBrowserNavigatingExtendedEventArgs) PublicEvent NavigatingExtendedAs WebBrowserNavigatingExtendedEventHandler 'This event will fire when a new window is about to be opened PublicDelegateSub WebBrowserNewWindowExtendedEventHandler(ByVal senderAsObject,ByVal eAs WebBrowserNewWindowExtendedEventArgs) PublicEvent NewWindowExtendedAs WebBrowserNewWindowExtendedEventHandler ProtectedFriendSub OnNavigatingExtended(ByVal UrlAsString,ByVal FrameAsString,ByVal PostdataAsByte(),ByVal HeadersAsString,ByRef CancelAsBoolean) Dim eAs WebBrowserNavigatingExtendedEventArgs =New WebBrowserNavigatingExtendedEventArgs(Url, Frame, Postdata, Headers) RaiseEvent NavigatingExtended(Me, e) Cancel = e.Cancel EndSub ProtectedFriendSub OnNewWindowExtended(ByVal UrlAsString,ByRef CancelAsBoolean,ByVal FlagsAs NWMF,ByVal UrlContextAsString) Dim eAs WebBrowserNewWindowExtendedEventArgs =New WebBrowserNewWindowExtendedEventArgs(Url, UrlContext, Flags) RaiseEvent NewWindowExtended(Me, e) Cancel = e.Cancel EndSub EndClass 'This class will capture events from the WebBrowser Class WebBrowserExtendedEvents Inherits System.Runtime.InteropServices.StandardOleMarshalObject Implements DWebBrowserEvents2 Private m_BrowserAs ExtendedWebBrowser PublicSubNew(ByVal browserAs ExtendedWebBrowser) m_Browser = browser EndSub 'Implement whichever events you wish PublicSub BeforeNavigate2(ByVal pDispAsObject,ByRef URLAsString,ByRef flagsAsObject,ByRef targetFrameNameAsString,ByRef postDataAsObject,ByRef headersAsString,ByRef cancelAsBoolean)Implements DWebBrowserEvents2.BeforeNavigate2 m_Browser.OnNavigatingExtended(URL, targetFrameName, CType(postData,Byte()), headers, cancel)EndSub PublicSub NewWindow3(ByVal pDispAsObject,ByRef CancelAsBoolean,ByRef FlagsAsObject,ByRef UrlContextAsString,ByRef UrlAsString)Implements DWebBrowserEvents2.NewWindow3 m_Browser.OnNewWindowExtended(Url, Cancel, CType(Flags, NWMF), UrlContext)EndSub EndClass <ComImport(), _ Guid("34A715A0-6587-11D0-924A-0020AFC7AC4D"), _ InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch), _ TypeLibType(TypeLibTypeFlags.FHidden)> _ PublicInterface DWebBrowserEvents2 <DispId(250)> _ <InAttribute(), MarshalAs(UnmanagedType.BStr)>ByRef URLAsString, _ <InAttribute()>ByRef flagsAsObject, _ <InAttribute(), MarshalAs(UnmanagedType.BStr)>ByRef targetFrameNameAsString, _ <InAttribute()>ByRef postdataAsObject, _ <InAttribute(), MarshalAs(UnmanagedType.BStr)>ByRef headersAsString, _ <InAttribute(), OutAttribute()>ByRef cancelAsBoolean) 'Note: Postdata is a SafeArray but for some reason, if I do a proper declaration, the event will not be raised: '<[In](), MarshalAs(UnmanagedType.SafeArray, safearraysubtype:=VarEnum.VT_UI1)> ByRef postdata() As Byte, _ <DispId(273)> _ Sub NewWindow3(<InAttribute(), MarshalAs(UnmanagedType.IDispatch)>ByVal pDispAsObject, _ <InAttribute(), OutAttribute()>ByRef cancelAsBoolean, _ <InAttribute()>ByRef FlagsAsObject, _ <InAttribute(), MarshalAs(UnmanagedType.BStr)>ByRef UrlContextAsString, _ <InAttribute(), MarshalAs(UnmanagedType.BStr)>ByRef UrlAsString) EndInterface End Module |
3. Now, Open your form1 in Code view
4. Copy/Paste the following to test your control
PublicClass Form1 'Source from wilfridB Private wbAsNew ExtendedWebBrowser PrivateSub Form1_Load(ByVal senderAsObject,ByVal eAs System.EventArgs)HandlesMe.Load AddHandler wb.NavigatingExtended,AddressOf wb_NavigatingExtended AddHandler wb.DocumentCompleted,AddressOf wb_DocumentCompleted AddHandler wb.NewWindowExtended,AddressOf wb_NewWindowExtended Me.Controls.Add(wb) wb.Dock = DockStyle.Fill wb.Navigate(New Uri("http://www.microsoft.com")) EndSub PrivateSub wb_NavigatingExtended(ByVal senderAsObject,ByVal eAs module1.WebBrowserNavigatingExtendedEventArgs) 'This is a new event Dim postdataAsString = e.Postdata Dim msgAsString = "Navigating to : " & e.Url & ControlChars.CrLf msg &= "Postdata : " & postdata & ControlChars.CrLf msg &= "Headers : " & e.Headers & ControlChars.CrLf msg &= "Frame : " & e.Frame & ControlChars.CrLf msg &= "Continue ?" Dim resAs DialogResult = MessageBox.Show(msg, "NavigatingExtended", MessageBoxButtons.YesNo, MessageBoxIcon.Question) If res = Windows.Forms.DialogResult.NoThen e.Cancel =True EndSub PrivateSub wb_DocumentCompleted(ByVal senderAsObject,ByVal eAs System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) 'This is a standard event MessageBox.Show("Document complete: " & e.Url.ToString, "DocumentCompleted", MessageBoxButtons.OK, MessageBoxIcon.Information) EndSub PrivateSub wb_NewWindowExtended(ByVal senderAsObject,ByVal eAs Module1.WebBrowserNewWindowExtendedEventArgs) 'This is a new event Dim msgAsString = "Navigation vers : " & e.Url & ControlChars.CrLf msg &= "UrlContext : " & e.UrlContext & ControlChars.CrLf msg &= "Flags : " & e.Flags.ToString & ControlChars.CrLf msg &= "Continue ?" Dim resAs DialogResult = MessageBox.Show(msg, "NewWindowExtended", MessageBoxButtons.YesNo, MessageBoxIcon.Question) If res = Windows.Forms.DialogResult.NoThen e.Cancel =True EndSub End Class |
That's it and it should work...
Any comment or additional event implementation is welcome...
And if somebody could give me the solution for properly retrieving the postdata using something like:
<[In](), MarshalAs(UnmanagedType.SafeArray, safearraysubtype:=VarEnum.VT_UI1)> ByRef postdata() As Byte, _
And converting an array of byte in a more decent way, that would be great.
wilfridB

