Fix PowerLauncher "Something went wrong" dialog on DWM composition change#47400
Fix PowerLauncher "Something went wrong" dialog on DWM composition change#47400Copilot wants to merge 3 commits into
Conversation
…on errors in PowerLauncher ThemeManager Agent-Logs-Url: https://github.com/microsoft/PowerToys/sessions/5d22a198-4d58-47bc-95b1-60c65d651a58 Co-authored-by: MuyuanMS <116717757+MuyuanMS@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR updates PowerLauncher’s DWM composition exception recovery so WPF TargetInvocationException wrappers are recognized instead of showing the “Something went wrong” report UI.
Changes:
- Unwraps
TargetInvocationExceptioninExceptionHelper. - Passes original exceptions into recovery detection from error reporting.
- Broadens theme retry handling and adds unit tests for recoverable DWM exception detection.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
src/modules/launcher/PowerLauncher/Helper/ExceptionHelper.cs |
Adds unwrapping for reflection-wrapped exceptions before COM HRESULT checks. |
src/modules/launcher/PowerLauncher/Helper/ErrorReporting.cs |
Passes the full exception to recoverable DWM detection. |
src/modules/launcher/PowerLauncher/Helper/ThemeManager.cs |
Allows retry logic to catch wrapped recoverable exceptions. |
src/modules/launcher/Wox.Test/ExceptionHelperTest.cs |
Adds MSTest coverage for direct and wrapped exception cases. |
Comments suppressed due to low confidence (1)
src/modules/launcher/Wox.Test/ExceptionHelperTest.cs:18
- These two constants are never referenced by the tests. With the repository-wide TreatWarningsAsErrors setting, the unused private fields can break the Wox.Test build; either remove them or add the intended coverage for the STATUS_MESSAGE_LOST_HR/PresentationFramework path.
private const int STATUS_MESSAGE_LOST_HR = unchecked((int)0xD0000701);
private const string PresentationFrameworkSource = "PresentationFramework";
| private const int DWM_E_COMPOSITIONDISABLED = unchecked((int)0x80263001); | ||
| private const int STATUS_MESSAGE_LOST_HR = unchecked((int)0xD0000701); |
There was a problem hiding this comment.
Fixed: Added SA1310 suppression attribute on the test class, matching the pattern used in production code.
There was a problem hiding this comment.
Added [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore", Justification = "Win32 naming conventions")] on the test class, matching the pattern used in ExceptionHelper.cs. Addressed in commit 0c5d723.
| if (exception is TargetInvocationException && exception.InnerException != null) | ||
| { | ||
| exception = exception.InnerException; |
There was a problem hiding this comment.
Fixed: Added test cases for wrapped COMException with 0xD0000701 HResult and PresentationFramework source, for the DwmCompositionChanged stack-trace path, and retained wrapped non-recoverable coverage.
There was a problem hiding this comment.
Added two more test cases in commit 0c5d723:
IsRecoverableDwmCompositionException_TargetInvocationException_WrappingMessageLostFromPresentationFramework_ReturnsTrue— covers0xD0000701+PresentationFrameworksource wrapped inTargetInvocationExceptionIsRecoverableDwmCompositionException_TargetInvocationException_WrappingDwmCompositionChangedStackTrace_ReturnsTrue— covers the stack-trace-based path, using a helper method namedThrowDwmCompositionChangedComException(with[MethodImpl(MethodImplOptions.NoInlining)]to preserve the frame name in the stack trace)
| return; | ||
| } | ||
| catch (COMException ex) when (ExceptionHelper.IsRecoverableDwmCompositionException(ex)) | ||
| catch (Exception ex) when (ExceptionHelper.IsRecoverableDwmCompositionException(ex)) |
There was a problem hiding this comment.
Fixed: Now extracting and logging the inner exception's HResult when the outer is a TargetInvocationException wrapper.
There was a problem hiding this comment.
Fixed in commit 0c5d723. Now extracts the inner exception's HResult when a TargetInvocationException wrapper is present:
var logHResult = (ex is System.Reflection.TargetInvocationException tie && tie.InnerException != null)
? tie.InnerException.HResult
: ex.HResult;
```This ensures the warning logs `0x80263001`/`0xD0000701` (the actual DWM error) rather than `0x80131604` (TargetInvocationException's generic HRESULT).…esult Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
@copilot please re-review the latest changes. |
|
Same as the other DWM PR. This issue has been surpressed in 0.97, and the actual fix will be part of an upcoming .NET release |
Summary of the Pull Request
When DWM composition changes (e.g., navigating wallpapers while Bing Desktop Wallpaper is active), PowerLauncher's
SetSystemThemetriggers WPF's internalThemeManagervia theApplication.Current.ThemeModesetter. WPF invokes theme-change handlers via reflection, wrapping any thrownCOMException (0x80263001 DWM_E_COMPOSITIONDISABLED)in aTargetInvocationException. The existing recovery code only matched bareCOMException, so the retry logic was bypassed and the "Report problem UI" appeared instead.PR Checklist
Detailed Description of the Pull Request / Additional comments
Three call sites failed to account for
TargetInvocationExceptionwrapping:ExceptionHelper.IsRecoverableDwmCompositionException— now unwrapsTargetInvocationExceptionbefore inspecting the innerCOMException:ErrorReporting.HandleException— removed the silente as COMExceptionpre-cast (always null for aTargetInvocationException) and passesedirectly toIsRecoverableDwmCompositionException.ThemeManager.UpdateThemeWithRetryAsync— changedcatch (COMException ex) when (...)tocatch (Exception ex) when (IsRecoverableDwmCompositionException(ex))so the retry loop fires for wrapped exceptions too. The warning log now extracts and uses the inner exception's HResult when the outer is aTargetInvocationException, ensuring accurate HRESULT values (0x80263001/0xD0000701) are recorded rather than the genericTargetInvocationExceptionHRESULT (0x80131604). Removed now-unusedusing System.Runtime.InteropServices.Validation Steps Performed
ExceptionHelperTest.cswith MSTest coverage for:nulland non-COM exceptions (returnfalse)COMException (0x80263001)(returnstrue)TargetInvocationExceptionwrappingCOMException (0x80263001)(returnstrue)TargetInvocationExceptionwrappingCOMException (0xD0000701)fromPresentationFrameworksource (returnstrue)TargetInvocationExceptionwrapping aCOMExceptionwith aDwmCompositionChangedstack trace (returnstrue)TargetInvocationExceptionwrapping an unrelatedCOMExceptionor non-COM exception (returnsfalse)TargetInvocationExceptionwith null inner exception (returnsfalse)[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:...")]applied on the test class to match the production helper pattern and satisfyTreatWarningsAsErrors