// Copyright © 2019 The CefSharp Authors. All rights reserved. // // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. using System; using System.Windows.Forms; using CefSharp.WinForms.Host; namespace CefSharp.WinForms { /// /// Helper extensions for performing common CefSharp related WinForms tasks /// public static class WebBrowserExtensions { [System.Runtime.InteropServices.DllImport("user32.dll")] private static extern bool DestroyWindow(IntPtr hWnd); /// /// Manually call https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-destroywindow /// passing in the handle returned from . /// This method can be used to manually close the underlying CefBrowser instance. /// This will avoid the WM_Close message that CEF sends by default to the top level window. /// (Which closes your application). This method should generally only be used in the WinForms version. /// /// the or instance. /// If the function succeeds, the return value is true. /// /// /// //Invoke on the CEF UI Thread /// Cef.UIThreadTaskFactory.StartNew(() => /// { /// var closed = chromiumWebBrowser.DestroyWindow(); /// }); /// /// public static bool DestroyWindow(this IChromiumWebBrowserBase chromiumWebBrowser) { if (!Cef.CurrentlyOnThread(CefThreadIds.TID_UI)) { throw new InvalidOperationException("This method can only be called on the CEF UI thread." + "Use Cef.UIThreadTaskFactory to marshal your call onto the CEF UI Thread."); } if (chromiumWebBrowser.IsDisposed) { return false; } var browser = chromiumWebBrowser.BrowserCore; if (browser == null) { return false; } var handle = browser.GetHost().GetWindowHandle(); return DestroyWindow(handle); } /// /// Open DevTools using as the parent control. If inspectElementAtX and/or inspectElementAtY are specified then /// the element at the specified (x,y) location will be inspected. /// For resize/moving to work correctly you will need to use the implementation. /// (Set to an instance of ) /// /// instance /// Control used as the parent for DevTools (a custom control will be added to the collection) /// Control name /// Dock Style /// x coordinate (used for inspectElement) /// y coordinate (used for inspectElement) /// Returns the that hosts the DevTools instance if successful, otherwise returns null on error. public static Control ShowDevToolsDocked(this IChromiumWebBrowserBase chromiumWebBrowser, Control parentControl, string controlName = nameof(ChromiumHostControl) + "DevTools", DockStyle dockStyle = DockStyle.Fill, int inspectElementAtX = 0, int inspectElementAtY = 0) { if (chromiumWebBrowser.IsDisposed || parentControl == null || parentControl.IsDisposed) { return null; } return chromiumWebBrowser.ShowDevToolsDocked((ctrl) => { parentControl.Controls.Add(ctrl); }, controlName, dockStyle, inspectElementAtX, inspectElementAtY); } /// /// Open DevTools using your own Control as the parent. If inspectElementAtX and/or inspectElementAtY are specified then /// the element at the specified (x,y) location will be inspected. /// For resize/moving to work correctly you will need to use the implementation. /// (Set to an instance of ) /// /// instance /// /// Action that is Invoked when the DevTools Host Control has been created and needs to be added to it's parent. /// It's important the control is added to it's intended parent at this point so the /// can be calculated to set the initial display size. /// control name /// Dock Style /// x coordinate (used for inspectElement) /// y coordinate (used for inspectElement) /// Returns the that hosts the DevTools instance if successful, otherwise returns null on error. public static Control ShowDevToolsDocked(this IChromiumWebBrowserBase chromiumWebBrowser, Action addParentControl, string controlName = nameof(ChromiumHostControl) + "DevTools", DockStyle dockStyle = DockStyle.Fill, int inspectElementAtX = 0, int inspectElementAtY = 0) { if (chromiumWebBrowser.IsDisposed || addParentControl == null) { return null; } var host = chromiumWebBrowser.GetBrowserHost(); if (host == null) { return null; } var control = new ChromiumHostControl() { Name = controlName, Dock = dockStyle }; control.CreateControl(); //It's now time for the user to add the control to it's parent addParentControl(control); //Devtools will be a child of the ChromiumHostControl var rect = control.ClientRectangle; var windowInfo = new WindowInfo(); var windowBounds = new CefSharp.Structs.Rect(rect.X, rect.Y, rect.Width, rect.Height); windowInfo.SetAsChild(control.Handle, windowBounds); host.ShowDevTools(windowInfo, inspectElementAtX, inspectElementAtY); return control; } } }