// Copyright © 2015 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.Runtime.InteropServices; using System.Text; namespace CefSharp.WinForms.Experimental { /// /// ChromiumWidgetHandleFinder is a helper class used to find the /// child Hwnd for the browser instance. /// public static class ChromiumRenderWidgetHandleFinder { /// /// Class Name of the Chrome_RenderWidgetHostHWND Child Window /// public const string ChromeRenderWidgetHostClassName = "Chrome_RenderWidgetHostHWND"; /// /// EnumWindowProc delegate used by /// /// A handle to a child window of the parent window specified in EnumChildWindows /// The application-defined value given in EnumChildWindows /// To continue enumeration, the callback function must return true; to stop enumeration, it must return false. private delegate bool EnumWindowProc(IntPtr hwnd, IntPtr lParam); [DllImport("user32")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr lParam); [DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); /// /// Chromium's message-loop Window isn't created synchronously, so this may not find it. /// If so, you need to wait and try again later. /// /// ChromiumWebBrowser instance /// Handle of the child HWND with the name /// returns true if the HWND was found otherwise false. public static bool TryFindHandle(IWebBrowser chromiumWebBrowser, out IntPtr chromerRenderWidgetHostHandle) { var host = chromiumWebBrowser.GetBrowserHost(); if (host == null) { throw new Exception("IBrowserHost is null, you've likely call this method before the underlying browser has been created."); } var hwnd = host.GetWindowHandle(); return TryFindHandle(hwnd, ChromeRenderWidgetHostClassName, out chromerRenderWidgetHostHandle); } /// /// Chromium's message-loop Window isn't created synchronously, so this may not find it. /// If so, you need to wait and try again later. /// /// IBrowser instance /// Handle of the child HWND with the name /// returns true if the HWND was found otherwise false. public static bool TryFindHandle(IBrowser browser, out IntPtr chromerRenderWidgetHostHandle) { var host = browser.GetHost(); if (host == null) { throw new Exception("IBrowserHost is null, you've likely call this method before the underlying browser has been created."); } var hwnd = host.GetWindowHandle(); return TryFindHandle(hwnd, ChromeRenderWidgetHostClassName, out chromerRenderWidgetHostHandle); } /// /// Helper function used to find the child HWND with the ClassName matching /// Chromium's message-loop Window isn't created synchronously, so this may not find it. /// If so, you need to wait and try again later. /// In most cases you should use the overload. /// /// control Handle /// class name used to match /// Handle of the child HWND with the name /// returns true if the HWND was found otherwise false. public static bool TryFindHandle(IntPtr chromiumWebBrowserHandle, string chromeRenderWidgetHostClassName, out IntPtr chromerRenderWidgetHostHandle) { var chromeRenderWidgetHostHwnd = IntPtr.Zero; EnumWindowProc childProc = (IntPtr hWnd, IntPtr lParam) => { var buffer = new StringBuilder(128); GetClassName(hWnd, buffer, buffer.Capacity); if (buffer.ToString() == chromeRenderWidgetHostClassName) { chromeRenderWidgetHostHwnd = hWnd; return false; } return true; }; EnumChildWindows(chromiumWebBrowserHandle, childProc, IntPtr.Zero); chromerRenderWidgetHostHandle = chromeRenderWidgetHostHwnd; return chromerRenderWidgetHostHandle != IntPtr.Zero; } } }