Skip to content

Commit e1b0d07

Browse files
committed
WinForms - Add ChromiumRenderWidgetHandleFinder/ChromiumWidgetNativeWindow
Used to hook the low level HWND and get message (e.g. mouse messages) Updated the example
1 parent e035c39 commit e1b0d07

File tree

6 files changed

+173
-114
lines changed

6 files changed

+173
-114
lines changed

CefSharp.WinForms.Example/BrowserTabUserControl.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,15 @@
1212
using CefSharp.Example.Handlers;
1313
using CefSharp.Example.JavascriptBinding;
1414
using CefSharp.WinForms.Example.Handlers;
15+
using CefSharp.WinForms.Experimental;
1516

1617
namespace CefSharp.WinForms.Example
1718
{
1819
public partial class BrowserTabUserControl : UserControl
1920
{
2021
public IWinFormsWebBrowser Browser { get; private set; }
2122
private IntPtr browserHandle;
22-
private ChromeWidgetMessageInterceptor messageInterceptor;
23+
private ChromiumWidgetNativeWindow messageInterceptor;
2324
private bool multiThreadedMessageLoopEnabled;
2425

2526
public BrowserTabUserControl(Action<string, int?> openNewTab, string url, bool multiThreadedMessageLoopEnabled)
@@ -277,9 +278,11 @@ private void SetupMessageInterceptor()
277278
while (true)
278279
{
279280
IntPtr chromeWidgetHostHandle;
280-
if (ChromeWidgetHandleFinder.TryFindHandle(browserHandle, out chromeWidgetHostHandle))
281+
if (ChromiumRenderWidgetHandleFinder.TryFindHandle(Browser, out chromeWidgetHostHandle))
281282
{
282-
messageInterceptor = new ChromeWidgetMessageInterceptor((Control)Browser, chromeWidgetHostHandle, message =>
283+
messageInterceptor = new ChromiumWidgetNativeWindow((Control)Browser, chromeWidgetHostHandle);
284+
285+
messageInterceptor.OnWndProc(message =>
283286
{
284287
const int WM_MOUSEACTIVATE = 0x0021;
285288
const int WM_NCLBUTTONDOWN = 0x00A1;
@@ -289,7 +292,7 @@ private void SetupMessageInterceptor()
289292
if (message.Msg == WM_DESTROY)
290293
{
291294
SetupMessageInterceptor();
292-
return;
295+
return false;
293296
}
294297

295298
if (message.Msg == WM_MOUSEACTIVATE)
@@ -324,6 +327,8 @@ private void SetupMessageInterceptor()
324327
// Console.WriteLine("WM_MOUSELEAVE");
325328
// break;
326329
//}
330+
331+
return false;
327332
});
328333

329334
break;

CefSharp.WinForms.Example/CefSharp.WinForms.Example.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@
8484
<Compile Include="BrowserTabUserControl.Designer.cs">
8585
<DependentUpon>BrowserTabUserControl.cs</DependentUpon>
8686
</Compile>
87-
<Compile Include="ChromeWidgetMessageInterceptor.cs" />
8887
<Compile Include="ChromiumContainerControl.cs">
8988
<SubType>Component</SubType>
9089
</Compile>

CefSharp.WinForms.Example/ChromeWidgetMessageInterceptor.cs

Lines changed: 0 additions & 109 deletions
This file was deleted.

CefSharp.WinForms/CefSharp.WinForms.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@
5858
</Compile>
5959
<Compile Include="CefSettings.cs" />
6060
<Compile Include="ChromiumWebBrowserDesigner.cs" />
61+
<Compile Include="Experimental\ChromiumRenderWidgetHandleFinder.cs" />
62+
<Compile Include="Experimental\ChromiumWidgetNativeWindow.cs" />
6163
<Compile Include="Internals\DefaultFocusHandler.cs" />
6264
<Compile Include="Internals\ControlExtensions.cs" />
6365
<Compile Include="Internals\ParentFormMessageInterceptor.cs" />
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Copyright © 2015 The CefSharp Authors. All rights reserved.
2+
//
3+
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
4+
5+
using System;
6+
using System.Runtime.InteropServices;
7+
using System.Text;
8+
9+
namespace CefSharp.WinForms.Experimental
10+
{
11+
/// <summary>
12+
/// ChromiumWidgetHandleFinder is a helper class used to find the <see cref="ChromeRenderWidgetHostClassName"/>
13+
/// child Hwnd for the browser instance.
14+
/// </summary>
15+
public static class ChromiumRenderWidgetHandleFinder
16+
{
17+
/// <summary>
18+
/// Class Name of the Chrome_RenderWidgetHostHWND Child Window
19+
/// </summary>
20+
public const string ChromeRenderWidgetHostClassName = "Chrome_RenderWidgetHostHWND";
21+
22+
/// <summary>
23+
/// EnumWindowProc delegate used by <see cref="EnumChildWindows(IntPtr, EnumWindowProc, IntPtr)"/>
24+
/// </summary>
25+
/// <param name="hwnd">A handle to a child window of the parent window specified in EnumChildWindows</param>
26+
/// <param name="lParam">The application-defined value given in EnumChildWindows</param>
27+
/// <returns>To continue enumeration, the callback function must return true; to stop enumeration, it must return false.</returns>
28+
private delegate bool EnumWindowProc(IntPtr hwnd, IntPtr lParam);
29+
30+
[DllImport("user32")]
31+
[return: MarshalAs(UnmanagedType.Bool)]
32+
private static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr lParam);
33+
34+
[DllImport("user32.dll", CharSet = CharSet.Auto)]
35+
private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
36+
37+
/// <summary>
38+
/// Chromium's message-loop Window isn't created synchronously, so this may not find it.
39+
/// If so, you need to wait and try again later.
40+
/// </summary>
41+
/// <param name="chromiumWebBrowser">ChromiumWebBrowser instance</param>
42+
/// <param name="chromerRenderWidgetHostHandle">Handle of the child HWND with the name <see cref="ChromeRenderWidgetHostClassName"/></param>
43+
/// <returns>returns true if the HWND was found otherwise false.</returns>
44+
public static bool TryFindHandle(IWebBrowser chromiumWebBrowser, out IntPtr chromerRenderWidgetHostHandle)
45+
{
46+
var host = chromiumWebBrowser.GetBrowserHost();
47+
if (host == null)
48+
{
49+
throw new Exception("IBrowserHost is null, you've likely call this method before the underlying browser has been created.");
50+
}
51+
52+
var hwnd = host.GetWindowHandle();
53+
54+
return TryFindHandle(hwnd, ChromeRenderWidgetHostClassName, out chromerRenderWidgetHostHandle);
55+
}
56+
57+
/// <summary>
58+
/// Helper function used to find the child HWND with the ClassName matching <paramref name="chromeRenderWidgetHostClassName"/>
59+
/// Chromium's message-loop Window isn't created synchronously, so this may not find it.
60+
/// If so, you need to wait and try again later.
61+
/// In most cases you should use the <see cref="TryFindHandle(ChromiumWebBrowser, out IntPtr)"/> overload.
62+
/// </summary>
63+
/// <param name="chromiumWebBrowserHandle"><see cref="ChromiumWebBrowser"/> control Handle</param>
64+
/// <param name="chromeRenderWidgetHostClassName">class name used to match</param>
65+
/// <param name="chromerRenderWidgetHostHandle">Handle of the child HWND with the name <see cref="ChromeRenderWidgetHostClassName"/></param>
66+
/// <returns>returns true if the HWND was found otherwise false.</returns>
67+
public static bool TryFindHandle(IntPtr chromiumWebBrowserHandle, string chromeRenderWidgetHostClassName, out IntPtr chromerRenderWidgetHostHandle)
68+
{
69+
var chromeRenderWidgetHostHwnd = IntPtr.Zero;
70+
71+
EnumWindowProc childProc = (IntPtr hWnd, IntPtr lParam) =>
72+
{
73+
var buffer = new StringBuilder(128);
74+
GetClassName(hWnd, buffer, buffer.Capacity);
75+
76+
if (buffer.ToString() == chromeRenderWidgetHostClassName)
77+
{
78+
chromeRenderWidgetHostHwnd = hWnd;
79+
return false;
80+
}
81+
82+
return true;
83+
};
84+
85+
EnumChildWindows(chromiumWebBrowserHandle, childProc, IntPtr.Zero);
86+
87+
chromerRenderWidgetHostHandle = chromeRenderWidgetHostHwnd;
88+
89+
return chromerRenderWidgetHostHandle != IntPtr.Zero;
90+
}
91+
}
92+
}
93+
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright © 2015 The CefSharp Authors. All rights reserved.
2+
//
3+
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
4+
5+
using System;
6+
using System.Windows.Forms;
7+
8+
namespace CefSharp.WinForms.Experimental
9+
{
10+
/// <summary>
11+
/// Provides a convenient <see cref="NativeWindow"/> implement
12+
/// that can be used without having to create your own class
13+
/// </summary>
14+
public class ChromiumWidgetNativeWindow : NativeWindow
15+
{
16+
private Func<Message, bool> wndProcHandler;
17+
18+
/// <summary>
19+
/// ChromiumWidgetMessageInterceptor constructor
20+
/// </summary>
21+
/// <param name="control">Control is used to handled the <see cref="Control.HandleDestroyed"/> event so
22+
/// we can automatically call <see cref="NativeWindow.ReleaseHandle"/>. If null then you are responsible
23+
/// for calling <see cref="NativeWindow.ReleaseHandle"/></param>
24+
/// <param name="chromeWidgetHostHandle">Hwnd to intercept messages for.</param>
25+
public ChromiumWidgetNativeWindow(Control control, IntPtr chromeWidgetHostHandle)
26+
{
27+
AssignHandle(chromeWidgetHostHandle);
28+
29+
if (control != null)
30+
{
31+
control.HandleDestroyed += BrowserHandleDestroyed;
32+
}
33+
}
34+
35+
private void BrowserHandleDestroyed(object sender, EventArgs e)
36+
{
37+
ReleaseHandle();
38+
39+
var control = (Control)sender;
40+
41+
control.HandleDestroyed -= BrowserHandleDestroyed;
42+
wndProcHandler = null;
43+
}
44+
45+
/// <summary>
46+
/// Register a Func which is used to intercept <see cref="WndProc(ref Message)"/>
47+
/// calls. <paramref name="wndProcHandler"/> should return true if the message
48+
/// was handled, otherwise false.
49+
/// </summary>
50+
/// <param name="wndProcHandler">Func to be used to intercept messages, null to clear an existing function.</param>
51+
public void OnWndProc(Func<Message, bool> wndProcHandler)
52+
{
53+
this.wndProcHandler = wndProcHandler;
54+
}
55+
56+
/// <inheritdoc/>
57+
protected override void WndProc(ref Message m)
58+
{
59+
var handler = wndProcHandler;
60+
61+
var handled = handler?.Invoke(m);
62+
63+
if (handled == false)
64+
{
65+
base.WndProc(ref m);
66+
}
67+
}
68+
}
69+
}

0 commit comments

Comments
 (0)