From ed8116ac09f27ce5fa834dd3ee7a185047b00388 Mon Sep 17 00:00:00 2001
From: Nikola Metulev <711864+nmetulev@users.noreply.github.com>
Date: Fri, 17 Jul 2026 18:43:20 -0700
Subject: [PATCH 1/3] Resolve Windows metadata from .NET SDK ref pack on
SDK-less hosts
The shipped MSBuild targets default `CsWinRTWindowsMetadata` to a bare Windows
SDK version (`$(WindowsSDKVersion)`/`$(TargetPlatformVersion)`), which
`cswinrt.exe` can only resolve via the registry
(`HKLM\...\Windows Kits\Installed Roots\KitsRoot10`). On hosts with no
registered Windows SDK (clean CI agents, containers, SDK-less dev machines)
that lookup throws "Could not find the Windows SDK in the registry", cascading
into downstream (e.g. XAML) build failures.
Add `CsWinRTResolveWindowsMetadataFromSdkRefPack`, which - only when no Windows
SDK is registered and the value is still the bare-version default - repoints
`CsWinRTWindowsMetadata` at the `\winmd` folder of the
`Microsoft.Windows.SDK.NET.Ref` projection ref pack the .NET SDK already
restores for `net*-windows10.0.x` TFMs (resolved robustly via
`@(ResolvedTargetingPack)`, versioned to `$(TargetPlatformVersion)`). Registered
-SDK builds (Visual Studio, SDK-installed CI) and explicit `CsWinRTWindowsMetadata`
values are unaffected.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4f8b6648-c42b-4fca-98a7-2025142b37bd
---
nuget/Microsoft.Windows.CsWinRT.targets | 60 +++++++++++++++++++++++++
nuget/readme.md | 10 +++++
2 files changed, 70 insertions(+)
diff --git a/nuget/Microsoft.Windows.CsWinRT.targets b/nuget/Microsoft.Windows.CsWinRT.targets
index 9c144cf6df..78d23b2bb5 100644
--- a/nuget/Microsoft.Windows.CsWinRT.targets
+++ b/nuget/Microsoft.Windows.CsWinRT.targets
@@ -79,6 +79,66 @@ Copyright (C) Microsoft Corporation. All rights reserved.
+
+
+
+
+
+ <_CsWinRTKitsRoot10>$([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Kits\Installed Roots', 'KitsRoot10', null, Microsoft.Win32.RegistryView.Registry32, Microsoft.Win32.RegistryView.Registry64))
+
+
+ <_CsWinRTWindowsMetadataIsBareVersion Condition="'$(CsWinRTWindowsMetadata)' != '' and
+ '$(CsWinRTWindowsMetadata)' != 'local' and
+ '$(CsWinRTWindowsMetadata)' != 'sdk' and
+ '$(CsWinRTWindowsMetadata)' != 'sdk+' and
+ !Exists('$(CsWinRTWindowsMetadata)')">true
+
+
+
+
+ <_CsWinRTSdkNetRefPackDir Include="@(ResolvedTargetingPack->'%(Path)')"
+ Condition="'%(ResolvedTargetingPack.NuGetPackageId)' == 'Microsoft.Windows.SDK.NET.Ref'" />
+ <_CsWinRTSdkNetRefPackDirDistinct Include="@(_CsWinRTSdkNetRefPackDir->Distinct())" />
+
+
+
+ <_CsWinRTSdkNetRefPackWinMDDir Condition="'@(_CsWinRTSdkNetRefPackDirDistinct)' != ''">@(_CsWinRTSdkNetRefPackDirDistinct)\winmd
+ $(_CsWinRTSdkNetRefPackWinMDDir)
+
+
+
+
+
diff --git a/nuget/readme.md b/nuget/readme.md
index cc027eca67..08f1459204 100644
--- a/nuget/readme.md
+++ b/nuget/readme.md
@@ -90,6 +90,16 @@ Windows Metadata is required for all C#/WinRT projections, and can be supplied b
If a Windows SDK is installed, $(WindowsSDKVersion) is defined when building from a VS command prompt.
+If no Windows SDK is registered on the machine (for example on clean CI agents, containers, or SDK-less
+developer machines), the default `$(WindowsSDKVersion)`/`$(TargetPlatformVersion)` value is a bare SDK
+version number that `cswinrt.exe` can only resolve through the registry, so the build would otherwise fail
+with "Could not find the Windows SDK in the registry". In that case, for modern .NET TFMs (e.g.
+`net*-windows10.0.x`), C#/WinRT automatically falls back to the Windows metadata (`.winmd`) files shipped in
+the `Microsoft.Windows.SDK.NET.Ref` projection ref pack that the .NET SDK restores (its `\winmd` folder,
+versioned to `$(TargetPlatformVersion)`). This fallback only applies when no Windows SDK is registered and
+`$(CsWinRTWindowsMetadata)` is still the bare-version default; an explicit `$(CsWinRTWindowsMetadata)` value
+(a path, or `local`/`sdk`) and registered-SDK builds are unaffected.
+
## Consuming and Producing
The C#/WinRT package can be used both to consume WinRT types, and to produce them (via CsWinRTComponent). It is also possible to combine these settings and do both. For example, a developer might want to *produce* a library that's implemented in terms of another WinRT runtime class (*consuming* it).
From 7271a49facf9f8dfd2cae83f0099747e063b2466 Mon Sep 17 00:00:00 2001
From: Nikola Metulev <711864+nmetulev@users.noreply.github.com>
Date: Fri, 17 Jul 2026 19:15:28 -0700
Subject: [PATCH 2/3] Clarify ref-pack resolution tolerates preview/suffix
versions
Document (in the targets comment) that @(ResolvedTargetingPack) resolves the
actually-restored Microsoft.Windows.SDK.NET.Ref pack via the SDK's own
targeting-pack resolution, so it tolerates ref-pack versions that do not
string-match $(TargetPlatformVersion) (e.g. a 10.0.26100.67-preview pack for a
project targeting 10.0.26100.0) - which an exact-version lookup would miss.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4f8b6648-c42b-4fca-98a7-2025142b37bd
---
nuget/Microsoft.Windows.CsWinRT.targets | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/nuget/Microsoft.Windows.CsWinRT.targets b/nuget/Microsoft.Windows.CsWinRT.targets
index 78d23b2bb5..adcaa1b799 100644
--- a/nuget/Microsoft.Windows.CsWinRT.targets
+++ b/nuget/Microsoft.Windows.CsWinRT.targets
@@ -123,7 +123,14 @@ Copyright (C) Microsoft Corporation. All rights reserved.
-
+
<_CsWinRTSdkNetRefPackDir Include="@(ResolvedTargetingPack->'%(Path)')"
Condition="'%(ResolvedTargetingPack.NuGetPackageId)' == 'Microsoft.Windows.SDK.NET.Ref'" />
<_CsWinRTSdkNetRefPackDirDistinct Include="@(_CsWinRTSdkNetRefPackDir->Distinct())" />
From cc67f3aae7fea095cc8a8f21e6ca5bf78c1bf41f Mon Sep 17 00:00:00 2001
From: Nikola Metulev
Date: Fri, 17 Jul 2026 21:24:14 -0700
Subject: [PATCH 3/3] Update nuget/Microsoft.Windows.CsWinRT.targets
Co-authored-by: Manodasan Wignarajah
---
nuget/Microsoft.Windows.CsWinRT.targets | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nuget/Microsoft.Windows.CsWinRT.targets b/nuget/Microsoft.Windows.CsWinRT.targets
index adcaa1b799..be41c5620d 100644
--- a/nuget/Microsoft.Windows.CsWinRT.targets
+++ b/nuget/Microsoft.Windows.CsWinRT.targets
@@ -143,7 +143,7 @@ Copyright (C) Microsoft Corporation. All rights reserved.
+ Text="C#/WinRT: no Windows SDK is registered; using Windows metadata from the Windows SDK projection ref pack: '$(_CsWinRTSdkNetRefPackWinMDDir)'." />