Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Workaround BeforeNavigate2 not being fired in WPF .NET

I need to send headers with every request I transmit using the System.Windows.Controls.WebBrowser control. Using C# with .Net, due to a bug described here, the BeforeNavigate2 event, which would help me with call-by-reference-parameters, is not being fired, and the BeforeNavigate event described in the bug report does not help me, as its parameters are read only.

The Solution described here are difficult to impossible to use as I have a lot of references to the Controls Web Browser that would have to be solved, leading through existing interfaces and other libraries in this project.

Like in the solution described, it would be sufficient to have a fixed string I can set externally, but I would need a solution setting Headers using the Controls Web Browser. Is there a solution that could satisfy my requirements without using Forms?

like image 927
Andreas Avatar asked Dec 30 '13 11:12

Andreas


1 Answers

Here is another approach, it uses the low-level COM connection point container interfaces to attach to the underlying DWebBrowserEvents2 source interface directly.

Grab the full project source code from here. I don't have VS2010, so it's a VS2012 project, but it targets .NET 4.0. A compiled app is included in the Debug folder, if you're ready to try it as is.

Here is the relevant code. It's a quick proof of concept which still may have bugs:

using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows;

namespace WpfWebBrowserEvents
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            this.Loaded += (s, e) =>
            {
                var sink = new WebBrowserEventSink();
                sink.Connect(this.webBrowser);

                this.webBrowser.Navigate("http://example.com");
            };
        }
    }

    /// <summary>
    /// Handling WebBrowser ActiveX events directly
    /// by Noseratio - http://stackoverflow.com/q/20838264/1768303
    /// </summary>

    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.None)]
    [ComDefaultInterface(typeof(SHDocVw.DWebBrowserEvents2))]
    public class WebBrowserEventSink : SHDocVw.DWebBrowserEvents2
    {
        System.Runtime.InteropServices.ComTypes.IConnectionPoint _sinkCP = null;
        int _sinkCookie = int.MaxValue;

        public void Connect(System.Windows.Controls.WebBrowser webBrowser)
        {
            if (_sinkCookie != int.MaxValue)
                throw new InvalidOperationException();

            var activeXInstance = webBrowser.GetType().InvokeMember("ActiveXInstance",
                BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
                null, webBrowser, new object[] { }) as SHDocVw.WebBrowser;

            var cpc = (System.Runtime.InteropServices.ComTypes.IConnectionPointContainer)activeXInstance;
            var guid = typeof(SHDocVw.DWebBrowserEvents2).GUID;
            System.Runtime.InteropServices.ComTypes.IConnectionPoint _sinkCP;
            cpc.FindConnectionPoint(ref guid, out _sinkCP);
            _sinkCP.Advise(this, out _sinkCookie);
        }

        public void Disconnect()
        {
            if (_sinkCookie == int.MaxValue)
                throw new InvalidOperationException();
            _sinkCP.Unadvise(_sinkCookie);
            _sinkCookie = int.MaxValue;
            _sinkCP = null;
        }

        #region SHDocVw.DWebBrowserEvents2

        public void StatusTextChange(string Text)
        {
        }

        public void ProgressChange(int Progress, int ProgressMax)
        {
        }

        public void CommandStateChange(int Command, bool Enable)
        {
        }

        public void DownloadBegin()
        {
        }

        public void DownloadComplete()
        {
        }

        public void TitleChange(string Text)
        {
        }

        public void PropertyChange(string szProperty)
        {
        }

        public void BeforeNavigate2(object pDisp, ref object URL, ref object Flags, ref object TargetFrameName, ref object PostData, ref object Headers, ref bool Cancel)
        {
            MessageBox.Show("BeforeNavigate2: " + URL.ToString());
        }

        public void NewWindow2(ref object ppDisp, ref bool Cancel)
        {
        }

        public void NavigateComplete2(object pDisp, ref object URL)
        {
        }

        public void DocumentComplete(object pDisp, ref object URL)
        {
        }

        public void OnQuit()
        {
        }

        public void OnVisible(bool Visible)
        {
        }

        public void OnToolBar(bool ToolBar)
        {
        }

        public void OnMenuBar(bool MenuBar)
        {
        }

        public void OnStatusBar(bool StatusBar)
        {
        }

        public void OnFullScreen(bool FullScreen)
        {
        }

        public void OnTheaterMode(bool TheaterMode)
        {
        }

        public void WindowSetResizable(bool Resizable)
        {
        }

        public void WindowSetLeft(int Left)
        {
        }

        public void WindowSetTop(int Top)
        {
        }

        public void WindowSetWidth(int Width)
        {
        }

        public void WindowSetHeight(int Height)
        {
        }

        public void WindowClosing(bool IsChildWindow, ref bool Cancel)
        {
        }

        public void ClientToHostWindow(ref int CX, ref int CY)
        {
        }

        public void SetSecureLockIcon(int SecureLockIcon)
        {
        }

        public void FileDownload(bool ActiveDocument, ref bool Cancel)
        {
        }

        public void NavigateError(object pDisp, ref object URL, ref object Frame, ref object StatusCode, ref bool Cancel)
        {
        }

        public void PrintTemplateInstantiation(object pDisp)
        {
        }

        public void PrintTemplateTeardown(object pDisp)
        {
        }

        public void UpdatePageStatus(object pDisp, ref object nPage, ref object fDone)
        {
        }

        public void PrivacyImpactedStateChange(bool bImpacted)
        {
        }

        public void NewWindow3(ref object ppDisp, ref bool Cancel, uint dwFlags, string bstrUrlContext, string bstrUrl)
        {
        }

        public void SetPhishingFilterStatus(int PhishingFilterStatus)
        {
        }

        public void WindowStateChanged(uint dwWindowStateFlags, uint dwValidFlagsMask)
        {
        }

        public void NewProcess(int lCauseFlag, object pWB2, ref bool Cancel)
        {
        }

        public void ThirdPartyUrlBlocked(ref object URL, uint dwCount)
        {
        }

        public void RedirectXDomainBlocked(object pDisp, ref object StartURL, ref object RedirectURL, ref object Frame, ref object StatusCode)
        {
        }

        public void BeforeScriptExecute(object pDispWindow)
        {
        }

        public void WebWorkerStarted(uint dwUniqueID, string bstrWorkerLabel)
        {
        }

        public void WebWorkerFinsihed(uint dwUniqueID)
        {
        }

        #endregion
    }

}
like image 147
noseratio Avatar answered Sep 20 '22 19:09

noseratio