Skip to content

fix(common): handle packaged context menu servicing shutdown - #50218

Open
Clint Rutkas (crutkas) wants to merge 1 commit into
mainfrom
crutkas-file-locksmith-hang
Open

fix(common): handle packaged context menu servicing shutdown#50218
Clint Rutkas (crutkas) wants to merge 1 commit into
mainfrom
crutkas-file-locksmith-hang

Conversation

@crutkas

Copy link
Copy Markdown
Member

Summary of the Pull Request

Fixes packaged context-menu HANG_QUIESCE failures during PowerToys update/uninstall for File Locksmith, PowerRename, Image Resizer, and New+.

These commands run in package-dedicated dllhost.exe COM surrogates. The surrogates have no top-level window, so packaged Win32 servicing has no WM_CLOSE target and waits for its timeout before force-terminating them. The Watson stack consequently shows the normal surrogate wait:

dllhost!wWinMain -> combase!CoRegisterSurrogateEx -> CSurrogateProcessActivator::WaitForSurrogateTimeout

This adds a shared lifecycle monitor in src/common/utils/context_menu_lifecycle.h and wires it into all four packaged context-menu DLLs.

PR Checklist

  • Closes: AB#51280953
  • Communication: Discussed with a core contributor during investigation
  • Tests: Automated coverage added and targeted builds pass; signed sparse-MSIX servicing A/B remains for CI/nightly validation
  • Localization: No end-user-facing strings changed

Detailed Description of the Pull Request / Additional comments

The shared helper:

  • Activates only inside the expected package family, so classic/unpackaged hosts are unchanged.
  • Holds an ordinary module reference so its window procedure remains valid after COM considers the server unloadable.
  • Creates one hidden top-level WS_POPUP window on a dedicated message-pump thread, outside DllMain.
  • Returns TRUE for WM_QUERYENDSESSION.
  • Atomically closes new activity admission on WM_CLOSE or confirmed WM_ENDSESSION, waits for already-admitted work, then terminates the stateless package-dedicated surrogate before servicing's timeout.
  • Cleans up and permits retry when monitor initialization fails.
  • Emits one initialization HRESULT telemetry event per module.

Module policy:

  • File Locksmith, PowerRename, and Image Resizer receive a 5-second grace period.
  • New+ receives 20 seconds because template copying and Explorer rename positioning happen in-process. Its rename worker transfers an activity token until completion.

DllCanUnloadNow remains based on the existing COM object/worker counts. No package manifest, registration, IPC contract, or user-facing command behavior changes.

A focused test in src/modules/FileLocksmith/Tests/FileLocksmith.UITests/FileLocksmithContextMenuTests.cs activates the real tier-1 command, locates the package-specific dllhost and lifecycle window, posts WM_CLOSE, requires process exit within five seconds, and verifies Explorer can reactivate the command.

This PR is intentionally separate from #49502. That PR concerns PowerToys.FileLocksmithUI.exe native handle enumeration and 0xc0000005; this PR concerns package servicing of context-menu COM surrogates.

Validation Steps Performed

  • Release x64 builds passed for all four context-menu projects plus File Locksmith, PowerRename, and Image Resizer UITest projects.
  • FileLocksmith.ContextMenu.ServicingShutdown is discovered by the MSTest executable.
  • Local native builds used /p:SpectreMitigation=false because this host lacks the optional Spectre-mitigated MSVC libraries, and /m:1 after a parallel PCH memory-pressure failure.
  • Package-generation events were disabled only for local compilation because project-local build logs are held while MakeAppx packs the same directory. No package-generation code changed.

Nightly validation after merge:

  1. Activate each modern command and confirm its package-specific dllhost owns the expected servicing window.
  2. Upgrade from 0.101.x to the nightly and verify the surrogates exit before the timeout with no new MOAPPLICATION_HANG_*ContextMenu!HANG_QUIESCE reports.
  3. Verify each command reactivates after its previous surrogate exits.
  4. Exercise File Locksmith launch, PowerRename multi-file launch, Image Resizer multi-file launch, and New+ template copy/rename before and after update.
  5. Compare initialization HRESULT telemetry and Watson buckets by version and integrity level.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b5be3824-61fb-4110-b87e-7c8f73cdcfe2
@github-actions

Copy link
Copy Markdown

Thank you for contributing to PowerToys. We've detected that this PR might include a new or modified telemetry event. Please ensure the following before merging:

@github-actions github-actions Bot added Product-File Locksmith Refers to the File Locksmith utility Product-Image Resizer Things regarding image resizing module Product-New+ Refers to the New+ PowerToys Utility Product-PowerRename Refers to the PowerRename PowerToy Ready for review labels Aug 28, 2026
@github-actions

Copy link
Copy Markdown

🧭 PR intake

Visual evidence: Not needed — The changed files do not indicate a visible UI change. No visual evidence is expected.

Recommendation

Link the issue this PR fixes using a closing keyword such as Closes #123.

✅ Ready for review

This PR passed the automated intake checks and is ready for maintainer review.

Automated PR intake; PowerToys maintainers make final decisions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Product-File Locksmith Refers to the File Locksmith utility Product-Image Resizer Things regarding image resizing module Product-New+ Refers to the New+ PowerToys Utility Product-PowerRename Refers to the PowerRename PowerToy Ready for review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants