Search code examples
.netwpfwebbrowser-controliwebbrowser2

Allow popups in WPF WebBrowser


Is there a way to allow popups within embedded WPF WebBrowser control? I didn't manage to find someone elses solution, nor COM interface which enables allowing popups.

I wouldn't like to change users registry settings or use similar invasive methods, as application is intended to be distributed through ClickOnce.


Solution

  • You can implement custom popups by handling NewWindow2 or NewWindow3 events sourced by the underlying WebBrowser ActiveX control. Below is a very basic example of how to do this. It can be further improved with a re-usable WebBrowser-based control, to support popups from popups.

    Updated to address the comment. To disable the built-in pop-up blocker, you need to implement WebBrowser Feature Control for FEATURE_WEBOC_POPUPMANAGEMENT. You do need to access Registry.CurrentUser hive, but that doesn't require admin rights. The code below shows how to do it.

    using System.Reflection;
    using System.Windows;
    using System.Windows.Controls;
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    using Microsoft.Win32;
    
    
    namespace WpfWbApp
    {
        public partial class MainWindow : Window
        {
            WebBrowser webBrowser;
    
            public MainWindow()
            {
                SetBrowserFeatureControl();
    
                InitializeComponent();
    
                this.webBrowser = new WebBrowser();
                this.Content = this.webBrowser;
    
                this.Loaded += MainWindow_Loaded;
            }
    
            void MainWindow_Loaded(object sender, RoutedEventArgs e)
            {
                var axWebBrowser = (SHDocVw.WebBrowser)GetActiveXInstance(this.webBrowser);
                axWebBrowser.NewWindow2 += axWebBrowser_NewWindow2;
    
                this.webBrowser.Navigate("http://example.com");
            }
    
            void axWebBrowser_NewWindow2(ref object ppDisp, ref bool Cancel)
            {
                var window = new Window { Width = 400, Height = 300 };
                var newWebBrowser = new WebBrowser();
                window.Content = newWebBrowser;
                window.Show();
                ppDisp = GetActiveXInstance(newWebBrowser);
            }
    
            /// <summary>
            /// Get the underlying WebBrowser ActiveX object;
            /// this code depends on SHDocVw.dll COM interop assembly,
            /// generate SHDocVw.dll: "tlbimp.exe ieframe.dll",
            /// and add as a reference to the project
            /// </summary>
            static object GetActiveXInstance(WebBrowser browser)
            {
                var document = browser.Document;
    
                return browser.GetType().InvokeMember("ActiveXInstance",
                    BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
                    null, browser, new object[] { }) as SHDocVw.WebBrowser;
            }
    
            /// <summary>
            /// SetBrowserFeatureControlKey
            /// </summary>
            static void SetBrowserFeatureControlKey(string feature, string appName, uint value)
            {
                using (var key = Registry.CurrentUser.CreateSubKey(
                    string.Concat(@"Software\Microsoft\Internet Explorer\Main\FeatureControl\", feature),
                    RegistryKeyPermissionCheck.ReadWriteSubTree))
                {
                    key.SetValue(appName, (uint)value, RegistryValueKind.DWord);
                }
            }
    
            /// <summary>
            /// SetBrowserFeatureControl
            /// </summary>
            static void SetBrowserFeatureControl()
            {
                // http://msdn.microsoft.com/en-us/library/ee330720(v=vs.85).aspx
    
                // FeatureControl settings are per-process
                var fileName = System.IO.Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName);
    
                // make the control is not running inside Visual Studio Designer
                if (string.Compare(fileName, "devenv.exe", true) == 0 || string.Compare(fileName, "XDesProc.exe", true) == 0)
                    return;
    
                // Webpages containing standards-based !DOCTYPE directives are displayed in IE10 Standards mode.
                SetBrowserFeatureControlKey("FEATURE_BROWSER_EMULATION", fileName, 10000);
    
                // Web Browser Control Popup Management
                SetBrowserFeatureControlKey("FEATURE_WEBOC_POPUPMANAGEMENT", fileName, 0);
            }
        }
    }
    

    According to the docs, the pop-up blocker can also be disabled with CoInternetSetFeatureEnabled and FEATURE_WEBOC_POPUPMANAGEMENT, via p/invoke. I haven't tried that venue myself.