Skip to content

Commit a773b51

Browse files
authored
Handle recoverable DWM composition exceptions gracefully (#4113)
1 parent c6c4132 commit a773b51

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

Flow.Launcher/Helper/ErrorReporting.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ private static void Report(Exception e, bool silent = false, [CallerMemberName]
1616
var logger = LogManager.GetLogger(methodName);
1717
logger.Fatal(ExceptionFormatter.FormatExcpetion(e));
1818
if (silent) return;
19+
20+
// Workaround for issue https://github.com/Flow-Launcher/Flow.Launcher/issues/4016
21+
// The crash occurs in PresentationFramework.dll, not necessarily when the Runner UI is visible, originating from this line:
22+
// https://github.com/dotnet/wpf/blob/3439f20fb8c685af6d9247e8fd2978cac42e74ac/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Shell/WindowChromeWorker.cs#L1005
23+
// Many bug reports because users see the "Error report UI" after the crash with System.Runtime.InteropServices.COMException 0xD0000701 or 0x80263001.
24+
// However, displaying this "Error report UI" during WPF crashes, especially when DWM composition is changing, is not ideal; some users reported it hangs for up to a minute before the it appears.
25+
// This change modifies the behavior to log the exception instead of showing the "Error report UI".
26+
if (ExceptionHelper.IsRecoverableDwmCompositionException(e)) return;
27+
1928
var reportWindow = new ReportWindow(e);
2029
reportWindow.Show();
2130
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// This is a direct copy of the file at https://github.com/microsoft/PowerToys/blob/main/src/modules/launcher/PowerLauncher/Helper/ExceptionHelper.cs and adapted for flow.
2+
3+
using System;
4+
using System.Runtime.InteropServices;
5+
6+
namespace Flow.Launcher.Helper;
7+
8+
internal static class ExceptionHelper
9+
{
10+
private const string PresentationFrameworkExceptionSource = "PresentationFramework";
11+
12+
private const int DWM_E_COMPOSITIONDISABLED = unchecked((int)0x80263001);
13+
14+
// HRESULT for NT STATUS STATUS_MESSAGE_LOST (0xC0000701 | 0x10000000 == 0xD0000701)
15+
private const int STATUS_MESSAGE_LOST_HR = unchecked((int)0xD0000701);
16+
17+
/// <summary>
18+
/// Returns true if the exception is a recoverable DWM composition exception.
19+
/// </summary>
20+
internal static bool IsRecoverableDwmCompositionException(Exception exception)
21+
{
22+
if (exception is not COMException comException)
23+
{
24+
return false;
25+
}
26+
27+
if (comException.HResult is DWM_E_COMPOSITIONDISABLED)
28+
{
29+
return true;
30+
}
31+
32+
if (comException.HResult is STATUS_MESSAGE_LOST_HR && comException.Source == PresentationFrameworkExceptionSource)
33+
{
34+
return true;
35+
}
36+
37+
// Check for common DWM composition changed patterns in the stack trace
38+
var stackTrace = comException.StackTrace;
39+
return !string.IsNullOrEmpty(stackTrace) &&
40+
stackTrace.Contains("DwmCompositionChanged", StringComparison.OrdinalIgnoreCase);
41+
}
42+
}

0 commit comments

Comments
 (0)