@@ -23,13 +23,330 @@ The following code snippets demonstrate how the `ProcessFailedEventArgs2` can be
2323
2424## Win32 C++
2525``` cpp
26+ // Get a string for the failure kind enum value.
27+ std::wstring ProcessComponent::ProcessFailedKindToString (
28+ const COREWEBVIEW2_PROCESS_FAILED_KIND kind)
29+ {
30+ switch (kind)
31+ {
32+ #define KIND_ENTRY(kindValue) \
33+ case kindValue: \
34+ return L#kindValue;
35+
36+ KIND_ENTRY(COREWEBVIEW2_PROCESS_FAILED_KIND_BROWSER_PROCESS_EXITED);
37+ KIND_ENTRY(COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_EXITED);
38+ KIND_ENTRY(COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_UNRESPONSIVE);
39+ KIND_ENTRY(COREWEBVIEW2_PROCESS_FAILED_KIND_FRAME_RENDER_PROCESS_EXITED);
40+ KIND_ENTRY(COREWEBVIEW2_PROCESS_FAILED_KIND_UTILITY_PROCESS_EXITED);
41+ KIND_ENTRY(COREWEBVIEW2_PROCESS_FAILED_KIND_SANDBOX_HELPER_PROCESS_EXITED);
42+ KIND_ENTRY(COREWEBVIEW2_PROCESS_FAILED_KIND_GPU_PROCESS_EXITED);
43+ KIND_ENTRY(COREWEBVIEW2_PROCESS_FAILED_KIND_PPAPI_PLUGIN_PROCESS_EXITED);
44+ KIND_ENTRY(COREWEBVIEW2_PROCESS_FAILED_KIND_PPAPI_BROKER_PROCESS_EXITED);
45+ KIND_ENTRY(COREWEBVIEW2_PROCESS_FAILED_KIND_UNKNOWN_PROCESS_EXITED);
46+
47+ #undef KIND_ENTRY
48+ }
49+
50+ return L"PROCESS_FAILED";
51+ }
52+
53+ // Get a string for the failure reason enum value.
54+ std::wstring ProcessComponent::ProcessFailedReasonToString(
55+ const COREWEBVIEW2_PROCESS_FAILED_REASON reason)
56+ {
57+ switch (reason)
58+ {
59+ #define REASON_ENTRY(reasonValue) \
60+ case reasonValue: \
61+ return L#reasonValue;
62+
63+ REASON_ENTRY(COREWEBVIEW2_PROCESS_FAILED_REASON_UNEXPECTED);
64+ REASON_ENTRY(COREWEBVIEW2_PROCESS_FAILED_REASON_UNRESPONSIVE);
65+ REASON_ENTRY(COREWEBVIEW2_PROCESS_FAILED_REASON_KILLED);
66+ REASON_ENTRY(COREWEBVIEW2_PROCESS_FAILED_REASON_CRASHED);
67+ REASON_ENTRY(COREWEBVIEW2_PROCESS_FAILED_REASON_LAUNCH_FAILED);
68+ REASON_ENTRY(COREWEBVIEW2_PROCESS_FAILED_REASON_OUT_OF_MEMORY);
69+
70+ #undef REASON_ENTRY
71+ }
72+
73+ return L"REASON";
74+ }
75+
76+ //! [ ProcessFailed]
77+ // Register a handler for the ProcessFailed event.
78+ // This handler checks the failure kind and tries to:
79+ // * Recreate the webview for browser failure and render unresponsive.
80+ // * Reload the webview for render failure.
81+ // * Reload the webview for frame-only render failure impacting app content.
82+ // * Log information about the failure for other failures.
83+ CHECK_FAILURE(m_webView->add_ProcessFailed(
84+ Callback<ICoreWebView2ProcessFailedEventHandler >(
85+ [ this] (ICoreWebView2* sender, ICoreWebView2ProcessFailedEventArgs* argsRaw)
86+ -> HRESULT {
87+ wil::com_ptr<ICoreWebView2ProcessFailedEventArgs > args = argsRaw;
88+ COREWEBVIEW2_PROCESS_FAILED_KIND failureKind;
89+ CHECK_FAILURE(args->get_ProcessFailedKind(&failureKind));
90+ if (failureKind == COREWEBVIEW2_PROCESS_FAILED_KIND_BROWSER_PROCESS_EXITED)
91+ {
92+ int button = MessageBox(
93+ m_appWindow->GetMainWindow(),
94+ L"Browser process exited unexpectedly. Recreate webview?",
95+ L"Browser process exited", MB_YESNO);
96+ if (button == IDYES)
97+ {
98+ m_appWindow->ReinitializeWebView();
99+ }
100+ }
101+ else if (failureKind == COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_UNRESPONSIVE)
102+ {
103+ int button = MessageBox(
104+ m_appWindow->GetMainWindow(),
105+ L"Browser render process has stopped responding. Recreate webview?",
106+ L"Web page unresponsive", MB_YESNO);
107+ if (button == IDYES)
108+ {
109+ m_appWindow->ReinitializeWebView();
110+ }
111+ }
112+ else if (failureKind == COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_EXITED)
113+ {
114+ int button = MessageBox(
115+ m_appWindow->GetMainWindow(),
116+ L"Browser render process exited unexpectedly. Reload page?",
117+ L"Web page unresponsive", MB_YESNO);
118+ if (button == IDYES)
119+ {
120+ CHECK_FAILURE(m_webView->Reload());
121+ }
122+ }
123+
124+ // Check the runtime event args implements the newer interface.
125+ auto args2 =
126+ args.try_query<ICoreWebView2ProcessFailedEventArgs2>();
127+ if (!args2)
128+ {
129+ return S_OK;
130+ }
131+
132+ if (failureKind ==
133+ COREWEBVIEW2_PROCESS_FAILED_KIND_FRAME_RENDER_PROCESS_EXITED)
134+ {
135+ // A frame-only renderer has exited unexpectedly. Check if reload is needed.
136+ wil::com_ptr<ICoreWebView2FrameInfoCollection> impactedFrames;
137+ wil::com_ptr<ICoreWebView2FrameInfoCollectionIterator> iterator;
138+ CHECK_FAILURE(args2->get_ImpactedFramesInfo(&impactedFrames));
139+ CHECK_FAILURE(impactedFrames->GetIterator(&iterator));
140+
141+ BOOL hasCurrent = FALSE;
142+ while (SUCCEEDED(iterator->HasCurrentFrameInfo(&hasCurrent)) && hasCurrent)
143+ {
144+ wil::com_ptr<ICoreWebView2FrameInfo> frameInfo;
145+ CHECK_FAILURE(iterator->GetCurrentFrameInfo(&frameInfo));
146+
147+ wil::unique_cotaskmem_string nameRaw;
148+ wil::unique_cotaskmem_string sourceRaw;
149+ CHECK_FAILURE(frameInfo->get_Name(&nameRaw));
150+ CHECK_FAILURE(frameInfo->get_Source(&sourceRaw));
151+ std::wstring source = sourceRaw.get();
152+
153+ // Content from our app uses a mapped host name.
154+ const std::wstring mappedAppHostName = L"https://appassets.example/";
155+ if (source.compare(0, mappedAppHostName.length(), mappedAppHostName) == 0)
156+ {
157+ int button = MessageBox(
158+ m_appWindow->GetMainWindow(),
159+ L"Browser render process for app frame exited unexpectedly. "
160+ L"Reload page?",
161+ L"App content frame unresponsive", MB_YESNO);
162+ if (button == IDYES)
163+ {
164+ CHECK_FAILURE(m_webView->Reload());
165+ }
166+ break;
167+ }
168+
169+ BOOL hasNext = FALSE;
170+ CHECK_FAILURE(iterator->MoveNext(&hasNext));
171+ }
172+ }
173+ else
174+ {
175+ // Show the process failure details. Apps can collect info for their logging
176+ // purposes.
177+ COREWEBVIEW2_PROCESS_FAILED_REASON reason;
178+ wil::unique_cotaskmem_string processDescription;
179+ int exitCode;
180+
181+ CHECK_FAILURE(args2->get_Reason(&reason));
182+ CHECK_FAILURE(args2->get_ProcessDescription(&processDescription));
183+ CHECK_FAILURE(args2->get_ExitCode(&exitCode));
184+
185+ std::wstringstream message;
186+ message << L"Process kind:\t" << ProcessFailedKindToString(failureKind) << L"\n"
187+ << L"Reason:\t" << ProcessFailedReasonToString(reason) << L"\n"
188+ << L"Exit code:\t" << std::to_wstring(exitCode) << L"\n"
189+ << L"Process description:\t" << processDescription.get() << std::endl;
190+ MessageBox(
191+ m_appWindow->GetMainWindow(), message.str().c_str(),
192+ L"Child process failed", MB_OK);
193+ }
194+ return S_OK;
195+ })
196+ .Get(),
197+ &m_processFailedToken));
198+ //! [ ProcessFailed]
199+
26200```
27201
28202## .NET C#
29203```xml
204+ <Window x:Class="WebView2WpfBrowser.MainWindow"
205+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
206+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
207+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
208+ xmlns:wv2="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
209+ xmlns:local="clr-namespace:WebView2WpfBrowser"
210+ x:Name="MyWindow"
211+ Title="MainWindow"
212+ Height="450"
213+ Width="800"
214+ >
215+
216+ <!-- ... -->
217+
218+ <DockPanel
219+ x:Name="MyDockPanel"
220+ >
221+ <!-- ... -->
222+
223+ <DockPanel DockPanel.Dock="Top">
224+
225+ <!-- ... -->
226+
227+ <TextBox x:Name="url" Text="{Binding ElementName=webView,Path=Source,Mode=OneWay}">
228+ <TextBox.InputBindings>
229+ <KeyBinding Key="Return" Command="NavigationCommands.GoToPage" CommandParameter="{Binding ElementName=url,Path=Text}" />
230+ </TextBox.InputBindings>
231+ </TextBox>
232+ </DockPanel>
233+
234+ <wv2:WebView2
235+ x:Name="webView"
236+ CreationProperties="{StaticResource EvergreenWebView2CreationProperties}"
237+ Source="https://www.bing.com/"
238+ NavigationStarting="WebView_NavigationStarting"
239+ NavigationCompleted="WebView_NavigationCompleted"
240+ />
241+ </DockPanel>
242+ </Window>
243+
30244```
31245
32246``` c#
247+ // This re-instantiates the control and attaches properties as set in the XAML
248+ // element. Replace once the control has reinit/uninitialize logic.
249+ void ReinitializeWebView ()
250+ {
251+ webView = new WebView2 ();
252+
253+ // Restore URI and other WebView state/setup.
254+ webView .CreationProperties = (CoreWebView2CreationProperties )this .FindResource (" EvergreenWebView2CreationProperties" );
255+ webView .NavigationStarting += WebView_NavigationStarting ;
256+ webView .NavigationCompleted += WebView_NavigationCompleted ;
257+
258+ Binding urlBinding = new Binding ()
259+ {
260+ Source = webView ,
261+ Path = new PropertyPath (" Source" ),
262+ Mode = BindingMode .OneWay
263+ };
264+ url .SetBinding (TextBox .TextProperty , urlBinding );
265+
266+ MyDockPanel .Children .Add (webView );
267+ webView .Source = _uriToRestore ?? new Uri (" https://www.bing.com" );
268+ }
269+
270+ async void WebView_ProcessFailed (CoreWebView2 sender , CoreWebView2ProcessFailedEventArgs e )
271+ {
272+ void AskForReinit (string message , string caption )
273+ {
274+ // Save URI or other state you want to restore when the WebView is recreated.
275+ _uriToRestore = webView .Source ;
276+ // Work around. An exception will be thrown while trying to redraw the
277+ // control as its CoreWebView2 is in the closed state.
278+ webView .Dispose ();
279+ webView = null ;
280+ var selection = MessageBox .Show (message , caption , MessageBoxButton .YesNo );
281+ if (selection == MessageBoxResult .Yes )
282+ {
283+ // Replace once the control has reinit/uninitialize logic.
284+ ReinitializeWebView ();
285+ }
286+ else
287+ {
288+ _uriToRestore = null ;
289+ }
290+ }
291+
292+ void AskForReload (string message , string caption )
293+ {
294+ var selection = MessageBox .Show (message , caption , MessageBoxButton .YesNo );
295+ if (selection == MessageBoxResult .Yes )
296+ {
297+ webView .Reload ();
298+ }
299+ }
300+
301+ string message ;
302+ string caption ;
303+ Debug .WriteLine (e .ProcessFailedKind );
304+ switch (e .ProcessFailedKind )
305+ {
306+ case CoreWebView2ProcessFailedKind .BrowserProcessExited :
307+ message = " Browser process exited unexpectedly. Recreate webview?" ;
308+ caption = " Browser process exited" ;
309+ AskForReinit (message , caption );
310+ break ;
311+ case CoreWebView2ProcessFailedKind .RenderProcessUnresponsive :
312+ message = " Browser render process has stopped responding. Recreate webview?" ;
313+ caption = " Web page unresponsive" ;
314+ AskForReinit (message , caption );
315+ break ;
316+ case CoreWebView2ProcessFailedKind .RenderProcessExited :
317+ message = " Browser render process exited unexpectedly. Reload page?" ;
318+ caption = " Web page unresponsive" ;
319+ AskForReload (message , caption );
320+ break ;
321+ case CoreWebView2ProcessFailedKind .FrameRenderProcessExited :
322+ // A frame-only renderer has exited unexpectedly. Check if reload is needed.
323+ // In this sample we only reload if the app's content has been impacted.
324+ foreach (CoreWebView2FrameInfo frameInfo in e .ImpactedFramesInfo )
325+ {
326+ // Sample virtual host name for the app's content.
327+ string virtualAppHostName = " https://appassets.example/" ;
328+ if (frameInfo .Source .StartsWith (virtualAppHostName ))
329+ {
330+ message = " Browser render process for app frame exited unexpectedly. Reload page?" ;
331+ caption = " App content frame unresponsive" ;
332+ AskForReload (message , caption );
333+ break ;
334+ }
335+ }
336+ break ;
337+ default :
338+ // Show the process failure details. Apps can collect info for their logging purposes.
339+ caption = " Child process failed" ;
340+ StringBuilder messageBuilder = new StringBuilder ();
341+ messageBuilder .AppendLine ($" Process kind: {e .ProcessFailedKind }" );
342+ messageBuilder .AppendLine ($" Reason: {e .Reason }" );
343+ messageBuilder .AppendLine ($" Exit code: {e .ExitCode }" );
344+ messageBuilder .AppendLine ($" Process description: {e .ProcessDescription }" );
345+ MessageBox .Show (messageBuilder .ToString (), caption , MessageBoxButton .OK );
346+ break ;
347+ }
348+ }
349+
33350```
34351
35352
0 commit comments