fix(powerrename): avoid WIC shutdown during DLL teardown #50593

Merged
LegendaryBlair opened 11:18pm on September 15, 2026 wanted to merge 2 commits into microsoft/powertoys main from
LegendaryBlair/fix-powerrename-wic-lifetime
LegendaryBlair authored
of work during September 16
Diff Delta:
0
About 0 Diff Delta/hour
Classified as:  Feature Add

LegendaryBlair's Description of Work

Summary of the Pull Request

Avoid releasing a process-global WIC imaging factory during DLL teardown. A real CI hang showed PowerRename.UnitTests.dll unloading under the loader lock, with the static g_wicFactory destructor entering Windows codecs, MFShutdown, and a thread-pool wait.

Create WIC factories only for decoder operations instead of retaining static COM ownership. Preserve the existing metadata-result cache and caller-owned COM initialization.

This is an independent PowerRename fix extracted from the investigation in #50576. It includes no Workspaces changes, diagnostic tooling, test exclusions, new dependencies, or installer changes.

PR Checklist


  • [x] Communication: The separate fix was requested after reviewing the captured shutdown evidence and diagnostic experiment.

  • [x] Tests: Added a factory-ownership regression and validated the exact patch against the PowerRename and mixed native test suites.

N/A: localization, new binaries, settings migrations, and user documentation changes.

Detailed Description of the Pull Request / Additional comments



  • src/modules/powerrename/lib/WICMetadataExtractor.cpp removes the global COM factory, initialization flag, and factory mutex. Factory references are now local to decoder creation rather than static object destruction.


  • src/modules/powerrename/lib/WICMetadataExtractor.h removes the obsolete initialization helper and grants the existing test pattern's private access to the new lifetime test class.


  • src/modules/powerrename/unittests/WICMetadataExtractorTests.cpp adds FactoryHasNoPersistentOwner. The original code leaves one hidden reference; the corrected code releases the final reference at the operation boundary.

Simply moving the factory into an extractor instance would not cover every path: Renaming.cpp also retains a static MetadataPatternExtractor. Its metadata-result cache is left intact, but it no longer owns a WIC factory indirectly.

The captured executor stack was identical in two non-suspending snapshots:

FreeLibrary

-> PowerRename.UnitTests DLL detach
-> static g_wicFactory destructor
-> IWICImagingFactory release
-> Windows codecs
-> MFShutdown
-> thread-pool wait

Microsoft's MFShutdown documentation warns against calling it from static destructors during process exit.

Tradeoff for review: a metadata cache miss now creates a factory for decoder work. Metadata results remain cached, so repeated cached lookups do not recreate it. Large uncached image batches and codec-specific costs have not been benchmarked; this PR does not claim a performance improvement.

Validation Steps Performed


  • Built the real PowerRename library and native tests in x64 Release.

  • Confirmed the new ownership regression fails against the old global factory: Expected: 0, Actual: 1 remaining references.

  • With the correction, all 249 PowerRename tests and 69 Workspaces tests passed together locally (318/318).

  • Diagnostic CI 388929, with the triggering 19 IPC tests unchanged, completed Native Tests in 182.5 seconds: 7,992 passed, 18 existing skips, 0 failures, and vstest.console.exe exit code 0.

  • Windows 10 PowerRename UI tests passed 25/25 in that run; Windows 11 and ARM64 UI jobs succeeded. The overall diagnostic run had a separate Workspaces process-enumeration UI failure, so it is not described as fully green.

  • Later IPC-fixture cleanup checks independently found and corrected missing callback-drain barriers. With the original WIC implementation restored locally, the corrected IPC fixture could still reproduce the same PowerRename shutdown stack. Both corrections together completed 321/321 mixed tests.

  • This main-based branch contains the exact tested PowerRename source. Independent CI 388938 fully succeeded, including x64 and ARM64 builds and the Windows 10, Windows 11, and ARM64 UI jobs.

Building updated commit group diff...
3 total changed files
Loading changes...
Loading changes...
Loading changes...