.NET MSIE OnBeforeNavigate2 fixDownload source code - 54 KbThe remainder of this article provides a fix in order to receive otherwise hidden events such like the famous OnBeforeNavigate2 from MS Internet Explorer.
1. Reusing the codeNamely, if you wish to use the Internet Explorer control in a .NET app, what you usually do is go in the Toolbox Window, Customize, search for the Microsoft Web Browser Control (shdocvw.dll), drop it on a form, and start exploring the object model. That's simple, but this does not work as expected. You never get notified of several subscribed events. If you are not interesting in the programming details, just reuse the source code. Don't be afraid of the size (54kb), that's somewhat big just because there are two interop assemblies, but the real addition is just 10 lines of code. The project was obtained by doing the following :
2. ExplanationsThere is a problem when you program MSIE in a .NET environment. For odd reasons, most likely to be a .NET 1.0 limitation, marshaling cannot handle complex variant(variant) types, which are at the core of most events triggered by the Unfortunately, the famous OnBeforeNavigate2 event is triggered through this interface. This event is often used by programmers to be notified any time the user clicked on a link or submitted a form, providing them with very valuable information including url, posted data, headers, and even the ability to cancel the navigation depending on the application logic. Now we know we can't have this event. But, because we are lucky guys, by watching carefully the core IDL Internet Explorer interfaces (by using MSDEV OLEView on Here is a extract of these IDL interfaces : [ uuid(8856F961-340A-11D0-A96B-00C04FD705A2), helpstring("WebBrowser Control"), control ] coclass WebBrowser { [default] interface IWebBrowser2; // default COM interface interface IWebBrowser; [default, source] dispinterface DWebBrowserEvents2; // default event source [source] dispinterface DWebBrowserEvents; }; [ uuid(34A715A0-6587-11D0-924A-0020AFC7AC4D), helpstring("Web Browser Control events interface"), hidden ] dispinterface DWebBrowserEvents2 { properties: methods: // please note the VARIANT* bullshit everywhere // (the VARIANT* is the heart of the issue we have) [id(0x000000fa)] void BeforeNavigate2( [in] IDispatch* pDisp, [in] VARIANT* URL, [in] VARIANT* Flags, [in] VARIANT* TargetFrameName, [in] VARIANT* PostData, [in] VARIANT* Headers, [in, out] VARIANT_BOOL* Cancel); ... } [ uuid(EAB22AC2-30C1-11CF-A7EB-0000C05BAE0B), helpstring("Web Browser Control Events (old)"), hidden ] dispinterface DWebBrowserEvents { properties: methods: [id(0x00000064)] void BeforeNavigate( [in] BSTR URL, long Flags, BSTR TargetFrameName, VARIANT* PostData, BSTR Headers, [in, out] VARIANT_BOOL* Cancel); ... } The important thing to note is that the IDL defines To go on, we are actually going to ask the interop marshaler to produce at run-time a wrapper for the /// <summary> /// Summary description for Form1. /// </summary> public class Form1 : System.Windows.Forms.Form { private AxSHDocVw.AxWebBrowser axWebBrowser1; private SHDocVw.WebBrowserClass ie_events; private System.Windows.Forms.TextBox textBox1; public Form1() { // // Required for Windows Form Designer support // InitializeComponent(); // -- begin code snippet -- ie_events = (SHDocVw.WebBrowserClass) Marshal.CreateWrapperOfType( axWebBrowser1.GetOcx(), typeof(SHDocVw.WebBrowserClass) ); // -- end code snippet -- ... } The The resulting RCW is stored in a member of our Form. Now we have the right interface to play with. By virtue of the IDL COM declaration, if we use intellisense on We are done, let's show how we use this event to get the actual notification. In .NET, we just create a delegate, and attach an event handler to it : public Form1() { // // Required for Windows Form Designer support // InitializeComponent(); // -- begin code snippet -- ie_events = (SHDocVw.WebBrowserClass) Marshal.CreateWrapperOfType( axWebBrowser1.GetOcx(), typeof(SHDocVw.WebBrowserClass) ); SHDocVw.DWebBrowserEvents_BeforeNavigateEventHandler BeforeNavigateE = new SHDocVw.DWebBrowserEvents_BeforeNavigateEventHandler( OnBeforeNavigate ); ie_events.BeforeNavigate += BeforeNavigateE; // -- end code snippet -- ... } public void OnBeforeNavigate(string url, int flags, string targetFrame, ref object postData, string headers, ref bool Cancel) { int c = 0; // PUT A BREAKPOINT HERE }
3. A demo appJust to see something happen on screen, we immediately ask the web browser to show CodeProject (face of relief...) : textBox1.Text = "http://www.codeproject.com"; OnNewUrl(null,null); // KeyUp handler (used to trap VK_RETURN from the text box) private void OnNewUrl(object sender, System.Windows.Forms.KeyEventArgs e) { object o = null; if (e==null || e.KeyCode==Keys.Enter) axWebBrowser1.Navigate(textBox1.Text, ref o, ref o, ref o, ref o); }
Eh voilà. Stephane Rodriguez - Oct 28 2002. |
Home Blog |