none
DWebBrowserEvents2_BeforeNavigate2EventHandler NOT working.

    Question

  • I've seen lots of similar posts but no definitive answers on how to get this to work. Please help.

    I'm having trouble getting my DWebBrowserEvents2_BeforeNavigate2EventHandler code to fire in the following environments:

    • Windows XP or Vista or 7
    • IE 7 or 8 or 9
    • Development Environment: VS2010, .NET 4.0, Win SDK 7.1, C#

    Also: No trouble with DWebBrowserEvents2_DocumentCompleteEventHandler, this handler gets called as expected.

    Code sample attached:

    using System;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    using mshtml;
    using SHDocVw;
    
    namespace TestAddOn
    {
    	[ComVisible(true),
    	Guid("5EDB942A-D8AB-4543-95D6-4E727F352AAE"),
    	ClassInterface(ClassInterfaceType.None)]
    	public class TestBHO : IObjectWithSite
    	{
    		private object _pUnkSite;
    		private IWebBrowser2 _webBrowser2;
    		private DWebBrowserEvents2_Event _webBrowser2Events;
    		
    		public int SetSite(object pUnkSite)
    		{
    			if (pUnkSite != null)
    			{
    				_pUnkSite = pUnkSite;
    				_webBrowser2 = (IWebBrowser2)pUnkSite;
    				_webBrowser2Events = (DWebBrowserEvents2_Event)pUnkSite;
    				_webBrowser2Events.DocumentComplete += _webBrowser2Events_DocumentComplete;
    				_webBrowser2Events.BeforeNavigate2 += _webBrowser2Events_BeforeNavigate2;
    			}
    			else
    			{
    				_webBrowser2Events.DocumentComplete -= _webBrowser2Events_DocumentComplete;
    				_webBrowser2Events.BeforeNavigate2 -= _webBrowser2Events_BeforeNavigate2;
    				_pUnkSite = null;
    			}
    			return 0;
    		}
    
    		void _webBrowser2Events_BeforeNavigate2(object pDisp, ref object URL, ref object Flags, ref object TargetFrameName, ref object PostData, ref object Headers, ref bool Cancel)
    		{
    			MessageBox.Show("BeforeNavigate2");
    		}
    
    
    		void _webBrowser2Events_DocumentComplete(object pDisp, ref object URL)
    		{
    			MessageBox.Show("DocumentComplete");
    		}
    		
    		public int GetSite(ref Guid riid, out IntPtr ppvSite)
    		{
    			var pUnk = Marshal.GetIUnknownForObject(_pUnkSite);
    			try
    			{
    				return Marshal.QueryInterface(pUnk, ref riid, out ppvSite);
    			}
    			finally
    			{
    				Marshal.Release(pUnk);
    			}
    		}
    	}
    
    	[ComImport,
    	Guid("FC4801A3-2BA9-11CF-A229-00AA003D7352"),
    	InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    	public interface IObjectWithSite
    	{
    		[PreserveSig]
    		int SetSite([In, MarshalAs(UnmanagedType.IUnknown)]object pUnkSite);
    		[PreserveSig]
    		int GetSite(ref Guid riid, out IntPtr ppvSite);
    	}
    }
    
    

     


    Tech_Net_User
    Monday, February 06, 2012 5:08 PM

Answers

  • Alright, I've got a work-around that look like its working properly (at least on XPsp3 with IE7 - haven't tested Vista/7 with IE8/9 yet). But maybe there's a better/standard/approved approach?

    The work-around involves:

    1. Removing the DWebBrowserEvents2_Event.BeforeNavigate2 handler.
    2. Adding a WebBrowser_V1.BeforeNavigate handler.

    Updated source attached:

    using System;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    using mshtml;
    using SHDocVw;
    
    namespace TestAddOn
    {
    	[ComVisible(true),
    	Guid("5EDB942A-D8AB-4543-95D6-4E727F352AAE"),
    	ClassInterface(ClassInterfaceType.None)]
    	public class TestBHO : IObjectWithSite
    	{
    		private object _pUnkSite;
    		private IWebBrowser2 _webBrowser2;
    		private DWebBrowserEvents2_Event _webBrowser2Events;
    
    		private SHDocVw.WebBrowser_V1 axDocumentV1;						// work-around
    
    		public int SetSite(object pUnkSite)
    		{
    			if (pUnkSite != null)
    			{
    				_pUnkSite = pUnkSite;
    				_webBrowser2 = (IWebBrowser2)pUnkSite;
    				_webBrowser2Events = (DWebBrowserEvents2_Event)pUnkSite;
    				_webBrowser2Events.DocumentComplete += _webBrowser2Events_DocumentComplete;
    
    				axDocumentV1 = (WebBrowser_V1)pUnkSite;				// work-around
    				axDocumentV1.BeforeNavigate += axDocumentV1_BeforeNavigate;		// work-around
    			}
    			else
    			{
    				_webBrowser2Events.DocumentComplete -= _webBrowser2Events_DocumentComplete;
    
    				axDocumentV1.BeforeNavigate -= axDocumentV1_BeforeNavigate;		// work-around
    				
    				_pUnkSite = null;
    			}
    			return 0;
    		}
    
    		// work-around
    		void axDocumentV1_BeforeNavigate(string URL, int Flags, string TargetFrameName, ref object PostData, string Headers, ref bool Cancel)
    		{
    			MessageBox.Show("axDocumentV1_BeforeNavigate");
    		}
    
    		void _webBrowser2Events_DocumentComplete(object pDisp, ref object URL)
    		{
    			MessageBox.Show("DocumentComplete");
    		}
    		
    		public int GetSite(ref Guid riid, out IntPtr ppvSite)
    		{
    			var pUnk = Marshal.GetIUnknownForObject(_pUnkSite);
    			try
    			{
    				return Marshal.QueryInterface(pUnk, ref riid, out ppvSite);
    			}
    			finally
    			{
    				Marshal.Release(pUnk);
    			}
    		}
    	}
    
    	[ComImport,
    	Guid("FC4801A3-2BA9-11CF-A229-00AA003D7352"),
    	InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    	public interface IObjectWithSite
    	{
    		[PreserveSig]
    		int SetSite([In, MarshalAs(UnmanagedType.IUnknown)]object pUnkSite);
    		[PreserveSig]
    		int GetSite(ref Guid riid, out IntPtr ppvSite);
    	}
    }
    
    

     


    Tech_Net_User
    Monday, February 06, 2012 8:38 PM

All replies

  • Alright, I've got a work-around that look like its working properly (at least on XPsp3 with IE7 - haven't tested Vista/7 with IE8/9 yet). But maybe there's a better/standard/approved approach?

    The work-around involves:

    1. Removing the DWebBrowserEvents2_Event.BeforeNavigate2 handler.
    2. Adding a WebBrowser_V1.BeforeNavigate handler.

    Updated source attached:

    using System;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    using mshtml;
    using SHDocVw;
    
    namespace TestAddOn
    {
    	[ComVisible(true),
    	Guid("5EDB942A-D8AB-4543-95D6-4E727F352AAE"),
    	ClassInterface(ClassInterfaceType.None)]
    	public class TestBHO : IObjectWithSite
    	{
    		private object _pUnkSite;
    		private IWebBrowser2 _webBrowser2;
    		private DWebBrowserEvents2_Event _webBrowser2Events;
    
    		private SHDocVw.WebBrowser_V1 axDocumentV1;						// work-around
    
    		public int SetSite(object pUnkSite)
    		{
    			if (pUnkSite != null)
    			{
    				_pUnkSite = pUnkSite;
    				_webBrowser2 = (IWebBrowser2)pUnkSite;
    				_webBrowser2Events = (DWebBrowserEvents2_Event)pUnkSite;
    				_webBrowser2Events.DocumentComplete += _webBrowser2Events_DocumentComplete;
    
    				axDocumentV1 = (WebBrowser_V1)pUnkSite;				// work-around
    				axDocumentV1.BeforeNavigate += axDocumentV1_BeforeNavigate;		// work-around
    			}
    			else
    			{
    				_webBrowser2Events.DocumentComplete -= _webBrowser2Events_DocumentComplete;
    
    				axDocumentV1.BeforeNavigate -= axDocumentV1_BeforeNavigate;		// work-around
    				
    				_pUnkSite = null;
    			}
    			return 0;
    		}
    
    		// work-around
    		void axDocumentV1_BeforeNavigate(string URL, int Flags, string TargetFrameName, ref object PostData, string Headers, ref bool Cancel)
    		{
    			MessageBox.Show("axDocumentV1_BeforeNavigate");
    		}
    
    		void _webBrowser2Events_DocumentComplete(object pDisp, ref object URL)
    		{
    			MessageBox.Show("DocumentComplete");
    		}
    		
    		public int GetSite(ref Guid riid, out IntPtr ppvSite)
    		{
    			var pUnk = Marshal.GetIUnknownForObject(_pUnkSite);
    			try
    			{
    				return Marshal.QueryInterface(pUnk, ref riid, out ppvSite);
    			}
    			finally
    			{
    				Marshal.Release(pUnk);
    			}
    		}
    	}
    
    	[ComImport,
    	Guid("FC4801A3-2BA9-11CF-A229-00AA003D7352"),
    	InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    	public interface IObjectWithSite
    	{
    		[PreserveSig]
    		int SetSite([In, MarshalAs(UnmanagedType.IUnknown)]object pUnkSite);
    		[PreserveSig]
    		int GetSite(ref Guid riid, out IntPtr ppvSite);
    	}
    }
    
    

     


    Tech_Net_User
    Monday, February 06, 2012 8:38 PM
  • Okay, I'm withdrawing the original question.

    I see from various post responses from MS MVPs that we shouldn't be using managed code to create BHOs due to the limitation of a single .NET framework loading in a given process (IE). So I'm converting the BHO to unmanaged C++ / ATL code as detailed in the MS article: Building Browser Helper Objects with Visual Studio 2005: http://msdn.microsoft.com/en-us/library/ie/bb250489(v=vs.85).aspx

    There were plenty of other issues with the C# BHO (like getting VS2010 to debug properly at F5 button push) and none of that's an issue with VS2010 and C++ / ATL.

    Thanks anyway...


    Tech_Net_User

    Tuesday, February 07, 2012 4:52 PM
  • Great!  If you have any questions about the native implementation, we can probably be more helpful.  My personal preference is to avoid ATL as well, since debugging into those header files when things go wrong is a total PITA.  However, it does save you about a man-week of typing.
    Tuesday, February 07, 2012 5:39 PM