Skip to content

Commit 79008ae

Browse files
molamaitland
authored andcommitted
WPF - Updated #2779 hack to run asynchronous without crashing. (#2879)
* Updated the issue #2779 hack to run asynchronous without crashing. * Fixed race condition between ChromiumWebBrowser.Dispose and running code on the CEF UI thread.
1 parent 59cdea0 commit 79008ae

File tree

1 file changed

+103
-47
lines changed

1 file changed

+103
-47
lines changed

CefSharp.Wpf/ChromiumWebBrowser.cs

Lines changed: 103 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1756,7 +1756,7 @@ private void PresentationSourceChangedHandler(object sender, SourceChangedEventA
17561756
}
17571757
}
17581758

1759-
private void OnWindowStateChanged(object sender, EventArgs e)
1759+
private async void OnWindowStateChanged(object sender, EventArgs e)
17601760
{
17611761
var window = (Window)sender;
17621762

@@ -1767,33 +1767,54 @@ private void OnWindowStateChanged(object sender, EventArgs e)
17671767
{
17681768
if (previousWindowState == WindowState.Minimized)
17691769
{
1770-
CefUiThreadRunAsync(() =>
1770+
await CefUiThreadRunAsync(async () =>
17711771
{
1772-
if (browser != null)
1772+
var host = browser?.GetHost();
1773+
if (host != null && !host.IsDisposed)
17731774
{
1774-
browser.GetHost().WasHidden(false);
1775+
try
1776+
{
1777+
host.WasHidden(false);
1778+
1779+
await ResizeHackFor2779();
1780+
}
1781+
catch (ObjectDisposedException)
1782+
{
1783+
// Because Dispose runs in another thread there's a race condition between
1784+
// that and this code running on the CEF UI thread, so the host could be disposed
1785+
// between the check and using it. We can either synchronize access using locking
1786+
// (potentially blocking the UI thread in Dispose) or catch the extremely rare
1787+
// exception, which is what we do here
1788+
}
17751789
}
17761790
});
1777-
1778-
ResizeHackFor2779();
17791791
}
17801792

17811793
break;
17821794
}
17831795
case WindowState.Minimized:
17841796
{
1785-
if (EnableResizeHackForIssue2779)
1786-
{
1787-
resizeHackForIssue2779Enabled = true;
1788-
}
1789-
1790-
CefUiThreadRunAsync(() =>
1797+
await CefUiThreadRunAsync(() =>
17911798
{
1792-
if (browser != null)
1799+
var host = browser?.GetHost();
1800+
if (host != null && !host.IsDisposed)
17931801
{
1794-
browser.GetHost().WasHidden(true);
1802+
if (EnableResizeHackForIssue2779)
1803+
{
1804+
resizeHackForIssue2779Enabled = true;
1805+
}
1806+
1807+
try
1808+
{
1809+
host.WasHidden(true);
1810+
}
1811+
catch (ObjectDisposedException)
1812+
{
1813+
// See comment in catch in OnWindowStateChanged
1814+
}
17951815
}
17961816
});
1817+
17971818
break;
17981819
}
17991820
}
@@ -1889,7 +1910,7 @@ internal void UiThreadRunAsync(Action action, DispatcherPriority priority = Disp
18891910
}
18901911
}
18911912

1892-
protected void CefUiThreadRunAsync(Action action)
1913+
protected async Task CefUiThreadRunAsync(Action action)
18931914
{
18941915
if (!IsDisposed && InternalIsBrowserInitialized())
18951916
{
@@ -1899,7 +1920,7 @@ protected void CefUiThreadRunAsync(Action action)
18991920
}
19001921
else
19011922
{
1902-
Cef.UIThreadTaskFactory.StartNew(delegate
1923+
await Cef.UIThreadTaskFactory.StartNew(delegate
19031924
{
19041925
action();
19051926
});
@@ -1929,54 +1950,96 @@ private void UiThreadRunSync(Action action, DispatcherPriority priority = Dispat
19291950
/// </summary>
19301951
/// <param name="sender">The sender.</param>
19311952
/// <param name="e">The <see cref="SizeChangedEventArgs"/> instance containing the event data.</param>
1932-
private void OnActualSizeChanged(object sender, SizeChangedEventArgs e)
1953+
private async void OnActualSizeChanged(object sender, SizeChangedEventArgs e)
19331954
{
19341955
// Initialize RenderClientAdapter when WPF has calculated the actual size of current content.
19351956
CreateOffscreenBrowser(e.NewSize);
19361957

1937-
//NOTE: Previous we used Math.Ceiling to round the sizing up, we
1938-
//now set UseLayoutRounding = true; on the control so the sizes are
1939-
//already rounded to a whole number for us.
1940-
viewRect = new Rect(0, 0, (int)e.NewSize.Width, (int)e.NewSize.Height);
1958+
// If the internal browser isn't initialized then the CEF UI thread is not yet running
1959+
// and so we need to set the view rectangle here because it has to be set.
1960+
var hasSetViewRect = false;
1961+
if (!InternalIsBrowserInitialized())
1962+
{
1963+
SetViewRect(e);
1964+
hasSetViewRect = true;
1965+
}
19411966

1942-
CefUiThreadRunAsync(() =>
1967+
await CefUiThreadRunAsync(() =>
19431968
{
1944-
if (browser != null)
1969+
// If we haven't already set the view rectangle we do it here.
1970+
// If the browser is initialized we need to set this on the CEF UI thread to
1971+
// avoid the crash issue reported here: https://github.com/cefsharp/CefSharp/issues/2779
1972+
if (!hasSetViewRect)
19451973
{
1946-
browser.GetHost().WasResized();
1974+
SetViewRect(e);
1975+
}
1976+
1977+
var host = browser?.GetHost();
1978+
if (host != null && !host.IsDisposed)
1979+
{
1980+
try
1981+
{
1982+
host.WasResized();
1983+
}
1984+
catch (ObjectDisposedException)
1985+
{
1986+
// See comment in catch in OnWindowStateChanged
1987+
}
19471988
}
19481989
});
19491990
}
19501991

1992+
private void SetViewRect(SizeChangedEventArgs e)
1993+
{
1994+
//NOTE: Previous we used Math.Ceiling to round the sizing up, we
1995+
//now set UseLayoutRounding = true; on the control so the sizes are
1996+
//already rounded to a whole number for us.
1997+
viewRect = new Rect(0, 0, (int)e.NewSize.Width, (int)e.NewSize.Height);
1998+
}
1999+
19512000
/// <summary>
19522001
/// Handles the <see cref="E:IsVisibleChanged" /> event.
19532002
/// </summary>
19542003
/// <param name="sender">The sender.</param>
19552004
/// <param name="args">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
1956-
private void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs args)
2005+
private async void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs args)
19572006
{
19582007
var isVisible = (bool)args.NewValue;
19592008

19602009
if (browser != null)
19612010
{
1962-
CefUiThreadRunAsync(() =>
2011+
await CefUiThreadRunAsync(async () =>
19632012
{
1964-
if (browser != null)
2013+
var host = browser?.GetHost();
2014+
if (host != null && !host.IsDisposed)
19652015
{
1966-
browser.GetHost().WasHidden(!isVisible);
2016+
try
2017+
{
2018+
host.WasHidden(!isVisible);
2019+
2020+
if (isVisible)
2021+
{
2022+
await ResizeHackFor2779();
2023+
}
2024+
else if (EnableResizeHackForIssue2779)
2025+
{
2026+
resizeHackForIssue2779Enabled = true;
2027+
}
2028+
}
2029+
catch (ObjectDisposedException)
2030+
{
2031+
// See comment in catch in OnWindowStateChanged
2032+
}
19672033
}
19682034
});
19692035

1970-
1971-
if (isVisible)
2036+
if (browser != null)
19722037
{
1973-
ResizeHackFor2779();
1974-
19752038
//Fix for #1778 - When browser becomes visible we update the zoom level
19762039
//browsers of the same origin will share the same zoomlevel and
19772040
//we need to track the update, so our ZoomLevelProperty works
19782041
//properly
1979-
browser.GetHost().GetZoomLevelAsync().ContinueWith(t =>
2042+
await browser.GetHost().GetZoomLevelAsync().ContinueWith(t =>
19802043
{
19812044
if (!IsDisposed)
19822045
{
@@ -1987,10 +2050,6 @@ private void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArg
19872050
TaskContinuationOptions.OnlyOnRanToCompletion,
19882051
TaskScheduler.FromCurrentSynchronizationContext());
19892052
}
1990-
else if (EnableResizeHackForIssue2779)
1991-
{
1992-
resizeHackForIssue2779Enabled = true;
1993-
}
19942053
}
19952054
}
19962055

@@ -2442,33 +2501,30 @@ protected bool InternalIsBrowserInitialized()
24422501
return Interlocked.CompareExchange(ref browserInitialized, 0, 0) == 1;
24432502
}
24442503

2445-
private void ResizeHackFor2779()
2504+
private async Task ResizeHackFor2779()
24462505
{
24472506
if (EnableResizeHackForIssue2779)
24482507
{
24492508
const int delayInMs = 50;
24502509

2451-
CefUiThreadRunAsync(async () =>
2510+
var host = browser?.GetHost();
2511+
if (host != null && !host.IsDisposed)
24522512
{
2453-
if (browser != null)
2454-
{
2455-
resizeHackForIssue2779Size = new Structs.Size(viewRect.Width - 1, viewRect.Height - 1);
2456-
browser.GetHost().WasResized();
2457-
}
2513+
resizeHackForIssue2779Size = new Structs.Size(viewRect.Width - 1, viewRect.Height - 1);
2514+
host.WasResized();
24582515

24592516
await Task.Delay(delayInMs);
24602517

2461-
if (browser != null)
2518+
if (!host.IsDisposed)
24622519
{
2463-
var host = browser.GetHost();
24642520
resizeHackForIssue2779Size = null;
24652521
host.WasResized();
24662522

24672523
resizeHackForIssue2779Enabled = false;
24682524

24692525
host.Invalidate(PaintElementType.View);
24702526
}
2471-
});
2527+
}
24722528
}
24732529
}
24742530
}

0 commit comments

Comments
 (0)