Next CefSharp integrated Google browser details (5) - official website example parsing 2 winform capture chromium WebBrowser message

The purpose of capturing browser message events is to prevent the click events of the drop-down menu from being swallowed by the browser. If the drop-down menu is swallowed, it will not automatically retract

Register the event in BrowserInitializedChanged.
In BrowserTabUserControl

browser.IsBrowserInitializedChanged += OnIsBrowserInitializedChanged;

private void OnIsBrowserInitializedChanged(object sender, IsBrowserInitializedChangedEventArgs args)
    {
        if (args.IsBrowserInitialized)
        {
            //Get the underlying browser host wrapper
            var browserHost = Browser.GetBrowser().GetHost();
            var requestContext = browserHost.RequestContext;
            string errorMessage;
            // Browser must be initialized before getting/setting preferences
            var success = requestContext.SetPreference("enable_do_not_track", true, out errorMessage);
            if(!success)
            {
                this.InvokeOnUiThreadIfRequired(() => MessageBox.Show("Unable to set preference enable_do_not_track errorMessage: " + errorMessage));
            }

            //Example of disable spellchecking
            //success = requestContext.SetPreference("browser.enable_spellchecking", false, out errorMessage);

            var preferences = requestContext.GetAllPreferences(true);
            var doNotTrack = (bool)preferences["enable_do_not_track"];

            //Use this to check that settings preferences are working in your code
            //success = requestContext.SetPreference("webkit.webprefs.minimum_font_size", 24, out errorMessage);

            //If we're using CefSetting.MultiThreadedMessageLoop (the default) then to hook the message pump,
            // which running in a different thread we have to use a NativeWindow

            if (multiThreadedMessageLoopEnabled)
            {
                Task.Run(() =>
                {
                    try
                    {
                        while (true)
                        {
                            IntPtr chromeWidgetHostHandle;
                            if                            (ChromeWidgetHandleFinder.TryFindHandle(browserHandle, out chromeWidgetHostHandle))
                            {
                                messageInterceptor = new ChromeWidgetMessageInterceptor((Control)Browser, chromeWidgetHostHandle, message =>
                                {
                                    const int WM_MOUSEACTIVATE = 0x0021;
                                    const int WM_NCLBUTTONDOWN = 0x00A1;
                                    const int WM_LBUTTONDOWN = 0x0201;

                                    if (message.Msg == WM_MOUSEACTIVATE)
                                    {
                                        // The default processing of WM_MOUSEACTIVATE results in MA_NOACTIVATE,
                                        // and the subsequent mouse click is eaten by Chrome.
                                        // This means any .NET ToolStrip or ContextMenuStrip does not get closed.
                                        // By posting a WM_NCLBUTTONDOWN message to a harmless co-ordinate of the
                                        // top-level window, we rely on the ToolStripManager's message handling
                                        // to close any open dropdowns:
                                        // http://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/ToolStripManager.cs,1249
                                        var topLevelWindowHandle = message.WParam;
                                        PostMessage(topLevelWindowHandle, WM_NCLBUTTONDOWN, IntPtr.Zero, IntPtr.Zero);
                                    }
                                    //Forward mouse button down message to browser control
                                    //else if(message.Msg == WM_LBUTTONDOWN)
                                    //{
                                    //    PostMessage(browserHandle, WM_LBUTTONDOWN, message.WParam, message.LParam);
                                    //}

                                    // The ChromiumWebBrowserControl does not fire MouseEnter/Move/Leave events, because Chromium handles these.
                                    // However we can hook into Chromium's messaging window to receive the events.
                                    //
                                    //const int WM_MOUSEMOVE = 0x0200;
                                    //const int WM_MOUSELEAVE = 0x02A3;
                                    //
                                    //switch (message.Msg) {
                                    //    case WM_MOUSEMOVE:
                                    //        Console.WriteLine("WM_MOUSEMOVE");
                                    //        break;
                                    //    case WM_MOUSELEAVE:
                                    //        Console.WriteLine("WM_MOUSELEAVE");
                                    //        break;
                                    //}
                                });

                                break;
                            }
                            else
                            {
                                // Chrome hasn't yet set up its message-loop window.
                                Thread.Sleep(10);
                            }
                        }
                    }
                    catch
                    {
                        // Errors are likely to occur if browser is disposed, and no good way to check from another thread
                    }
                });
            }
        }

if                       (ChromeWidgetHandleFinder.TryFindHandle(browserHandle, out chromeWidgetHostHandle))

This sentence is to use the local API of windows to search the message handle clicked by the browser. If there is one, execute the logic POST in if, click the message to windwindows form to make the menu automatically retract.

Look for the browser message handle

private static bool EnumWindow(IntPtr hWnd, IntPtr lParam)
    {
        const string chromeWidgetHostClassName = "Chrome_RenderWidgetHostHWND";

        var buffer = new StringBuilder(128);
        GetClassName(hWnd, buffer, buffer.Capacity);

        if (buffer.ToString() == chromeWidgetHostClassName)
        {
            var gcHandle = GCHandle.FromIntPtr(lParam);

            var classDetails = (ClassDetails)gcHandle.Target;

            classDetails.DescendantFound = hWnd;
            return false;
        }

        return true;
    }

Let's mention it, Chrome_RenderWidgetHostHWND is the characteristic string of Google browser in windows. Every control in winfrom is a windows, so we use the method of traversing the child controls to find the message handle of the browser.

Previous CefSharp integrated Google browser details (4) - official website example analysis 3 RegisterJsObject CefSharpSchemeHandlerFactory

The official example is more complicated.

Tags: Windows Google

Posted on Sat, 23 May 2020 12:38:38 -0400 by hpg4815