Skip to content

Fix PowerToys Run crashes when DWM desktop composition is disabled#47414

Draft
Copilot wants to merge 4 commits into
mainfrom
copilot/fix-desktop-synthesis-issue
Draft

Fix PowerToys Run crashes when DWM desktop composition is disabled#47414
Copilot wants to merge 4 commits into
mainfrom
copilot/fix-desktop-synthesis-issue

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 29, 2026

Summary of the Pull Request

PowerToys Run crashes with COMException: 已禁用桌面合成 (HRESULT 0x80263001 / DWM_E_COMPOSITIONDISABLED) in scenarios where DWM composition is temporarily or permanently unavailable (e.g. RDP sessions, compatibility modes). The existing recovery logic failed to catch DWM errors wrapped in WPF framework exception types.

ExceptionHelper.IsRecoverableDwmCompositionException

  • Previously only inspected the outermost exception; WPF can wrap COMException inside other types
  • Now walks the full exception chain up to 10 levels deep

ErrorReporting.HandleException

  • Was passing e as COMException (→ null for non-COMException types) to a method whose signature takes Exception, making inner-exception detection a no-op
  • Now passes e directly

ThemeManager.UpdateThemeWithRetryAsync

  • catch (COMException ex) when (IsRecoverableDwmCompositionException(ex)) misses WPF wrapper types
  • Changed to catch (Exception ex) when (...) — the when guard keeps semantics identical for non-DWM exceptions

MainWindow.OnSourceInitialized

  • DwmSetWindowAttribute (rounded corners, Win11 only) was unprotected; a DWM failure here propagated to the global handler, disrupting window initialization
  • Wrapped in try/catch — only consequence of failure is non-rounded corners (cosmetic)

PR Checklist

  • Closes: #xxx
  • Communication: I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected
  • Tests: Added/updated and all pass
  • Localization: All end-user-facing strings can be localized
  • Dev docs: Added/updated
  • New binaries: Added on the required places
  • Documentation updated: If checked, please file a pull request on our docs repo and link it here: #xxx

Detailed Description of the Pull Request / Additional comments

The core detection logic in IsRecoverableDwmCompositionException now walks the exception chain:

// Before: only checked if exception itself was COMException
if (exception is not COMException comException) return false;

// After: walk up to 10 inner exceptions
for (var depth = 0; current != null && depth < maxDepth; depth++, current = current.InnerException)
{
    if (current is COMException comException)
    {
        if (comException.HResult is DWM_E_COMPOSITIONDISABLED) return true;
        // ...
    }
}

The HandleException fix removes the redundant narrowing cast that prevented inner-exception detection from working even after this method was updated:

// Before (cast to null for non-COMException types):
if (ExceptionHelper.IsRecoverableDwmCompositionException(e as COMException))

// After:
if (ExceptionHelper.IsRecoverableDwmCompositionException(e))

Validation Steps Performed

  • Code review of all affected exception handling paths
  • Verified Exception.HResult is a public property in .NET (used consistently elsewhere in the codebase, e.g. ProgramLogger.cs, Log.cs)
  • No new strings introduced; no binaries added

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • o3svsblobprodcus318.vsblob.vsassets.io
    • Triggering command: /usr/bin/dotnet dotnet build --no-restore (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI linked an issue Apr 29, 2026 that may be closed by this pull request
Copilot AI and others added 3 commits April 29, 2026 11:24
- ExceptionHelper.IsRecoverableDwmCompositionException now walks the
  full exception chain (including inner exceptions) to detect wrapped
  DWM composition errors
- ErrorReporting.HandleException passes the exception directly instead
  of casting to COMException first, enabling inner-exception checks
- ThemeManager.UpdateThemeWithRetryAsync catches any Exception (not
  just COMException) that represents a DWM composition error, so WPF
  wrapper exceptions are also handled with retry logic
- MainWindow.OnSourceInitialized wraps DwmSetWindowAttribute in a
  try-catch so a disabled DWM only logs a warning instead of crashing

Agent-Logs-Url: https://github.com/microsoft/PowerToys/sessions/9cfe5580-2f9e-4888-863a-659ebdbcb04f

Co-authored-by: MuyuanMS <116717757+MuyuanMS@users.noreply.github.com>
Addresses code review feedback - caps inner-exception traversal at 10
levels to prevent pathological overhead while still covering typical
1-3 level wrapping patterns.

Agent-Logs-Url: https://github.com/microsoft/PowerToys/sessions/9cfe5580-2f9e-4888-863a-659ebdbcb04f

Co-authored-by: MuyuanMS <116717757+MuyuanMS@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix disabled desktop synthesis in PowerToys Fix PowerToys Run crashes when DWM desktop composition is disabled Apr 29, 2026
Copilot AI requested a review from MuyuanMS April 29, 2026 11:28
@niels9001 niels9001 added the Product-PowerToys Run Improved app launch PT Run (Win+R) Window label Apr 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Product-PowerToys Run Improved app launch PT Run (Win+R) Window

Projects

None yet

Development

Successfully merging this pull request may close these issues.

已禁用桌面合成

3 participants