Summary
On hosts with no registered Windows SDK (clean CI agents, containers, SDK-less/VS-less developer machines), C#/WinRT projection and authoring fail early with:
Could not find the Windows SDK in the registry
which cascades into downstream failures (e.g. WinUI/WMC XAML compilation).
Root cause
nuget/Microsoft.Windows.CsWinRT.targets defaults CsWinRTWindowsMetadata to a bare Windows SDK version number, sourced from $(WindowsSDKVersion) and then $(TargetPlatformVersion) (e.g. 10.0.19041.0).
That bare version is passed to cswinrt.exe as -input <version>. In src/cswinrt/cmd_reader.h, the files() resolver treats a bare N.N.N.N version by calling get_sdk_path() → open_sdk(), which reads the SDK install root from the registry:
HKLM\SOFTWARE\Microsoft\Windows Kits\Installed Roots\KitsRoot10
When no SDK is installed, KitsRoot10 is empty and the tool throws Could not find the Windows SDK in the registry.
The tool itself is not the problem — it already accepts -input <folder>, -input <file>, and -input local. The fragility is purely in the default the targets pick: a bare version that only the registry can resolve.
Proposed fix
For modern .NET TFMs (net*-windows10.0.x), the .NET SDK auto-restores the Microsoft.Windows.SDK.NET.Ref projection ref pack, whose Windows metadata (.winmd) files live under its \winmd folder and are versioned to $(TargetPlatformVersion) (more correct than local, which yields the running OS's winmds).
When the current bare-version default would be used and no Windows SDK is registered, the targets should point CsWinRTWindowsMetadata at that ref-pack \winmd folder instead. The ref-pack path is resolved robustly via @(ResolvedTargetingPack) (filtered by NuGetPackageId == Microsoft.Windows.SDK.NET.Ref), not by globbing the NuGet cache.
This should be gated so that machines with a registered Windows SDK (Visual Studio, SDK-installed CI) keep their existing behavior unchanged.
Repro
- Any
net*-windows10.0.x project consuming/authoring C#/WinRT projections on a host where HKLM\...\Windows Kits\Installed Roots\KitsRoot10 is empty (no Windows SDK installed).
- Projection/authoring build fails immediately with the registry error above.
Notes
A complementary short-term shim is being implemented in the winapp CLI (auto-injecting CsWinRTWindowsMetadata on SDK-less hosts). That shim is temporary — the durable solution is this upstream targets fix.
A PR implementing the gated ref-pack fallback follows.
Summary
On hosts with no registered Windows SDK (clean CI agents, containers, SDK-less/VS-less developer machines), C#/WinRT projection and authoring fail early with:
which cascades into downstream failures (e.g. WinUI/WMC XAML compilation).
Root cause
nuget/Microsoft.Windows.CsWinRT.targetsdefaultsCsWinRTWindowsMetadatato a bare Windows SDK version number, sourced from$(WindowsSDKVersion)and then$(TargetPlatformVersion)(e.g.10.0.19041.0).That bare version is passed to
cswinrt.exeas-input <version>. Insrc/cswinrt/cmd_reader.h, thefiles()resolver treats a bareN.N.N.Nversion by callingget_sdk_path()→open_sdk(), which reads the SDK install root from the registry:When no SDK is installed,
KitsRoot10is empty and the tool throwsCould not find the Windows SDK in the registry.The tool itself is not the problem — it already accepts
-input <folder>,-input <file>, and-input local. The fragility is purely in the default the targets pick: a bare version that only the registry can resolve.Proposed fix
For modern .NET TFMs (
net*-windows10.0.x), the .NET SDK auto-restores theMicrosoft.Windows.SDK.NET.Refprojection ref pack, whose Windows metadata (.winmd) files live under its\winmdfolder and are versioned to$(TargetPlatformVersion)(more correct thanlocal, which yields the running OS's winmds).When the current bare-version default would be used and no Windows SDK is registered, the targets should point
CsWinRTWindowsMetadataat that ref-pack\winmdfolder instead. The ref-pack path is resolved robustly via@(ResolvedTargetingPack)(filtered byNuGetPackageId == Microsoft.Windows.SDK.NET.Ref), not by globbing the NuGet cache.This should be gated so that machines with a registered Windows SDK (Visual Studio, SDK-installed CI) keep their existing behavior unchanged.
Repro
net*-windows10.0.xproject consuming/authoring C#/WinRT projections on a host whereHKLM\...\Windows Kits\Installed Roots\KitsRoot10is empty (no Windows SDK installed).Notes
A complementary short-term shim is being implemented in the winapp CLI (auto-injecting
CsWinRTWindowsMetadataon SDK-less hosts). That shim is temporary — the durable solution is this upstream targets fix.A PR implementing the gated ref-pack fallback follows.