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.cppremoves 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.hremoves the obsolete initialization helper and grants the existing test pattern's private access to the new lifetime test class. -
src/modules/powerrename/unittests/WICMetadataExtractorTests.cppaddsFactoryHasNoPersistentOwner. 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: 1remaining 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.exeexit 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.