Navigating Event Not Raised when a Page Redirects

2019-08-07 18:01发布

问题:

I have a Windows Forms application which is consuming an OAUTH service. In order to authenticate, I use a Web Browser control to navigate to the service's login page. The user enters username and password, and this works well.

Next, the service displays a "Grant access" page. When the user clicks "Grant access", the page redirects to a URL of my choice, passing the authentication token in the query string.

This worked well on the Windows 7 machine that I developed on. I capture the query string in the Navigating event, hide the web browser control, and can then use the service by using the token I received. But on Windows 8 and Windows Server 2012, the Navigating event never happens. Instead, the Web Browser control displays a 404 error.

Is there some way that I can capture the results of that redirect?

P.S. I tried using an HttpListener, and it worked, but it requires that the application be installed by an Administrator to set up the http bindings.

回答1:

Try handling the raw BeforeNavigate2 event on the underlying WebBrowser ActiveX, here's a WinForms version (based on the original WPF version):

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace WindowsForms_22311110
{
    public partial class MainForm : Form
    {
        WebBrowser webBrowser;

        public MainForm()
        {
            InitializeComponent();

            this.webBrowser = new WebBrowser();
            this.webBrowser.Dock = DockStyle.Fill;
            this.Controls.Add(this.webBrowser);
            this.webBrowser.Visible = true;

            this.Load += MainForm_Load;
        }

        void MainForm_Load(object sender, EventArgs e)
        {
            // the below line makes sure the underlying ActiveX gets created
            if (this.webBrowser.Document != null || this.webBrowser.ActiveXInstance == null)
                throw new InvalidOperationException("webBrowser");

            var sink = new WebBrowserEventSink();
            sink.Connect(this.webBrowser);

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

    /// <summary>
    /// Handling WinForms WebBrowser ActiveX events directly
    /// this code depends on SHDocVw.dll COM interop assembly,
    /// generate SHDocVw.dll: "tlbimp.exe ieframe.dll",
    /// and add as a reference to the project
    ///
    /// by Noseratio - https://stackoverflow.com/a/22312476/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(WebBrowser webBrowser)
        {
            if (_sinkCookie != int.MaxValue)
                throw new InvalidOperationException();

            var activeXInstance = webBrowser.ActiveXInstance;

            var cpc = (System.Runtime.InteropServices.ComTypes.IConnectionPointContainer)activeXInstance;
            var guid = typeof(SHDocVw.DWebBrowserEvents2).GUID;

            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
    }
}