Skip to content

Commit c3bbd37

Browse files
authored
Reorder dispose pattern in ChromiumWebBrowser (#2701)
* WinForms/Wpf/OffScreen - Reorder Dispose methods - Set browser initialized to false - Release event handlers - Dispose managedCefBrowserAdapter - Set handlers to null * WinForms/WPF/OffScreen - Set Handlers to null immediately after event handlers cleared The one exception is LifeSpanHandler which is released after managedCefBrowserAdapter.Dispose
1 parent ba008ee commit c3bbd37

File tree

4 files changed

+62
-51
lines changed

4 files changed

+62
-51
lines changed

CefSharp.OffScreen/ChromiumWebBrowser.cs

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -353,15 +353,8 @@ protected virtual void Dispose(bool disposing)
353353

354354
if (disposing)
355355
{
356-
browser = null;
357356
IsBrowserInitialized = false;
358357

359-
if (managedCefBrowserAdapter != null)
360-
{
361-
managedCefBrowserAdapter.Dispose();
362-
managedCefBrowserAdapter = null;
363-
}
364-
365358
// Don't reference event listeners any longer:
366359
AddressChanged = null;
367360
BrowserInitialized = null;
@@ -374,10 +367,21 @@ protected virtual void Dispose(bool disposing)
374367
StatusMessage = null;
375368
TitleChanged = null;
376369

377-
// Release reference to handlers, make sure this is done after we dispose managedCefBrowserAdapter
378-
// otherwise the ILifeSpanHandler.DoClose will not be invoked. (More important in the WinForms version,
379-
// we do it here for consistency)
380-
this.SetHandlersToNull();
370+
// Release reference to handlers, except LifeSpanHandler which is done after Disposing
371+
// ManagedCefBrowserAdapter otherwise the ILifeSpanHandler.DoClose will not be invoked.
372+
this.SetHandlersToNullExceptLifeSpan();
373+
374+
browser = null;
375+
376+
if (managedCefBrowserAdapter != null)
377+
{
378+
managedCefBrowserAdapter.Dispose();
379+
managedCefBrowserAdapter = null;
380+
}
381+
382+
// LifeSpanHandler is set to null after managedCefBrowserAdapter.Dispose so ILifeSpanHandler.DoClose
383+
// is called.
384+
LifeSpanHandler = null;
381385
}
382386

383387
Cef.RemoveDisposable(this);

CefSharp.WinForms/ChromiumWebBrowser.cs

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -485,34 +485,38 @@ private void InternalDispose(bool disposing)
485485
{
486486
IsBrowserInitialized = false;
487487

488+
// Don't maintain a reference to event listeners anylonger:
489+
AddressChanged = null;
490+
ConsoleMessage = null;
491+
FrameLoadEnd = null;
492+
FrameLoadStart = null;
493+
IsBrowserInitializedChanged = null;
494+
LoadError = null;
495+
LoadingStateChanged = null;
496+
StatusMessage = null;
497+
TitleChanged = null;
498+
499+
// Release reference to handlers, except LifeSpanHandler which is done after Disposing
500+
// ManagedCefBrowserAdapter otherwise the ILifeSpanHandler.DoClose will not be invoked.
501+
this.SetHandlersToNullExceptLifeSpan();
502+
488503
browser = null;
489504

490505
if (parentFormMessageInterceptor != null)
491506
{
492507
parentFormMessageInterceptor.Dispose();
493508
parentFormMessageInterceptor = null;
494509
}
495-
510+
496511
if (managedCefBrowserAdapter != null)
497512
{
498513
managedCefBrowserAdapter.Dispose();
499514
managedCefBrowserAdapter = null;
500515
}
501516

502-
// Don't maintain a reference to event listeners anylonger:
503-
AddressChanged = null;
504-
ConsoleMessage = null;
505-
FrameLoadEnd = null;
506-
FrameLoadStart = null;
507-
IsBrowserInitializedChanged = null;
508-
LoadError = null;
509-
LoadingStateChanged = null;
510-
StatusMessage = null;
511-
TitleChanged = null;
512-
513-
// Release reference to handlers, make sure this is done after we dispose managedCefBrowserAdapter
514-
// otherwise the ILifeSpanHandler.DoClose will not be invoked.
515-
this.SetHandlersToNull();
517+
// LifeSpanHandler is set to null after managedCefBrowserAdapter.Dispose so ILifeSpanHandler.DoClose
518+
// is called.
519+
LifeSpanHandler = null;
516520
}
517521

518522
Cef.RemoveDisposable(this);

CefSharp.Wpf/ChromiumWebBrowser.cs

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,29 @@ private void InternalDispose(bool disposing)
591591
{
592592
if (disposing)
593593
{
594+
Interlocked.Exchange(ref browserInitialized, 0);
595+
596+
UiThreadRunAsync(() =>
597+
{
598+
SetCurrentValue(IsBrowserInitializedProperty, false);
599+
WebBrowser = null;
600+
});
601+
602+
// No longer reference event listeners:
603+
ConsoleMessage = null;
604+
FrameLoadEnd = null;
605+
FrameLoadStart = null;
606+
IsBrowserInitializedChanged = null;
607+
LoadError = null;
608+
LoadingStateChanged = null;
609+
Paint = null;
610+
StatusMessage = null;
611+
TitleChanged = null;
612+
613+
// Release reference to handlers, except LifeSpanHandler which is done after Disposing
614+
// ManagedCefBrowserAdapter otherwise the ILifeSpanHandler.DoClose will not be invoked.
615+
this.SetHandlersToNullExceptLifeSpan();
616+
594617
browser = null;
595618

596619
// Incase we accidentally have a reference to the CEF drag data
@@ -599,7 +622,7 @@ private void InternalDispose(bool disposing)
599622
currentDragData.Dispose();
600623
currentDragData = null;
601624
}
602-
625+
603626
PresentationSource.RemoveSourceChangedHandler(this, PresentationSourceChangedHandler);
604627
// Release window event listeners if PresentationSourceChangedHandler event wasn't
605628
// fired before Dispose
@@ -642,28 +665,9 @@ private void InternalDispose(bool disposing)
642665
managedCefBrowserAdapter = null;
643666
}
644667

645-
Interlocked.Exchange(ref browserInitialized, 0);
646-
UiThreadRunAsync(() =>
647-
{
648-
SetCurrentValue(IsBrowserInitializedProperty, false);
649-
WebBrowser = null;
650-
});
651-
652-
// No longer reference event listeners:
653-
ConsoleMessage = null;
654-
FrameLoadEnd = null;
655-
FrameLoadStart = null;
656-
IsBrowserInitializedChanged = null;
657-
LoadError = null;
658-
LoadingStateChanged = null;
659-
Paint = null;
660-
StatusMessage = null;
661-
TitleChanged = null;
662-
663-
// Release reference to handlers, make sure this is done after we dispose managedCefBrowserAdapter
664-
// otherwise the ILifeSpanHandler.DoClose will not be invoked. (More important in the WinForms version,
665-
// we do it here for consistency)
666-
this.SetHandlersToNull();
668+
// LifeSpanHandler is set to null after managedCefBrowserAdapter.Dispose so ILifeSpanHandler.DoClose
669+
// is called.
670+
LifeSpanHandler = null;
667671

668672
WpfKeyboardHandler.Dispose();
669673

CefSharp/Internals/InternalWebBrowserExtensions.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,12 @@ namespace CefSharp.Internals
66
{
77
internal static class InternalWebBrowserExtensions
88
{
9-
internal static void SetHandlersToNull(this IWebBrowserInternal browser)
9+
internal static void SetHandlersToNullExceptLifeSpan(this IWebBrowserInternal browser)
1010
{
1111
browser.DialogHandler = null;
1212
browser.RequestHandler = null;
1313
browser.DisplayHandler = null;
1414
browser.LoadHandler = null;
15-
browser.LifeSpanHandler = null;
1615
browser.KeyboardHandler = null;
1716
browser.JsDialogHandler = null;
1817
browser.DragHandler = null;

0 commit comments

Comments
 (0)