Skip to content

Commit eca57f6

Browse files
committed
Prevent crashes when calling MoveFocus in transient states
The `MoveFocus` method can throw `E_INVALIDARG` or `E_INVALID_STATE` exceptions when called during asynchronous initialization or window activation races. These exceptions represent transient states that do not require intervention, but can lead to application crashes if unhandled. This change introduces `SafeCallController` to gracefully handle and ignore these specific exceptions.
1 parent a7fe46d commit eca57f6

1 file changed

Lines changed: 34 additions & 1 deletion

File tree

src/Avalonia.Controls.WebView.Core/Win/WebView2/WebView2BaseAdapter.cs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,11 +245,44 @@ private Task<Stream> PrintToPdfStreamAsyncInternal(WebViewPrintSettings? setting
245245

246246
public void Focus()
247247
{
248-
controller.MoveFocus(0 /* Programmatic */);
248+
SafeCallController(() =>
249+
controller.MoveFocus(COREWEBVIEW2_MOVE_FOCUS_REASON.COREWEBVIEW2_MOVE_FOCUS_REASON_PROGRAMMATIC));
249250
}
250251

251252
public void ResignFocus() { }
252253

254+
private void SafeCallController(Action action)
255+
{
256+
if (Disposed || controller == null)
257+
{
258+
return;
259+
}
260+
try
261+
{
262+
action();
263+
}
264+
catch (ArgumentException ex) when (ex.HResult == HResult.EInvalidArg)
265+
{
266+
// Controller rejected MoveFocus with E_INVALIDARG — transient state during
267+
// async init or window-activation race. Safe to ignore; focus re-establishes
268+
// naturally once the controller reaches a ready state.
269+
}
270+
catch (COMException ex) when (ex.HResult is HResult.EInvalidArg or HResult.EInvalidState)
271+
{
272+
// Same transient rejection surfaced as COMException depending on the
273+
// source-generated interop path (e.g. during controller teardown).
274+
}
275+
}
276+
277+
private static class HResult
278+
{
279+
// E_INVALIDARG (0x80070057): returned by MoveFocus when the controller rejects
280+
// the call during async init or window-activation races.
281+
public const int EInvalidArg = unchecked((int)0x80070057);
282+
// ERROR_INVALID_STATE (0x8007139F): observed in teardown-phase rejections.
283+
public const int EInvalidState = unchecked((int)0x8007139F);
284+
}
285+
253286
internal EventHandler<WebViewNavigationStartingEventArgs>? GetNavigationStarted() => NavigationStarted;
254287
internal EventHandler<WebViewNavigationCompletedEventArgs>? GetNavigationCompleted() => NavigationCompleted;
255288
internal EventHandler<WebMessageReceivedEventArgs>? GetWebMessageReceived() => WebMessageReceived;

0 commit comments

Comments
 (0)