mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-07-04 01:20:02 +02:00
Compare commits
5 Commits
main
...
copilot/fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0f794565a | ||
|
|
04945cc4ab | ||
|
|
8fa2aba6a2 | ||
|
|
7cbfac0198 | ||
|
|
b9f48ee68c |
@@ -61,7 +61,7 @@ namespace PowerLauncher.Helper
|
||||
// Many bug reports because users see the "Report problem UI" after "the" crash with System.Runtime.InteropServices.COMException 0xD0000701 or 0x80263001.
|
||||
// However, displaying this "Report problem 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 "Report problem UI" appears.
|
||||
// This change modifies the behavior to log the exception instead of showing the "Report problem UI".
|
||||
if (ExceptionHelper.IsRecoverableDwmCompositionException(e as System.Runtime.InteropServices.COMException))
|
||||
if (ExceptionHelper.IsRecoverableDwmCompositionException(e))
|
||||
{
|
||||
var logger = LogManager.GetLogger(LoggerName);
|
||||
logger.Error($"From {(isNotUIThread ? "non" : string.Empty)} UI thread's exception: {ExceptionFormatter.FormatException(e)}");
|
||||
|
||||
@@ -19,26 +19,36 @@ namespace PowerLauncher.Helper
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the exception is a recoverable DWM composition exception.
|
||||
/// Also checks inner exceptions to handle cases where a DWM error is wrapped by another exception type.
|
||||
/// </summary>
|
||||
internal static bool IsRecoverableDwmCompositionException(Exception exception)
|
||||
{
|
||||
if (exception is not COMException comException)
|
||||
if (exception == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (comException.HResult is DWM_E_COMPOSITIONDISABLED)
|
||||
// Walk the exception chain (up to a reasonable depth) to detect DWM composition errors at any level
|
||||
const int maxDepth = 10;
|
||||
var current = exception;
|
||||
for (var depth = 0; current != null && depth < maxDepth; depth++, current = current.InnerException)
|
||||
{
|
||||
return true;
|
||||
if (current is COMException comException)
|
||||
{
|
||||
if (comException.HResult is DWM_E_COMPOSITIONDISABLED)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (comException.HResult is STATUS_MESSAGE_LOST_HR && comException.Source == PresentationFrameworkExceptionSource)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (comException.HResult is STATUS_MESSAGE_LOST_HR && comException.Source == PresentationFrameworkExceptionSource)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for common DWM composition changed patterns in the stack trace
|
||||
var stackTrace = comException.StackTrace;
|
||||
// Check for common DWM composition changed patterns in the stack trace of the outermost exception
|
||||
var stackTrace = exception.StackTrace;
|
||||
return !string.IsNullOrEmpty(stackTrace) &&
|
||||
stackTrace.Contains("DwmCompositionChanged");
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
@@ -160,12 +159,16 @@ namespace PowerLauncher.Helper
|
||||
|
||||
return;
|
||||
}
|
||||
catch (COMException ex) when (ExceptionHelper.IsRecoverableDwmCompositionException(ex))
|
||||
catch (Exception ex) when (ExceptionHelper.IsRecoverableDwmCompositionException(ex))
|
||||
{
|
||||
var hresult = ex is System.Reflection.TargetInvocationException { InnerException: not null }
|
||||
? ex.InnerException.HResult
|
||||
: ex.HResult;
|
||||
|
||||
switch (attempt)
|
||||
{
|
||||
case 1:
|
||||
Log.Warn($"Desktop composition is disabled (HRESULT: 0x{ex.HResult:X}). Scheduling retries for theme update.", typeof(ThemeManager));
|
||||
Log.Warn($"Desktop composition is disabled (HRESULT: 0x{hresult:X}). Scheduling retries for theme update.", typeof(ThemeManager));
|
||||
delayMs = InitialDelayMs;
|
||||
break;
|
||||
case < maxAttempts:
|
||||
|
||||
@@ -196,10 +196,17 @@ namespace PowerLauncher
|
||||
if (OSVersionHelper.IsGreaterThanWindows11_21H2())
|
||||
{
|
||||
// ResizeMode="NoResize" removes rounded corners. So force them to rounded.
|
||||
IntPtr hWnd = new WindowInteropHelper(GetWindow(this)).EnsureHandle();
|
||||
DWMWINDOWATTRIBUTE attribute = DWMWINDOWATTRIBUTE.DWMWA_WINDOW_CORNER_PREFERENCE;
|
||||
DWM_WINDOW_CORNER_PREFERENCE preference = DWM_WINDOW_CORNER_PREFERENCE.DWMWCP_ROUND;
|
||||
DwmSetWindowAttribute(hWnd, attribute, ref preference, sizeof(uint));
|
||||
try
|
||||
{
|
||||
IntPtr hWnd = new WindowInteropHelper(GetWindow(this)).EnsureHandle();
|
||||
DWMWINDOWATTRIBUTE attribute = DWMWINDOWATTRIBUTE.DWMWA_WINDOW_CORNER_PREFERENCE;
|
||||
DWM_WINDOW_CORNER_PREFERENCE preference = DWM_WINDOW_CORNER_PREFERENCE.DWMWCP_ROUND;
|
||||
DwmSetWindowAttribute(hWnd, attribute, ref preference, sizeof(uint));
|
||||
}
|
||||
catch (Exception ex) when (ExceptionHelper.IsRecoverableDwmCompositionException(ex))
|
||||
{
|
||||
Log.Warn($"Desktop composition is disabled. Unable to set window corner preference (cosmetic only). HRESULT: 0x{ex.HResult:X}", typeof(MainWindow));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
63
src/modules/launcher/Wox.Test/ExceptionHelperTest.cs
Normal file
63
src/modules/launcher/Wox.Test/ExceptionHelperTest.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using PowerLauncher.Helper;
|
||||
|
||||
namespace Wox.Test;
|
||||
|
||||
[TestClass]
|
||||
public class ExceptionHelperTest
|
||||
{
|
||||
private const int DwmCompositionDisabledHResult = unchecked((int)0x80263001);
|
||||
|
||||
[TestMethod]
|
||||
public void IsRecoverableDwmCompositionException_ReturnsTrue_ForDirectRecoverableComException()
|
||||
{
|
||||
var exception = CreateComException(DwmCompositionDisabledHResult);
|
||||
|
||||
Assert.IsTrue(ExceptionHelper.IsRecoverableDwmCompositionException(exception));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void IsRecoverableDwmCompositionException_ReturnsTrue_ForWrappedRecoverableComException()
|
||||
{
|
||||
var innerException = CreateComException(DwmCompositionDisabledHResult);
|
||||
var exception = new TargetInvocationException(innerException);
|
||||
|
||||
Assert.IsTrue(ExceptionHelper.IsRecoverableDwmCompositionException(exception));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void IsRecoverableDwmCompositionException_ReturnsFalse_ForWrappedNonRecoverableException()
|
||||
{
|
||||
var exception = new TargetInvocationException(new InvalidOperationException("Not a DWM composition failure."));
|
||||
|
||||
Assert.IsFalse(ExceptionHelper.IsRecoverableDwmCompositionException(exception));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void IsRecoverableDwmCompositionException_ReturnsTrue_ForDwmCompositionChangedInStackTrace()
|
||||
{
|
||||
var exception = Assert.ThrowsException<InvalidOperationException>(DwmCompositionChangedThrower);
|
||||
|
||||
Assert.IsTrue(ExceptionHelper.IsRecoverableDwmCompositionException(exception));
|
||||
}
|
||||
|
||||
private static COMException CreateComException(int hresult)
|
||||
{
|
||||
var exception = Marshal.GetExceptionForHR(hresult);
|
||||
Assert.IsNotNull(exception);
|
||||
Assert.IsInstanceOfType<COMException>(exception);
|
||||
return (COMException)exception;
|
||||
}
|
||||
|
||||
private static void DwmCompositionChangedThrower()
|
||||
{
|
||||
throw new InvalidOperationException("Stack trace fallback path.");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user