5

I need to confirm programatically (i.e, answer 'yes') to a script error dialog box into WebBrowser otherwise the page will stop working. I have no code to show because I have no idea how I could do this.

Here's a image from dialog box I'm talking about:

enter image description here (take from this, btw)

Jack
  • 16,276
  • 55
  • 159
  • 284
  • Can't you just prevent it? for Winforms: http://msdn.microsoft.com/library/system.windows.forms.webbrowser.scripterrorssuppressed.aspx and for WPF: http://stackoverflow.com/questions/6138199/wpf-webbrowser-control-how-to-supress-script-errors – Simon Mourier Jul 30 '14 at 06:56
  • It's same that click 'no'. Page will stop working this way – Jack Jul 30 '14 at 06:57
  • Are you using WPF or WinForms? – HerbalMart Jul 30 '14 at 08:46
  • @HerbalMart: WinForms. I will add in tags – Jack Jul 30 '14 at 20:04
  • can you edit the webpage? you can prevent the popup from happening. – Batavia Jul 30 '14 at 20:32
  • @Batavia: No, I can't. The page isn't mine. – Jack Jul 30 '14 at 20:33
  • @Jack suppose the JS takes a long time to finish, how long do you plan to wait? You have no way to find whether all scripts are executed till the end or not. When I see such a question, I always think it is a some kind of [XY-problem](http://www.perlmonks.org/?node=xy+problem). – L.B Jul 30 '14 at 20:53

1 Answers1

9

According to the "How to handle script errors as a WebBrowser control host" MSKB article, you need to handle CGID_DocHostCommandHandler/OLECMDID_SHOWSCRIPTERROR command in the WebBrowser host.

With a bit of coding, here is how it can be done for the WinForms WebBrowser version, and it actually works:

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

namespace WindowsFormsApplication1
{
    public class WebBrowserEx: WebBrowser
    {
        class WebBrowserSiteEx : WebBrowserSite, NativeMethods.IOleCommandTarget
        {
            public WebBrowserSiteEx(WebBrowser browser): base(browser)
            {
            }

            public int QueryStatus(IntPtr pguidCmdGroup, uint cCmds, NativeMethods.OLECMD[] prgCmds, ref NativeMethods.OLECMDTEXT CmdText)
            {
                return NativeMethods.OLECMDERR_E_UNKNOWNGROUP;
            }

            public int Exec(IntPtr pguidCmdGroup, uint nCmdId, uint nCmdExecOpt, IntPtr pvaIn, IntPtr pvaOut)
            {
                if (pguidCmdGroup != IntPtr.Zero)
                {
                    Guid guid = (Guid)Marshal.PtrToStructure(pguidCmdGroup, typeof(Guid));
                    if (guid == NativeMethods.CGID_DocHostCommandHandler)
                    {
                        if (nCmdId == NativeMethods.OLECMDID_SHOWSCRIPTERROR)
                        {
                            // if DOM needed: dynamic document = Marshal.GetObjectForNativeVariant(pvaIn);

                            // continue running scripts
                            if (pvaOut != IntPtr.Zero)
                                Marshal.GetNativeVariantForObject(true, pvaOut); 

                            return NativeMethods.S_OK; 
                        }
                    }
                }
                return NativeMethods.OLECMDERR_E_UNKNOWNGROUP;
            }
        }

        protected override WebBrowserSiteBase CreateWebBrowserSiteBase()
        {
            return new WebBrowserSiteEx(this);
        }
    }

    public partial class Form1 : Form
    {
        WebBrowserEx _browser;
        public Form1()
        {
            InitializeComponent();
            _browser = new WebBrowserEx();
            _browser.Dock = DockStyle.Fill;
            this.Controls.Add(_browser);

        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // testing
            _browser.DocumentText = "<script>alert(bad.bad)</script>";
        }
    }

    static class NativeMethods
    {
        [StructLayout(LayoutKind.Sequential)]
        public struct OLECMD
        {
            public uint cmdID;
            public uint cmdf;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct OLECMDTEXT
        {
            public UInt32 cmdtextf;
            public UInt32 cwActual;
            public UInt32 cwBuf;
            public char rgwz;
        }

        public const int OLECMDERR_E_UNKNOWNGROUP = unchecked((int)0x80040102);
        public const int OLECMDID_SHOWSCRIPTERROR = 40;
        public static readonly Guid CGID_DocHostCommandHandler = new Guid("f38bc242-b950-11d1-8918-00c04fc2c836");
        public const int S_OK = 0;

        [ComImport, Guid("b722bccb-4e68-101b-a2bc-00aa00404770"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IOleCommandTarget
        {
            [PreserveSig]
            int QueryStatus(
                IntPtr pguidCmdGroup,
                UInt32 cCmds,
                [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] OLECMD[] prgCmds,
                ref OLECMDTEXT CmdText);

            [PreserveSig]
            int Exec(
                IntPtr pguidCmdGroup,
                uint nCmdId,
                uint nCmdExecOpt,
                IntPtr pvaIn,
                IntPtr pvaOut);
        }
    }
}


Updated to address the comment:

I need to capture the JavaScript error info in order to log it while still not displaying it to the user. I looked at the document object (the commented out line) and didn't see anything there. Is there an easy way to capture this info?

Check the article I linked at the beginning. There are special properties errorLine, errorCharacter, errorCode, errorMessage, errorUrl available on document.parentWindow.event object.

noseratio
  • 59,932
  • 34
  • 208
  • 486
  • 1
    Words can't descrive what I felt when I seen it working. BIG THANKS! have a nice month. – Jack Jul 31 '14 at 03:53
  • @Jack, glad it helped. Have a nice month, too :) – noseratio Jul 31 '14 at 03:55
  • 1
    It helped SO much. I had even gave up(before try SendMessage(), wonder the pain). It seemed no one on earth knew how to solve that. In two hours I will give you the 50+ points. – Jack Jul 31 '14 at 03:59
  • @Noseration: I know it should be another thread but do you have any idea if can I do something like this with certificate error in internet explorer? – Jack Jul 31 '14 at 07:05
  • 1
    @Jack, you do this by implementing `IHttpSecurity` *service* on the `WebBrowserSiteEx` object, e.g. [like this](http://jiangsheng.net/2013/07/17/howto-ignoring-web-browser-certificate-errors-in-webbrowser-host). – noseratio Jul 31 '14 at 07:11
  • Thanks ver much for link. It didn't worked for me... I'll open a new thread. – Jack Jul 31 '14 at 15:44
  • 1
    This is a great solution, thank you! I just have one question about this, as I'm not familiar with native methods to do this. I need to capture the JavaScript error info in order to log it while still not displaying it to the user. I looked at the document object (the commented out line) and didn't see anything there. Is there an easy way to capture this info? – Ilya Feb 13 '15 at 13:43
  • 1
    Noseratio, thank you for pointing those properties out. Works like a charm! – Ilya Feb 14 '15 at 23:22