Skip to content

Commit 40b01d6

Browse files
committed
Add support for resizing the browser
- Should probably see if we can use https://docs.microsoft.com/en-us/windows/win32/inputmsg/wm-parentnotify to get notifications from the process
1 parent fb83c62 commit 40b01d6

7 files changed

Lines changed: 186 additions & 30 deletions

File tree

CefSharp.OutOfProcess.BrowserProcess/CefSharp.OutOfProcess.BrowserProcess.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
</PropertyGroup>
1212

1313
<ItemGroup>
14-
<PackageReference Include="CefSharp.Common.NETCore" Version="102.0.90" />
14+
<PackageReference Include="CefSharp.Common.NETCore" Version="102.0.90-RCI4501" />
1515
</ItemGroup>
1616

1717
</Project>

CefSharp.OutOfProcess.BrowserProcess/Program.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public static int Main(string[] args)
3131
var browser = new ChromiumWebBrowser("https://github.com");
3232

3333
var windowInfo = new WindowInfo();
34+
windowInfo.WindowName = "CefSharpBrowserProcess";
3435
windowInfo.SetAsChild(new IntPtr(hostHwnd));
3536

3637
browser.CreateBrowser(windowInfo);

CefSharp.OutOfProcess.Example/CefSharp.OutOfProcess.Example.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
<ItemGroup>
1313
<PackageReference Include="PInvoke.Kernel32" Version="0.7.104" />
14+
<PackageReference Include="PInvoke.User32" Version="0.7.104" />
1415
</ItemGroup>
1516

1617
<ItemGroup>

CefSharp.OutOfProcess.Example/ChromiumHostControl.cs

Lines changed: 0 additions & 18 deletions
This file was deleted.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using PInvoke;
2+
using System;
3+
using System.Runtime.InteropServices;
4+
5+
namespace CefSharp.OutOfProcess.Example
6+
{
7+
/// <summary>
8+
/// ChromiumWidgetHandleFinder
9+
/// </summary>
10+
public static class ChromiumRenderWidgetHandleFinder
11+
{
12+
/// <summary>
13+
/// EnumWindowProc delegate used by <see cref="EnumChildWindows(IntPtr, EnumWindowProc, IntPtr)"/>
14+
/// </summary>
15+
/// <param name="hwnd">A handle to a child window of the parent window specified in EnumChildWindows</param>
16+
/// <param name="lParam">The application-defined value given in EnumChildWindows</param>
17+
/// <returns>To continue enumeration, the callback function must return true; to stop enumeration, it must return false.</returns>
18+
private delegate bool EnumWindowProc(IntPtr hwnd, IntPtr lParam);
19+
20+
[DllImport("user32")]
21+
[return: MarshalAs(UnmanagedType.Bool)]
22+
private static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr lParam);
23+
24+
/// <summary>
25+
/// Helper function used to find the child HWND with the ClassName matching <paramref name="chromeRenderWidgetHostClassName"/>
26+
/// Chromium's message-loop Window isn't created synchronously, so this may not find it.
27+
/// If so, you need to wait and try again later.
28+
/// In most cases you should use the <see cref="TryFindHandle(IWebBrowser, out IntPtr)"/> overload.
29+
/// </summary>
30+
/// <param name="parent">Parent control Handle</param>
31+
/// <param name="chromeRenderWidgetHostClassName">class name used to match</param>
32+
/// <param name="chromerRenderWidgetHostHandle">Handle of the child HWND with the name</param>
33+
/// <returns>returns true if the HWND was found otherwise false.</returns>
34+
public static bool TryFindHandle(IntPtr parent, string chromeRenderWidgetHostClassName, out IntPtr chromerRenderWidgetHostHandle)
35+
{
36+
var chromeRenderWidgetHostHwnd = IntPtr.Zero;
37+
38+
EnumWindowProc childProc = (IntPtr hWnd, IntPtr lParam) =>
39+
{
40+
var className = User32.GetClassName(hWnd);
41+
42+
if (className == chromeRenderWidgetHostClassName)
43+
{
44+
chromeRenderWidgetHostHwnd = hWnd;
45+
return false;
46+
}
47+
48+
return true;
49+
};
50+
51+
EnumChildWindows(parent, childProc, IntPtr.Zero);
52+
53+
chromerRenderWidgetHostHandle = chromeRenderWidgetHostHwnd;
54+
55+
return chromerRenderWidgetHostHandle != IntPtr.Zero;
56+
}
57+
}
58+
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
using System;
2+
using System.Diagnostics;
3+
using System.Drawing;
4+
using System.Windows.Forms;
5+
using PInvoke;
6+
7+
namespace CefSharp.OutOfProcess.Example
8+
{
9+
public class ChromiumWebBrowser : Control
10+
{
11+
private IntPtr _browserHwnd = IntPtr.Zero;
12+
private Process _browserProces;
13+
14+
/// <summary>
15+
/// The <see cref="Process"/> in which the CEF Browser is actually running.
16+
/// </summary>
17+
public Process BrowserProcess
18+
{
19+
get { return _browserProces; }
20+
}
21+
22+
/// <summary>
23+
/// Gets the default size of the control.
24+
/// </summary>
25+
/// <value>
26+
/// The default <see cref="T:System.Drawing.Size" /> of the control.
27+
/// </value>
28+
protected override Size DefaultSize
29+
{
30+
get { return new Size(200, 100); }
31+
}
32+
33+
protected override void OnHandleCreated(EventArgs e)
34+
{
35+
base.OnHandleCreated(e);
36+
37+
var currentProcess = Process.GetCurrentProcess();
38+
39+
var args = $"--parentProcessId={currentProcess.Id} --hostHwnd={Handle.ToInt32()}";
40+
41+
_browserProces = Process.Start("CefSharp.OutOfProcess.BrowserProcess.exe", args);
42+
}
43+
44+
/// <inheritdoc />
45+
protected override void OnVisibleChanged(EventArgs e)
46+
{
47+
if (Visible)
48+
{
49+
ShowInternal(Width, Height);
50+
}
51+
else
52+
{
53+
HideInternal();
54+
}
55+
56+
base.OnVisibleChanged(e);
57+
}
58+
59+
protected override void OnSizeChanged(EventArgs e)
60+
{
61+
ResizeBrowser(Width, Height);
62+
63+
base.OnSizeChanged(e);
64+
}
65+
66+
/// <summary>
67+
/// Resizes the browser to the specified <paramref name="width"/> and <paramref name="height"/>.
68+
/// If <paramref name="width"/> and <paramref name="height"/> are both 0 then the browser
69+
/// will be hidden and resource usage will be minimised.
70+
/// </summary>
71+
/// <param name="width">width</param>
72+
/// <param name="height">height</param>
73+
protected virtual void ResizeBrowser(int width, int height)
74+
{
75+
if (_browserHwnd == IntPtr.Zero)
76+
{
77+
var result = ChromiumRenderWidgetHandleFinder.TryFindHandle(Handle, "CefBrowserWindow", out var handle);
78+
if (result)
79+
{
80+
_browserHwnd = handle;
81+
}
82+
}
83+
84+
if (_browserHwnd != IntPtr.Zero)
85+
{
86+
if (width == 0 && height == 0)
87+
{
88+
// For windowed browsers when the frame window is minimized set the
89+
// browser window size to 0x0 to reduce resource usage.
90+
HideInternal();
91+
}
92+
else
93+
{
94+
ShowInternal(width, height);
95+
}
96+
}
97+
}
98+
99+
/// <summary>
100+
/// When minimized set the browser window size to 0x0 to reduce resource usage.
101+
/// https://github.com/chromiumembedded/cef/blob/c7701b8a6168f105f2c2d6b239ce3958da3e3f13/tests/cefclient/browser/browser_window_std_win.cc#L87
102+
/// </summary>
103+
internal virtual void HideInternal()
104+
{
105+
if (_browserHwnd != IntPtr.Zero)
106+
{
107+
User32.SetWindowPos(_browserHwnd, IntPtr.Zero, 0, 0, 0, 0, User32.SetWindowPosFlags.SWP_NOZORDER | User32.SetWindowPosFlags.SWP_NOMOVE | User32.SetWindowPosFlags.SWP_NOACTIVATE);
108+
}
109+
}
110+
111+
/// <summary>
112+
/// Show the browser (called after previous minimised)
113+
/// </summary>
114+
internal virtual void ShowInternal(int width, int height)
115+
{
116+
if (_browserHwnd != IntPtr.Zero)
117+
{
118+
User32.SetWindowPos(_browserHwnd, IntPtr.Zero, 0, 0, width, height, User32.SetWindowPosFlags.SWP_NOZORDER);
119+
}
120+
}
121+
}
122+
}

CefSharp.OutOfProcess.Example/HostForm.cs

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System;
2-
using System.Diagnostics;
32
using System.Windows.Forms;
43

54
namespace CefSharp.OutOfProcess.Example
@@ -23,17 +22,10 @@ private void HostFormOResize(object sender, EventArgs e)
2322

2423
private void HostFormOnLoad(object sender, EventArgs e)
2524
{
26-
var host = new ChromiumHostControl();
27-
host.CreateControl();
28-
var hostHwnd = host.Handle;
25+
var browser = new ChromiumWebBrowser();
26+
browser.Dock = DockStyle.Fill;
2927

30-
splitContainer.Panel2.Controls.Add(host);
31-
32-
var currentProcess = Process.GetCurrentProcess();
33-
34-
var args = $"--parentProcessId={currentProcess.Id} --hostHwnd={hostHwnd.ToInt32()}";
35-
36-
var browserProcess = Process.Start("CefSharp.OutOfProcess.BrowserProcess.exe", args);
28+
splitContainer.Panel2.Controls.Add(browser);
3729
}
3830

3931
private void ExitToolStripMenuItemClick(object sender, EventArgs e)

0 commit comments

Comments
 (0)