@@ -4,39 +4,41 @@ browser process exit. Manually waiting for the process to exit requires
44additional work on the host app, so we are proposing the ` BrowserProcessExited `
55event. The ` ProcessFailed ` event already lets app developers handle unexpected
66browser process exits for a WebView, this new API lets you listen to both
7- expected and unexpected termination of the processes associated to an
7+ expected and unexpected termination of the browser process associated to an
88environment from the ` ICoreWebView2Environment3 ` interface so you can, e.g.,
99cleanup the user data folder when it's no longer in use. In this document we
1010describe the new API. We'd appreciate your feedback.
1111
1212
1313# Description
1414The ` BrowserProcessExited ` event allows developers to subscribe event handlers
15- to be run when the WebView2 Runtime processes (including the browser process)
16- associated to a ` CoreWebView2Environment ` terminate. Key scenarios are cleanup
17- of the user data folder used by the WebView2 Runtime, which is locked while the
18- runtime's browser process is active, and moving to a new WebView2 Runtime
19- version after a ` NewBrowserVersionAvailable ` event.
15+ to be run when the WebView2 Runtime browser process associated to the
16+ ` CoreWebView2Environment ` terminates. If the browser process terminates before
17+ its associated processes, the ` BrowserProcessExited ` event is not raised until
18+ all the associated processes have also terminated. Key scenarios for this event
19+ are cleanup of the user data folder used by the WebView2 Runtime, which is
20+ locked while the runtime's browser process is active, and moving to a new
21+ WebView2 Runtime version after a ` NewBrowserVersionAvailable ` event.
2022
2123This event is raised for both expected and unexpected browser process
2224termination, after all resources, including the user data folder, used by the
2325browser process (and related processes) have been released. The
2426` ICoreWebView2BrowserProcessExitedEventArgs ` interface lets app developers get
2527the ` BrowserProcessExitKind ` so they can decide how to handle different exit
26- kinds or bypass handling if an event handler for the ` CoreWebView2 ` s
27- ` ProcessFailed ` event (for ` CoreWebView2ProcessFailedKind.BrowserProcessFailed ` )
28- is already registered. In case of a browser process crash, both
29- ` BrowserProcessExited ` and ` ProcessFailed ` events are raised, but the order is
30- not guaranteed.
31-
32- All ` CoreWebView2Environment ` objects across different app processes that use
33- the same browser process receive this event when the browser process (and
34- associated processes) exits. If the browser process (and therefore the user data
35- folder) in use by the app process (through the ` CoreWebView2Environment ` options
36- used) is shared with other processes, these processes need to coordinate to
37- handle the potential race condition on the use of the resources. E.g., if one
38- app process tries to clear the user data folder, while other tries to recreate
39- its WebViews on crash.
28+ kinds. For example, you might want to bypass handling if an event handler for
29+ the ` CoreWebView2 ` s ` ProcessFailed ` event
30+ (for ` CoreWebView2ProcessFailedKind.BrowserProcessFailed ` ) is already
31+ registered. In case of a browser process crash, both ` BrowserProcessExited ` and
32+ ` ProcessFailed ` events are raised, but the order is not guaranteed.
33+
34+ Multiple app processes can share a single browser process by creating their
35+ ` CoreWebView2Environment ` with the same user data folder. When that shared
36+ browser process (and its associated processes) exits, all associated
37+ ` CoreWebview2Environment ` objects receive the ` BrowserProcessExited ` event.
38+ Multiple processes sharing the same browser process need to coordinate their use
39+ of the shared user data folder to avoid race conditions. For example, one
40+ process should not clear the user data folder at the same time that another
41+ process recovers from the crash by recreating its WebView controls .
4042
4143
4244# Examples
@@ -45,34 +47,44 @@ be used:
4547
4648## Win32 C++
4749``` cpp
48- // Before closing the WebView, register a handler with code to run once the
49- // browser process is terminated.
50- EventRegistrationToken browserExitedEventToken;
51-
52- CHECK_FAILURE (m_webViewEnvironment->add_BrowserProcessExited(
53- Callback<ICoreWebView2BrowserProcessExitedEventHandler >(
54- [ browserExitedEventToken, this] (
55- ICoreWebView2Environment* sender,
56- ICoreWebView2BrowserProcessExitedEventArgs* args) {
57- COREWEBVIEW2_BROWSER_PROCESS_EXIT_KIND kind;
58- CHECK_FAILURE(args->get_BrowserProcessExitKind(&kind));
59-
60- // Watch for graceful browser process exit. Let ProcessFailed event
61- // handler take care of failed browser process termination.
62- if (kind == COREWEBVIEW2_BROWSER_PROCESS_EXIT_KIND_NORMAL)
63- {
64- CHECK_FAILURE(
65- m_webViewEnvironment->remove_BrowserProcessExited(browserExitedEventToken));
66- // Release the environment only after the handler is invoked.
67- // Otherwise, there will be no environment to raise the event when
68- // the process exits.
69- m_webViewEnvironment = nullptr;
70- CleanupUserDataFolder();
71- }
50+ class MyApp {
51+ // ...
52+ EventRegistrationToken m_browserExitedEventToken = {};
53+ }
7254
73- return S_OK;
74- }).Get(),
75- &browserExitedEventToken));
55+ void MyApp::CloseWebViewAndCleanup {
56+ // Before closing the WebView, register a handler with code to run once the
57+ // browser process is terminated.
58+ CHECK_FAILURE(m_webViewEnvironment->add_BrowserProcessExited(
59+ Callback<ICoreWebView2BrowserProcessExitedEventHandler >(
60+ [ this] (
61+ ICoreWebView2Environment* sender,
62+ ICoreWebView2BrowserProcessExitedEventArgs* args) {
63+ COREWEBVIEW2_BROWSER_PROCESS_EXIT_KIND kind;
64+ CHECK_FAILURE(args->get_BrowserProcessExitKind(&kind));
65+
66+ // Watch for graceful browser process exit. Let ProcessFailed event
67+ // handler take care of failed browser process termination.
68+ if (kind == COREWEBVIEW2_BROWSER_PROCESS_EXIT_KIND_NORMAL)
69+ {
70+ CHECK_FAILURE(
71+ m_webViewEnvironment->remove_BrowserProcessExited(m_browserExitedEventToken));
72+ // Release the environment only after the handler is invoked.
73+ // Otherwise, there will be no environment to raise the event when
74+ // the process exits.
75+ m_webViewEnvironment = nullptr;
76+ CleanupUserDataFolder();
77+ }
78+
79+ return S_OK;
80+ }).Get(),
81+ &m_browserExitedEventToken));
82+
83+ // Close the WebView through ICoreWebView2Controller
84+ CHECK_FAILURE (m_controller->Close());
85+
86+ // Other app state cleanup...
87+ }
7688```
7789
7890## .NET C#
@@ -82,40 +94,59 @@ private Uri _uriToRestore;
8294
8395async void RegisterForNewVersion()
8496{
85- // We need to make sure the CoreWebView2 property is not null, so we can get
86- // the environment from it. Alternatively, if the WebView was created from
87- // an environment provided to the control, we can use that environment
88- // object directly.
97+ // We call `EnsureCoreWebiew2Async` so the ` CoreWebView2` property is
98+ // initialized and not null as we will access the environment from it.
99+ // Alternatively, if the WebView was created from an environment provided to
100+ // the control, we can use that environment object directly.
89101 await webView.EnsureCoreWebView2Async();
90102 _coreWebView2Environment = webView.CoreWebView2.Environment;
91103 _coreWebView2Environment.NewBrowserVersionAvailable += Environment_NewBrowserVersionAvailable;
92104}
93105
94106// A new version of the WebView2 Runtime is available, our handler gets called.
95- // We close our WebView and set a handler to reinitialize it once the browser
96- // process is gone, so we get the new version of the WebView2 Runtime.
97- void Environment_NewBrowserVersionAvailable(object sender, object e)
107+ // We close all app WebViews and set handlers to reinitialize them once the
108+ // browser process is gone, so we get the new version of the WebView2 Runtime.
109+ async void Environment_NewBrowserVersionAvailable(CoreWebView2Environment sender, object e)
98110{
99111 StringBuilder messageBuilder = new StringBuilder(256);
100112 messageBuilder.Append("We detected there is a new version of the WebView2 Runtime installed. ");
101113 messageBuilder.Append("Do you want to switch to it now? This will re-create the WebView.");
102114 var selection = MessageBox.Show(this, messageBuilder.ToString(), "New WebView2 Runtime detected", MessageBoxButton.YesNo);
103115 if (selection == MessageBoxResult.Yes)
104116 {
105- // Save URI or other state you want to restore when the WebView is recreated.
106- _uriToRestore = webView.Source;
107- _coreWebView2Environment.BrowserProcessExited += Environment_BrowserProcessExited;
108- // We dispose of the control so the internal WebView objects are released
109- // and the associated browser process exits. If there are any other WebViews
110- // from the same environment configuration, they need to be closed too.
111- webView.Dispose();
112- webView = null;
117+ // If this or any other application creates additional WebViews from the same
118+ // environment configuration, all those WebViews need to be closed before
119+ // the browser process will exit. This sample creates a single WebView per
120+ // MainWindow, we let each MainWindow prepare to recreate and close its WebView.
121+ CloseAppWebViewsForUpdate();
113122 }
114123}
115124
116- void Environment_BrowserProcessExited(object sender, CoreWebView2BrowserProcessExitedEventArgs e )
125+ void CloseAppWebViewsForUpdate( )
117126{
118- ((CoreWebView2Environment)sender).BrowserProcessExited -= Environment_BrowserProcessExited;
127+ foreach (Window window in Application.Current.Windows)
128+ {
129+ if (window is MainWindow mainWindow)
130+ {
131+ mainWindow.CloseWebViewForUpdate();
132+ }
133+ }
134+ }
135+
136+ void CloseWebViewForUpdate()
137+ {
138+ // Save URI or other state you want to restore when the WebView is recreated.
139+ _uriToRestore = webView.Source;
140+ _coreWebView2Environment.BrowserProcessExited += Environment_BrowserProcessExited;
141+ // We dispose of the control so the internal WebView objects are released
142+ // and the associated browser process exits.
143+ webView.Dispose();
144+ webView = null;
145+ }
146+
147+ void Environment_BrowserProcessExited(CoreWebView2Environment sender, CoreWebView2BrowserProcessExitedEventArgs e)
148+ {
149+ sender.BrowserProcessExited -= Environment_BrowserProcessExited;
119150 ReinitializeWebView();
120151}
121152
@@ -137,7 +168,7 @@ void ReinitializeWebView()
137168 url.SetBinding(TextBox.TextProperty, urlBinding);
138169
139170 MyWindow.MyDockPanel.Children.Add(webView);
140- webView.Source = ( _uriToRestore != null) ? _uriToRestore : new Uri("https://www.bing.com");
171+ webView.Source = _uriToRestore ?? new Uri("https://www.bing.com");
141172 RegisterForNewVersion();
142173}
143174```
@@ -197,13 +228,17 @@ interface ICoreWebView2Environment3 : ICoreWebView2Environment2
197228 /// this environment after earlier ` BrowserProcessExited ` events are raised.
198229 ///
199230 /// All ` CoreWebView2Environment ` objects across different app processes that use
200- /// the same browser process receive this event when the browser process (and
201- /// associated processes) exits. If the browser process (and therefore the user data
202- /// folder) in use by the app process (through the ` CoreWebView2Environment ` options
203- /// used) is shared with other processes, these processes need to coordinate to
204- /// handle the potential race condition on the use of the resources. E.g., if one
205- /// app process tries to clear the user data folder, while other tries to recreate
206- /// its WebViews on crash.
231+ /// the same browser process receive this event when the browser process exits.
232+ /// If the browser process terminates before its associated processes, the
233+ /// ` BrowserProcessExited ` event is not raised until all the associated processes
234+ /// have also terminated.
235+ ///
236+ /// Multiple app processes can share a single browser process by creating their
237+ /// ` CoreWebView2Environment ` with the same user data folder. These processes
238+ /// sharing the same browser process need to coordinate their use of the shared
239+ /// user data folder to avoid race conditions. For example, one process should
240+ /// not clear the user data folder at the same time that another process recovers
241+ /// from the crash by recreating its WebView controls.
207242 ///
208243 /// Note this is an event from the ` ICoreWebView2Environment3 ` interface, not the
209244 /// ` ICoreWebView2 ` . The difference between this ` BrowserProcessExited ` event and
@@ -273,13 +308,17 @@ namespace Microsoft.Web.WebView2.Core
273308 /// been released.
274309 ///
275310 /// All `CoreWebView2Environment` objects across different app processes that use
276- /// the same browser process receive this event when the browser process (and
277- /// associated processes) exits. If the browser process (and therefore the user data
278- /// folder) in use by the app process (through the `CoreWebView2Environment` options
279- /// used) is shared with other processes, these processes need to coordinate to
280- /// handle the potential race condition on the use of the resources. E.g., if one
281- /// app process tries to clear the user data folder, while other tries to recreate
282- /// its WebViews on crash.
311+ /// the same browser process receive this event when the browser process exits.
312+ /// If the browser process terminates before its associated processes, the
313+ /// `BrowserProcessExited` event is not raised until all the associated processes
314+ /// have also terminated.
315+ ///
316+ /// Multiple app processes can share a single browser process by creating their
317+ /// `CoreWebView2Environment` with the same user data folder. These processes
318+ /// sharing the same browser process need to coordinate their use of the shared
319+ /// user data folder to avoid race conditions. For example, one process should
320+ /// not clear the user data folder at the same time that another process recovers
321+ /// from the crash by recreating its WebView controls.
283322 ///
284323 /// Note this is an event from the `ICoreWebView2Environment3` interface, not the
285324 /// `ICoreWebView2`. The difference between this `BrowserProcessExited` event and
0 commit comments