Skip to content

Commit 0af352e

Browse files
committed
Add sample code
1 parent 8abd7a5 commit 0af352e

1 file changed

Lines changed: 317 additions & 0 deletions

File tree

specs/ExtendedProcessFailed.md

Lines changed: 317 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)