Files
Boliang ZhangandCopilot 670743b011 fix(build): disable Hybrid CRT by default (#51432)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

Disable Hybrid CRT by default as a scoped rollback of the build-policy
change in #50899, mitigating Runner exit hangs involving the shared UCRT
exit-table lock.

`Cpp.Build.props` now defaults `EnableHybridCRT` to `false` when no
value is supplied. Native projects return to private static UCRT
linkage, while explicit opt-ins and independent project-level Hybrid CRT
linker settings remain supported.

The New+ locale/environment-variable changes and the logger
environment-variable fix from #50899 are intentionally retained. Only
`Cpp.Build.props` and the directly related runtime guidance in
`doc/devdocs/development/guidelines.md` change.

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [ ] Closes: N/A (partial rollback of #50899; no separate issue linked)
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **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. No new application unit
tests; native build and effective-linkage validation are listed below.
- [x] **Localization:** All end-user-facing strings can be localized
(N/A: no user-facing strings)
- [x] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places (N/A: no new
binaries)
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: N/A (developer guidance is updated in this PR; no user
documentation changes)

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

### Why restore private UCRT linkage?

Matching-symbol inspection of installed 0.102.2883.0 found Runner
performing static module destruction inside
`ucrtbase!execute_onexit_table`. In one confirmed wait cycle:

- The Runner main thread holds the CRT exit-table lock and joins the
PowerDisplay executor while destroying the module.
- The executor creates an ATL `CString` while sending the shutdown
message. Lazy static initialization calls
`atexit`/`register_onexit_function`, which needs the same shared CRT
lock.

Other captured remnants show related exit-table/loader waits involving
Light Switch listener cleanup and Mouse Highlighter DLL detach. Sharing
the UCRT makes these previously separate runtime locks shared across the
executable and module DLLs.

The reported working/failing boundary is 0.101.2362.0 to 0.102.2803.0.
Git ancestry confirms that the latter includes #50899 but does not yet
include #50897 or #51115. This is a build-policy mitigation, not a
rewrite of Runner shutdown sequencing.

### Scope and tradeoffs

- Preserve `/MT` and `/MTd`; disable the default `libucrt` exclusion and
shared-UCRT import-library selection by making their existing condition
false.
- Preserve `CalculatorEngineCommon`'s explicit opt-in, the Command
Palette Extensions SDK's independent Hybrid CRT linker configuration,
and existing project opt-outs.
- No CI/workflow/build-script override re-enables Hybrid CRT for Runner
or its affected native modules.
- Preserve the New+ and logger fixes, settings/IPC formats, and
installed-user state.
- Accept losing the default binary-size reduction until shutdown
lifetimes are made safe for a shared CRT. No current installer-size
measurement is claimed.

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

### Native builds: passed

The following commands were run in the isolated worktree. All completed
with exit code 0 after restoring the fresh worktree's missing native
packages.

```powershell
# PASS: native package restore.
& 'C:\Program Files\PowerShell\7\pwsh.exe' -NoProfile -File 'D:\PowerToys-hybrid-crt-rollback\tools\build\build.ps1' -Platform x64 -Configuration Release -Path 'D:\PowerToys-hybrid-crt-rollback\src\modules\powerdisplay\PowerDisplayModuleInterface' '/t:Restore' '/p:RestorePackagesConfig=true' '/p:SolutionDir=D:\PowerToys-hybrid-crt-rollback\' '/p:SkipLongPathsCheck=true'

# PASS: PowerDisplayModuleInterface and native dependencies; 0 errors, 0 warnings.
& 'C:\Program Files\PowerShell\7\pwsh.exe' -NoProfile -File 'D:\PowerToys-hybrid-crt-rollback\tools\build\build.ps1' -Platform x64 -Configuration Release -Path 'D:\PowerToys-hybrid-crt-rollback\src\modules\powerdisplay\PowerDisplayModuleInterface' '/p:SolutionDir=D:\PowerToys-hybrid-crt-rollback\' '/p:SkipLongPathsCheck=true'

# PASS: Runner and native dependencies; 0 errors, 1 host LIB-path warning.
& 'C:\Program Files\PowerShell\7\pwsh.exe' -NoProfile -File 'D:\PowerToys-hybrid-crt-rollback\tools\build\build.ps1' -Platform x64 -Configuration Release -Path 'D:\PowerToys-hybrid-crt-rollback\src\runner' '/restore' '/p:RestorePackagesConfig=true' '/p:SolutionDir=D:\PowerToys-hybrid-crt-rollback\' '/p:SkipLongPathsCheck=true'
```

The host has Windows long-path support disabled; the repository's
documented `SkipLongPathsCheck` override was used for these scoped
native builds without changing machine policy. Runner's warning was
CS1668 for a nonexistent Visual Studio `LIB` search directory, not a
source warning introduced by this change.

### Effective compiler/linker configuration: 25 cases passed

A local-only MSBuild diagnostic target imported the original
`Cpp.Build.targets`, added a non-built `Link` probe item to obtain
evaluated item-definition metadata, and returned `EnableHybridCRT`, the
actual `ClCompile.RuntimeLibrary` values,
`Link.IgnoreSpecificDefaultLibraries`, and `Link.AdditionalOptions`.

For each project/configuration/platform row, the command was:

```powershell
# PASS for all 24 matrix rows; $probe is the local ReportCrtLinkage.targets file.
& $msbuild $project /nologo /v:q /t:ReportCrtLinkage /getTargetResult:ReportCrtLinkage "/p:Platform=$platform" "/p:Configuration=$configuration" '/p:SolutionDir=D:\PowerToys-hybrid-crt-rollback\' "/p:ForceImportAfterCppTargets=$probe" /p:SkipLongPathsCheck=true

# PASS: additional Runner x64 Release positive control, using the same command with:
# /p:EnableHybridCRT=true
```

| Projects | Configurations | Platforms | Result |
|---|---|---|---|
| Runner, PowerDisplayModuleInterface, LightSwitchModuleInterface,
MouseHighlighter | Debug, Release | x64, ARM64 | Private UCRT; `/MTd` or
`/MT`; no shared-UCRT linker overrides |
| CalculatorEngineCommon | Debug, Release | x64, ARM64 | Explicit Hybrid
CRT opt-in retained |
| Command Palette Extensions SDK | Debug, Release | x64, ARM64 |
Independent Hybrid CRT linker configuration retained |
| Runner with explicit `EnableHybridCRT=true` | Release | x64 | Opt-in
still selects the shared UCRT |

The four affected native projects and the positive control were
evaluated with VS 2026 MSBuild. The two unchanged UWP opt-in projects
were evaluated with installed VS 2022 MSBuild because the VS 2026 Build
Tools installation lacks the UWP XAML targets. These are configuration
evaluations, not ARM64 build/runtime passes.

### Rebuilt binary imports: passed

```powershell
# PASS: both dumpbin commands exited 0.
& $dumpbin /nologo /imports 'D:\PowerToys-hybrid-crt-rollback\x64\Release\PowerToys.exe'
& $dumpbin /nologo /imports 'D:\PowerToys-hybrid-crt-rollback\x64\Release\PowerToys.PowerDisplayModuleInterface.dll'
```

Both rebuilt binaries have no `api-ms-win-crt-*`, `ucrtbase.dll`, or
`ucrtbased.dll` imports. This checks the resulting linkage, not only the
property value.

`git diff --check` also passed.

Not claimed: application unit/UI test execution, a full installer or
ARM64 build, or a post-change installed-product shutdown/restart A/B.
The installed PowerToys binaries and existing hung-process evidence were
not replaced or terminated.

(cherry picked from commit cf45de4118)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: cf21252c-f253-42f2-a45c-3146c2481127
2026-10-21 11:35:14 +08:00
..
2026-02-11 22:59:53 +01:00
2026-02-11 22:59:53 +01:00