From 8b494aa12aefdcb4d0e3e43c94fdafad30cf2d08 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Fri, 1 May 2026 21:34:03 -0700 Subject: [PATCH 001/105] Add cswinrtwinmdgen and WinRT.Host.Shim to NuGet package Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- build/AzurePipelineTemplates/CsWinRT-Build-Steps.yml | 12 ++++++++++-- .../CsWinRT-BuildAndTest-Stage-OneBranch.yml | 1 + .../CsWinRT-PublishToNuGet-Steps.yml | 2 +- nuget/Microsoft.Windows.CsWinRT.nuspec | 4 +++- src/build.cmd | 3 ++- 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/build/AzurePipelineTemplates/CsWinRT-Build-Steps.yml b/build/AzurePipelineTemplates/CsWinRT-Build-Steps.yml index 17314a9c0..dca90bf22 100644 --- a/build/AzurePipelineTemplates/CsWinRT-Build-Steps.yml +++ b/build/AzurePipelineTemplates/CsWinRT-Build-Steps.yml @@ -255,8 +255,6 @@ steps: - task: CopyFiles@2 displayName: Stage WinRT.Host.Shim condition: and(succeeded(), eq(variables['BuildPlatform'], 'x86'), eq(variables['BuildConfiguration'], 'release')) - enabled: false - continueOnError: True inputs: SourceFolder: $(Build.SourcesDirectory)\src\Authoring\WinRT.Host.Shim\bin\$(BuildConfiguration)\net10.0 Contents: | @@ -295,6 +293,16 @@ steps: cswinrtprojectiongen.pdb TargetFolder: $(StagingFolder)\net10.0\native + - task: CopyFiles@2 + displayName: Stage cswinrtwinmdgen + condition: and(succeeded(), or(eq(variables['BuildPlatform'], 'x64'), eq(variables['BuildPlatform'], 'arm64')), eq(variables['BuildConfiguration'], 'release')) + inputs: + SourceFolder: $(Build.SourcesDirectory)\src\WinRT.WinMD.Generator\bin\$(BuildConfiguration)\net10.0\win-$(BuildPlatform)\publish + Contents: | + cswinrtwinmdgen.exe + cswinrtwinmdgen.pdb + TargetFolder: $(StagingFolder)\net10.0\native + - task: CopyFiles@2 displayName: Stage WinRT.Generator.Tasks condition: and(succeeded(), eq(variables['BuildPlatform'], 'x86'), eq(variables['BuildConfiguration'], 'release')) diff --git a/build/AzurePipelineTemplates/CsWinRT-BuildAndTest-Stage-OneBranch.yml b/build/AzurePipelineTemplates/CsWinRT-BuildAndTest-Stage-OneBranch.yml index 12dcc4907..1722e98bf 100644 --- a/build/AzurePipelineTemplates/CsWinRT-BuildAndTest-Stage-OneBranch.yml +++ b/build/AzurePipelineTemplates/CsWinRT-BuildAndTest-Stage-OneBranch.yml @@ -73,6 +73,7 @@ jobs: net10.0/native/cswinrtinteropgen.exe; net10.0/native/cswinrtimplgen.exe; net10.0/native/cswinrtprojectiongen.exe; + net10.0/native/cswinrtwinmdgen.exe; search_root: $(StagingFolder) - task: onebranch.pipeline.signing@1 diff --git a/build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml b/build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml index 22fe1c493..c2c5b3c94 100644 --- a/build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml +++ b/build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml @@ -95,7 +95,7 @@ steps: command: pack searchPatternPack: nuget/Microsoft.Windows.CsWinRT.nuspec configurationToPack: Release - buildProperties: cswinrt_nuget_version=$(NugetVersion);cswinrt_exe=$(Build.SourcesDirectory)\release_x86\native\cswinrt.exe;interop_winmd=$(Build.SourcesDirectory)\release_x86\native\WindowsRuntime.Internal.winmd;net10_runtime=$(Build.SourcesDirectory)\release_x86\net10.0\WinRT.Runtime.dll;net10_runtime_xml=$(Build.SourcesDirectory)\release_x86\net10.0\WinRT.Runtime.xml;source_generator=$(Build.SourcesDirectory)\release_x86\net10.0\WinRT.SourceGenerator.dll;winrt_shim=$(Build.SourcesDirectory)\release_x86\net10.0\WinRT.Host.Shim.dll;winrt_host_x86=$(Build.SourcesDirectory)\release_x86\native\WinRT.Host.dll;winrt_host_x64=$(Build.SourcesDirectory)\release_x64\native\WinRT.Host.dll;winrt_host_arm64=$(Build.SourcesDirectory)\release_arm64\native\WinRT.Host.dll;winrt_host_resource_x86=$(Build.SourcesDirectory)\release_x86\native\WinRT.Host.dll.mui;winrt_host_resource_x64=$(Build.SourcesDirectory)\release_x64\native\WinRT.Host.dll.mui;winrt_host_resource_arm64=$(Build.SourcesDirectory)\release_arm64\native\WinRT.Host.dll.mui;cswinrtinteropgen_x64=$(Build.SourcesDirectory)\release_x64\net10.0\native\cswinrtinteropgen.exe;cswinrtinteropgen_arm64=$(Build.SourcesDirectory)\release_arm64\net10.0\native\cswinrtinteropgen.exe;cswinrtimplgen_x64=$(Build.SourcesDirectory)\release_x64\net10.0\native\cswinrtimplgen.exe;cswinrtimplgen_arm64=$(Build.SourcesDirectory)\release_arm64\net10.0\native\cswinrtimplgen.exe;cswinrtprojectiongen_x64=$(Build.SourcesDirectory)\release_x64\net10.0\native\cswinrtprojectiongen.exe;cswinrtprojectiongen_arm64=$(Build.SourcesDirectory)\release_arm64\net10.0\native\cswinrtprojectiongen.exe;run_cswinrt_generator_task=$(Build.SourcesDirectory)\release_x86\netstandard2.0\WinRT.Generator.Tasks.dll;branch=$(Build.SourceBranchName);commit=$(Build.SourceVersion) + buildProperties: cswinrt_nuget_version=$(NugetVersion);cswinrt_exe=$(Build.SourcesDirectory)\release_x86\native\cswinrt.exe;interop_winmd=$(Build.SourcesDirectory)\release_x86\native\WindowsRuntime.Internal.winmd;net10_runtime=$(Build.SourcesDirectory)\release_x86\net10.0\WinRT.Runtime.dll;net10_runtime_xml=$(Build.SourcesDirectory)\release_x86\net10.0\WinRT.Runtime.xml;source_generator=$(Build.SourcesDirectory)\release_x86\net10.0\WinRT.SourceGenerator.dll;winrt_shim=$(Build.SourcesDirectory)\release_x86\net10.0\WinRT.Host.Shim.dll;winrt_host_x86=$(Build.SourcesDirectory)\release_x86\native\WinRT.Host.dll;winrt_host_x64=$(Build.SourcesDirectory)\release_x64\native\WinRT.Host.dll;winrt_host_arm64=$(Build.SourcesDirectory)\release_arm64\native\WinRT.Host.dll;winrt_host_resource_x86=$(Build.SourcesDirectory)\release_x86\native\WinRT.Host.dll.mui;winrt_host_resource_x64=$(Build.SourcesDirectory)\release_x64\native\WinRT.Host.dll.mui;winrt_host_resource_arm64=$(Build.SourcesDirectory)\release_arm64\native\WinRT.Host.dll.mui;cswinrtinteropgen_x64=$(Build.SourcesDirectory)\release_x64\net10.0\native\cswinrtinteropgen.exe;cswinrtinteropgen_arm64=$(Build.SourcesDirectory)\release_arm64\net10.0\native\cswinrtinteropgen.exe;cswinrtimplgen_x64=$(Build.SourcesDirectory)\release_x64\net10.0\native\cswinrtimplgen.exe;cswinrtimplgen_arm64=$(Build.SourcesDirectory)\release_arm64\net10.0\native\cswinrtimplgen.exe;cswinrtprojectiongen_x64=$(Build.SourcesDirectory)\release_x64\net10.0\native\cswinrtprojectiongen.exe;cswinrtprojectiongen_arm64=$(Build.SourcesDirectory)\release_arm64\net10.0\native\cswinrtprojectiongen.exe;cswinrtwinmdgen_x64=$(Build.SourcesDirectory)\release_x64\net10.0\native\cswinrtwinmdgen.exe;cswinrtwinmdgen_arm64=$(Build.SourcesDirectory)\release_arm64\net10.0\native\cswinrtwinmdgen.exe;run_cswinrt_generator_task=$(Build.SourcesDirectory)\release_x86\netstandard2.0\WinRT.Generator.Tasks.dll;branch=$(Build.SourceBranchName);commit=$(Build.SourceVersion) packDestination: $(ob_outputDirectory)\packages - ${{ if eq(parameters.IsGitHub, false) }}: diff --git a/nuget/Microsoft.Windows.CsWinRT.nuspec b/nuget/Microsoft.Windows.CsWinRT.nuspec index 1b9f18d74..8a5ae471f 100644 --- a/nuget/Microsoft.Windows.CsWinRT.nuspec +++ b/nuget/Microsoft.Windows.CsWinRT.nuspec @@ -37,7 +37,7 @@ - + - + WinRT.Host.Shim.dll PreserveNewest @@ -294,7 +294,7 @@ Copyright (C) Microsoft Corporation. All rights reserved. --> - + true lib\$(TargetFramework) diff --git a/nuget/Microsoft.Windows.CsWinRT.nuspec b/nuget/Microsoft.Windows.CsWinRT.nuspec index 8a5ae471f..f4eb20b78 100644 --- a/nuget/Microsoft.Windows.CsWinRT.nuspec +++ b/nuget/Microsoft.Windows.CsWinRT.nuspec @@ -37,7 +37,7 @@ - + + - $(CsWinRTPath)lib\net10.0 $(CsWinRTPath)runtimes\**\native - - - From ed230ec8f11a469343d5abfca43e29ef15f46239 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Fri, 1 May 2026 23:33:30 -0700 Subject: [PATCH 003/105] Remove dead CsWinRTRemoveHostingDllReferences target WinRT.Host.dll lives under hosting\\native\ which NuGet does not auto-resolve, so the runtimes\**\native\WinRT.Host.dll Remove entries never matched anything. Leftover from a previous layout. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- nuget/Microsoft.Windows.CsWinRT.targets | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/nuget/Microsoft.Windows.CsWinRT.targets b/nuget/Microsoft.Windows.CsWinRT.targets index 80f5d127b..96a5ed604 100644 --- a/nuget/Microsoft.Windows.CsWinRT.targets +++ b/nuget/Microsoft.Windows.CsWinRT.targets @@ -128,18 +128,6 @@ Copyright (C) Microsoft Corporation. All rights reserved. - - - - $(CsWinRTPath)runtimes\**\native - - - - - - - - From f29d76e0aa223fba0115ea1b02d030afc4966012 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 2 May 2026 15:56:21 -0700 Subject: [PATCH 004/105] Add missing authoring targets to NuGet package Microsoft.Windows.CsWinRT.Authoring.targets and Microsoft.Windows.CsWinRT.Authoring.Transitive.targets were commented out in the nuspec, and Microsoft.Windows.CsWinRT.Authoring.WinMD.targets was missing entirely. All three are needed by component-authoring builds (CsWinRTComponent=true). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- nuget/Microsoft.Windows.CsWinRT.nuspec | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nuget/Microsoft.Windows.CsWinRT.nuspec b/nuget/Microsoft.Windows.CsWinRT.nuspec index f4eb20b78..69b004d73 100644 --- a/nuget/Microsoft.Windows.CsWinRT.nuspec +++ b/nuget/Microsoft.Windows.CsWinRT.nuspec @@ -25,10 +25,11 @@ - + + - + From 1998bb6c566cdf700ff7f7489f982420de65df9d Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 2 May 2026 15:56:21 -0700 Subject: [PATCH 005/105] Remove stale Embedded and IIDOptimizer targets Neither targets file is imported by anything in CsWinRT 3.0 nor packaged in the NuGet. They are CsWinRT 2.x leftovers. Updated cswinrt.slnx to drop the entries and add the Authoring.WinMD.targets entry alongside the other authoring targets. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ...Microsoft.Windows.CsWinRT.Embedded.targets | 76 ---------------- ...osoft.Windows.CsWinRT.IIDOptimizer.targets | 88 ------------------- src/cswinrt.slnx | 3 +- 3 files changed, 1 insertion(+), 166 deletions(-) delete mode 100644 nuget/Microsoft.Windows.CsWinRT.Embedded.targets delete mode 100644 nuget/Microsoft.Windows.CsWinRT.IIDOptimizer.targets diff --git a/nuget/Microsoft.Windows.CsWinRT.Embedded.targets b/nuget/Microsoft.Windows.CsWinRT.Embedded.targets deleted file mode 100644 index ff8015f1f..000000000 --- a/nuget/Microsoft.Windows.CsWinRT.Embedded.targets +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - $(DefineConstants);EMBED - - true - $(CsWinRTPath)embedded\ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/nuget/Microsoft.Windows.CsWinRT.IIDOptimizer.targets b/nuget/Microsoft.Windows.CsWinRT.IIDOptimizer.targets deleted file mode 100644 index 640a3a4b7..000000000 --- a/nuget/Microsoft.Windows.CsWinRT.IIDOptimizer.targets +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - $(CsWinRTPath)build\tools\IIDOptimizer\ - - @(BuiltProjectOutputGroupKeyOutput->'%(Identity)') - - $([MSBuild]::NormalizeDirectory('$(MSBuildProjectDirectory)', '$(IntermediateOutputPath)', 'IIDOptimizer')) - - @(ReferencePathWithRefAssemblies->'--refs %(Identity)', ' ') - - ---target -$(CsWinRTIIDOptimizerTargetAssembly) ---outdir -$(IIDOptimizerInterimDir) -$(GuidPatchTargetAssemblyReferences) - - - - - - - $(IIDOptimizerInterimDir)cswinrt_iidoptimizer.rsp - "$(CsWinRTIIDOptimizerPath)IIDOptimizer.exe" %40"$(CsWinRTIIDOptimizerResponseFile)" - - - - - - - - - - - - - - - - - - - - - - - - - - - $([System.IO.Directory]::GetParent($(CsWinRTIIDOptimizerTargetAssembly))) - - - - - - - - \ No newline at end of file diff --git a/src/cswinrt.slnx b/src/cswinrt.slnx index 8c2dc47d6..47b477190 100644 --- a/src/cswinrt.slnx +++ b/src/cswinrt.slnx @@ -79,9 +79,8 @@ + - - From 2e96a3a23b36aa57b890f9595173d63e9cb9d5f0 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 2 May 2026 18:24:49 -0700 Subject: [PATCH 006/105] Auto-import Native.targets for vcxproj consumers Pack Microsoft.Windows.CsWinRT.Native.targets at build\native\Microsoft.Windows.CsWinRT.targets so NuGet auto-imports it for native (vcxproj) consumers via the package's .targets convention. Drop the inline CsWinRTBuildComponentInterop target from the AuthoringConsumptionTest vcxproj in favor of importing Native.targets directly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- nuget/Microsoft.Windows.CsWinRT.nuspec | 1 + .../AuthoringConsumptionTest.vcxproj | 36 +++---------------- 2 files changed, 5 insertions(+), 32 deletions(-) diff --git a/nuget/Microsoft.Windows.CsWinRT.nuspec b/nuget/Microsoft.Windows.CsWinRT.nuspec index 69b004d73..0aa0e2b51 100644 --- a/nuget/Microsoft.Windows.CsWinRT.nuspec +++ b/nuget/Microsoft.Windows.CsWinRT.nuspec @@ -25,6 +25,7 @@ + diff --git a/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj b/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj index 8d55f37bf..ac5131c1d 100644 --- a/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj +++ b/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj @@ -127,32 +127,6 @@ - - - <_CsWinRTComponentProjectPath>..\AuthoringTest\AuthoringTest.csproj - <_CsWinRTComponentOutputDir>..\AuthoringTest\bin\$(_WinMDPlatform)\$(Configuration)\net10.0\ - <_CsWinRTComponentIntermediateDir>..\AuthoringTest\obj\$(_WinMDPlatform)\$(Configuration)\net10.0\ - - - - - - - <_CsWinRTJitGeneratedDlls Include="$(_CsWinRTComponentIntermediateDir)WinRT.Component.dll" Condition="Exists('$(_CsWinRTComponentIntermediateDir)WinRT.Component.dll')" /> - <_CsWinRTJitGeneratedDlls Include="$(_CsWinRTComponentIntermediateDir)WinRT.Interop.dll" Condition="Exists('$(_CsWinRTComponentIntermediateDir)WinRT.Interop.dll')" /> - <_CsWinRTJitGeneratedDlls Include="$(_CsWinRTComponentIntermediateDir)WinRT.Projection.dll" Condition="Exists('$(_CsWinRTComponentIntermediateDir)WinRT.Projection.dll')" /> - <_CsWinRTJitGeneratedDlls Include="$(_CsWinRTComponentIntermediateDir)WinRT.Sdk.Projection.dll" Condition="Exists('$(_CsWinRTComponentIntermediateDir)WinRT.Sdk.Projection.dll')" /> - <_CsWinRTJitGeneratedDlls Include="$(_CsWinRTComponentIntermediateDir)WinRT.Sdk.Xaml.Projection.dll" Condition="Exists('$(_CsWinRTComponentIntermediateDir)WinRT.Sdk.Xaml.Projection.dll')" /> - - - ..\AuthoringTest\bin\$(_WinMDPlatform)\$(Configuration)\net10.0\win-$(Platform)\AuthoringTest.winmd @@ -160,15 +134,13 @@ - + - - + + From 5c9dddb4ef4746d3f40ecf19cba735f0ef717ace Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 2 May 2026 19:45:17 -0700 Subject: [PATCH 007/105] Fix NETSDK1130 in Native.targets aggregator project The synthesized aggregator csproj ProjectReferences each CsWinRT component, which flows the component's .winmd into the aggregator's resolved reference set. The .NET SDK rejects that with NETSDK1130 (.NET 5+ disallows direct .winmd references). The aggregator doesn't import CsWinRT.targets (no PackageReference), so the standard CsWinRTRemoveWinMDReferences target isn't available. Inline a winmd-scrub target into the generated aggregator csproj content. It runs between ResolveProjectReferences and ResolveAssemblyReferences, removing any .winmd from _ResolvedProjectReferencePaths (and defensively from Reference/ReferencePath) so the SDK's NETSDK1130 check sees no winmd references. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- nuget/Microsoft.Windows.CsWinRT.Native.targets | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/nuget/Microsoft.Windows.CsWinRT.Native.targets b/nuget/Microsoft.Windows.CsWinRT.Native.targets index 6542a2603..7343d342b 100644 --- a/nuget/Microsoft.Windows.CsWinRT.Native.targets +++ b/nuget/Microsoft.Windows.CsWinRT.Native.targets @@ -94,6 +94,21 @@ Properties: <_CsWinRTTempProjectLines Include=" <ItemGroup>" /> <_CsWinRTTempProjectLines Include=" <ProjectReference Include="%(_CsWinRTComponentProjectPaths.Identity)" />" /> <_CsWinRTTempProjectLines Include=" </ItemGroup>" /> + + <_CsWinRTTempProjectLines Include=" <Target Name="_CsWinRTAggregatorRemoveWinMDReferences" AfterTargets="ResolveProjectReferences" BeforeTargets="ResolveAssemblyReferences">" /> + <_CsWinRTTempProjectLines Include=" <ItemGroup>" /> + <_CsWinRTTempProjectLines Include=" <_ResolvedProjectReferencePaths Remove="@(_ResolvedProjectReferencePaths)" Condition="'%(_ResolvedProjectReferencePaths.Extension)' == '.winmd'" />" /> + <_CsWinRTTempProjectLines Include=" <Reference Remove="@(Reference)" Condition="'%(Reference.Extension)' == '.winmd'" />" /> + <_CsWinRTTempProjectLines Include=" <ReferencePath Remove="@(ReferencePath)" Condition="'%(ReferencePath.Extension)' == '.winmd'" />" /> + <_CsWinRTTempProjectLines Include=" </ItemGroup>" /> + <_CsWinRTTempProjectLines Include=" </Target>" /> <_CsWinRTTempProjectLines Include="</Project>" /> From 5c109f43fbdc5d3b082dd7831334eb3fbd3d85e2 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 2 May 2026 20:04:28 -0700 Subject: [PATCH 008/105] Import CsWinRT props/targets directly in aggregator csproj The synthesized aggregator csproj had no PackageReference to cswinrt and no other path to import cswinrt's targets, so its CsWinRTBuildForNativeConsumer / CsWinRTGenerateInteropAssembly properties had no consumer in scope. cswinrtinteropgen never ran on the aggregator, and the merged WinRT.Component.dll / WinRT.Interop.dll never got produced. The .winmd scrub from the prior commit handled NETSDK1130 but didn't fix the missing consumer of those properties. Resolution: have Native.targets compute the absolute paths of Microsoft.Windows.CsWinRT.props and Microsoft.Windows.CsWinRT.targets relative to its own location and inject explicit elements at the top and bottom of the aggregator csproj content. This brings cswinrt's full target tree into the aggregator's evaluation, so CsWinRTGen.targets correctly wires cswinrtinteropgen and CsWinRTRemoveWinMDReferences scrubs the .winmd inputs (replacing the inline scrub from the prior commit). Zero version skew (the imported targets are the same cswinrt that's running Native.targets) and no NuGet restore overhead. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Microsoft.Windows.CsWinRT.Native.targets | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/nuget/Microsoft.Windows.CsWinRT.Native.targets b/nuget/Microsoft.Windows.CsWinRT.Native.targets index 7343d342b..3c5454ac5 100644 --- a/nuget/Microsoft.Windows.CsWinRT.Native.targets +++ b/nuget/Microsoft.Windows.CsWinRT.Native.targets @@ -74,12 +74,23 @@ Properties: <_CsWinRTTempProjectPath>$(_CsWinRTTempProjectDir)CsWinRT.NativeConsumer.csproj <_CsWinRTTempProjectTFMDir>$(_CsWinRTComponentTargetFramework) + + <_CsWinRTPropsForAggregator>$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)..\Microsoft.Windows.CsWinRT.props')) + <_CsWinRTTargetsForAggregator>$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)..\Microsoft.Windows.CsWinRT.targets')) <_CsWinRTTempProjectLines Include="<Project Sdk="Microsoft.NET.Sdk">" /> + <_CsWinRTTempProjectLines Include=" <Import Project="$(_CsWinRTPropsForAggregator)" />" /> <_CsWinRTTempProjectLines Include=" <PropertyGroup>" /> <_CsWinRTTempProjectLines Include=" <TargetFramework>$(_CsWinRTComponentTargetFramework)</TargetFramework>" /> <_CsWinRTTempProjectLines Include=" <Platforms>x64%3Bx86%3BARM64</Platforms>" /> @@ -89,26 +100,11 @@ Properties: <_CsWinRTTempProjectLines Include=" <EnableDefaultItems>false</EnableDefaultItems>" /> <_CsWinRTTempProjectLines Include=" <GenerateAssemblyInfo>false</GenerateAssemblyInfo>" /> <_CsWinRTTempProjectLines Include=" <ProduceReferenceAssembly>false</ProduceReferenceAssembly>" /> - <_CsWinRTTempProjectLines Include=" <NoWarn>$(NoWarn)%3BNETSDK1130</NoWarn>" /> <_CsWinRTTempProjectLines Include=" </PropertyGroup>" /> <_CsWinRTTempProjectLines Include=" <ItemGroup>" /> <_CsWinRTTempProjectLines Include=" <ProjectReference Include="%(_CsWinRTComponentProjectPaths.Identity)" />" /> <_CsWinRTTempProjectLines Include=" </ItemGroup>" /> - - <_CsWinRTTempProjectLines Include=" <Target Name="_CsWinRTAggregatorRemoveWinMDReferences" AfterTargets="ResolveProjectReferences" BeforeTargets="ResolveAssemblyReferences">" /> - <_CsWinRTTempProjectLines Include=" <ItemGroup>" /> - <_CsWinRTTempProjectLines Include=" <_ResolvedProjectReferencePaths Remove="@(_ResolvedProjectReferencePaths)" Condition="'%(_ResolvedProjectReferencePaths.Extension)' == '.winmd'" />" /> - <_CsWinRTTempProjectLines Include=" <Reference Remove="@(Reference)" Condition="'%(Reference.Extension)' == '.winmd'" />" /> - <_CsWinRTTempProjectLines Include=" <ReferencePath Remove="@(ReferencePath)" Condition="'%(ReferencePath.Extension)' == '.winmd'" />" /> - <_CsWinRTTempProjectLines Include=" </ItemGroup>" /> - <_CsWinRTTempProjectLines Include=" </Target>" /> + <_CsWinRTTempProjectLines Include=" <Import Project="$(_CsWinRTTargetsForAggregator)" />" /> <_CsWinRTTempProjectLines Include="</Project>" /> From 12375bb9a7d667f6cc1157ad04f31db54f2e8313 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 2 May 2026 20:31:07 -0700 Subject: [PATCH 009/105] Probe both package and source layouts for CsWinRT props/targets When Native.targets is consumed from the in-repo source tree (e.g. by the AuthoringConsumptionTest vcxproj's local-dev ), it sits at nuget\Microsoft.Windows.CsWinRT.Native.targets next to the props/targets. When consumed from the shipped package, it sits at build\native\Microsoft.Windows.CsWinRT.targets and the props/targets are one folder up at build\. The previous fixed '..\' path worked only for the package layout and failed in the source layout with MSB4019. Probe both relative locations via Exists() and pick whichever resolves first, preferring the package layout. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- nuget/Microsoft.Windows.CsWinRT.Native.targets | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/nuget/Microsoft.Windows.CsWinRT.Native.targets b/nuget/Microsoft.Windows.CsWinRT.Native.targets index 3c5454ac5..c16458330 100644 --- a/nuget/Microsoft.Windows.CsWinRT.Native.targets +++ b/nuget/Microsoft.Windows.CsWinRT.Native.targets @@ -81,9 +81,16 @@ Properties: through the package convention. Without these explicit imports, the aggregator's CsWinRTBuildForNativeConsumer / CsWinRTGenerateInteropAssembly properties have no consumer in scope and cswinrtinteropgen never runs. + + Layout differs between the shipped package and the in-repo source tree: + Package: Native.targets at build\native\, props/targets at build\ (..\) + Source : Native.targets at nuget\, props/targets at nuget\ (.\) + Probe both, prefer the package layout. --> - <_CsWinRTPropsForAggregator>$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)..\Microsoft.Windows.CsWinRT.props')) - <_CsWinRTTargetsForAggregator>$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)..\Microsoft.Windows.CsWinRT.targets')) + <_CsWinRTPropsForAggregator Condition="'$(_CsWinRTPropsForAggregator)' == '' and Exists('$(MSBuildThisFileDirectory)..\Microsoft.Windows.CsWinRT.props')">$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)..\Microsoft.Windows.CsWinRT.props')) + <_CsWinRTPropsForAggregator Condition="'$(_CsWinRTPropsForAggregator)' == '' and Exists('$(MSBuildThisFileDirectory)Microsoft.Windows.CsWinRT.props')">$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)Microsoft.Windows.CsWinRT.props')) + <_CsWinRTTargetsForAggregator Condition="'$(_CsWinRTTargetsForAggregator)' == '' and Exists('$(MSBuildThisFileDirectory)..\Microsoft.Windows.CsWinRT.targets')">$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)..\Microsoft.Windows.CsWinRT.targets')) + <_CsWinRTTargetsForAggregator Condition="'$(_CsWinRTTargetsForAggregator)' == '' and Exists('$(MSBuildThisFileDirectory)Microsoft.Windows.CsWinRT.targets')">$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)Microsoft.Windows.CsWinRT.targets')) From 9953bd9ff1fba6110b53b5e673ee1b52f32cdca1 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 2 May 2026 20:33:46 -0700 Subject: [PATCH 010/105] Mirror package layout (nuget\native) in source tree Move nuget\Microsoft.Windows.CsWinRT.Native.targets to nuget\native\Microsoft.Windows.CsWinRT.targets so the source tree matches the shipped package layout (build\native\Microsoft.Windows.CsWinRT.targets). Native.targets's '..\Microsoft.Windows.CsWinRT.props' / '..\Microsoft.Windows.CsWinRT.targets' relative imports now resolve identically in both source and package layouts; no Exists() probing or repo-specific special casing required. Update the nuspec source path and the AuthoringConsumptionTest vcxproj's local-dev import to match. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- nuget/Microsoft.Windows.CsWinRT.nuspec | 2 +- .../Microsoft.Windows.CsWinRT.targets} | 11 ++--------- .../AuthoringConsumptionTest.vcxproj | 2 +- 3 files changed, 4 insertions(+), 11 deletions(-) rename nuget/{Microsoft.Windows.CsWinRT.Native.targets => native/Microsoft.Windows.CsWinRT.targets} (85%) diff --git a/nuget/Microsoft.Windows.CsWinRT.nuspec b/nuget/Microsoft.Windows.CsWinRT.nuspec index 0aa0e2b51..738ef0f91 100644 --- a/nuget/Microsoft.Windows.CsWinRT.nuspec +++ b/nuget/Microsoft.Windows.CsWinRT.nuspec @@ -25,7 +25,7 @@ - + diff --git a/nuget/Microsoft.Windows.CsWinRT.Native.targets b/nuget/native/Microsoft.Windows.CsWinRT.targets similarity index 85% rename from nuget/Microsoft.Windows.CsWinRT.Native.targets rename to nuget/native/Microsoft.Windows.CsWinRT.targets index c16458330..3c5454ac5 100644 --- a/nuget/Microsoft.Windows.CsWinRT.Native.targets +++ b/nuget/native/Microsoft.Windows.CsWinRT.targets @@ -81,16 +81,9 @@ Properties: through the package convention. Without these explicit imports, the aggregator's CsWinRTBuildForNativeConsumer / CsWinRTGenerateInteropAssembly properties have no consumer in scope and cswinrtinteropgen never runs. - - Layout differs between the shipped package and the in-repo source tree: - Package: Native.targets at build\native\, props/targets at build\ (..\) - Source : Native.targets at nuget\, props/targets at nuget\ (.\) - Probe both, prefer the package layout. --> - <_CsWinRTPropsForAggregator Condition="'$(_CsWinRTPropsForAggregator)' == '' and Exists('$(MSBuildThisFileDirectory)..\Microsoft.Windows.CsWinRT.props')">$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)..\Microsoft.Windows.CsWinRT.props')) - <_CsWinRTPropsForAggregator Condition="'$(_CsWinRTPropsForAggregator)' == '' and Exists('$(MSBuildThisFileDirectory)Microsoft.Windows.CsWinRT.props')">$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)Microsoft.Windows.CsWinRT.props')) - <_CsWinRTTargetsForAggregator Condition="'$(_CsWinRTTargetsForAggregator)' == '' and Exists('$(MSBuildThisFileDirectory)..\Microsoft.Windows.CsWinRT.targets')">$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)..\Microsoft.Windows.CsWinRT.targets')) - <_CsWinRTTargetsForAggregator Condition="'$(_CsWinRTTargetsForAggregator)' == '' and Exists('$(MSBuildThisFileDirectory)Microsoft.Windows.CsWinRT.targets')">$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)Microsoft.Windows.CsWinRT.targets')) + <_CsWinRTPropsForAggregator>$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)..\Microsoft.Windows.CsWinRT.props')) + <_CsWinRTTargetsForAggregator>$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)..\Microsoft.Windows.CsWinRT.targets')) diff --git a/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj b/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj index ac5131c1d..9ca7e738b 100644 --- a/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj +++ b/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj @@ -140,7 +140,7 @@ + Project="..\..\..\nuget\native\Microsoft.Windows.CsWinRT.targets" /> From 9c4514fd194b52d2323ecb6be6ce5e2186a1e8ff Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 2 May 2026 21:08:09 -0700 Subject: [PATCH 011/105] Import cswinrt targets after Sdk.targets in aggregator CsWinRTGen.targets has many import-time PropertyGroups that derive paths from $(IntermediateOutputPath) (e.g. CsWinRTGeneratorInteropAssemblyDirectory, _RunCsWinRTGeneratorPropertyInputsCachePath, _CsWinRTGeneratorMergedProjectionAssemblyPath, _CsWinRTGeneratorComponentAssemblyPath, _CsWinRTSdkProjectionAssemblyPath, _CsWinRTRefAssemblyPath, CsWinRTGeneratorForwarderAssemblyDirectory). When the aggregator imports cswinrt.targets via the implicit form, the import happens before Sdk.targets sets IntermediateOutputPath, so all those derived paths evaluate to empty leading to MSB4044 (RunCsWinRTMergedProjectionGenerator missing GeneratedAssemblyDirectory) and similar. Switch the aggregator to the explicit form with explicit tags so we can place the cswinrt.targets after Sdk.targets. cswinrt.props still goes between Sdk.props and Sdk.targets so its BeforeMicrosoftNETSdkTargets contribution is in scope when Sdk.targets evaluates. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- nuget/native/Microsoft.Windows.CsWinRT.targets | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nuget/native/Microsoft.Windows.CsWinRT.targets b/nuget/native/Microsoft.Windows.CsWinRT.targets index 3c5454ac5..e2579ac92 100644 --- a/nuget/native/Microsoft.Windows.CsWinRT.targets +++ b/nuget/native/Microsoft.Windows.CsWinRT.targets @@ -89,7 +89,8 @@ Properties: - <_CsWinRTTempProjectLines Include="<Project Sdk="Microsoft.NET.Sdk">" /> + <_CsWinRTTempProjectLines Include="<Project>" /> + <_CsWinRTTempProjectLines Include=" <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />" /> <_CsWinRTTempProjectLines Include=" <Import Project="$(_CsWinRTPropsForAggregator)" />" /> <_CsWinRTTempProjectLines Include=" <PropertyGroup>" /> <_CsWinRTTempProjectLines Include=" <TargetFramework>$(_CsWinRTComponentTargetFramework)</TargetFramework>" /> @@ -104,6 +105,7 @@ Properties: <_CsWinRTTempProjectLines Include=" <ItemGroup>" /> <_CsWinRTTempProjectLines Include=" <ProjectReference Include="%(_CsWinRTComponentProjectPaths.Identity)" />" /> <_CsWinRTTempProjectLines Include=" </ItemGroup>" /> + <_CsWinRTTempProjectLines Include=" <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />" /> <_CsWinRTTempProjectLines Include=" <Import Project="$(_CsWinRTTargetsForAggregator)" />" /> <_CsWinRTTempProjectLines Include="</Project>" /> From d5d9febe21fd0371cc6fc440dce1dc63be68bbd9 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 2 May 2026 22:59:49 -0700 Subject: [PATCH 012/105] Skip CopyEmbeddedSymbols when Pdb2Pdb package isn't resolved The repo's Directory.Build.targets cascades into the synthesized aggregator csproj that Native.targets generates under src\_build\...\obj\cswinrt\, but the aggregator's restore doesn't resolve Microsoft.DiaSymReader.Pdb2Pdb (the package is added implicitly via Directory.Build.targets, but GeneratePathProperty doesn't always materialize for synthesized projects). Result: PkgMicrosoft_DiaSymReader_Pdb2Pdb is empty, the Pdb2Pdb path collapses to '\tools\Pdb2Pdb.exe', and the Exec fails. Gate the target on the package property being non-empty. This is a defensive change that benefits any csproj where Pdb2Pdb isn't resolvable, not aggregator-specific. Keeps the shipping artifact (Native.targets) free of repo-local concerns. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Directory.Build.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index 056a8ddd2..27f69c3ec 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -103,7 +103,7 @@ From 7086de1cc7b57d6af349c8de26c70d382d45b899 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 3 May 2026 00:06:39 -0700 Subject: [PATCH 013/105] Pin aggregator IntermediateOutputPath to the post-build Copy path The .NET SDK's default IntermediateOutputPath injects \ for non-AnyCPU builds, so an x86/x64/ARM64 aggregator outputs to obj\\\\. Native.targets's post-build Copy reads from a fixed obj\\\ path (no platform). Path mismatch -> Exists() guards no-op -> WinRT.Component.dll / WinRT.Interop.dll / projection assemblies never bin-place -> all 49 AuthoringConsumptionTest activation tests fail with 'Unknown C++ exception' at first activation. Pass IntermediateOutputPath and BaseIntermediateOutputPath as global properties to the aggregator's Restore/Build invocations, pinning them to the same path Native.targets will read from. Both sides agree by construction; no SDK platform-folder logic to mirror. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../native/Microsoft.Windows.CsWinRT.targets | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/nuget/native/Microsoft.Windows.CsWinRT.targets b/nuget/native/Microsoft.Windows.CsWinRT.targets index e2579ac92..2258573a0 100644 --- a/nuget/native/Microsoft.Windows.CsWinRT.targets +++ b/nuget/native/Microsoft.Windows.CsWinRT.targets @@ -115,21 +115,30 @@ Properties: Lines="@(_CsWinRTTempProjectLines)" Overwrite="true" /> - + + + <_CsWinRTTempProjectIntermediateDir>$(_CsWinRTTempProjectDir)obj\$(Configuration)\$(_CsWinRTTempProjectTFMDir)\ + <_CsWinRTTempProjectBaseIntermediateDir>$(_CsWinRTTempProjectDir)obj\ + + + + Properties="Configuration=$(Configuration);Platform=$(Platform);IntermediateOutputPath=$(_CsWinRTTempProjectIntermediateDir);BaseIntermediateOutputPath=$(_CsWinRTTempProjectBaseIntermediateDir)" /> + Properties="Configuration=$(Configuration);Platform=$(Platform);IntermediateOutputPath=$(_CsWinRTTempProjectIntermediateDir);BaseIntermediateOutputPath=$(_CsWinRTTempProjectBaseIntermediateDir)" /> - - <_CsWinRTTempProjectIntermediateDir>$(_CsWinRTTempProjectDir)obj\$(Configuration)\$(_CsWinRTTempProjectTFMDir)\ - <_CsWinRTGeneratedDlls Include="$(_CsWinRTTempProjectIntermediateDir)WinRT.Component.dll" Condition="Exists('$(_CsWinRTTempProjectIntermediateDir)WinRT.Component.dll')" /> From 20a756d4496238d4764e9fc1f2662288a34f7604 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 3 May 2026 00:13:58 -0700 Subject: [PATCH 014/105] Reword IntermediateOutputPath comment to describe intent Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- nuget/native/Microsoft.Windows.CsWinRT.targets | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/nuget/native/Microsoft.Windows.CsWinRT.targets b/nuget/native/Microsoft.Windows.CsWinRT.targets index 2258573a0..7ef5c976c 100644 --- a/nuget/native/Microsoft.Windows.CsWinRT.targets +++ b/nuget/native/Microsoft.Windows.CsWinRT.targets @@ -122,11 +122,12 @@ Properties: Date: Sun, 3 May 2026 00:44:57 -0700 Subject: [PATCH 015/105] Set aggregator IntermediateOutputPath as project-local property Embed the pinned BaseIntermediateOutputPath / IntermediateOutputPath inside the aggregator csproj's PropertyGroup rather than passing them on the parent MSBuild call. Project-local properties stay scoped to the aggregator; global properties propagate transitively into ProjectReferences (component csproj, then the C++ cswinrt.vcxproj it references), where the legacy packages.config NuGet resolver fails because the inherited intermediate path has no lockfile for that vcxproj's packages. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../native/Microsoft.Windows.CsWinRT.targets | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/nuget/native/Microsoft.Windows.CsWinRT.targets b/nuget/native/Microsoft.Windows.CsWinRT.targets index 7ef5c976c..b87e7ed76 100644 --- a/nuget/native/Microsoft.Windows.CsWinRT.targets +++ b/nuget/native/Microsoft.Windows.CsWinRT.targets @@ -74,6 +74,13 @@ Properties: <_CsWinRTTempProjectPath>$(_CsWinRTTempProjectDir)CsWinRT.NativeConsumer.csproj <_CsWinRTTempProjectTFMDir>$(_CsWinRTComponentTargetFramework) + + <_CsWinRTTempProjectBaseIntermediateDir>$(_CsWinRTTempProjectDir)obj\ + <_CsWinRTTempProjectIntermediateDir>$(_CsWinRTTempProjectBaseIntermediateDir)$(Configuration)\$(_CsWinRTTempProjectTFMDir)\ + <_CsWinRTTempProjectLines Include=" <BaseIntermediateOutputPath>$(_CsWinRTTempProjectBaseIntermediateDir)</BaseIntermediateOutputPath>" /> + <_CsWinRTTempProjectLines Include=" <IntermediateOutputPath>$(_CsWinRTTempProjectIntermediateDir)</IntermediateOutputPath>" /> <_CsWinRTTempProjectLines Include=" <CsWinRTBuildForNativeConsumer>true</CsWinRTBuildForNativeConsumer>" /> <_CsWinRTTempProjectLines Include=" <CsWinRTGenerateInteropAssembly>true</CsWinRTGenerateInteropAssembly>" /> <_CsWinRTTempProjectLines Include=" <CsWinRTGenerateProjection>false</CsWinRTGenerateProjection>" /> @@ -115,29 +131,16 @@ Properties: Lines="@(_CsWinRTTempProjectLines)" Overwrite="true" /> - - - <_CsWinRTTempProjectIntermediateDir>$(_CsWinRTTempProjectDir)obj\$(Configuration)\$(_CsWinRTTempProjectTFMDir)\ - <_CsWinRTTempProjectBaseIntermediateDir>$(_CsWinRTTempProjectDir)obj\ - - - + + Properties="Configuration=$(Configuration);Platform=$(Platform)" /> + Properties="Configuration=$(Configuration);Platform=$(Platform)" /> From c48e6aa85144cd2bc5f128ca32930edebecb24ba Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 3 May 2026 10:36:57 -0700 Subject: [PATCH 016/105] Account for SDK TFM appending on aggregator IntermediateOutputPath Pin the aggregator's IntermediateOutputPath only up through Configuration. The .NET SDK appends a TargetFramework segment to IntermediateOutputPath in its post-evaluation pass; previously we passed the full path including TFM and the SDK appended a second TFM, producing obj\Debug\net10.0\net10.0\. cswinrtinteropgen wrote merged DLLs there while Native.targets's post-build Copy step read from the single-TFM path. Now the pinned PropertyGroup value ends at \\, the SDK appends \\, and the final on-disk path matches _CsWinRTTempProjectIntermediateDir that the Copy step reads from. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- nuget/native/Microsoft.Windows.CsWinRT.targets | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/nuget/native/Microsoft.Windows.CsWinRT.targets b/nuget/native/Microsoft.Windows.CsWinRT.targets index b87e7ed76..bd9ccadd3 100644 --- a/nuget/native/Microsoft.Windows.CsWinRT.targets +++ b/nuget/native/Microsoft.Windows.CsWinRT.targets @@ -75,12 +75,16 @@ Properties: <_CsWinRTTempProjectTFMDir>$(_CsWinRTComponentTargetFramework) <_CsWinRTTempProjectBaseIntermediateDir>$(_CsWinRTTempProjectDir)obj\ - <_CsWinRTTempProjectIntermediateDir>$(_CsWinRTTempProjectBaseIntermediateDir)$(Configuration)\$(_CsWinRTTempProjectTFMDir)\ + <_CsWinRTTempProjectIntermediateConfigDir>$(_CsWinRTTempProjectBaseIntermediateDir)$(Configuration)\ + <_CsWinRTTempProjectIntermediateDir>$(_CsWinRTTempProjectIntermediateConfigDir)$(_CsWinRTTempProjectTFMDir)\ <_CsWinRTTempProjectLines Include=" <BaseIntermediateOutputPath>$(_CsWinRTTempProjectBaseIntermediateDir)</BaseIntermediateOutputPath>" /> - <_CsWinRTTempProjectLines Include=" <IntermediateOutputPath>$(_CsWinRTTempProjectIntermediateDir)</IntermediateOutputPath>" /> + <_CsWinRTTempProjectLines Include=" <IntermediateOutputPath>$(_CsWinRTTempProjectIntermediateConfigDir)</IntermediateOutputPath>" /> <_CsWinRTTempProjectLines Include=" <CsWinRTBuildForNativeConsumer>true</CsWinRTBuildForNativeConsumer>" /> <_CsWinRTTempProjectLines Include=" <CsWinRTGenerateInteropAssembly>true</CsWinRTGenerateInteropAssembly>" /> <_CsWinRTTempProjectLines Include=" <CsWinRTGenerateProjection>false</CsWinRTGenerateProjection>" /> From 14e4653d79096cc2a18857e25c0f33c3bb2d17f3 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 3 May 2026 11:59:31 -0700 Subject: [PATCH 017/105] Replace temp-aggregator csproj with per-component MSBuild dispatch The temp-aggregator approach can't see component assemblies in its ReferencePath because Authoring.targets reports the component's primary output as the .winmd (with the .dll only as ManagedImplementation metadata). After CsWinRTRemoveWinMDReferences scrubs the winmd, nothing from the component is left in ReferencePath, so the aggregator's component projection generator finds no component types and emits no WinRT.Component.dll. Replace the aggregator with per-component direct MSBuild dispatch (matching what the original inline target in AuthoringConsumptionTest.vcxproj was doing): for each detected CsWinRTComponent project reference, invoke its Build with CsWinRTBuildForNativeConsumer=true so the component's own pipeline produces the merged hosting bundle in its own intermediate dir, then copy from there. Translates the C++ \='Win32' to the managed platform 'x86' for the path math. Single-component scenarios (the only ones currently exercised by tests) now work end to end. Multi-component aggregation - which has type-map duplicate-key concerns and was the original motivation for the aggregator csproj - is deferred as separate work. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../native/Microsoft.Windows.CsWinRT.targets | 156 +++++------------- 1 file changed, 43 insertions(+), 113 deletions(-) diff --git a/nuget/native/Microsoft.Windows.CsWinRT.targets b/nuget/native/Microsoft.Windows.CsWinRT.targets index bd9ccadd3..86d1ff073 100644 --- a/nuget/native/Microsoft.Windows.CsWinRT.targets +++ b/nuget/native/Microsoft.Windows.CsWinRT.targets @@ -3,15 +3,17 @@ Copyright (C) Microsoft Corporation. All rights reserved. Targets for native (C++) projects consuming C# WinRT component projects. -Import this file in your .vcxproj after Microsoft.Cpp.targets to enable -automatic generation of WinRT.Component.dll and WinRT.Interop.dll for -JIT hosting of authored WinRT components. -This target: - 1. Detects component project references (via CsWinRTComponent metadata) - 2. Generates a temporary C# project that references all component projects - 3. Builds the temporary project to produce interop assemblies - 4. Copies generated DLLs to the output directory +When a vcxproj imports this file (typically via the Microsoft.Windows.CsWinRT NuGet's +`build\native\Microsoft.Windows.CsWinRT.targets` auto-import), it walks the resolved +ProjectReference set, picks references whose CsWinRTComponent metadata is 'true', and +for each such component: + 1. Invokes the component's Build target with CsWinRTBuildForNativeConsumer=true so the + component's own pipeline generates its merged hosting bundle (WinRT.Component.dll, + WinRT.Interop.dll, WinRT.Projection.dll, WinRT.Sdk.Projection.dll, etc.) into the + component's intermediate directory. + 2. Copies those generated assemblies to the consumer's output directory, where the + C++ host loads them at runtime via WinRT.Host.dll / WinRT.Host.Shim.dll. Properties: - CsWinRTDisableNativeComponentInterop: set to 'true' to disable @@ -19,144 +21,72 @@ Properties: --> - - <_CsWinRTNativeConsumerIntermediateDir>$(IntDir)cswinrt\ - - - + <_CsWinRTComponentProjectPaths Include="%(_ResolvedProjectReferencePaths.MSBuildSourceProjectFile)" - Condition="'%(_ResolvedProjectReferencePaths.CsWinRTComponent)' == 'true'" /> + Condition="'%(_ResolvedProjectReferencePaths.CsWinRTComponent)' == 'true'"> + %(_ResolvedProjectReferencePaths.CsWinRTComponentTargetFramework) + - + - <_CsWinRTComponentTargetFramework>%(_ResolvedProjectReferencePaths.CsWinRTComponentTargetFramework) - <_CsWinRTComponentTargetFramework Condition="'$(_CsWinRTComponentTargetFramework)' == ''">net10.0-windows10.0.26100.1 + <_CsWinRTNativeConsumerManagedPlatform>$(Platform) + <_CsWinRTNativeConsumerManagedPlatform Condition="'$(Platform)' == 'Win32'">x86 - + Condition="'$(CsWinRTDisableNativeComponentInterop)' != 'true'" + Outputs="%(_CsWinRTComponentProjectPaths.Identity)"> - - <_CsWinRTHasComponentReferences Condition="'@(_CsWinRTComponentProjectPaths)' != ''">true - - - - - - - <_CsWinRTTempProjectDir>$(_CsWinRTNativeConsumerIntermediateDir) - <_CsWinRTTempProjectPath>$(_CsWinRTTempProjectDir)CsWinRT.NativeConsumer.csproj - - <_CsWinRTTempProjectTFMDir>$(_CsWinRTComponentTargetFramework) - - <_CsWinRTTempProjectBaseIntermediateDir>$(_CsWinRTTempProjectDir)obj\ - <_CsWinRTTempProjectIntermediateConfigDir>$(_CsWinRTTempProjectBaseIntermediateDir)$(Configuration)\ - <_CsWinRTTempProjectIntermediateDir>$(_CsWinRTTempProjectIntermediateConfigDir)$(_CsWinRTTempProjectTFMDir)\ - - <_CsWinRTPropsForAggregator>$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)..\Microsoft.Windows.CsWinRT.props')) - <_CsWinRTTargetsForAggregator>$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)..\Microsoft.Windows.CsWinRT.targets')) + <_CsWinRTComponentProjectFile>%(_CsWinRTComponentProjectPaths.Identity) + <_CsWinRTComponentProjectDir>$([System.IO.Path]::GetDirectoryName('$(_CsWinRTComponentProjectFile)'))\ + <_CsWinRTComponentTFM>%(_CsWinRTComponentProjectPaths.CsWinRTComponentTargetFramework) + <_CsWinRTComponentTFM Condition="'$(_CsWinRTComponentTFM)' == ''">net10.0 + <_CsWinRTComponentIntermediateDir>$(_CsWinRTComponentProjectDir)obj\$(_CsWinRTNativeConsumerManagedPlatform)\$(Configuration)\$(_CsWinRTComponentTFM)\ - - - - <_CsWinRTTempProjectLines Include="<Project>" /> - <_CsWinRTTempProjectLines Include=" <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />" /> - <_CsWinRTTempProjectLines Include=" <Import Project="$(_CsWinRTPropsForAggregator)" />" /> - <_CsWinRTTempProjectLines Include=" <PropertyGroup>" /> - <_CsWinRTTempProjectLines Include=" <TargetFramework>$(_CsWinRTComponentTargetFramework)</TargetFramework>" /> - <_CsWinRTTempProjectLines Include=" <Platforms>x64%3Bx86%3BARM64</Platforms>" /> - - <_CsWinRTTempProjectLines Include=" <BaseIntermediateOutputPath>$(_CsWinRTTempProjectBaseIntermediateDir)</BaseIntermediateOutputPath>" /> - <_CsWinRTTempProjectLines Include=" <IntermediateOutputPath>$(_CsWinRTTempProjectIntermediateConfigDir)</IntermediateOutputPath>" /> - <_CsWinRTTempProjectLines Include=" <CsWinRTBuildForNativeConsumer>true</CsWinRTBuildForNativeConsumer>" /> - <_CsWinRTTempProjectLines Include=" <CsWinRTGenerateInteropAssembly>true</CsWinRTGenerateInteropAssembly>" /> - <_CsWinRTTempProjectLines Include=" <CsWinRTGenerateProjection>false</CsWinRTGenerateProjection>" /> - <_CsWinRTTempProjectLines Include=" <EnableDefaultItems>false</EnableDefaultItems>" /> - <_CsWinRTTempProjectLines Include=" <GenerateAssemblyInfo>false</GenerateAssemblyInfo>" /> - <_CsWinRTTempProjectLines Include=" <ProduceReferenceAssembly>false</ProduceReferenceAssembly>" /> - <_CsWinRTTempProjectLines Include=" </PropertyGroup>" /> - <_CsWinRTTempProjectLines Include=" <ItemGroup>" /> - <_CsWinRTTempProjectLines Include=" <ProjectReference Include="%(_CsWinRTComponentProjectPaths.Identity)" />" /> - <_CsWinRTTempProjectLines Include=" </ItemGroup>" /> - <_CsWinRTTempProjectLines Include=" <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />" /> - <_CsWinRTTempProjectLines Include=" <Import Project="$(_CsWinRTTargetsForAggregator)" />" /> - <_CsWinRTTempProjectLines Include="</Project>" /> - - - - - - - - + + Properties="Configuration=$(Configuration);Platform=$(_CsWinRTNativeConsumerManagedPlatform);TargetFramework=$(_CsWinRTComponentTFM);CsWinRTBuildForNativeConsumer=true" /> - - - - <_CsWinRTGeneratedDlls Include="$(_CsWinRTTempProjectIntermediateDir)WinRT.Component.dll" Condition="Exists('$(_CsWinRTTempProjectIntermediateDir)WinRT.Component.dll')" /> - <_CsWinRTGeneratedDlls Include="$(_CsWinRTTempProjectIntermediateDir)WinRT.Interop.dll" Condition="Exists('$(_CsWinRTTempProjectIntermediateDir)WinRT.Interop.dll')" /> - <_CsWinRTGeneratedDlls Include="$(_CsWinRTTempProjectIntermediateDir)WinRT.Projection.dll" Condition="Exists('$(_CsWinRTTempProjectIntermediateDir)WinRT.Projection.dll')" /> - <_CsWinRTGeneratedDlls Include="$(_CsWinRTTempProjectIntermediateDir)WinRT.Sdk.Projection.dll" Condition="Exists('$(_CsWinRTTempProjectIntermediateDir)WinRT.Sdk.Projection.dll')" /> - <_CsWinRTGeneratedDlls Include="$(_CsWinRTTempProjectIntermediateDir)WinRT.Sdk.Xaml.Projection.dll" Condition="Exists('$(_CsWinRTTempProjectIntermediateDir)WinRT.Sdk.Xaml.Projection.dll')" /> + + <_CsWinRTNativeConsumerOutputs Include="$(_CsWinRTComponentIntermediateDir)WinRT.Component.dll" Condition="Exists('$(_CsWinRTComponentIntermediateDir)WinRT.Component.dll')" /> + <_CsWinRTNativeConsumerOutputs Include="$(_CsWinRTComponentIntermediateDir)WinRT.Interop.dll" Condition="Exists('$(_CsWinRTComponentIntermediateDir)WinRT.Interop.dll')" /> + <_CsWinRTNativeConsumerOutputs Include="$(_CsWinRTComponentIntermediateDir)WinRT.Projection.dll" Condition="Exists('$(_CsWinRTComponentIntermediateDir)WinRT.Projection.dll')" /> + <_CsWinRTNativeConsumerOutputs Include="$(_CsWinRTComponentIntermediateDir)WinRT.Sdk.Projection.dll" Condition="Exists('$(_CsWinRTComponentIntermediateDir)WinRT.Sdk.Projection.dll')" /> + <_CsWinRTNativeConsumerOutputs Include="$(_CsWinRTComponentIntermediateDir)WinRT.Sdk.Xaml.Projection.dll" Condition="Exists('$(_CsWinRTComponentIntermediateDir)WinRT.Sdk.Xaml.Projection.dll')" /> - + From 3e6184084f90ffafb6c6898d8f0b515954367387 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 3 May 2026 12:03:02 -0700 Subject: [PATCH 018/105] Restore aggregator design with explicit component .dll references Bring back the temp-aggregator csproj that ProjectReferences every detected CsWinRTComponent and runs cswinrt's full generator pipeline once across the union, so a single deduplicated WinRT.Interop.dll / WinRT.Component.dll / projection bundle is produced and the multi-component scenario (preventing type-map duplicate-key collisions across components) keeps working. Fix the previous structural blocker: each component's TargetPathWithTargetPlatformMoniker reports the .winmd as primary, with the .dll only as ManagedImplementation metadata, so after CsWinRTRemoveWinMDReferences nothing from the component remained in the aggregator's ReferencePath. Native.targets now captures %(_ResolvedProjectReferencePaths.ManagedImplementation) for component refs and emits an explicit per component into the aggregator csproj, alongside the existing . cswinrt's component projection generator now sees the [WindowsRuntimeComponentAssembly] markers and produces WinRT.Component.dll. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../native/Microsoft.Windows.CsWinRT.targets | 174 +++++++++++++----- 1 file changed, 133 insertions(+), 41 deletions(-) diff --git a/nuget/native/Microsoft.Windows.CsWinRT.targets b/nuget/native/Microsoft.Windows.CsWinRT.targets index 86d1ff073..67106451d 100644 --- a/nuget/native/Microsoft.Windows.CsWinRT.targets +++ b/nuget/native/Microsoft.Windows.CsWinRT.targets @@ -6,14 +6,25 @@ Targets for native (C++) projects consuming C# WinRT component projects. When a vcxproj imports this file (typically via the Microsoft.Windows.CsWinRT NuGet's `build\native\Microsoft.Windows.CsWinRT.targets` auto-import), it walks the resolved -ProjectReference set, picks references whose CsWinRTComponent metadata is 'true', and -for each such component: - 1. Invokes the component's Build target with CsWinRTBuildForNativeConsumer=true so the - component's own pipeline generates its merged hosting bundle (WinRT.Component.dll, - WinRT.Interop.dll, WinRT.Projection.dll, WinRT.Sdk.Projection.dll, etc.) into the - component's intermediate directory. - 2. Copies those generated assemblies to the consumer's output directory, where the - C++ host loads them at runtime via WinRT.Host.dll / WinRT.Host.Shim.dll. +ProjectReference set, picks references whose CsWinRTComponent metadata is 'true', and: + + 1. Synthesizes a temporary aggregator csproj in the consumer's intermediate directory + that ProjectReferences every detected component and explicitly References each + component's managed implementation .dll. The explicit Reference is necessary + because Authoring.targets reports each component's primary output as the .winmd + (with the .dll attached only as ManagedImplementation metadata); the aggregator + needs the .dll in its ReferencePath so cswinrt's component projection generator + can detect [WindowsRuntimeComponentAssembly]-marked types from the references. + + 2. Builds the aggregator with CsWinRTBuildForNativeConsumer=true so cswinrt's full + component / interop / projection generator pipeline runs once across the union + of all referenced components, producing a single deduplicated WinRT.Interop.dll + (avoiding type-map duplicate-key collisions that per-component generation would + hit) along with WinRT.Component.dll, WinRT.Projection.dll, and WinRT.Sdk.Projection.dll. + + 3. Copies the generated DLLs from the aggregator's intermediate directory to the + consumer's output directory, where the C++ host loads them at runtime through + WinRT.Host.dll / WinRT.Host.Shim.dll. Properties: - CsWinRTDisableNativeComponentInterop: set to 'true' to disable @@ -21,72 +32,153 @@ Properties: --> + + <_CsWinRTNativeConsumerIntermediateDir>$(IntDir)cswinrt\ + + - <_CsWinRTComponentProjectPaths Include="%(_ResolvedProjectReferencePaths.MSBuildSourceProjectFile)" - Condition="'%(_ResolvedProjectReferencePaths.CsWinRTComponent)' == 'true'"> - %(_ResolvedProjectReferencePaths.CsWinRTComponentTargetFramework) - + Condition="'%(_ResolvedProjectReferencePaths.CsWinRTComponent)' == 'true'" /> + <_CsWinRTComponentManagedImplementationPaths Include="%(_ResolvedProjectReferencePaths.ManagedImplementation)" + Condition="'%(_ResolvedProjectReferencePaths.CsWinRTComponent)' == 'true' and '%(_ResolvedProjectReferencePaths.ManagedImplementation)' != ''" /> - + - <_CsWinRTNativeConsumerManagedPlatform>$(Platform) - <_CsWinRTNativeConsumerManagedPlatform Condition="'$(Platform)' == 'Win32'">x86 + <_CsWinRTComponentTargetFramework>%(_ResolvedProjectReferencePaths.CsWinRTComponentTargetFramework) + <_CsWinRTComponentTargetFramework Condition="'$(_CsWinRTComponentTargetFramework)' == ''">net10.0-windows10.0.26100.1 - + Condition="'$(CsWinRTDisableNativeComponentInterop)' != 'true'"> - <_CsWinRTComponentProjectFile>%(_CsWinRTComponentProjectPaths.Identity) - <_CsWinRTComponentProjectDir>$([System.IO.Path]::GetDirectoryName('$(_CsWinRTComponentProjectFile)'))\ - <_CsWinRTComponentTFM>%(_CsWinRTComponentProjectPaths.CsWinRTComponentTargetFramework) - <_CsWinRTComponentTFM Condition="'$(_CsWinRTComponentTFM)' == ''">net10.0 - <_CsWinRTComponentIntermediateDir>$(_CsWinRTComponentProjectDir)obj\$(_CsWinRTNativeConsumerManagedPlatform)\$(Configuration)\$(_CsWinRTComponentTFM)\ + <_CsWinRTHasComponentReferences Condition="'@(_CsWinRTComponentProjectPaths)' != ''">true + + + + + + <_CsWinRTTempProjectDir>$(_CsWinRTNativeConsumerIntermediateDir) + <_CsWinRTTempProjectPath>$(_CsWinRTTempProjectDir)CsWinRT.NativeConsumer.csproj + <_CsWinRTTempProjectTFMDir>$(_CsWinRTComponentTargetFramework) + + <_CsWinRTTempProjectBaseIntermediateDir>$(_CsWinRTTempProjectDir)obj\ + <_CsWinRTTempProjectIntermediateConfigDir>$(_CsWinRTTempProjectBaseIntermediateDir)$(Configuration)\ + <_CsWinRTTempProjectIntermediateDir>$(_CsWinRTTempProjectIntermediateConfigDir)$(_CsWinRTTempProjectTFMDir)\ + + <_CsWinRTPropsForAggregator>$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)..\Microsoft.Windows.CsWinRT.props')) + <_CsWinRTTargetsForAggregator>$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)..\Microsoft.Windows.CsWinRT.targets')) - - + + + <_CsWinRTTempProjectLines Include="<Project>" /> + <_CsWinRTTempProjectLines Include=" <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />" /> + <_CsWinRTTempProjectLines Include=" <Import Project="$(_CsWinRTPropsForAggregator)" />" /> + <_CsWinRTTempProjectLines Include=" <PropertyGroup>" /> + <_CsWinRTTempProjectLines Include=" <TargetFramework>$(_CsWinRTComponentTargetFramework)</TargetFramework>" /> + <_CsWinRTTempProjectLines Include=" <Platforms>x64%3Bx86%3BARM64</Platforms>" /> + + <_CsWinRTTempProjectLines Include=" <BaseIntermediateOutputPath>$(_CsWinRTTempProjectBaseIntermediateDir)</BaseIntermediateOutputPath>" /> + <_CsWinRTTempProjectLines Include=" <IntermediateOutputPath>$(_CsWinRTTempProjectIntermediateConfigDir)</IntermediateOutputPath>" /> + <_CsWinRTTempProjectLines Include=" <CsWinRTBuildForNativeConsumer>true</CsWinRTBuildForNativeConsumer>" /> + <_CsWinRTTempProjectLines Include=" <CsWinRTGenerateInteropAssembly>true</CsWinRTGenerateInteropAssembly>" /> + <_CsWinRTTempProjectLines Include=" <CsWinRTGenerateProjection>false</CsWinRTGenerateProjection>" /> + <_CsWinRTTempProjectLines Include=" <EnableDefaultItems>false</EnableDefaultItems>" /> + <_CsWinRTTempProjectLines Include=" <GenerateAssemblyInfo>false</GenerateAssemblyInfo>" /> + <_CsWinRTTempProjectLines Include=" <ProduceReferenceAssembly>false</ProduceReferenceAssembly>" /> + <_CsWinRTTempProjectLines Include=" </PropertyGroup>" /> + <_CsWinRTTempProjectLines Include=" <ItemGroup>" /> + <_CsWinRTTempProjectLines Include=" <ProjectReference Include="%(_CsWinRTComponentProjectPaths.Identity)" />" /> + + <_CsWinRTTempProjectLines Include=" <Reference Include="%(_CsWinRTComponentManagedImplementationPaths.Identity)"><Private>false</Private></Reference>" /> + <_CsWinRTTempProjectLines Include=" </ItemGroup>" /> + <_CsWinRTTempProjectLines Include=" <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />" /> + <_CsWinRTTempProjectLines Include=" <Import Project="$(_CsWinRTTargetsForAggregator)" />" /> + <_CsWinRTTempProjectLines Include="</Project>" /> + + + + + + + + + Properties="Configuration=$(Configuration);Platform=$(Platform)" /> - - <_CsWinRTNativeConsumerOutputs Include="$(_CsWinRTComponentIntermediateDir)WinRT.Component.dll" Condition="Exists('$(_CsWinRTComponentIntermediateDir)WinRT.Component.dll')" /> - <_CsWinRTNativeConsumerOutputs Include="$(_CsWinRTComponentIntermediateDir)WinRT.Interop.dll" Condition="Exists('$(_CsWinRTComponentIntermediateDir)WinRT.Interop.dll')" /> - <_CsWinRTNativeConsumerOutputs Include="$(_CsWinRTComponentIntermediateDir)WinRT.Projection.dll" Condition="Exists('$(_CsWinRTComponentIntermediateDir)WinRT.Projection.dll')" /> - <_CsWinRTNativeConsumerOutputs Include="$(_CsWinRTComponentIntermediateDir)WinRT.Sdk.Projection.dll" Condition="Exists('$(_CsWinRTComponentIntermediateDir)WinRT.Sdk.Projection.dll')" /> - <_CsWinRTNativeConsumerOutputs Include="$(_CsWinRTComponentIntermediateDir)WinRT.Sdk.Xaml.Projection.dll" Condition="Exists('$(_CsWinRTComponentIntermediateDir)WinRT.Sdk.Xaml.Projection.dll')" /> + + + + <_CsWinRTGeneratedDlls Include="$(_CsWinRTTempProjectIntermediateDir)WinRT.Component.dll" Condition="Exists('$(_CsWinRTTempProjectIntermediateDir)WinRT.Component.dll')" /> + <_CsWinRTGeneratedDlls Include="$(_CsWinRTTempProjectIntermediateDir)WinRT.Interop.dll" Condition="Exists('$(_CsWinRTTempProjectIntermediateDir)WinRT.Interop.dll')" /> + <_CsWinRTGeneratedDlls Include="$(_CsWinRTTempProjectIntermediateDir)WinRT.Projection.dll" Condition="Exists('$(_CsWinRTTempProjectIntermediateDir)WinRT.Projection.dll')" /> + <_CsWinRTGeneratedDlls Include="$(_CsWinRTTempProjectIntermediateDir)WinRT.Sdk.Projection.dll" Condition="Exists('$(_CsWinRTTempProjectIntermediateDir)WinRT.Sdk.Projection.dll')" /> + <_CsWinRTGeneratedDlls Include="$(_CsWinRTTempProjectIntermediateDir)WinRT.Sdk.Xaml.Projection.dll" Condition="Exists('$(_CsWinRTTempProjectIntermediateDir)WinRT.Sdk.Xaml.Projection.dll')" /> - + From 08486c278b594130c93149b6c0a7c4d380a73ddb Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 3 May 2026 12:22:39 -0700 Subject: [PATCH 019/105] Use Windows-targeted TFM for AuthoringTest; rely on SDK winmd handling Switch AuthoringTest's TargetFramework from net10.0 to net10.0-windows10.0.26100.1 (the CsWinRT 3.0 convention - .1 revision identifies the 3.0 stack). Update AuthoringConsumptionTest.vcxproj's hardcoded references to the AuthoringTest output path to match. Now that the aggregator's TargetFramework propagates from the component as a Windows-targeted TFM, Microsoft.NET.Windows.targets imports into the aggregator and its built-in RemoveManagedWinRTComponentWinMDReferences / AddWinRTComponentImplementationReference targets fire automatically. They scrub the component's .winmd from _ResolvedProjectReferencePaths and re-inject the managed implementation .dll (from ManagedImplementation metadata that Authoring.targets:166 already attaches) as an explicit Reference. So cswinrt's component projection generator sees [WindowsRuntimeComponentAssembly] on the .dll naturally. Drop the manual / _CsWinRTComponentManagedImplementationPaths plumbing in Native.targets - the SDK now provides this for us. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../native/Microsoft.Windows.CsWinRT.targets | 26 +++++-------------- .../AuthoringConsumptionTest.vcxproj | 10 +++---- src/Tests/AuthoringTest/AuthoringTest.csproj | 2 +- 3 files changed, 13 insertions(+), 25 deletions(-) diff --git a/nuget/native/Microsoft.Windows.CsWinRT.targets b/nuget/native/Microsoft.Windows.CsWinRT.targets index 67106451d..f1a582607 100644 --- a/nuget/native/Microsoft.Windows.CsWinRT.targets +++ b/nuget/native/Microsoft.Windows.CsWinRT.targets @@ -9,12 +9,12 @@ When a vcxproj imports this file (typically via the Microsoft.Windows.CsWinRT Nu ProjectReference set, picks references whose CsWinRTComponent metadata is 'true', and: 1. Synthesizes a temporary aggregator csproj in the consumer's intermediate directory - that ProjectReferences every detected component and explicitly References each - component's managed implementation .dll. The explicit Reference is necessary - because Authoring.targets reports each component's primary output as the .winmd - (with the .dll attached only as ManagedImplementation metadata); the aggregator - needs the .dll in its ReferencePath so cswinrt's component projection generator - can detect [WindowsRuntimeComponentAssembly]-marked types from the references. + that ProjectReferences every detected component. The aggregator's TargetFramework + is taken from the components themselves (which are required to use a Windows- + targeted TFM such as net10.0-windows10.0.X.Y), so Microsoft.NET.Windows.targets' + RemoveManagedWinRTComponentWinMDReferences / AddWinRTComponentImplementationReference + pair fires automatically and re-injects each component's managed implementation .dll + into the aggregator's Reference set. 2. Builds the aggregator with CsWinRTBuildForNativeConsumer=true so cswinrt's full component / interop / projection generator pipeline runs once across the union @@ -40,9 +40,7 @@ Properties: ============================================================ _DetectCsWinRTNativeComponentReferences - Collects component project reference paths and the managed implementation .dll path - for each (extracted from ManagedImplementation metadata that Authoring.targets attaches - to each component's TargetPathWithTargetPlatformMoniker output). + Collects component project reference paths. ============================================================ --> <_CsWinRTComponentProjectPaths Include="%(_ResolvedProjectReferencePaths.MSBuildSourceProjectFile)" Condition="'%(_ResolvedProjectReferencePaths.CsWinRTComponent)' == 'true'" /> - <_CsWinRTComponentManagedImplementationPaths Include="%(_ResolvedProjectReferencePaths.ManagedImplementation)" - Condition="'%(_ResolvedProjectReferencePaths.CsWinRTComponent)' == 'true' and '%(_ResolvedProjectReferencePaths.ManagedImplementation)' != ''" /> @@ -138,14 +134,6 @@ Properties: <_CsWinRTTempProjectLines Include=" </PropertyGroup>" /> <_CsWinRTTempProjectLines Include=" <ItemGroup>" /> <_CsWinRTTempProjectLines Include=" <ProjectReference Include="%(_CsWinRTComponentProjectPaths.Identity)" />" /> - - <_CsWinRTTempProjectLines Include=" <Reference Include="%(_CsWinRTComponentManagedImplementationPaths.Identity)"><Private>false</Private></Reference>" /> <_CsWinRTTempProjectLines Include=" </ItemGroup>" /> <_CsWinRTTempProjectLines Include=" <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />" /> <_CsWinRTTempProjectLines Include=" <Import Project="$(_CsWinRTTargetsForAggregator)" />" /> diff --git a/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj b/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj index 9ca7e738b..d4f5a2ab0 100644 --- a/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj +++ b/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj @@ -99,7 +99,7 @@ {41e2a272-150f-42f5-ad40-047aad9088a0} - TargetFramework=net10.0 + TargetFramework=net10.0-windows10.0.26100.1 - + @@ -129,7 +129,7 @@ - ..\AuthoringTest\bin\$(_WinMDPlatform)\$(Configuration)\net10.0\win-$(Platform)\AuthoringTest.winmd + ..\AuthoringTest\bin\$(_WinMDPlatform)\$(Configuration)\net10.0-windows10.0.26100.1\win-$(Platform)\AuthoringTest.winmd true diff --git a/src/Tests/AuthoringTest/AuthoringTest.csproj b/src/Tests/AuthoringTest/AuthoringTest.csproj index 72ed2eacc..a0d28b670 100644 --- a/src/Tests/AuthoringTest/AuthoringTest.csproj +++ b/src/Tests/AuthoringTest/AuthoringTest.csproj @@ -1,7 +1,7 @@ - net10.0 + net10.0-windows10.0.26100.1 x64;x86 true true From 3bf45d29b1aff334a5532936bb6b13a287b8ed4b Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 3 May 2026 12:40:04 -0700 Subject: [PATCH 020/105] Scrub CsWinRT3 framework references in repo build The .NET 10 SDK auto-injects Microsoft.Windows.SDK.NET.Ref.CsWinRT3.Windows (and .CsWinRT3.Xaml when UseUwp=true) for projects targeting a CsWinRT3 TFM (revision .1). The repo previously only scrubbed the 2.x-era names; AuthoringTest's recent move to net10.0-windows10.0.26100.1 means it now picks up the CsWinRT3 variants. Add removes for those so repo-local builds keep using cswinrt's locally-generated projection rather than the SDK's pinned reference assemblies. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Directory.Build.targets | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index 27f69c3ec..1b889581d 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -24,6 +24,8 @@ + + From c3675b2314c9252bb525a36d6d0c1402fde9ca17 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 3 May 2026 13:18:38 -0700 Subject: [PATCH 021/105] Revert "Scrub CsWinRT3 framework references in repo build" This reverts commit 3bf45d29b1aff334a5532936bb6b13a287b8ed4b. --- src/Directory.Build.targets | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index 1b889581d..27f69c3ec 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -24,8 +24,6 @@ - - From b3d184624057530f1e64e8a8191d01e5c30cfe39 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 3 May 2026 13:20:12 -0700 Subject: [PATCH 022/105] Reapply "Scrub CsWinRT3 framework references in repo build" This reverts commit c3675b2314c9252bb525a36d6d0c1402fde9ca17. --- src/Directory.Build.targets | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index 27f69c3ec..1b889581d 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -24,6 +24,8 @@ + + From cbe5ad80a640ab0c42258f81fab8179593a8043f Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 3 May 2026 13:21:30 -0700 Subject: [PATCH 023/105] Exclude Microsoft.WindowsAppSDK.WinUI assets in AuthoringTest AuthoringTest builds against the locally-generated WinAppSDK projection (via WinAppSDK.csproj), not the strong-named Microsoft.WinUI shipped in the WindowsAppSDK package. With AuthoringTest's TFM at net10.0 (non-Windows), the package's assets didn't activate. With net10.0-windows10.0.26100.1, they do, and the package's Microsoft.WinUI 3.0.0.0 (PKT de31ebe4ad15742b) conflicts with the locally-built unsigned 1.0.0.0, surfacing as MSB3243 + NETSDK1148 ('a referenced assembly was compiled using a newer version of Microsoft.Windows.SDK.NET.dll'). Mirror the existing ExcludeAssets=all pattern already used for Microsoft.Web.WebView2 on the next line. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Tests/AuthoringTest/AuthoringTest.csproj | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Tests/AuthoringTest/AuthoringTest.csproj b/src/Tests/AuthoringTest/AuthoringTest.csproj index a0d28b670..e6d347d18 100644 --- a/src/Tests/AuthoringTest/AuthoringTest.csproj +++ b/src/Tests/AuthoringTest/AuthoringTest.csproj @@ -33,7 +33,9 @@ - + + all + all From acccf831fa0c561bc4da8b29a95522be62455632 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 3 May 2026 14:30:29 -0700 Subject: [PATCH 024/105] Capture component winmds before SDK scrubs them from ProjectReferences On Windows-targeted TFMs the .NET SDK's RemoveManagedWinRTComponentWinMDReferences runs AfterTargets=ResolveProjectReferences and scrubs CsWinRT-component winmds from _ResolvedProjectReferencePaths. Our CsWinRTRemoveWinMDReferences runs later (AfterTargets=ResolveReferences) and only sees the post-scrub state, so component winmds never reach CsWinRTInputs / _WinMDPathsList. cswinrtprojectiongen then runs without the winmd in --winmd-paths, finds no component types, emits no WinRT.Component.dll, and cswinrtinteropgen fails with CSWINRTINTEROPGEN0091. Add CsWinRTCaptureProjectReferenceWinMDs that runs AfterTargets=ResolveProjectReferences and BeforeTargets=RemoveManagedWinRTComponentWinMDReferences. It captures Extension=.winmd + Implementation=WinRT.Host.dll items from _ResolvedProjectReferencePaths into CsWinRTInputs before the SDK removes them. _WinMDPathsList now includes the component winmds and cswinrt's generators see the component types. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- nuget/Microsoft.Windows.CsWinRT.targets | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/nuget/Microsoft.Windows.CsWinRT.targets b/nuget/Microsoft.Windows.CsWinRT.targets index 96a5ed604..e97580c05 100644 --- a/nuget/Microsoft.Windows.CsWinRT.targets +++ b/nuget/Microsoft.Windows.CsWinRT.targets @@ -135,6 +135,23 @@ Copyright (C) Microsoft Corporation. All rights reserved. + + + + + + + From 7e2e354fc26627beb0557492affc16af2560e748 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 3 May 2026 16:06:05 -0700 Subject: [PATCH 025/105] Revert "Reapply "Scrub CsWinRT3 framework references in repo build"" This reverts commit b3d184624057530f1e64e8a8191d01e5c30cfe39. --- src/Directory.Build.targets | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index 1b889581d..27f69c3ec 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -24,8 +24,6 @@ - - From 8eae4b21658e1362a79cad476635537913846389 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 3 May 2026 16:09:57 -0700 Subject: [PATCH 026/105] Reapply "Reapply "Scrub CsWinRT3 framework references in repo build"" This reverts commit 7e2e354fc26627beb0557492affc16af2560e748. --- src/Directory.Build.targets | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index 27f69c3ec..1b889581d 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -24,6 +24,8 @@ + + From 07010bf89cc3f6d6411c81d10299d9abebd94794 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 3 May 2026 16:11:04 -0700 Subject: [PATCH 027/105] Revert "Reapply "Reapply "Scrub CsWinRT3 framework references in repo build""" This reverts commit 8eae4b21658e1362a79cad476635537913846389. --- src/Directory.Build.targets | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index 1b889581d..27f69c3ec 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -24,8 +24,6 @@ - - From 77cdea0abaa69ff0b1c9036d5ad6d80558cc883b Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 3 May 2026 16:25:35 -0700 Subject: [PATCH 028/105] Narrow Microsoft.WindowsAppSDK.WinUI ExcludeAssets to compile;runtime ExcludeAssets=all also excludes the build asset, which removes WinAppSDK's MakePri targets from the import graph. That's why AuthoringTest.pri was no longer being generated under the new Windows-targeted TFM. Narrow the exclusion so the Microsoft.WinUI 3.0.0.0-vs-1.0.0.0 compile/runtime conflict is still suppressed but the PRI generation step still runs. --- src/Tests/AuthoringTest/AuthoringTest.csproj | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Tests/AuthoringTest/AuthoringTest.csproj b/src/Tests/AuthoringTest/AuthoringTest.csproj index e6d347d18..0da7dbbf9 100644 --- a/src/Tests/AuthoringTest/AuthoringTest.csproj +++ b/src/Tests/AuthoringTest/AuthoringTest.csproj @@ -34,7 +34,9 @@ - all + + compile;runtime all From b7d2aeefedf34d5079a86aba075a0f2481e8021c Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 3 May 2026 16:30:51 -0700 Subject: [PATCH 029/105] Scrub CsWinRT3 SDK ref-package framework references in repo build The .1-revision Windows TFM causes the .NET SDK to inject Microsoft.Windows.SDK.NET.Ref.CsWinRT3.{Windows,Xaml}, which carry the prebuilt SDK projection assemblies. This repo builds those projections from source, so let the local copies be the only ones in scope by removing the SDK-injected framework references. --- src/Directory.Build.targets | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index 27f69c3ec..0e6514ea3 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -24,6 +24,11 @@ + + + From 7bb15f5247f662f5ef7404b4e68d29a5f09980bb Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 3 May 2026 18:36:09 -0700 Subject: [PATCH 030/105] Propagate CsWinRTBuildForNativeConsumer to component ProjectReferences The aggregator csproj sets CsWinRTBuildForNativeConsumer=true on itself, but that property doesn't flow into transitive ProjectReferences by default. Each referenced component (e.g. AuthoringTest.csproj) compiles with the property unset, so TypeMapAssemblyTargetGenerator's gate (isOutputTypeExe || isPublishAotLibrary || isBuildForNativeConsumer) stays off. Result: no [TypeMapAssemblyTarget] assembly attributes are emitted on the component .dll, and runtime activation through WinRT.Host fails because the type map groups can't be resolved. Set the property explicitly via AdditionalProperties on the synthesized ProjectReference so each component sees it. --- nuget/native/Microsoft.Windows.CsWinRT.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nuget/native/Microsoft.Windows.CsWinRT.targets b/nuget/native/Microsoft.Windows.CsWinRT.targets index f1a582607..2f35c43c8 100644 --- a/nuget/native/Microsoft.Windows.CsWinRT.targets +++ b/nuget/native/Microsoft.Windows.CsWinRT.targets @@ -133,7 +133,7 @@ Properties: <_CsWinRTTempProjectLines Include=" <ProduceReferenceAssembly>false</ProduceReferenceAssembly>" /> <_CsWinRTTempProjectLines Include=" </PropertyGroup>" /> <_CsWinRTTempProjectLines Include=" <ItemGroup>" /> - <_CsWinRTTempProjectLines Include=" <ProjectReference Include="%(_CsWinRTComponentProjectPaths.Identity)" />" /> + <_CsWinRTTempProjectLines Include=" <ProjectReference Include="%(_CsWinRTComponentProjectPaths.Identity)" AdditionalProperties="CsWinRTBuildForNativeConsumer=true" />" /> <_CsWinRTTempProjectLines Include=" </ItemGroup>" /> <_CsWinRTTempProjectLines Include=" <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />" /> <_CsWinRTTempProjectLines Include=" <Import Project="$(_CsWinRTTargetsForAggregator)" />" /> From 9ae425b2354be978708b6ce5ab22d5552f7ebe36 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 3 May 2026 18:47:24 -0700 Subject: [PATCH 031/105] Disable per-component interop generation when propagating CsWinRTBuildForNativeConsumer Setting CsWinRTBuildForNativeConsumer=true on the component project also implicitly enables CsWinRTGenerateInteropAssembly (CsWinRTGen.targets:23), which makes the component try to run its own interop / projection / SDK projection generators. That manipulates the component's reference set in ways that break compile-time resolution of forwarder types (CS1069 for Button, IXamlType, IWwwFormUrlDecoderEntry, etc.). The aggregator is the one that generates the merged interop pipeline. Pass CsWinRTGenerateInteropAssembly=false alongside the new-consumer flag so the component only emits type-map assembly attributes via the source generator and skips the per-project pipeline. --- nuget/native/Microsoft.Windows.CsWinRT.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nuget/native/Microsoft.Windows.CsWinRT.targets b/nuget/native/Microsoft.Windows.CsWinRT.targets index 2f35c43c8..9b21d6fe7 100644 --- a/nuget/native/Microsoft.Windows.CsWinRT.targets +++ b/nuget/native/Microsoft.Windows.CsWinRT.targets @@ -133,7 +133,7 @@ Properties: <_CsWinRTTempProjectLines Include=" <ProduceReferenceAssembly>false</ProduceReferenceAssembly>" /> <_CsWinRTTempProjectLines Include=" </PropertyGroup>" /> <_CsWinRTTempProjectLines Include=" <ItemGroup>" /> - <_CsWinRTTempProjectLines Include=" <ProjectReference Include="%(_CsWinRTComponentProjectPaths.Identity)" AdditionalProperties="CsWinRTBuildForNativeConsumer=true" />" /> + <_CsWinRTTempProjectLines Include=" <ProjectReference Include="%(_CsWinRTComponentProjectPaths.Identity)" AdditionalProperties="CsWinRTBuildForNativeConsumer=true%3BCsWinRTGenerateInteropAssembly=false" />" /> <_CsWinRTTempProjectLines Include=" </ItemGroup>" /> <_CsWinRTTempProjectLines Include=" <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />" /> <_CsWinRTTempProjectLines Include=" <Import Project="$(_CsWinRTTargetsForAggregator)" />" /> From 2cf196801dd8e04a58d543307a3839a0598d66bc Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 3 May 2026 19:12:18 -0700 Subject: [PATCH 032/105] Emit TypeMapAssemblyTarget on component libraries Replace the source generator's isBuildForNativeConsumer leg with an isComponent (CsWinRTComponent=true) check. Components are by definition the deployable unit when consumed natively and part of the deployable unit when consumed by a managed app, so they should always be self- describing for the runtime's TypeMap discovery. This also removes the build-twice race that was masking missing TypeMap attributes when AuthoringConsumptionTest.vcxproj's direct ProjectReference to AuthoringTest.csproj was building the component without the property and the aggregator was building it again with the property; whichever build ran last won, and that was usually the one without attributes. Drop the aggregator's now-redundant AdditionalProperties workaround on the synthesized component ProjectReference. --- nuget/native/Microsoft.Windows.CsWinRT.targets | 2 +- .../TypeMapAssemblyTargetGenerator.cs | 18 +++++++----------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/nuget/native/Microsoft.Windows.CsWinRT.targets b/nuget/native/Microsoft.Windows.CsWinRT.targets index 9b21d6fe7..f1a582607 100644 --- a/nuget/native/Microsoft.Windows.CsWinRT.targets +++ b/nuget/native/Microsoft.Windows.CsWinRT.targets @@ -133,7 +133,7 @@ Properties: <_CsWinRTTempProjectLines Include=" <ProduceReferenceAssembly>false</ProduceReferenceAssembly>" /> <_CsWinRTTempProjectLines Include=" </PropertyGroup>" /> <_CsWinRTTempProjectLines Include=" <ItemGroup>" /> - <_CsWinRTTempProjectLines Include=" <ProjectReference Include="%(_CsWinRTComponentProjectPaths.Identity)" AdditionalProperties="CsWinRTBuildForNativeConsumer=true%3BCsWinRTGenerateInteropAssembly=false" />" /> + <_CsWinRTTempProjectLines Include=" <ProjectReference Include="%(_CsWinRTComponentProjectPaths.Identity)" />" /> <_CsWinRTTempProjectLines Include=" </ItemGroup>" /> <_CsWinRTTempProjectLines Include=" <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />" /> <_CsWinRTTempProjectLines Include=" <Import Project="$(_CsWinRTTargetsForAggregator)" />" /> diff --git a/src/Authoring/WinRT.SourceGenerator2/TypeMapAssemblyTargetGenerator.cs b/src/Authoring/WinRT.SourceGenerator2/TypeMapAssemblyTargetGenerator.cs index 0fc02a3df..37999224c 100644 --- a/src/Authoring/WinRT.SourceGenerator2/TypeMapAssemblyTargetGenerator.cs +++ b/src/Authoring/WinRT.SourceGenerator2/TypeMapAssemblyTargetGenerator.cs @@ -40,10 +40,10 @@ public void Initialize(IncrementalGeneratorInitializationContext context) return options.GlobalOptions.GetCsWinRTUseWindowsUIXamlProjections(); }); - // Get whether the project is being built for a native consumer - IncrementalValueProvider isBuildForNativeConsumer = context.AnalyzerConfigOptionsProvider.Select(static (options, token) => + // Get whether the current project is itself a component + IncrementalValueProvider isComponent = context.AnalyzerConfigOptionsProvider.Select(static (options, token) => { - return options.GlobalOptions.GetBuildForNativeConsumer(); + return options.GlobalOptions.GetCsWinRTComponent(); }); // Get whether the current project is a library published with Native AOT @@ -52,11 +52,13 @@ public void Initialize(IncrementalGeneratorInitializationContext context) .Combine(isPublishAot) .Select(static (flags, token) => flags.Left && flags.Right); - // Get whether the generator should actually run or not + // Get whether the generator should actually run or not. + // The gate fires for any unit that ships TypeMap entries: an executable, a NativeAOT-published library, + // or a Windows Runtime component (the component .dll itself is the deployable when consumed natively). IncrementalValueProvider isGeneratorEnabled = isOutputTypeExe .Combine(isPublishAotLibrary) - .Combine(isBuildForNativeConsumer) + .Combine(isComponent) .Select(static (flags, token) => flags.Left.Left || flags.Left.Right || flags.Right); // Gather all PE references from the current compilation @@ -108,12 +110,6 @@ public void Initialize(IncrementalGeneratorInitializationContext context) // Also generate the '[TypeMapAssemblyTarget]' entry for the merged projection context.RegisterImplementationSourceOutput(hasMergedProjection, Execute.EmitMergedProjectionTypeMapAssemblyTargetAttributes); - // Get whether the current project is a component - IncrementalValueProvider isComponent = context.AnalyzerConfigOptionsProvider.Select(static (options, token) => - { - return options.GlobalOptions.GetCsWinRTComponent(); - }); - // Whether any component assemblies are referenced, or the current project is itself a component IncrementalValueProvider hasComponentAssembly = collectedComponentAssemblyNames From cdfa093860bcb1cf11ed004c485658f12610a6a0 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 3 May 2026 20:53:48 -0700 Subject: [PATCH 033/105] Tidy comments on AuthoringTest ExcludeAssets and FrameworkReference removals --- src/Directory.Build.targets | 5 ++--- src/Tests/AuthoringTest/AuthoringTest.csproj | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index 0e6514ea3..5a10c6a6d 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -21,12 +21,11 @@ + - diff --git a/src/Tests/AuthoringTest/AuthoringTest.csproj b/src/Tests/AuthoringTest/AuthoringTest.csproj index 0da7dbbf9..6d0747e6c 100644 --- a/src/Tests/AuthoringTest/AuthoringTest.csproj +++ b/src/Tests/AuthoringTest/AuthoringTest.csproj @@ -34,8 +34,7 @@ - + compile;runtime From 25119585a83d026fee9f6bc8e6d579d33a06510a Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 3 May 2026 23:40:38 -0700 Subject: [PATCH 034/105] Fix two issues uncovered by external NuGet consumer testing (1) ProjectionGenerator: in Windows-SDK-only mode, when no Microsoft.Windows.SDK.NET reference assembly is present in the reference set, the fallback at line 254 calls WriteWindowsSdkFilters to hardcode the SDK includes but forgot to set hasTypesToProject=true. That caused Run() to early-exit before invoking cswinrt.exe + Roslyn, so no WinRT.Sdk.Projection.dll was produced and the merged projection generator subsequently failed with FileNotFoundException. Mirrors the flag-set in the parallel branch at line 232. (2) Native.targets: _CsWinRTNativeConsumerIntermediateDir was set to '\cswinrt\\' which is relative for a vcxproj. The relative value was written into the synthesized aggregator csproj as BaseIntermediateOutputPath; when the aggregator is built, MSBuild re-resolves that relative path against the aggregator's own directory (which is itself the cswinrt\\ folder), causing the cswinrt\\ segment to double in all derived paths. Fixed by normalizing absolute up front via MSBuild::NormalizeDirectory. --- nuget/native/Microsoft.Windows.CsWinRT.targets | 2 +- .../Generation/ProjectionGenerator.Generate.cs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/nuget/native/Microsoft.Windows.CsWinRT.targets b/nuget/native/Microsoft.Windows.CsWinRT.targets index f1a582607..e897ba308 100644 --- a/nuget/native/Microsoft.Windows.CsWinRT.targets +++ b/nuget/native/Microsoft.Windows.CsWinRT.targets @@ -33,7 +33,7 @@ Properties: - <_CsWinRTNativeConsumerIntermediateDir>$(IntDir)cswinrt\ + <_CsWinRTNativeConsumerIntermediateDir>$([MSBuild]::NormalizeDirectory('$(MSBuildProjectDirectory)', '$(IntDir)', 'cswinrt')) + $([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)', '..\metadata\WindowsRuntime.Internal.winmd')) + - + + WinRT.Projection .NETCoreApp From e7d757663dbd2ec7ebb0c7002e371562ec9d1d1a Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Mon, 4 May 2026 00:15:44 -0700 Subject: [PATCH 037/105] Wire WindowsSdkPackageVersion through to the synthesized aggregator csproj (1) Authoring.targets: each component csproj now exposes its WindowsSdkPackageVersion as 'CsWinRTComponentWindowsSdkPackageVersion' metadata on TargetPathWithTargetPlatformMoniker, mirroring how 'CsWinRTComponent' / 'CsWinRTComponentTargetFramework' are exposed today. This lets native consumers see the value through _ResolvedProjectReferencePaths. (2) Native.targets (synthesized aggregator): the aggregator csproj now sets WindowsSdkPackageVersion to (in precedence order): - CsWinRTNativeConsumerWindowsSdkPackageVersion (consumer override from the vcxproj), or - CsWinRTComponentWindowsSdkPackageVersion from the first component reference. Without this the SDK-injected Microsoft.Windows.SDK.NET.Ref FrameworkReference would fall back to its default version, which may not be available locally and silently leaves 'Microsoft.Windows.SDK.NET.dll' out of the aggregator's reference set. (3) Interop generator: drop the redundant filename-based lookup of the SDK projection module in DefineInteropModule. The module is loaded explicitly in Discover.cs from args.WinRTSdkProjectionAssemblyPath and tracked on discoveryState.WindowsRuntimeSdkProjectionModule (which is [MemberNotNull] after TrackWindowsRuntimeSdkProjectionModule), and downstream code already reads the tracked field directly. The lookup was hardcoding 'Microsoft.Windows.SDK.NET.dll' (a CsWinRT 2.x-era filename) and would fail in legitimate CsWinRT 3.0 scenarios where that ref dll is not in the reference set. Remove the unused OUT param and the now-unreached WellKnownInteropExceptions helper for error 0040. --- .../Microsoft.Windows.CsWinRT.Authoring.targets | 3 +++ nuget/native/Microsoft.Windows.CsWinRT.targets | 16 ++++++++++++++++ .../Errors/WellKnownInteropExceptions.cs | 8 -------- .../Generation/InteropGenerator.Emit.cs | 17 ++++++----------- 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/nuget/Microsoft.Windows.CsWinRT.Authoring.targets b/nuget/Microsoft.Windows.CsWinRT.Authoring.targets index 1cab382a1..1d416861c 100644 --- a/nuget/Microsoft.Windows.CsWinRT.Authoring.targets +++ b/nuget/Microsoft.Windows.CsWinRT.Authoring.targets @@ -172,6 +172,9 @@ Copyright (C) Microsoft Corporation. All rights reserved. true $(TargetFramework) + + $(WindowsSdkPackageVersion) diff --git a/nuget/native/Microsoft.Windows.CsWinRT.targets b/nuget/native/Microsoft.Windows.CsWinRT.targets index e897ba308..c4e57e891 100644 --- a/nuget/native/Microsoft.Windows.CsWinRT.targets +++ b/nuget/native/Microsoft.Windows.CsWinRT.targets @@ -55,6 +55,17 @@ Properties: <_CsWinRTComponentTargetFramework>%(_ResolvedProjectReferencePaths.CsWinRTComponentTargetFramework) <_CsWinRTComponentTargetFramework Condition="'$(_CsWinRTComponentTargetFramework)' == ''">net10.0-windows10.0.26100.1 + + <_CsWinRTAggregatorWindowsSdkPackageVersion Condition="'$(CsWinRTNativeConsumerWindowsSdkPackageVersion)' != ''">$(CsWinRTNativeConsumerWindowsSdkPackageVersion) + <_CsWinRTAggregatorWindowsSdkPackageVersion Condition="'$(_CsWinRTAggregatorWindowsSdkPackageVersion)' == ''">%(_ResolvedProjectReferencePaths.CsWinRTComponentWindowsSdkPackageVersion) @@ -116,6 +127,11 @@ Properties: <_CsWinRTTempProjectLines Include=" <PropertyGroup>" /> <_CsWinRTTempProjectLines Include=" <TargetFramework>$(_CsWinRTComponentTargetFramework)</TargetFramework>" /> <_CsWinRTTempProjectLines Include=" <Platforms>x64%3Bx86%3BARM64</Platforms>" /> + + <_CsWinRTTempProjectLines Condition="'$(_CsWinRTAggregatorWindowsSdkPackageVersion)' != ''" + Include=" <WindowsSdkPackageVersion>$(_CsWinRTAggregatorWindowsSdkPackageVersion)</WindowsSdkPackageVersion>" /> $([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)', '..\metadata\WindowsRuntime.Internal.winmd')) From 157b930a7ab7bf269a89db02873c0999a611b3cf Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Mon, 4 May 2026 18:27:57 -0700 Subject: [PATCH 049/105] Drop per-component ProjectionTypesInitializer; only WinRT.Component.dll emits it The per-component module initializer was emitted by AuthoringExportTypesGenerator to set the entry assembly when a component dll was loaded by WinRT.Host.dll without an aggregator. With WinRT.Component.dll always being the entry point in the aggregator path, the per-component initializer is redundant. Consumers using a single component dll directly (without WinRT.Component.dll) already know which assembly should be the entry assembly and can call Assembly.SetEntryAssembly themselves. The merged WinRT.Component.dll keeps its initializer (still idempotent so a host-set entry assembly wins). --- .../AuthoringExportTypesGenerator.Execute.cs | 51 ------------------- .../AuthoringExportTypesGenerator.cs | 9 ---- .../ProjectionGenerator.AuxiliarySources.cs | 8 +-- 3 files changed, 4 insertions(+), 64 deletions(-) diff --git a/src/Authoring/WinRT.SourceGenerator2/AuthoringExportTypesGenerator.Execute.cs b/src/Authoring/WinRT.SourceGenerator2/AuthoringExportTypesGenerator.Execute.cs index 17b6c7560..952beb1e3 100644 --- a/src/Authoring/WinRT.SourceGenerator2/AuthoringExportTypesGenerator.Execute.cs +++ b/src/Authoring/WinRT.SourceGenerator2/AuthoringExportTypesGenerator.Execute.cs @@ -390,56 +390,5 @@ file static class WindowsRuntimeImports context.AddSource("NativeExports.g.cs", writer.ToStringAndClear()); } - - /// - /// Emits an idempotent [ModuleInitializer]-driven SetEntryAssembly for - /// component dlls. In hosted scenarios (e.g. WinRT.Host.dll activating the - /// component) the .NET runtime has no natural entry assembly, and TypeMap discovery - /// requires one. This emission designates the component dll as the entry assembly - /// only when one isn't already set, so that in multi-component aggregator scenarios - /// where WinRT.Component.dll sets itself first, this initializer is a no-op. - /// - /// The instance to use. - /// The input info. - public static void EmitProjectionTypesInitializer(SourceProductionContext context, AuthoringNativeExportsInfo info) - { - // Only emit for components. In merge-only / non-component scenarios there's - // typically a managed exe driving the load and the entry assembly is already set. - if (!info.Options.IsComponent) - { - return; - } - - string source = $$""" - // - #pragma warning disable - - namespace ABI.{{info.AssemblyName.EscapeIdentifierName()}}; - - /// - /// Designates the component dll as the entry assembly for the hosted .NET runtime - /// so that [TypeMapAssemblyTarget] discovery (rooted at the entry assembly) - /// works. Idempotent: skips if an entry assembly is already set (e.g. when this - /// component is loaded as a participant in a multi-component aggregation and - /// WinRT.Component.dll set itself first). - /// - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - internal static class ProjectionTypesInitializer - { - #pragma warning disable CA2255 // The 'ModuleInitializer' attribute should not be used in libraries - [global::System.Runtime.CompilerServices.ModuleInitializer] - #pragma warning restore CA2255 - internal static void InitializeProjectionTypes() - { - if (global::System.Reflection.Assembly.GetEntryAssembly() is null) - { - global::System.Reflection.Assembly.SetEntryAssembly(typeof(ProjectionTypesInitializer).Assembly); - } - } - } - """; - - context.AddSource("ProjectionTypesInitializer.g.cs", source); - } } } \ No newline at end of file diff --git a/src/Authoring/WinRT.SourceGenerator2/AuthoringExportTypesGenerator.cs b/src/Authoring/WinRT.SourceGenerator2/AuthoringExportTypesGenerator.cs index b112af9ee..c81da7aa3 100644 --- a/src/Authoring/WinRT.SourceGenerator2/AuthoringExportTypesGenerator.cs +++ b/src/Authoring/WinRT.SourceGenerator2/AuthoringExportTypesGenerator.cs @@ -33,14 +33,5 @@ public void Initialize(IncrementalGeneratorInitializationContext context) // Generate the native exports type context.RegisterImplementationSourceOutput(nativeExportsInfo, Execute.EmitNativeExports); - - // Generate an idempotent SetEntryAssembly module initializer. This ensures that when a - // component dll is consumed in a hosted scenario where there's no natural entry assembly - // (e.g. via WinRT.Host.dll), the dll designates itself as the entry assembly so the - // .NET runtime's TypeMap discovery rooted at the entry assembly works. The check is - // idempotent so that, in the multi-component aggregator scenario where 'WinRT.Component.dll' - // loads first and sets itself as the entry assembly, this per-component initializer does - // not override that. - context.RegisterImplementationSourceOutput(nativeExportsInfo, Execute.EmitProjectionTypesInitializer); } } \ No newline at end of file diff --git a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.AuxiliarySources.cs b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.AuxiliarySources.cs index f490904b3..d1dc85b2e 100644 --- a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.AuxiliarySources.cs +++ b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.AuxiliarySources.cs @@ -53,10 +53,10 @@ private static void EmitAuxiliaryComponentSources(ProjectionGeneratorArgs args, /// /// Emits a [ModuleInitializer]-driven SetEntryAssembly in WinRT.Component.dll. /// This designates WinRT.Component.dll as the entry assembly the .NET runtime uses - /// to root [TypeMapAssemblyTarget] discovery. The runtime side ensures - /// WinRT.Component.dll loads first (so this initializer fires before per-component - /// module initializers), and the check is idempotent so any later per-component module - /// initializer (which is also idempotent in the new design) is a no-op. + /// to root [TypeMapAssemblyTarget] discovery. Idempotent: skipped if the host has + /// already set an entry assembly. Per-component dlls intentionally do not emit a similar + /// initializer; consumers using a single component dll directly must call + /// Assembly.SetEntryAssembly themselves if they need TypeMap discovery rooted there. /// private static void WriteProjectionTypesInitializer(ProjectionGeneratorProcessingState processingState) { From a0a97c9ecaec7b9b1ba8c1e0092019ad46eaea49 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Mon, 4 May 2026 18:30:08 -0700 Subject: [PATCH 050/105] Restore original WindowsSdkProjectionModuleNotFound message from staging/3.0 --- .../Errors/WellKnownInteropExceptions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/WinRT.Interop.Generator/Errors/WellKnownInteropExceptions.cs b/src/WinRT.Interop.Generator/Errors/WellKnownInteropExceptions.cs index bdaddc95c..cb47d5686 100644 --- a/src/WinRT.Interop.Generator/Errors/WellKnownInteropExceptions.cs +++ b/src/WinRT.Interop.Generator/Errors/WellKnownInteropExceptions.cs @@ -351,11 +351,11 @@ public static WellKnownInteropException UserDefinedVtableTypeCodeGenerationError } /// - /// The Windows SDK ref/forwarder dll (i.e. Microsoft.Windows.SDK.NET.dll) was not in the reference set. + /// The Windows SDK projection module was not found. /// public static WellKnownInteropException WindowsSdkProjectionModuleNotFound() { - return Exception(40, "The Windows SDK ref/forwarder dll (i.e. 'Microsoft.Windows.SDK.NET.dll') was not in the reference set. This usually indicates that the consuming project's build is missing the Microsoft.Windows.SDK.NET.Ref framework reference (e.g. the WindowsSdkPackageVersion property was unset or pointed at a version that could not be resolved)."); + return Exception(40, "The Windows SDK projection module (i.e. 'Microsoft.Windows.SDK.NET.dll') was not found (this might mean that its path was not valid, or that it failed to load)."); } /// From f2266f4ee31711fff32fe22084a5481e7d8bdad6 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Mon, 4 May 2026 18:30:55 -0700 Subject: [PATCH 051/105] Restore InteropGenerator.Emit.cs to staging/3.0 original --- .../Generation/InteropGenerator.Emit.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs index 82dc47c16..6817914a1 100644 --- a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs +++ b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs @@ -38,7 +38,8 @@ private static void Emit(InteropGeneratorArgs args, InteropGeneratorDiscoverySta ModuleDefinition module = DefineInteropModule( args: args, discoveryState: discoveryState, - windowsRuntimeModule: out ModuleDefinition windowsRuntimeModule); + windowsRuntimeModule: out ModuleDefinition windowsRuntimeModule, + windowsRuntimeSdkProjectionModule: out _); args.Token.ThrowIfCancellationRequested(); @@ -201,11 +202,13 @@ private static void Emit(InteropGeneratorArgs args, InteropGeneratorDiscoverySta /// /// /// The for the Windows Runtime assembly. + /// The for the Windows SDK projection assembly. /// The interop module to populate and emit. private static ModuleDefinition DefineInteropModule( InteropGeneratorArgs args, InteropGeneratorDiscoveryState discoveryState, - out ModuleDefinition windowsRuntimeModule) + out ModuleDefinition windowsRuntimeModule, + out ModuleDefinition windowsRuntimeSdkProjectionModule) { // Get the loaded module for the application .dll (this should always be available here) if (!discoveryState.Modules.TryGetValue(args.OutputAssemblyPath, out ModuleDefinition? assemblyModule)) @@ -220,12 +223,9 @@ private static ModuleDefinition DefineInteropModule( throw WellKnownInteropExceptions.WinRTRuntimeModuleNotFound(); } - // Validate that the Windows SDK ref/forwarder ('Microsoft.Windows.SDK.NET.dll') reached the - // reference set. The SDK projection itself ('WinRT.Sdk.Projection.dll') is loaded explicitly - // in discovery from 'args.WinRTSdkProjectionAssemblyPath' and read downstream via - // 'discoveryState.WindowsRuntimeSdkProjectionModule', so this check is purely a sanity - // check that the consumer's build has the expected CsWinRT 3.0 reference layout. - if (!discoveryState.Modules.Any(static kvp => Path.GetFileName(Path.Normalize(kvp.Key)).Equals("Microsoft.Windows.SDK.NET.dll"))) + // Get the loaded module for the Windows SDK projection .dll (same as above) + if ((windowsRuntimeSdkProjectionModule = discoveryState.Modules.FirstOrDefault( + predicate: static kvp => Path.GetFileName(Path.Normalize(kvp.Key)).Equals("Microsoft.Windows.SDK.NET.dll")).Value) is null) { throw WellKnownInteropExceptions.WindowsSdkProjectionModuleNotFound(); } From da8e8b9113d7d4d598ff3b8c46e7a57553c50369 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Mon, 4 May 2026 18:40:40 -0700 Subject: [PATCH 052/105] Rename auxiliary sources file to WinRTComponentSources; consolidate StringBuilder usage - Rename ProjectionGenerator.AuxiliarySources.cs to ProjectionGenerator.WinRTComponentSources.cs and EmitAuxiliaryComponentSources to EmitWinRTComponentSources, since every emission in this file is specific to building WinRT.Component.dll. - Replace per-line sb.AppendLine sequences with raw string literals in WriteMergedManagedExports and use interpolated strings in WriteTypeMapAssemblyTargets for readability. --- ...arySources.cs => ProjectionGenerator.WinRTComponentSources.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/WinRT.Projection.Generator/Generation/{ProjectionGenerator.AuxiliarySources.cs => ProjectionGenerator.WinRTComponentSources.cs} (100%) diff --git a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.AuxiliarySources.cs b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.WinRTComponentSources.cs similarity index 100% rename from src/WinRT.Projection.Generator/Generation/ProjectionGenerator.AuxiliarySources.cs rename to src/WinRT.Projection.Generator/Generation/ProjectionGenerator.WinRTComponentSources.cs From 15515e39b838f1bfee364d0ac0dff84f7adef5de Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Mon, 4 May 2026 18:48:02 -0700 Subject: [PATCH 053/105] Drop residual 'auxiliary' wording from ProjectionGenerator entrypoint --- .../Generation/ProjectionGenerator.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.cs b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.cs index 7d3d4c906..7ec3baff8 100644 --- a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.cs +++ b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.cs @@ -80,17 +80,17 @@ public static void Run([Argument] string responseFilePath, CancellationToken tok args.Token.ThrowIfCancellationRequested(); - // In component mode (i.e. producing 'WinRT.Component.dll'), emit auxiliary source - // files alongside cswinrt.exe's output so the merged dll plays the entry-assembly + // In component mode (i.e. producing 'WinRT.Component.dll'), emit the supporting + // source files alongside cswinrt.exe's output so the merged dll plays the entry-assembly // and merged-activation roles (TypeMap union, SetEntryAssembly module init, merged // 'ABI.WinRT.Component.ManagedExports.GetActivationFactory', and AOT native export). try { - EmitAuxiliaryComponentSources(args, processingState); + EmitWinRTComponentSources(args, processingState); } catch (Exception e) when (!e.IsWellKnown) { - throw new UnhandledProjectionGeneratorException("auxiliary-sources", e); + throw new UnhandledProjectionGeneratorException("winrt-component-sources", e); } args.Token.ThrowIfCancellationRequested(); From e4ef25e7a645224a62a6d58df8a629f3836119ac Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Mon, 4 May 2026 18:51:18 -0700 Subject: [PATCH 054/105] Consolidate StringBuilder usage in WinRTComponentSources Replace per-line sb.AppendLine sequences in WriteMergedManagedExports with a raw string literal template (the per-component dispatch cases are still accumulated in a small inner StringBuilder and interpolated in via {{dispatchCases.ToString().TrimEnd()}}). Collapse the Append chain in WriteTypeMapAssemblyTargets into a single interpolated AppendLine. Also rename the entrypoint method from EmitAuxiliaryComponentSources to EmitWinRTComponentSources to match the renamed file. --- ...ojectionGenerator.WinRTComponentSources.cs | 112 +++++++++--------- 1 file changed, 55 insertions(+), 57 deletions(-) diff --git a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.WinRTComponentSources.cs b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.WinRTComponentSources.cs index d1dc85b2e..26cf9b46e 100644 --- a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.WinRTComponentSources.cs +++ b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.WinRTComponentSources.cs @@ -12,10 +12,10 @@ namespace WindowsRuntime.ProjectionGenerator.Generation; internal partial class ProjectionGenerator { /// - /// Component-mode only. Emits the auxiliary source files for WinRT.Component.dll: - /// (a) a module initializer that designates this assembly as the entry assembly for - /// .NET TypeMap discovery, (b) a [TypeMapAssemblyTarget] union covering each - /// component plus shared infrastructure assemblies, (c) a merged + /// Component-mode only. Emits the supporting source files that make WinRT.Component.dll + /// the merged aggregator dll: (a) a module initializer that designates this assembly as the + /// entry assembly for .NET TypeMap discovery, (b) a [TypeMapAssemblyTarget] union + /// covering each component plus shared infrastructure assemblies, (c) a merged /// ABI.WinRT.Component.ManagedExports.GetActivationFactory that the /// WinRT.Host.Shim reflects on, and (d, AOT only) a C-callable /// DllGetActivationFactory export wrapping the merged factory. @@ -25,7 +25,7 @@ internal partial class ProjectionGenerator /// (the same folder cswinrt.exe targets), so they are picked up automatically by the /// Roslyn compile step in . /// - private static void EmitAuxiliaryComponentSources(ProjectionGeneratorArgs args, ProjectionGeneratorProcessingState processingState) + private static void EmitWinRTComponentSources(ProjectionGeneratorArgs args, ProjectionGeneratorProcessingState processingState) { // Only emit these files when producing 'WinRT.Component.dll'. if (args.AssemblyName != "WinRT.Component") @@ -145,11 +145,7 @@ private static void WriteTypeMapAssemblyTargets(ProjectionGeneratorArgs args, Pr { foreach (string targetAssembly in targetAssemblyNames) { - _ = sb.Append("[assembly: global::System.Runtime.InteropServices.TypeMapAssemblyTarget<") - .Append(targetTypeMapGroup) - .Append(">(\"") - .Append(targetAssembly) - .AppendLine("\")]"); + _ = sb.AppendLine($"[assembly: global::System.Runtime.InteropServices.TypeMapAssemblyTarget<{targetTypeMapGroup}>(\"{targetAssembly}\")]"); } _ = sb.AppendLine(); @@ -231,58 +227,60 @@ private static bool HasMergedProjectionReferences(ProjectionGeneratorArgs args, /// private static void WriteMergedManagedExports(ProjectionGeneratorProcessingState processingState) { - StringBuilder sb = new(); - - _ = sb.AppendLine("// "); - _ = sb.AppendLine("#pragma warning disable"); - _ = sb.AppendLine(); - _ = sb.AppendLine("namespace ABI.WinRT.Component;"); - _ = sb.AppendLine(); - _ = sb.AppendLine("/// "); - _ = sb.AppendLine("/// Merged managed activation entry point for WinRT.Component.dll. Reflectively"); - _ = sb.AppendLine("/// invoked by WinRT.Host.Shim.GetActivationFactory when the manifest-free"); - _ = sb.AppendLine("/// activation flow loads WinRT.Component.dll; iterates per-component"); - _ = sb.AppendLine("/// ABI.{ComponentName}.ManagedExports.GetActivationFactory entries."); - _ = sb.AppendLine("/// "); - _ = sb.AppendLine("[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]"); - _ = sb.AppendLine("public static unsafe class ManagedExports"); - _ = sb.AppendLine("{"); - _ = sb.AppendLine(" /// "); - _ = sb.AppendLine(" /// Retrieves the activation factory for the requested runtime class by"); - _ = sb.AppendLine(" /// dispatching to each input component's ManagedExports in turn."); - _ = sb.AppendLine(" /// "); - _ = sb.AppendLine(" /// The runtime class identifier."); - _ = sb.AppendLine(" /// A pointer to the factory, or null if no component handles the class."); - _ = sb.AppendLine(" public static void* GetActivationFactory(global::System.ReadOnlySpan activatableClassId)"); - _ = sb.AppendLine(" {"); - _ = sb.AppendLine(" void* factory;"); + StringBuilder dispatchCases = new(); foreach (string componentAssemblyName in processingState.ComponentAssemblyNames) { - _ = sb.AppendLine(); - _ = sb.Append(" factory = global::ABI.") - .Append(componentAssemblyName) - .AppendLine(".ManagedExports.GetActivationFactory(activatableClassId);"); - _ = sb.AppendLine(" if (factory is not null)"); - _ = sb.AppendLine(" {"); - _ = sb.AppendLine(" return factory;"); - _ = sb.AppendLine(" }"); + _ = dispatchCases.AppendLine($$""" + + factory = global::ABI.{{componentAssemblyName}}.ManagedExports.GetActivationFactory(activatableClassId); + if (factory is not null) + { + return factory; + } + """); } - _ = sb.AppendLine(); - _ = sb.AppendLine(" return null;"); - _ = sb.AppendLine(" }"); - _ = sb.AppendLine(); - _ = sb.AppendLine(" /// "); - _ = sb.AppendLine(" /// Reflection-friendly overload used by managed runtime hosts (e.g. WinRT.Host.Shim)."); - _ = sb.AppendLine(" /// "); - _ = sb.AppendLine(" public static nint GetActivationFactory(string activatableClassId)"); - _ = sb.AppendLine(" {"); - _ = sb.AppendLine(" return (nint)GetActivationFactory(global::System.MemoryExtensions.AsSpan(activatableClassId));"); - _ = sb.AppendLine(" }"); - _ = sb.AppendLine("}"); - - File.WriteAllText(Path.Combine(processingState.SourcesFolder, "MergedManagedExports.g.cs"), sb.ToString()); + string source = $$""" + // + #pragma warning disable + + namespace ABI.WinRT.Component; + + /// + /// Merged managed activation entry point for WinRT.Component.dll. Reflectively + /// invoked by WinRT.Host.Shim.GetActivationFactory when the manifest-free + /// activation flow loads WinRT.Component.dll; iterates per-component + /// ABI.{ComponentName}.ManagedExports.GetActivationFactory entries. + /// + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + public static unsafe class ManagedExports + { + /// + /// Retrieves the activation factory for the requested runtime class by + /// dispatching to each input component's ManagedExports in turn. + /// + /// The runtime class identifier. + /// A pointer to the factory, or null if no component handles the class. + public static void* GetActivationFactory(global::System.ReadOnlySpan activatableClassId) + { + void* factory; + {{dispatchCases.ToString().TrimEnd()}} + + return null; + } + + /// + /// Reflection-friendly overload used by managed runtime hosts (e.g. WinRT.Host.Shim). + /// + public static nint GetActivationFactory(string activatableClassId) + { + return (nint)GetActivationFactory(global::System.MemoryExtensions.AsSpan(activatableClassId)); + } + } + """; + + File.WriteAllText(Path.Combine(processingState.SourcesFolder, "MergedManagedExports.g.cs"), source); } /// From df0d1abec2ec326b9d5b2e19d0aa0e6b08575ef6 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Tue, 5 May 2026 01:13:21 -0700 Subject: [PATCH 055/105] Remove unused processingState parameter from HasMergedProjectionReferences The helper only consults args.ReferenceAssemblyPaths; processingState was plumbed but never read, with a 'discard' suppression for the warning. Drop both the parameter and the suppression. --- .../Generation/ProjectionGenerator.WinRTComponentSources.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.WinRTComponentSources.cs b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.WinRTComponentSources.cs index 26cf9b46e..126f81281 100644 --- a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.WinRTComponentSources.cs +++ b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.WinRTComponentSources.cs @@ -123,7 +123,7 @@ private static void WriteTypeMapAssemblyTargets(ProjectionGeneratorArgs args, Pr // Windows Runtime reference assemblies in scope (i.e. third-party projection references). // Only include it in the union when that condition holds; otherwise the runtime would // fail with FileNotFoundException trying to enumerate a non-existent assembly. - if (HasMergedProjectionReferences(args, processingState)) + if (HasMergedProjectionReferences(args)) { targetAssemblyNames.Add("WinRT.Projection"); } @@ -159,9 +159,8 @@ private static void WriteTypeMapAssemblyTargets(ProjectionGeneratorArgs args, Pr /// reference assembly in scope - i.e. the same condition the merged projection target /// uses to determine whether WinRT.Projection.dll needs to be generated. /// - private static bool HasMergedProjectionReferences(ProjectionGeneratorArgs args, ProjectionGeneratorProcessingState processingState) + private static bool HasMergedProjectionReferences(ProjectionGeneratorArgs args) { - _ = processingState; string[] resolverPaths = [.. System.Linq.Enumerable.Where(args.ReferenceAssemblyPaths, p => !p.EndsWith(".winmd", StringComparison.OrdinalIgnoreCase))]; From 8ffc2f80bb677ff5b57d8f3eb46b774d03157df9 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Tue, 5 May 2026 20:28:05 -0700 Subject: [PATCH 056/105] Remove dead-code WriteNativeExports DllGetActivationFactory emission on WinRT.Component.dll The projection generator emitted [UnmanagedCallersOnly(EntryPoint=DllGetActivationFactory)] into WinRT.Component.dll's source via WriteNativeExports gated on a PublishAot flag we plumbed through. But WinRT.Component.dll is produced by the projection generator's own in-process Roslyn compilation (a side-output of the aggregator csproj's build) - ILC never sees that side-output, so the attribute never becomes a real native PE export under any current path. The actual AOT activation entrypoint is the source generator's AuthoringExportTypesGenerator.EmitNativeExports, which emits DllGetActivationFactory on each component's primary assembly (e.g. MyComponent.dll); ILC compiles that csproj and the export materializes correctly. The WinRT.Component.dll variant was redundant metadata that did nothing. Removes: - WriteNativeExports + the args.PublishAot gate in EmitWinRTComponentSources. - ProjectionGeneratorArgs.PublishAot (--publish-aot). - ProjectionGeneratorArgs.Parsing PublishAot binding. - RunCsWinRTMergedProjectionGenerator.PublishAot property and response-file write. - PublishAot= attribute in CsWinRTGen.targets. --- ...crosoft.Windows.CsWinRT.CsWinRTGen.targets | 1 - .../RunCsWinRTMergedProjectionGenerator.cs | 13 --- ...ojectionGenerator.WinRTComponentSources.cs | 109 +----------------- .../ProjectionGeneratorArgs.Parsing.cs | 1 - .../Generation/ProjectionGeneratorArgs.cs | 10 -- 5 files changed, 2 insertions(+), 132 deletions(-) diff --git a/nuget/Microsoft.Windows.CsWinRT.CsWinRTGen.targets b/nuget/Microsoft.Windows.CsWinRT.CsWinRTGen.targets index 2859d055a..5dbdf5007 100644 --- a/nuget/Microsoft.Windows.CsWinRT.CsWinRTGen.targets +++ b/nuget/Microsoft.Windows.CsWinRT.CsWinRTGen.targets @@ -407,7 +407,6 @@ Copyright (C) Microsoft Corporation. All rights reserved. WindowsMetadata="$(CsWinRTWindowsMetadata)" CsWinRTExePath="$(CsWinRTExe)" AssemblyName="WinRT.Component" - PublishAot="$(PublishAot)" CsWinRTToolsDirectory="$(CsWinRTMergedProjectionEffectiveToolsDirectory)" CsWinRTToolsArchitecture="$(CsWinRTToolsArchitecture)" StandardOutputImportance="$(CsWinRTGeneratorStandardOutputImportance)" diff --git a/src/WinRT.Generator.Tasks/RunCsWinRTMergedProjectionGenerator.cs b/src/WinRT.Generator.Tasks/RunCsWinRTMergedProjectionGenerator.cs index aaaf5b77c..307304eda 100644 --- a/src/WinRT.Generator.Tasks/RunCsWinRTMergedProjectionGenerator.cs +++ b/src/WinRT.Generator.Tasks/RunCsWinRTMergedProjectionGenerator.cs @@ -86,14 +86,6 @@ public sealed class RunCsWinRTMergedProjectionGenerator : ToolTask /// public bool WindowsUIXamlProjection { get; set; } - /// - /// Gets or sets whether the consuming build is publishing with Native AOT. Forwarded to - /// the projection generator so that, in component mode (WinRT.Component.dll), an - /// [UnmanagedCallersOnly] DllGetActivationFactory wrapper is also emitted. Has no - /// effect outside component mode. - /// - public bool PublishAot { get; set; } - /// protected override string ToolName => "cswinrtprojectiongen.exe"; @@ -216,11 +208,6 @@ protected override string GenerateResponseFileCommands() AppendResponseFileCommand(args, "--windows-ui-xaml-projection", "true"); } - if (PublishAot) - { - AppendResponseFileCommand(args, "--publish-aot", "true"); - } - // Add any additional arguments that are not statically known foreach (ITaskItem additionalArgument in AdditionalArguments ?? []) { diff --git a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.WinRTComponentSources.cs b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.WinRTComponentSources.cs index 126f81281..48e1e1ebd 100644 --- a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.WinRTComponentSources.cs +++ b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.WinRTComponentSources.cs @@ -15,10 +15,9 @@ internal partial class ProjectionGenerator /// Component-mode only. Emits the supporting source files that make WinRT.Component.dll /// the merged aggregator dll: (a) a module initializer that designates this assembly as the /// entry assembly for .NET TypeMap discovery, (b) a [TypeMapAssemblyTarget] union - /// covering each component plus shared infrastructure assemblies, (c) a merged + /// covering each component plus shared infrastructure assemblies, and (c) a merged /// ABI.WinRT.Component.ManagedExports.GetActivationFactory that the - /// WinRT.Host.Shim reflects on, and (d, AOT only) a C-callable - /// DllGetActivationFactory export wrapping the merged factory. + /// WinRT.Host.Shim reflects on. /// /// /// These emissions write directly into @@ -43,11 +42,6 @@ private static void EmitWinRTComponentSources(ProjectionGeneratorArgs args, Proj WriteProjectionTypesInitializer(processingState); WriteTypeMapAssemblyTargets(args, processingState); WriteMergedManagedExports(processingState); - - if (args.PublishAot) - { - WriteNativeExports(processingState); - } } /// @@ -281,103 +275,4 @@ public static nint GetActivationFactory(string activatableClassId) File.WriteAllText(Path.Combine(processingState.SourcesFolder, "MergedManagedExports.g.cs"), source); } - - /// - /// (AOT only) Emits the C-callable DllGetActivationFactory on - /// WinRT.Component.dll. JIT consumers reach the merged factory through - /// WinRT.Host.Shim's managed reflection path; AOT consumers (or any caller using - /// LoadLibrary + GetProcAddress directly) need the native export. - /// - private static void WriteNativeExports(ProjectionGeneratorProcessingState processingState) - { - const string source = """ - // - #pragma warning disable - - namespace ABI.WinRT.Component; - - using global::System; - using global::System.Runtime.CompilerServices; - using global::System.Runtime.InteropServices; - using global::System.Runtime.Versioning; - - using HRESULT = int; - using unsafe HSTRING = void*; - using unsafe IActivationFactory = void*; - - /// - /// Native exports on WinRT.Component.dll for AOT consumers. Wraps the merged - /// managed . - /// - [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] - internal static unsafe class NativeExports - { - /// - [UnmanagedCallersOnly(EntryPoint = nameof(DllGetActivationFactory), CallConvs = [typeof(CallConvStdcall)])] - public static HRESULT DllGetActivationFactory(HSTRING activatableClassId, IActivationFactory* factory) - { - const int E_INVALIDARG = unchecked((int)0x80070057); - const int CLASS_E_CLASSNOTAVAILABLE = unchecked((int)(0x80040111)); - const int S_OK = 0; - - if (activatableClassId is null || factory is null) - { - return E_INVALIDARG; - } - - ReadOnlySpan managedActivatableClassId = HStringMarshaller.ConvertToManagedUnsafe(activatableClassId); - - try - { - IActivationFactory result = ManagedExports.GetActivationFactory(managedActivatableClassId); - - if ((void*)result is null) - { - *factory = null; - - return CLASS_E_CLASSNOTAVAILABLE; - } - - *factory = (void*)result; - - return S_OK; - } - catch (Exception e) - { - return Marshal.GetHRForException(e); - } - } - - /// - [UnmanagedCallersOnly(EntryPoint = nameof(DllCanUnloadNow), CallConvs = [typeof(CallConvStdcall)])] - public static HRESULT DllCanUnloadNow() - { - const HRESULT S_FALSE = 1; - - return S_FALSE; - } - } - - file static class HStringMarshaller - { - public static unsafe ReadOnlySpan ConvertToManagedUnsafe(HSTRING value) - { - uint length; - char* buffer = WindowsRuntimeImports.WindowsGetStringRawBuffer(value, &length); - - return new(buffer, (int)length); - } - } - - file static class WindowsRuntimeImports - { - /// - [DllImport("api-ms-win-core-winrt-string-l1-1-0.dll", EntryPoint = "WindowsGetStringRawBuffer", ExactSpelling = true)] - [SupportedOSPlatform("windows6.2")] - public static unsafe extern char* WindowsGetStringRawBuffer(HSTRING @string, uint* length); - } - """; - - File.WriteAllText(Path.Combine(processingState.SourcesFolder, "NativeExports.g.cs"), source); - } } diff --git a/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorArgs.Parsing.cs b/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorArgs.Parsing.cs index 320406620..7f90150ca 100644 --- a/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorArgs.Parsing.cs +++ b/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorArgs.Parsing.cs @@ -82,7 +82,6 @@ public static ProjectionGeneratorArgs ParseFromResponseFile(string path, Cancell AssemblyName = GetOptionalStringArgument(argsMap, nameof(AssemblyName), "WinRT.Projection"), WindowsSdkOnly = GetOptionalBoolArgument(argsMap, nameof(WindowsSdkOnly)), WindowsUIXamlProjection = GetOptionalBoolArgument(argsMap, nameof(WindowsUIXamlProjection)), - PublishAot = GetOptionalBoolArgument(argsMap, nameof(PublishAot)), Token = token }; } diff --git a/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorArgs.cs b/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorArgs.cs index ebb3d7e29..2b8e4e6f2 100644 --- a/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorArgs.cs +++ b/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorArgs.cs @@ -54,16 +54,6 @@ internal sealed partial class ProjectionGeneratorArgs [CommandLineArgumentName("--windows-ui-xaml-projection")] public bool WindowsUIXamlProjection { get; init; } - /// - /// Gets whether the consuming build is publishing with Native AOT. When true in - /// component mode (i.e. producing WinRT.Component.dll), an - /// [UnmanagedCallersOnly] DllGetActivationFactory wrapper is emitted - /// alongside the merged managed activation logic. JIT consumers do not need this - /// (the host reaches the merged factory through a managed delegation chain). - /// - [CommandLineArgumentName("--publish-aot")] - public bool PublishAot { get; init; } - /// Gets the token for the operation. public required CancellationToken Token { get; init; } } \ No newline at end of file From bab172007cfcdc89550b2bbb350a848cf10dcfeb Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Fri, 8 May 2026 22:08:22 -0700 Subject: [PATCH 057/105] Native consumer aggregator improvements Targets file changes (nuget/native/Microsoft.Windows.CsWinRT.targets): - Walk @(CsWinRTNativeComponent) items contributed by component-package targets files alongside the existing walk. Mixed project + package component sources flow through one aggregator. - Add CsWinRTComponentTargetFrameworkOverride property. Error when component refs disagree on CsWinRTComponentTargetFramework (with a message pointing at the override). Error when no TFM is derivable and no override is set. Drop the hardcoded 26100.1 fallback. - Add Win32 -> x86 platform mapping (_CsWinRTNormalizedPlatform) for the synthesized csproj's Configuration/Platform properties, matching the established pattern in Authoring.Transitive.targets and Directory.Build.props. - Walk both ref sources (project + package) for CsWinRTComponentWindowsSdkPackageVersion. - Add Inputs/Outputs to CsWinRTGenerateComponentInterop so no-op rebuilds skip the aggregator MSBuild call. - Add a Message at $(CsWinRTMessageImportance) when the aggregator fires, listing the components and the output dll. - Document override properties in the file's header comment. Tests: - Add a minimal AuthoringTest2 component and a focused AuthoringConsumptionTest2 vcxproj that exercises multi-component aggregation only. Wire both into cswinrt.slnx. - Add a CI test step running AuthoringConsumptionTest2. Doc: - nuget/readme.md: new "Consuming CsWinRT components from a native (C++) app" section with the consumer-side property list and the two distribution options for component authors (managed dll + build/native/{PackageId}.targets contributing to @(CsWinRTNativeComponent), or AOT-published native binary), with a copy-pasteable example. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../CsWinRT-Test-Steps.yml | 12 ++ .../native/Microsoft.Windows.CsWinRT.targets | 202 ++++++++++-------- nuget/readme.md | 55 +++++ .../AuthoringConsumptionTest2.exe.manifest | 14 ++ .../AuthoringConsumptionTest2.vcxproj | 147 +++++++++++++ .../Directory.Build.targets | 16 ++ .../DoNotImport_MsAppxPackageTargets.targets | 3 + .../WinRT.Host.runtimeconfig.json | 10 + .../AuthoringConsumptionTest2/packages.config | 13 ++ src/Tests/AuthoringConsumptionTest2/pch.cpp | 1 + src/Tests/AuthoringConsumptionTest2/pch.h | 12 ++ src/Tests/AuthoringConsumptionTest2/test.cpp | 37 ++++ .../AuthoringTest2/AuthoringTest2.csproj | 16 ++ src/Tests/AuthoringTest2/Greeter.cs | 14 ++ src/Tests/AuthoringTest2/Module.cs | 12 ++ src/cswinrt.slnx | 20 ++ 16 files changed, 492 insertions(+), 92 deletions(-) create mode 100644 src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.exe.manifest create mode 100644 src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj create mode 100644 src/Tests/AuthoringConsumptionTest2/Directory.Build.targets create mode 100644 src/Tests/AuthoringConsumptionTest2/DoNotImport_MsAppxPackageTargets.targets create mode 100644 src/Tests/AuthoringConsumptionTest2/WinRT.Host.runtimeconfig.json create mode 100644 src/Tests/AuthoringConsumptionTest2/packages.config create mode 100644 src/Tests/AuthoringConsumptionTest2/pch.cpp create mode 100644 src/Tests/AuthoringConsumptionTest2/pch.h create mode 100644 src/Tests/AuthoringConsumptionTest2/test.cpp create mode 100644 src/Tests/AuthoringTest2/AuthoringTest2.csproj create mode 100644 src/Tests/AuthoringTest2/Greeter.cs create mode 100644 src/Tests/AuthoringTest2/Module.cs diff --git a/build/AzurePipelineTemplates/CsWinRT-Test-Steps.yml b/build/AzurePipelineTemplates/CsWinRT-Test-Steps.yml index 01a55b79f..53f7f769b 100644 --- a/build/AzurePipelineTemplates/CsWinRT-Test-Steps.yml +++ b/build/AzurePipelineTemplates/CsWinRT-Test-Steps.yml @@ -70,6 +70,18 @@ steps: dir _build\$(BuildPlatform)\$(BuildConfiguration)\AuthoringConsumptionTest\bin _build\$(BuildPlatform)\$(BuildConfiguration)\AuthoringConsumptionTest\bin\AuthoringConsumptionTest.exe --gtest_output=xml:AUTHORINGTEST-$(Build.BuildNumber).xml +# Run Multi-Component Authoring Consumption Tests + - task: CmdLine@2 + displayName: Run Multi-Component Authoring Consumption Tests + enabled: true + condition: and(succeeded(), eq(variables['BuildPlatform'], 'x64')) + continueOnError: True + inputs: + workingDirectory: $(Build.SourcesDirectory)\src + script: | + dir _build\$(BuildPlatform)\$(BuildConfiguration)\AuthoringConsumptionTest2\bin + _build\$(BuildPlatform)\$(BuildConfiguration)\AuthoringConsumptionTest2\bin\AuthoringConsumptionTest2.exe --gtest_output=xml:AUTHORINGTEST2-$(Build.BuildNumber).xml + # Run WUX Tests - task: CmdLine@2 displayName: Run WUX Tests diff --git a/nuget/native/Microsoft.Windows.CsWinRT.targets b/nuget/native/Microsoft.Windows.CsWinRT.targets index c4e57e891..579f79380 100644 --- a/nuget/native/Microsoft.Windows.CsWinRT.targets +++ b/nuget/native/Microsoft.Windows.CsWinRT.targets @@ -2,143 +2,160 @@ *********************************************************************************************** Copyright (C) Microsoft Corporation. All rights reserved. -Targets for native (C++) projects consuming C# WinRT component projects. - -When a vcxproj imports this file (typically via the Microsoft.Windows.CsWinRT NuGet's -`build\native\Microsoft.Windows.CsWinRT.targets` auto-import), it walks the resolved -ProjectReference set, picks references whose CsWinRTComponent metadata is 'true', and: - - 1. Synthesizes a temporary aggregator csproj in the consumer's intermediate directory - that ProjectReferences every detected component. The aggregator's TargetFramework - is taken from the components themselves (which are required to use a Windows- - targeted TFM such as net10.0-windows10.0.X.Y), so Microsoft.NET.Windows.targets' - RemoveManagedWinRTComponentWinMDReferences / AddWinRTComponentImplementationReference - pair fires automatically and re-injects each component's managed implementation .dll - into the aggregator's Reference set. - - 2. Builds the aggregator with CsWinRTBuildForNativeConsumer=true so cswinrt's full - component / interop / projection generator pipeline runs once across the union - of all referenced components, producing a single deduplicated WinRT.Interop.dll - (avoiding type-map duplicate-key collisions that per-component generation would - hit) along with WinRT.Component.dll, WinRT.Projection.dll, and WinRT.Sdk.Projection.dll. - - 3. Copies the generated DLLs from the aggregator's intermediate directory to the - consumer's output directory, where the C++ host loads them at runtime through - WinRT.Host.dll / WinRT.Host.Shim.dll. - -Properties: - - CsWinRTDisableNativeComponentInterop: set to 'true' to disable +Targets imported by native (C++) projects consuming CsWinRT component projects via the +Microsoft.Windows.CsWinRT NuGet (auto-imported as build/native/Microsoft.Windows.CsWinRT.targets). + +Walks both sources of CsWinRT component references attached to the consuming vcxproj: + - ProjectReferences whose CsWinRTComponent metadata is 'true'. + - @(CsWinRTNativeComponent) items contributed by component-package targets files + (each item's Identity is the path to a managed component .dll). + +Synthesizes a temporary aggregator csproj that references every detected component, builds it +with CsWinRTBuildForNativeConsumer=true so the cswinrt projection / interop pipeline runs once +across the union of all referenced components (a single deduplicated WinRT.Interop.dll plus +WinRT.Component.dll, WinRT.Projection.dll and WinRT.Sdk.Projection.dll), and copies the merged +hosting bundle to the consumer's output directory. + +@(CsWinRTNativeComponent) item metadata: + Identity (required) Path to the managed component .dll. + CsWinRTComponentTargetFramework (required) The TFM the component was compiled for. + +Properties consumers may set on the vcxproj: + CsWinRTDisableNativeComponentInterop Set to 'true' to disable aggregator generation. + CsWinRTComponentTargetFrameworkOverride TFM to use for the aggregator csproj. Required when + referenced components disagree on TFM, or when no + referenced component supplies a TFM. + CsWinRTNativeConsumerWindowsSdkPackageVersion + WindowsSdkPackageVersion to pass to the aggregator. + Falls back to a value picked from any component ref + metadata, then to the SDK default. *********************************************************************************************** --> <_CsWinRTNativeConsumerIntermediateDir>$([MSBuild]::NormalizeDirectory('$(MSBuildProjectDirectory)', '$(IntDir)', 'cswinrt')) + + + normal + + + <_CsWinRTNormalizedPlatform Condition="'$(Platform)' == 'Win32'">x86 + <_CsWinRTNormalizedPlatform Condition="'$(_CsWinRTNormalizedPlatform)' == ''">$(Platform) + <_CsWinRTComponentProjectPaths Include="%(_ResolvedProjectReferencePaths.MSBuildSourceProjectFile)" Condition="'%(_ResolvedProjectReferencePaths.CsWinRTComponent)' == 'true'" /> + + + <_CsWinRTComponentTargetFrameworkValues Include="%(_ResolvedProjectReferencePaths.CsWinRTComponentTargetFramework)" + Condition="'%(_ResolvedProjectReferencePaths.CsWinRTComponent)' == 'true' and '%(_ResolvedProjectReferencePaths.CsWinRTComponentTargetFramework)' != ''" /> + <_CsWinRTComponentTargetFrameworkValues Include="%(CsWinRTNativeComponent.CsWinRTComponentTargetFramework)" + Condition="'%(CsWinRTNativeComponent.CsWinRTComponentTargetFramework)' != ''" /> + + + <_CsWinRTComponentSdkPackageVersionValues Include="%(_ResolvedProjectReferencePaths.CsWinRTComponentWindowsSdkPackageVersion)" + Condition="'%(_ResolvedProjectReferencePaths.CsWinRTComponent)' == 'true' and '%(_ResolvedProjectReferencePaths.CsWinRTComponentWindowsSdkPackageVersion)' != ''" /> + <_CsWinRTComponentSdkPackageVersionValues Include="%(CsWinRTNativeComponent.CsWinRTComponentWindowsSdkPackageVersion)" + Condition="'%(CsWinRTNativeComponent.CsWinRTComponentWindowsSdkPackageVersion)' != ''" /> - - <_CsWinRTComponentTargetFramework>%(_ResolvedProjectReferencePaths.CsWinRTComponentTargetFramework) - <_CsWinRTComponentTargetFramework Condition="'$(_CsWinRTComponentTargetFramework)' == ''">net10.0-windows10.0.26100.1 - + <_CsWinRTHasComponentReferences Condition="'@(_CsWinRTComponentProjectPaths)' != '' or '@(CsWinRTNativeComponent)' != ''">true + + + <_CsWinRTDistinctComponentTargetFrameworks>@(_CsWinRTComponentTargetFrameworkValues->Distinct(), ';') + + + <_CsWinRTComponentTargetFramework Condition="'$(CsWinRTComponentTargetFrameworkOverride)' != ''">$(CsWinRTComponentTargetFrameworkOverride) + <_CsWinRTComponentTargetFramework Condition="'$(_CsWinRTComponentTargetFramework)' == '' and '$(_CsWinRTDistinctComponentTargetFrameworks)' != '' and !$(_CsWinRTDistinctComponentTargetFrameworks.Contains(';'))">$(_CsWinRTDistinctComponentTargetFrameworks) + + + + + + + + + + <_CsWinRTAggregatorWindowsSdkPackageVersion Condition="'$(CsWinRTNativeConsumerWindowsSdkPackageVersion)' != ''">$(CsWinRTNativeConsumerWindowsSdkPackageVersion) - <_CsWinRTAggregatorWindowsSdkPackageVersion Condition="'$(_CsWinRTAggregatorWindowsSdkPackageVersion)' == ''">%(_ResolvedProjectReferencePaths.CsWinRTComponentWindowsSdkPackageVersion) + <_CsWinRTAggregatorWindowsSdkPackageVersion Condition="'$(_CsWinRTAggregatorWindowsSdkPackageVersion)' == ''">@(_CsWinRTComponentSdkPackageVersionValues->Distinct()) + + + <_CsWinRTAggregatorInputs Include="@(_ResolvedProjectReferencePaths)" + Condition="'%(_ResolvedProjectReferencePaths.CsWinRTComponent)' == 'true'" /> + <_CsWinRTAggregatorInputs Include="@(CsWinRTNativeComponent)" /> + <_CsWinRTAggregatorInputs Include="$(MSBuildThisFileFullPath)" /> + + - - - <_CsWinRTHasComponentReferences Condition="'@(_CsWinRTComponentProjectPaths)' != ''">true - + Inputs="@(_CsWinRTAggregatorInputs)" + Outputs="$(OutDir)WinRT.Component.dll" + Condition="'$(CsWinRTDisableNativeComponentInterop)' != 'true' and '$(_CsWinRTHasComponentReferences)' == 'true'"> - + - + <_CsWinRTTempProjectDir>$(_CsWinRTNativeConsumerIntermediateDir) <_CsWinRTTempProjectPath>$(_CsWinRTTempProjectDir)CsWinRT.NativeConsumer.csproj <_CsWinRTTempProjectTFMDir>$(_CsWinRTComponentTargetFramework) - + + <_CsWinRTTempProjectBaseIntermediateDir>$(_CsWinRTTempProjectDir)obj\ <_CsWinRTTempProjectIntermediateConfigDir>$(_CsWinRTTempProjectBaseIntermediateDir)$(Configuration)\ <_CsWinRTTempProjectIntermediateDir>$(_CsWinRTTempProjectIntermediateConfigDir)$(_CsWinRTTempProjectTFMDir)\ - + + <_CsWinRTPropsForAggregator>$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)..\Microsoft.Windows.CsWinRT.props')) <_CsWinRTTargetsForAggregator>$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)..\Microsoft.Windows.CsWinRT.targets')) - + - + <_CsWinRTTempProjectLines Include="<Project>" /> <_CsWinRTTempProjectLines Include=" <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />" /> <_CsWinRTTempProjectLines Include=" <Import Project="$(_CsWinRTPropsForAggregator)" />" /> <_CsWinRTTempProjectLines Include=" <PropertyGroup>" /> <_CsWinRTTempProjectLines Include=" <TargetFramework>$(_CsWinRTComponentTargetFramework)</TargetFramework>" /> <_CsWinRTTempProjectLines Include=" <Platforms>x64%3Bx86%3BARM64</Platforms>" /> - <_CsWinRTTempProjectLines Condition="'$(_CsWinRTAggregatorWindowsSdkPackageVersion)' != ''" Include=" <WindowsSdkPackageVersion>$(_CsWinRTAggregatorWindowsSdkPackageVersion)</WindowsSdkPackageVersion>" /> - + <_CsWinRTTempProjectLines Include=" <BaseIntermediateOutputPath>$(_CsWinRTTempProjectBaseIntermediateDir)</BaseIntermediateOutputPath>" /> <_CsWinRTTempProjectLines Include=" <IntermediateOutputPath>$(_CsWinRTTempProjectIntermediateConfigDir)</IntermediateOutputPath>" /> <_CsWinRTTempProjectLines Include=" <CsWinRTBuildForNativeConsumer>true</CsWinRTBuildForNativeConsumer>" /> @@ -149,32 +166,33 @@ Properties: <_CsWinRTTempProjectLines Include=" <ProduceReferenceAssembly>false</ProduceReferenceAssembly>" /> <_CsWinRTTempProjectLines Include=" </PropertyGroup>" /> <_CsWinRTTempProjectLines Include=" <ItemGroup>" /> + <_CsWinRTTempProjectLines Include=" <ProjectReference Include="%(_CsWinRTComponentProjectPaths.Identity)" />" /> + + <_CsWinRTTempProjectLines Include=" <Reference Include="%(CsWinRTNativeComponent.Filename)">" /> + <_CsWinRTTempProjectLines Include=" <HintPath>%(CsWinRTNativeComponent.Identity)</HintPath>" /> + <_CsWinRTTempProjectLines Include=" <CsWinRTComponent>true</CsWinRTComponent>" /> + <_CsWinRTTempProjectLines Include=" <Private>true</Private>" /> + <_CsWinRTTempProjectLines Include=" </Reference>" /> <_CsWinRTTempProjectLines Include=" </ItemGroup>" /> <_CsWinRTTempProjectLines Include=" <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />" /> <_CsWinRTTempProjectLines Include=" <Import Project="$(_CsWinRTTargetsForAggregator)" />" /> <_CsWinRTTempProjectLines Include="</Project>" /> - - - + Properties="Configuration=$(Configuration);Platform=$(_CsWinRTNormalizedPlatform)" /> - + Properties="Configuration=$(Configuration);Platform=$(_CsWinRTNormalizedPlatform)" /> - - - + <_CsWinRTGeneratedDlls Include="$(_CsWinRTTempProjectIntermediateDir)WinRT.Component.dll" Condition="Exists('$(_CsWinRTTempProjectIntermediateDir)WinRT.Component.dll')" /> <_CsWinRTGeneratedDlls Include="$(_CsWinRTTempProjectIntermediateDir)WinRT.Interop.dll" Condition="Exists('$(_CsWinRTTempProjectIntermediateDir)WinRT.Interop.dll')" /> <_CsWinRTGeneratedDlls Include="$(_CsWinRTTempProjectIntermediateDir)WinRT.Projection.dll" Condition="Exists('$(_CsWinRTTempProjectIntermediateDir)WinRT.Projection.dll')" /> @@ -182,7 +200,7 @@ Properties: <_CsWinRTGeneratedDlls Include="$(_CsWinRTTempProjectIntermediateDir)WinRT.Sdk.Xaml.Projection.dll" Condition="Exists('$(_CsWinRTTempProjectIntermediateDir)WinRT.Sdk.Xaml.Projection.dll')" /> - + diff --git a/nuget/readme.md b/nuget/readme.md index 392c45f1a..7f4a8008e 100644 --- a/nuget/readme.md +++ b/nuget/readme.md @@ -84,6 +84,61 @@ If a Windows SDK is installed, $(WindowsSDKVersion) is defined when building fro 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). +## Consuming CsWinRT components from a native (C++) app + +When a native (C++) `.vcxproj` references one or more managed CsWinRT components, the CsWinRT package's +`build/native/Microsoft.Windows.CsWinRT.targets` walks the component references and synthesizes a temporary +aggregator project. That aggregator runs the cswinrt projection, interop and component pipeline once across +the union of all referenced components, producing a single deduplicated `WinRT.Interop.dll` plus +`WinRT.Component.dll`, `WinRT.Projection.dll` and `WinRT.Sdk.Projection.dll`. The merged hosting bundle is +copied to the consumer's output directory next to `WinRT.Host.dll` / `WinRT.Host.Shim.dll`. + +Component references are picked up from two sources, treated as equivalent inputs: + +* `` items whose `CsWinRTComponent` metadata is `true`. Components built with + `CsWinRTComponent=true` automatically expose this metadata. +* `@(CsWinRTNativeComponent)` items contributed by component-package targets files (see below). + +Consumer-side properties: + +| Property | Description | +|-|-| +| `CsWinRTDisableNativeComponentInterop` | Set to `true` to disable aggregator generation. | +| `CsWinRTComponentTargetFrameworkOverride` | TFM to use for the aggregator project. Required when referenced components disagree on TFM, or when no referenced component supplies a TFM. | +| `CsWinRTNativeConsumerWindowsSdkPackageVersion` | `WindowsSdkPackageVersion` to pass to the aggregator. Falls back to a value picked from any component reference, then to the SDK default. | + +### Distributing a CsWinRT component for native consumers + +A CsWinRT component is built with `CsWinRTComponent=true` in its `.csproj`. The build produces a managed +`{AssemblyName}.dll` plus a `.winmd`. Two distribution shapes are supported: + +#### Option 1 — Ship the managed component .dll (JIT hosting, supports merged multi-component aggregation) + +Native consumers reference the managed component and the consumer's own `WinRT.Host.dll`/`WinRT.Host.Shim.dll` +load it at runtime. Component packages opt in by shipping a small `build/native/{PackageId}.targets` that +contributes the component .dll to `@(CsWinRTNativeComponent)` and its `.winmd` to `@(CsWinRTInputs)`: + +```xml + + + + + net10.0-windows10.0.26100.1 + + + + +``` + +The `Identity` is the path to the component .dll. `CsWinRTComponentTargetFramework` is required and is used +by the consumer to derive the aggregator's target framework. + +#### Option 2 — AOT-publish the component and ship the resulting native binary + +The component author runs `dotnet publish -p:PublishAot=true` on the component themselves and distributes +the resulting native dll. Native consumers load that binary directly through whatever activation mechanism +they prefer; they do not go through the aggregator. + ## Troubleshooting The MSBuild verbosity level maps to MSBuild message importance as follows: diff --git a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.exe.manifest b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.exe.manifest new file mode 100644 index 000000000..9f946b8f4 --- /dev/null +++ b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.exe.manifest @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj new file mode 100644 index 000000000..5c967ffe1 --- /dev/null +++ b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj @@ -0,0 +1,147 @@ + + + + + + + + + + + + Debug + x64 + + + Release + x64 + + + + {8a4b1f2a-9c2e-4d3a-bf68-2a4f5b7c8d9e} + Win32Proj + AuthoringConsumptionTest2 + Application + v143 + v142 + Unicode + <_WinMDPlatform>$(Platform) + false + true + + + + + + + + + + + + + + Create + + + + + + + + true + + + + + {ffa9a78b-f53f-43ee-af87-24a80f4c330a} + TargetFramework=net10.0 + + + {7B803846-91AE-4B98-AC93-D3FCFB2DE5AA} + TargetFramework=net10.0 + + + {0bb8f82d-874e-45aa-bca3-20ce0562164a} + TargetFramework=net10.0 + + + {7e33bcb7-19c5-4061-981d-ba695322708a} + + + {25244ced-966e-45f2-9711-1f51e951ff89} + TargetFramework=net10.0 + + + {41e2a272-150f-42f5-ad40-047aad9088a0} + TargetFramework=net10.0-windows10.0.26100.1 + + + TargetFramework=net10.0-windows10.0.26100.1 + + + + + ..\AuthoringTest\bin\$(_WinMDPlatform)\$(Configuration)\net10.0-windows10.0.26100.1\win-$(Platform)\AuthoringTest.winmd + true + + + ..\AuthoringTest2\bin\$(_WinMDPlatform)\$(Configuration)\net10.0-windows10.0.26100.1\win-$(Platform)\AuthoringTest2.winmd + true + + + + + + + + + + + + + + + + + + + + + + Use + pch.h + Disabled + X64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level3 + + + true + Console + + + + + Use + pch.h + MaxSpeed + X64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + true + MultiThreadedDLL + Level3 + + + true + true + true + Console + + + + + + + diff --git a/src/Tests/AuthoringConsumptionTest2/Directory.Build.targets b/src/Tests/AuthoringConsumptionTest2/Directory.Build.targets new file mode 100644 index 000000000..07d00c59d --- /dev/null +++ b/src/Tests/AuthoringConsumptionTest2/Directory.Build.targets @@ -0,0 +1,16 @@ + + + + $(MSBuildProjectDirectory)/DoNotImport_MsAppxPackageTargets.targets + CopyTestAssets;$(PrepareForRunDependsOn) + + + + + + + + + diff --git a/src/Tests/AuthoringConsumptionTest2/DoNotImport_MsAppxPackageTargets.targets b/src/Tests/AuthoringConsumptionTest2/DoNotImport_MsAppxPackageTargets.targets new file mode 100644 index 000000000..74f0916e0 --- /dev/null +++ b/src/Tests/AuthoringConsumptionTest2/DoNotImport_MsAppxPackageTargets.targets @@ -0,0 +1,3 @@ + + + diff --git a/src/Tests/AuthoringConsumptionTest2/WinRT.Host.runtimeconfig.json b/src/Tests/AuthoringConsumptionTest2/WinRT.Host.runtimeconfig.json new file mode 100644 index 000000000..8b3ddec35 --- /dev/null +++ b/src/Tests/AuthoringConsumptionTest2/WinRT.Host.runtimeconfig.json @@ -0,0 +1,10 @@ +{ + "runtimeOptions": { + "tfm": "net10.0", + "rollForward": "LatestMinor", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "10.0.0-preview.6.25358.103" + } + } +} diff --git a/src/Tests/AuthoringConsumptionTest2/packages.config b/src/Tests/AuthoringConsumptionTest2/packages.config new file mode 100644 index 000000000..0470fd6c7 --- /dev/null +++ b/src/Tests/AuthoringConsumptionTest2/packages.config @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/Tests/AuthoringConsumptionTest2/pch.cpp b/src/Tests/AuthoringConsumptionTest2/pch.cpp new file mode 100644 index 000000000..1d9f38c57 --- /dev/null +++ b/src/Tests/AuthoringConsumptionTest2/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/src/Tests/AuthoringConsumptionTest2/pch.h b/src/Tests/AuthoringConsumptionTest2/pch.h new file mode 100644 index 000000000..e18686d32 --- /dev/null +++ b/src/Tests/AuthoringConsumptionTest2/pch.h @@ -0,0 +1,12 @@ +#pragma once + +#undef GetCurrentTime + +#include +#include +#include + +#include +#include + +#include "gtest/gtest.h" diff --git a/src/Tests/AuthoringConsumptionTest2/test.cpp b/src/Tests/AuthoringConsumptionTest2/test.cpp new file mode 100644 index 000000000..85f6bd396 --- /dev/null +++ b/src/Tests/AuthoringConsumptionTest2/test.cpp @@ -0,0 +1,37 @@ +#include "pch.h" + +using namespace winrt; +using namespace Windows::Foundation; + +// Verifies multi-component aggregation: a single native exe references two managed CsWinRT +// components (AuthoringTest and AuthoringTest2) and the merged WinRT.Component.dll produced +// by Microsoft.Windows.CsWinRT.targets resolves activation for both. + +TEST(MultiComponent, AuthoringTestStatics) +{ + EXPECT_EQ(AuthoringTest::TestClass::GetDefaultFactor(), 1); + EXPECT_EQ(AuthoringTest::TestClass::GetDefaultNumber(), 2); +} + +TEST(MultiComponent, AuthoringTest2Greeter) +{ + AuthoringTest2::Greeter greeter; + EXPECT_EQ(greeter.Greet(L"world"), hstring(L"Hello, world!")); + EXPECT_EQ(greeter.Add(2, 3), 5); +} + +TEST(MultiComponent, BothComponentsActivateInOneProcess) +{ + AuthoringTest::TestClass first; + AuthoringTest2::Greeter second; + + EXPECT_EQ(first.GetFactor(), 1); + EXPECT_EQ(second.Add(10, 20), 30); +} + +int main(int argc, char** argv) +{ + init_apartment(); + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/src/Tests/AuthoringTest2/AuthoringTest2.csproj b/src/Tests/AuthoringTest2/AuthoringTest2.csproj new file mode 100644 index 000000000..c00c16ea6 --- /dev/null +++ b/src/Tests/AuthoringTest2/AuthoringTest2.csproj @@ -0,0 +1,16 @@ + + + + net10.0-windows10.0.26100.1 + x64;x86 + true + win-x86;win-x64;win-arm64 + + + + + + + + + diff --git a/src/Tests/AuthoringTest2/Greeter.cs b/src/Tests/AuthoringTest2/Greeter.cs new file mode 100644 index 000000000..efa6a6aca --- /dev/null +++ b/src/Tests/AuthoringTest2/Greeter.cs @@ -0,0 +1,14 @@ +namespace AuthoringTest2; + +public sealed class Greeter +{ + public string Greet(string name) + { + return $"Hello, {name}!"; + } + + public int Add(int a, int b) + { + return a + b; + } +} diff --git a/src/Tests/AuthoringTest2/Module.cs b/src/Tests/AuthoringTest2/Module.cs new file mode 100644 index 000000000..56fd158d7 --- /dev/null +++ b/src/Tests/AuthoringTest2/Module.cs @@ -0,0 +1,12 @@ +using System.Reflection; + +[assembly: global::System.Runtime.Versioning.SupportedOSPlatform("Windows")] + +namespace AuthoringTest2; + +internal class Program +{ + static void Main(string[] args) + { + } +} diff --git a/src/cswinrt.slnx b/src/cswinrt.slnx index 47b477190..cbaaf737c 100644 --- a/src/cswinrt.slnx +++ b/src/cswinrt.slnx @@ -174,6 +174,18 @@ + + + + + + + + + + + + @@ -182,6 +194,14 @@ + + + + + + + + From a8736958d86b1b69cc48e3d846e696a2426d09a5 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Fri, 8 May 2026 22:11:17 -0700 Subject: [PATCH 058/105] Use 10.0.0 RTM version in AuthoringConsumptionTest2 runtimeconfig Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AuthoringConsumptionTest2/WinRT.Host.runtimeconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tests/AuthoringConsumptionTest2/WinRT.Host.runtimeconfig.json b/src/Tests/AuthoringConsumptionTest2/WinRT.Host.runtimeconfig.json index 8b3ddec35..88b184e83 100644 --- a/src/Tests/AuthoringConsumptionTest2/WinRT.Host.runtimeconfig.json +++ b/src/Tests/AuthoringConsumptionTest2/WinRT.Host.runtimeconfig.json @@ -4,7 +4,7 @@ "rollForward": "LatestMinor", "framework": { "name": "Microsoft.NETCore.App", - "version": "10.0.0-preview.6.25358.103" + "version": "10.0.0" } } } From 7f9f1b1104c0dba19ac207c8e226fbe1de815a74 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Fri, 8 May 2026 22:25:12 -0700 Subject: [PATCH 059/105] Exercise merged TypeMap dedup in AuthoringConsumptionTest2 Adds generic collection instantiations to AuthoringTest2.Greeter (IList, IDictionary) and extends test.cpp with two new tests that consume generic returns from both components in the same process. This actually exercises the load-bearing constraint the aggregator exists to satisfy: a single deduplicated marshalling closure covering generics across all components, with no duplicate TypeMap registrations. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Tests/AuthoringConsumptionTest2/test.cpp | 39 ++++++++++++++++++++ src/Tests/AuthoringTest2/Greeter.cs | 23 ++++++++++++ 2 files changed, 62 insertions(+) diff --git a/src/Tests/AuthoringConsumptionTest2/test.cpp b/src/Tests/AuthoringConsumptionTest2/test.cpp index 85f6bd396..3d0326f92 100644 --- a/src/Tests/AuthoringConsumptionTest2/test.cpp +++ b/src/Tests/AuthoringConsumptionTest2/test.cpp @@ -2,6 +2,7 @@ using namespace winrt; using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; // Verifies multi-component aggregation: a single native exe references two managed CsWinRT // components (AuthoringTest and AuthoringTest2) and the merged WinRT.Component.dll produced @@ -29,6 +30,44 @@ TEST(MultiComponent, BothComponentsActivateInOneProcess) EXPECT_EQ(second.Add(10, 20), 30); } +// Exercises the merged TypeMap deduplication that justifies the aggregator's existence: +// both components expose generic collection instantiations across the WinRT ABI, and the +// merged WinRT.Interop.dll must register marshalling for each instantiation exactly once. +// If per-component interop generation had run independently, type-map registration would +// fail at publish time with duplicate-key errors, or these calls would fail at runtime. + +TEST(MultiComponent, GenericCollectionsFromBothComponents) +{ + // IList from component 2. + AuthoringTest2::Greeter greeter; + auto numbers = greeter.GetNumbers(); + ASSERT_EQ(numbers.Size(), 6u); + EXPECT_EQ(numbers.GetAt(0), 1); + EXPECT_EQ(numbers.GetAt(5), 13); + + // IList from component 1. + auto bools = AuthoringTest::TestClass::GetBools(); + EXPECT_GT(bools.Size(), 0u); + + // IReadOnlyList from component 1: exercises a reference-type generic + // instantiation that the merged interop closure must marshal correctly. + auto uris = AuthoringTest::TestClass::GetUris(); + EXPECT_GT(uris.Size(), 0u); +} + +TEST(MultiComponent, GenericMapFromComponent2) +{ + // IDictionary from component 2: a generic map instantiation that + // exists only in component 2; covers the IMap marshalling path. + AuthoringTest2::Greeter greeter; + auto counts = greeter.GetCounts(); + + ASSERT_EQ(counts.Size(), 3u); + EXPECT_EQ(counts.Lookup(L"alpha"), 1); + EXPECT_EQ(counts.Lookup(L"beta"), 2); + EXPECT_EQ(counts.Lookup(L"gamma"), 3); +} + int main(int argc, char** argv) { init_apartment(); diff --git a/src/Tests/AuthoringTest2/Greeter.cs b/src/Tests/AuthoringTest2/Greeter.cs index efa6a6aca..91d42f4a9 100644 --- a/src/Tests/AuthoringTest2/Greeter.cs +++ b/src/Tests/AuthoringTest2/Greeter.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; + namespace AuthoringTest2; public sealed class Greeter @@ -11,4 +13,25 @@ public int Add(int a, int b) { return a + b; } + + // Generic collection instantiations exposed across the WinRT ABI boundary. + // The aggregator must produce a single deduplicated marshalling closure that covers + // these instantiations alongside any others used by sibling components in the same + // exe. If per-component marshalling stubs were generated independently, the merged + // TypeMap registration would fail with a duplicate-key error at publish time, and + // these calls would either fail to activate or produce wrong values at runtime. + public IList GetNumbers() + { + return new List { 1, 2, 3, 5, 8, 13 }; + } + + public IDictionary GetCounts() + { + return new Dictionary + { + { "alpha", 1 }, + { "beta", 2 }, + { "gamma", 3 }, + }; + } } From 6c26b3e67a4826450fee85d1b20c115b7ea6b4c7 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Fri, 8 May 2026 23:07:57 -0700 Subject: [PATCH 060/105] Set SimulateCsWinRTNugetReference=true on AuthoringTest2 This opts the in-repo component into the CsWinRT package import flow (nuget/Microsoft.Windows.CsWinRT.props/.targets), which scrubs cswinrt.winmd out of the project's reference set via CsWinRTRemoveWinMDReferences and so avoids NETSDK1130. Same pattern the other in-repo CsWinRT components use (AuthoringTest, AuthoringWuxTest, etc.). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Tests/AuthoringTest2/Directory.Build.props | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/Tests/AuthoringTest2/Directory.Build.props diff --git a/src/Tests/AuthoringTest2/Directory.Build.props b/src/Tests/AuthoringTest2/Directory.Build.props new file mode 100644 index 000000000..6a86d69f2 --- /dev/null +++ b/src/Tests/AuthoringTest2/Directory.Build.props @@ -0,0 +1,9 @@ + + + + true + + + + + From a9356409374ae8238dac4cb8fa9ac4f3dcf19997 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Fri, 8 May 2026 23:10:04 -0700 Subject: [PATCH 061/105] Run AuthoringConsumptionTest2 from build.cmd; align AuthoringTest2 props - src/build.cmd: invoke AuthoringConsumptionTest2.exe in the authortest step (x64 only, mirroring CI). Local `build.cmd test` invocations now exercise multi-component aggregation alongside the existing single- component path. - src/Tests/AuthoringTest2/AuthoringTest2.csproj: add IsTrimmable=true and TargetPlatformResourceVersion to match AuthoringTest's shape. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Tests/AuthoringTest2/AuthoringTest2.csproj | 2 ++ src/build.cmd | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/src/Tests/AuthoringTest2/AuthoringTest2.csproj b/src/Tests/AuthoringTest2/AuthoringTest2.csproj index c00c16ea6..3de365851 100644 --- a/src/Tests/AuthoringTest2/AuthoringTest2.csproj +++ b/src/Tests/AuthoringTest2/AuthoringTest2.csproj @@ -4,6 +4,8 @@ net10.0-windows10.0.26100.1 x64;x86 true + true + 10.0.18362.0 win-x86;win-x64;win-arm64 diff --git a/src/build.cmd b/src/build.cmd index 844b5b4bd..d723b43bb 100644 --- a/src/build.cmd +++ b/src/build.cmd @@ -228,6 +228,16 @@ if ErrorLevel 1 ( rem exit /b !ErrorLevel! ) +if /I "%cswinrt_platform%"=="x64" ( + call :exec %this_dir%_build\%cswinrt_platform%\%cswinrt_configuration%\AuthoringConsumptionTest2\bin\AuthoringConsumptionTest2.exe --gtest_output=xml:%this_dir%authoringtest2_%cswinrt_version_string%.xml + if ErrorLevel 1 ( + echo. + rem Not skipping due to known issue. + rem echo ERROR: Multi-component authoring test failed, skipping NuGet pack + rem exit /b !ErrorLevel! + ) +) + :functionaltest rem Run functional tests if "%run_functional_tests%" EQU "true" ( From 99e7fe1e112a07db68e43868907364d66b8c5d86 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Fri, 8 May 2026 23:44:49 -0700 Subject: [PATCH 062/105] Replace wrong-arch WinRT.Host.dll in vcxproj reference closure Native vcxproj consumers can end up with a wrong-arch WinRT.Host.dll in their output when a referenced CsWinRT component csproj is built AnyCPU (its bin captures one specific arch's host dll, which then flows through ProjectReference resolution into the vcxproj's ReferenceCopyLocalPaths). Add _CsWinRTReplaceArchSelectedHostingAssets target that, after the SDK's standard reference resolution, removes any WinRT.Host.dll / WinRT.Host.dll.mui items from ReferenceCopyLocalPaths and replaces them with the arch-correct copies from the CsWinRT package's hosting//native/ folder. Skipped when the package-layout hosting folder isn't on disk (in-repo simulation), so existing test workarounds keep working. Opt-out via CsWinRTSkipNativeHostingAssetsOverride for consumers that ship their own host bundle. Doesn't affect: - Component author packing path (Authoring.targets all-arch Content) - Managed app + ProjectReference (csproj-side flow unchanged) - Managed app + PackageReference (component package's renamed transitive targets fire in csproj context, not vcxproj context) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../native/Microsoft.Windows.CsWinRT.targets | 38 +++++++++++++++++++ nuget/readme.md | 1 + 2 files changed, 39 insertions(+) diff --git a/nuget/native/Microsoft.Windows.CsWinRT.targets b/nuget/native/Microsoft.Windows.CsWinRT.targets index 579f79380..7108f18a7 100644 --- a/nuget/native/Microsoft.Windows.CsWinRT.targets +++ b/nuget/native/Microsoft.Windows.CsWinRT.targets @@ -29,6 +29,10 @@ Properties consumers may set on the vcxproj: WindowsSdkPackageVersion to pass to the aggregator. Falls back to a value picked from any component ref metadata, then to the SDK default. + CsWinRTSkipNativeHostingAssetsOverride Set to 'true' to suppress the arch-correct + replacement of WinRT.Host.dll/.mui in the consumer's + ReferenceCopyLocalPaths. Useful when the consumer + ships its own host bundle. *********************************************************************************************** --> @@ -204,4 +208,38 @@ Properties consumers may set on the vcxproj: + + + + + <_CsWinRTHostDllPath>$(MSBuildThisFileDirectory)..\..\hosting\$(_CsWinRTNormalizedPlatform)\native\WinRT.Host.dll + <_CsWinRTHostMuiPath>$(MSBuildThisFileDirectory)..\..\hosting\$(_CsWinRTNormalizedPlatform)\native\en-US\WinRT.Host.dll.mui + + + + <_CsWinRTWrongArchHostingItems Include="@(ReferenceCopyLocalPaths)" + Condition="'%(Filename)%(Extension)' == 'WinRT.Host.dll' or '%(Filename)%(Extension)' == 'WinRT.Host.dll.mui'" /> + + + + + + + diff --git a/nuget/readme.md b/nuget/readme.md index 7f4a8008e..2acda618a 100644 --- a/nuget/readme.md +++ b/nuget/readme.md @@ -106,6 +106,7 @@ Consumer-side properties: | `CsWinRTDisableNativeComponentInterop` | Set to `true` to disable aggregator generation. | | `CsWinRTComponentTargetFrameworkOverride` | TFM to use for the aggregator project. Required when referenced components disagree on TFM, or when no referenced component supplies a TFM. | | `CsWinRTNativeConsumerWindowsSdkPackageVersion` | `WindowsSdkPackageVersion` to pass to the aggregator. Falls back to a value picked from any component reference, then to the SDK default. | +| `CsWinRTSkipNativeHostingAssetsOverride` | Set to `true` to skip the arch-correct replacement of `WinRT.Host.dll` / `WinRT.Host.dll.mui` in the consumer's reference closure. Use when the consumer ships its own host bundle. | ### Distributing a CsWinRT component for native consumers From c3ca105c33226e0d4ad0c10f2d84df312efdec56 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 9 May 2026 00:02:02 -0700 Subject: [PATCH 063/105] Trim test comments; reword opt-out property as opt-out - src/Tests/AuthoringConsumptionTest2/test.cpp: drop the per-line comments that just restate the call (the variable name and call site already convey it). Keep one short header per logical block. - src/Tests/AuthoringTest2/Greeter.cs: collapse the multi-line block about generic instantiations into a one-liner; the test side carries the explanatory context. - CsWinRTSkipNativeHostingAssetsOverride: described as an opt-out rather than with speculative justification. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- nuget/native/Microsoft.Windows.CsWinRT.targets | 7 +++---- nuget/readme.md | 2 +- src/Tests/AuthoringConsumptionTest2/test.cpp | 16 +++------------- src/Tests/AuthoringTest2/Greeter.cs | 7 +------ 4 files changed, 8 insertions(+), 24 deletions(-) diff --git a/nuget/native/Microsoft.Windows.CsWinRT.targets b/nuget/native/Microsoft.Windows.CsWinRT.targets index 7108f18a7..96fcfb330 100644 --- a/nuget/native/Microsoft.Windows.CsWinRT.targets +++ b/nuget/native/Microsoft.Windows.CsWinRT.targets @@ -29,10 +29,9 @@ Properties consumers may set on the vcxproj: WindowsSdkPackageVersion to pass to the aggregator. Falls back to a value picked from any component ref metadata, then to the SDK default. - CsWinRTSkipNativeHostingAssetsOverride Set to 'true' to suppress the arch-correct - replacement of WinRT.Host.dll/.mui in the consumer's - ReferenceCopyLocalPaths. Useful when the consumer - ships its own host bundle. + CsWinRTSkipNativeHostingAssetsOverride Set to 'true' to opt out of the arch-correct + replacement of WinRT.Host.dll / .mui in the + consumer's ReferenceCopyLocalPaths. *********************************************************************************************** --> diff --git a/nuget/readme.md b/nuget/readme.md index 2acda618a..094a25656 100644 --- a/nuget/readme.md +++ b/nuget/readme.md @@ -106,7 +106,7 @@ Consumer-side properties: | `CsWinRTDisableNativeComponentInterop` | Set to `true` to disable aggregator generation. | | `CsWinRTComponentTargetFrameworkOverride` | TFM to use for the aggregator project. Required when referenced components disagree on TFM, or when no referenced component supplies a TFM. | | `CsWinRTNativeConsumerWindowsSdkPackageVersion` | `WindowsSdkPackageVersion` to pass to the aggregator. Falls back to a value picked from any component reference, then to the SDK default. | -| `CsWinRTSkipNativeHostingAssetsOverride` | Set to `true` to skip the arch-correct replacement of `WinRT.Host.dll` / `WinRT.Host.dll.mui` in the consumer's reference closure. Use when the consumer ships its own host bundle. | +| `CsWinRTSkipNativeHostingAssetsOverride` | Set to `true` to opt out of the arch-correct replacement of `WinRT.Host.dll` / `.mui` in the consumer's reference closure. | ### Distributing a CsWinRT component for native consumers diff --git a/src/Tests/AuthoringConsumptionTest2/test.cpp b/src/Tests/AuthoringConsumptionTest2/test.cpp index 3d0326f92..658f029ca 100644 --- a/src/Tests/AuthoringConsumptionTest2/test.cpp +++ b/src/Tests/AuthoringConsumptionTest2/test.cpp @@ -4,9 +4,7 @@ using namespace winrt; using namespace Windows::Foundation; using namespace Windows::Foundation::Collections; -// Verifies multi-component aggregation: a single native exe references two managed CsWinRT -// components (AuthoringTest and AuthoringTest2) and the merged WinRT.Component.dll produced -// by Microsoft.Windows.CsWinRT.targets resolves activation for both. +// Activation tests across two CsWinRT components aggregated into one WinRT.Component.dll. TEST(MultiComponent, AuthoringTestStatics) { @@ -30,35 +28,27 @@ TEST(MultiComponent, BothComponentsActivateInOneProcess) EXPECT_EQ(second.Add(10, 20), 30); } -// Exercises the merged TypeMap deduplication that justifies the aggregator's existence: -// both components expose generic collection instantiations across the WinRT ABI, and the -// merged WinRT.Interop.dll must register marshalling for each instantiation exactly once. +// Generic instantiations from both components flow through the merged WinRT.Interop.dll. // If per-component interop generation had run independently, type-map registration would -// fail at publish time with duplicate-key errors, or these calls would fail at runtime. +// fail at publish time or these calls would fail at runtime. TEST(MultiComponent, GenericCollectionsFromBothComponents) { - // IList from component 2. AuthoringTest2::Greeter greeter; auto numbers = greeter.GetNumbers(); ASSERT_EQ(numbers.Size(), 6u); EXPECT_EQ(numbers.GetAt(0), 1); EXPECT_EQ(numbers.GetAt(5), 13); - // IList from component 1. auto bools = AuthoringTest::TestClass::GetBools(); EXPECT_GT(bools.Size(), 0u); - // IReadOnlyList from component 1: exercises a reference-type generic - // instantiation that the merged interop closure must marshal correctly. auto uris = AuthoringTest::TestClass::GetUris(); EXPECT_GT(uris.Size(), 0u); } TEST(MultiComponent, GenericMapFromComponent2) { - // IDictionary from component 2: a generic map instantiation that - // exists only in component 2; covers the IMap marshalling path. AuthoringTest2::Greeter greeter; auto counts = greeter.GetCounts(); diff --git a/src/Tests/AuthoringTest2/Greeter.cs b/src/Tests/AuthoringTest2/Greeter.cs index 91d42f4a9..2895b53c7 100644 --- a/src/Tests/AuthoringTest2/Greeter.cs +++ b/src/Tests/AuthoringTest2/Greeter.cs @@ -14,12 +14,7 @@ public int Add(int a, int b) return a + b; } - // Generic collection instantiations exposed across the WinRT ABI boundary. - // The aggregator must produce a single deduplicated marshalling closure that covers - // these instantiations alongside any others used by sibling components in the same - // exe. If per-component marshalling stubs were generated independently, the merged - // TypeMap registration would fail with a duplicate-key error at publish time, and - // these calls would either fail to activate or produce wrong values at runtime. + // Generic collection returns; exercise the merged interop's marshalling closure. public IList GetNumbers() { return new List { 1, 2, 3, 5, 8, 13 }; From 4aedf3a7f047cc6c5287d99efee8779190491257 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 9 May 2026 00:06:16 -0700 Subject: [PATCH 064/105] Make host dll arch correction conditional on something already copying Change _CsWinRTReplaceArchSelectedHostingAssets to only Include the arch-correct WinRT.Host.dll / .mui in ReferenceCopyLocalPaths when something else (typically a JIT-built component csproj's items via Authoring.targets) was already contributing one. If nothing is contributing (e.g. AOT-published components where Authoring.targets gates the items out), the target now does nothing rather than imposing a host dll the consumer doesn't need. Net effect: - Direct PR + JIT (AnyCPU): wrong-arch dll replaced with right arch - Direct PR + AOT: no host dll injected (consumer doesn't need one) - Mixed JIT/AOT direct PRs: replaced (JIT path needs it; AOT exports work regardless) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../native/Microsoft.Windows.CsWinRT.targets | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/nuget/native/Microsoft.Windows.CsWinRT.targets b/nuget/native/Microsoft.Windows.CsWinRT.targets index 96fcfb330..fe3c56b9a 100644 --- a/nuget/native/Microsoft.Windows.CsWinRT.targets +++ b/nuget/native/Microsoft.Windows.CsWinRT.targets @@ -211,14 +211,14 @@ Properties consumers may set on the vcxproj: ============================================================ _CsWinRTReplaceArchSelectedHostingAssets - Standard ProjectReference / package transitive flow may have brought a wrong-arch - WinRT.Host.dll / WinRT.Host.dll.mui into ReferenceCopyLocalPaths (e.g. when the - referenced component csproj was built AnyCPU and its bin captured a single arch's - host dll). Replace any such items with the arch-correct copies from the CsWinRT - package's hosting/$(_CsWinRTNormalizedPlatform)/native/ folder. - - Skipped if the package-layout host dll is not found on disk (e.g. in-repo simulation - that doesn't stage hosting/$arch/native/), so existing in-repo workarounds keep working. + If the standard reference flow brought a WinRT.Host.dll / WinRT.Host.dll.mui into + ReferenceCopyLocalPaths (e.g. via a JIT-built component's + items), replace it with the arch-correct copy from the CsWinRT package's + hosting/$(_CsWinRTNormalizedPlatform)/native/ folder. If nothing contributes one + (e.g. AOT-published component, or the consumer manages its own host bundle), this + target does nothing - we only correct what would already be copied. + + Skipped if the package-layout host dll is not found on disk (in-repo simulation). Skipped if the consumer sets CsWinRTSkipNativeHostingAssetsOverride=true. ============================================================ --> @@ -232,11 +232,13 @@ Properties consumers may set on the vcxproj: - <_CsWinRTWrongArchHostingItems Include="@(ReferenceCopyLocalPaths)" + <_CsWinRTHostingItemsToReplace Include="@(ReferenceCopyLocalPaths)" Condition="'%(Filename)%(Extension)' == 'WinRT.Host.dll' or '%(Filename)%(Extension)' == 'WinRT.Host.dll.mui'" /> - - - + + + From 6550824c57a111c6baabab1c0c7ccca385c51049 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 9 May 2026 00:13:09 -0700 Subject: [PATCH 065/105] Apply X86/X64 macro dance in AuthoringConsumptionTest2 pch.h cppwinrt-projected winrt/Windows.System.h uses identifiers that collide with the X86/X64 macros defined by Windows.h, causing C2143/C2059/C3770 errors when the header is transitively included via the AuthoringTest projection. Mirror the push_macro/undef pattern AuthoringConsumptionTest's pch.h already uses. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Tests/AuthoringConsumptionTest2/pch.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Tests/AuthoringConsumptionTest2/pch.h b/src/Tests/AuthoringConsumptionTest2/pch.h index e18686d32..e156e8485 100644 --- a/src/Tests/AuthoringConsumptionTest2/pch.h +++ b/src/Tests/AuthoringConsumptionTest2/pch.h @@ -1,11 +1,21 @@ #pragma once +// Undefine GetCurrentTime macro to prevent +// conflict with Storyboard::GetCurrentTime #undef GetCurrentTime #include #include #include +#pragma push_macro("X86") +#pragma push_macro("X64") +#undef X86 +#undef X64 +#include "winrt/Windows.System.h" +#pragma pop_macro("X64") +#pragma pop_macro("X86") + #include #include From 780900f99c8678fdad12357d44fa60bf4166dba8 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 9 May 2026 12:33:41 -0700 Subject: [PATCH 066/105] Restore in-body gating of aggregator on _CsWinRTHasComponentReferences MSBuild evaluates a target's Condition BEFORE running its DependsOnTargets, so the bab17200 refactor that put _CsWinRTHasComponentReferences=='true' on the Target Condition silently skipped the aggregator on every config: the property is populated inside _DetectCsWinRTNativeComponentReferences (the DependsOnTargets), which never ran because the Condition was already false. Move the check back inside the target body as Condition attributes on each ItemGroup/PropertyGroup/Task, matching the pre-bab17200 shape. Keep CsWinRTDisableNativeComponentInterop on the Target Condition (consumer-set, available before DependsOnTargets). Aggregator outputs (WinRT.Component.dll, WinRT.Interop.dll, WinRT.Projection.dll, WinRT.Sdk.Projection.dll) will now appear in vcxproj OutDir again for x86 Debug/Release and x64 Debug. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../native/Microsoft.Windows.CsWinRT.targets | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/nuget/native/Microsoft.Windows.CsWinRT.targets b/nuget/native/Microsoft.Windows.CsWinRT.targets index fe3c56b9a..06ccaf5c3 100644 --- a/nuget/native/Microsoft.Windows.CsWinRT.targets +++ b/nuget/native/Microsoft.Windows.CsWinRT.targets @@ -127,12 +127,18 @@ Properties consumers may set on the vcxproj: BeforeTargets="Link" Inputs="@(_CsWinRTAggregatorInputs)" Outputs="$(OutDir)WinRT.Component.dll" - Condition="'$(CsWinRTDisableNativeComponentInterop)' != 'true' and '$(_CsWinRTHasComponentReferences)' == 'true'"> + Condition="'$(CsWinRTDisableNativeComponentInterop)' != 'true'"> - + + + - + <_CsWinRTTempProjectDir>$(_CsWinRTNativeConsumerIntermediateDir) <_CsWinRTTempProjectPath>$(_CsWinRTTempProjectDir)CsWinRT.NativeConsumer.csproj <_CsWinRTTempProjectTFMDir>$(_CsWinRTComponentTargetFramework) @@ -147,9 +153,9 @@ Properties consumers may set on the vcxproj: <_CsWinRTTargetsForAggregator>$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)..\Microsoft.Windows.CsWinRT.targets')) - + - + <_CsWinRTTempProjectLines Include="<Project>" /> <_CsWinRTTempProjectLines Include=" <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />" /> <_CsWinRTTempProjectLines Include=" <Import Project="$(_CsWinRTPropsForAggregator)" />" /> @@ -183,19 +189,22 @@ Properties consumers may set on the vcxproj: <_CsWinRTTempProjectLines Include="</Project>" /> - - - - + <_CsWinRTGeneratedDlls Include="$(_CsWinRTTempProjectIntermediateDir)WinRT.Component.dll" Condition="Exists('$(_CsWinRTTempProjectIntermediateDir)WinRT.Component.dll')" /> <_CsWinRTGeneratedDlls Include="$(_CsWinRTTempProjectIntermediateDir)WinRT.Interop.dll" Condition="Exists('$(_CsWinRTTempProjectIntermediateDir)WinRT.Interop.dll')" /> <_CsWinRTGeneratedDlls Include="$(_CsWinRTTempProjectIntermediateDir)WinRT.Projection.dll" Condition="Exists('$(_CsWinRTTempProjectIntermediateDir)WinRT.Projection.dll')" /> @@ -203,7 +212,7 @@ Properties consumers may set on the vcxproj: <_CsWinRTGeneratedDlls Include="$(_CsWinRTTempProjectIntermediateDir)WinRT.Sdk.Xaml.Projection.dll" Condition="Exists('$(_CsWinRTTempProjectIntermediateDir)WinRT.Sdk.Xaml.Projection.dll')" /> - + From 02e54c562658d05c9b1f7647a7ddee0eec1f6a6f Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 9 May 2026 15:27:26 -0700 Subject: [PATCH 067/105] Skip Reference/ProjectReference lines when their item source is empty When the synthesized aggregator csproj's emitted both and lines unconditionally, the empty-itemset case (e.g. AuthoringConsumptionTest which has only project refs and no @(CsWinRTNativeComponent) items) still produced one line with an empty Include attribute, causing csproj parse error MSB4035: The required attribute 'Include' is empty or missing from Gate each metadata-batched line on its source item collection being non-empty. Project-only consumers omit the lines; package-only consumers omit the line; mixed consumers emit both. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- nuget/native/Microsoft.Windows.CsWinRT.targets | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/nuget/native/Microsoft.Windows.CsWinRT.targets b/nuget/native/Microsoft.Windows.CsWinRT.targets index 06ccaf5c3..843bdefdc 100644 --- a/nuget/native/Microsoft.Windows.CsWinRT.targets +++ b/nuget/native/Microsoft.Windows.CsWinRT.targets @@ -176,13 +176,19 @@ Properties consumers may set on the vcxproj: <_CsWinRTTempProjectLines Include=" </PropertyGroup>" /> <_CsWinRTTempProjectLines Include=" <ItemGroup>" /> - <_CsWinRTTempProjectLines Include=" <ProjectReference Include="%(_CsWinRTComponentProjectPaths.Identity)" />" /> + <_CsWinRTTempProjectLines Condition="'@(_CsWinRTComponentProjectPaths)' != ''" + Include=" <ProjectReference Include="%(_CsWinRTComponentProjectPaths.Identity)" />" /> - <_CsWinRTTempProjectLines Include=" <Reference Include="%(CsWinRTNativeComponent.Filename)">" /> - <_CsWinRTTempProjectLines Include=" <HintPath>%(CsWinRTNativeComponent.Identity)</HintPath>" /> - <_CsWinRTTempProjectLines Include=" <CsWinRTComponent>true</CsWinRTComponent>" /> - <_CsWinRTTempProjectLines Include=" <Private>true</Private>" /> - <_CsWinRTTempProjectLines Include=" </Reference>" /> + <_CsWinRTTempProjectLines Condition="'@(CsWinRTNativeComponent)' != ''" + Include=" <Reference Include="%(CsWinRTNativeComponent.Filename)">" /> + <_CsWinRTTempProjectLines Condition="'@(CsWinRTNativeComponent)' != ''" + Include=" <HintPath>%(CsWinRTNativeComponent.Identity)</HintPath>" /> + <_CsWinRTTempProjectLines Condition="'@(CsWinRTNativeComponent)' != ''" + Include=" <CsWinRTComponent>true</CsWinRTComponent>" /> + <_CsWinRTTempProjectLines Condition="'@(CsWinRTNativeComponent)' != ''" + Include=" <Private>true</Private>" /> + <_CsWinRTTempProjectLines Condition="'@(CsWinRTNativeComponent)' != ''" + Include=" </Reference>" /> <_CsWinRTTempProjectLines Include=" </ItemGroup>" /> <_CsWinRTTempProjectLines Include=" <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />" /> <_CsWinRTTempProjectLines Include=" <Import Project="$(_CsWinRTTargetsForAggregator)" />" /> From ad69028c45f5538633012f93b339f17e4b62f7fe Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 9 May 2026 15:32:34 -0700 Subject: [PATCH 068/105] AuthoringConsumptionTest2 Release|x64: AOT-merged native host Adds a consumer-authored .AOT host project that bundles AuthoringTest + AuthoringTest2 into one self-contained native dll via PublishAot + NativeLib=Shared + CsWinRTMergeReferencedActivationFactories. Demonstrates the consumer-owned AOT-with-merging path that needs no CsWinRT target changes - just the building blocks CsWinRT already exposes (source generator's merge mode + standard AOT publish properties). Files: - src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj (csproj, Directory.Build.props, EntryPoint.cs) - src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.AOT.exe.manifest (registers AuthoringTest.TestClass and AuthoringTest2.Greeter against the merged dll, since the merged dll's name doesn't match either component's namespace for cppwinrt's namespace-based fallback) - vcxproj Release|x64: skips JIT projection/host/runtime refs and the CsWinRT native targets import; CsWinRTLink target invokes Publish on the .AOT csproj and adds the published native dll to ReferenceCopyLocalPaths; uses the .AOT manifest instead of the JIT one - cswinrt.slnx: adds AuthoringConsumptionTest2.AOT.csproj as a BuildDependency of the vcxproj, gated to Release|x64 Other configurations are unaffected; Debug|x64 still uses the JIT aggregator path producing WinRT.Component.dll. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AuthoringConsumptionTest2.AOT.csproj | 30 ++++++++++ .../Directory.Build.props | 9 +++ .../EntryPoint.cs | 8 +++ ...AuthoringConsumptionTest2.AOT.exe.manifest | 14 +++++ .../AuthoringConsumptionTest2.vcxproj | 57 +++++++++++++++++-- src/cswinrt.slnx | 12 ++++ 6 files changed, 125 insertions(+), 5 deletions(-) create mode 100644 src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj create mode 100644 src/Tests/AuthoringConsumptionTest2.AOT/Directory.Build.props create mode 100644 src/Tests/AuthoringConsumptionTest2.AOT/EntryPoint.cs create mode 100644 src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.AOT.exe.manifest diff --git a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj new file mode 100644 index 000000000..a2d4800bb --- /dev/null +++ b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj @@ -0,0 +1,30 @@ + + + + net10.0-windows10.0.26100.1 + x64 + win-x64 + + + true + + + true + Shared + true + Exe + true + true + + + + + + + + + + + + diff --git a/src/Tests/AuthoringConsumptionTest2.AOT/Directory.Build.props b/src/Tests/AuthoringConsumptionTest2.AOT/Directory.Build.props new file mode 100644 index 000000000..6a86d69f2 --- /dev/null +++ b/src/Tests/AuthoringConsumptionTest2.AOT/Directory.Build.props @@ -0,0 +1,9 @@ + + + + true + + + + + diff --git a/src/Tests/AuthoringConsumptionTest2.AOT/EntryPoint.cs b/src/Tests/AuthoringConsumptionTest2.AOT/EntryPoint.cs new file mode 100644 index 000000000..ae24a069c --- /dev/null +++ b/src/Tests/AuthoringConsumptionTest2.AOT/EntryPoint.cs @@ -0,0 +1,8 @@ +[assembly: global::System.Runtime.Versioning.SupportedOSPlatform("Windows")] + +internal static class Program +{ + static void Main() + { + } +} diff --git a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.AOT.exe.manifest b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.AOT.exe.manifest new file mode 100644 index 000000000..83938fbd5 --- /dev/null +++ b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.AOT.exe.manifest @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj index 5c967ffe1..fcbd634c7 100644 --- a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj +++ b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj @@ -48,11 +48,16 @@ - + true - + + {ffa9a78b-f53f-43ee-af87-24a80f4c330a} TargetFramework=net10.0 @@ -80,21 +85,63 @@ TargetFramework=net10.0-windows10.0.26100.1 - + + + AuthoringConsumptionTest2.AOT + $([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\$(NativeLibraryProjectName)'))\ + $(NativeLibraryProjectDirectory)$(NativeLibraryProjectName).csproj + $(NativeLibraryProjectDirectory)bin\$(Platform)\$(Configuration)\net10.0-windows10.0.26100.1\win-$(Platform)\publish\ + $(NativeLibraryPublishFolder)$(NativeLibraryProjectName).dll + + + + + + + + + + ..\AuthoringTest\bin\$(_WinMDPlatform)\$(Configuration)\net10.0-windows10.0.26100.1\win-$(Platform)\AuthoringTest.winmd + true + + + ..\AuthoringTest2\bin\$(_WinMDPlatform)\$(Configuration)\net10.0-windows10.0.26100.1\win-$(Platform)\AuthoringTest2.winmd + true + + + + ..\AuthoringTest\bin\$(_WinMDPlatform)\$(Configuration)\net10.0-windows10.0.26100.1\win-$(Platform)\AuthoringTest.winmd true + AuthoringConsumptionTest2.AOT.dll ..\AuthoringTest2\bin\$(_WinMDPlatform)\$(Configuration)\net10.0-windows10.0.26100.1\win-$(Platform)\AuthoringTest2.winmd true + AuthoringConsumptionTest2.AOT.dll - + + - + diff --git a/src/cswinrt.slnx b/src/cswinrt.slnx index cbaaf737c..2dc9b5773 100644 --- a/src/cswinrt.slnx +++ b/src/cswinrt.slnx @@ -177,6 +177,7 @@ + @@ -186,6 +187,17 @@ + + + + + + + + + + + From d40bf02c3984b16f3f199610106e82d8f5477108 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 9 May 2026 18:15:39 -0700 Subject: [PATCH 069/105] Force AOT in CsWinRTLink, drop duplicate Compile, add x86 to test2 Three issues uncovered by CI log 454.txt: 1. AuthoringConsumptionTest's Release|x64 was silently doing PublishTrimmed JIT instead of NativeAOT. Evidence: ILLink IL1012 with --trim-mode link, no ilc invocation for AuthoringTest. apparently does not reliably trigger the ILC pipeline when PublishAot=true is only set via the inner csproj's Directory.Build.props - the AOT detection happens before that evaluation. Fix: pass PublishAot=true plus the rest of the AOT switches (NativeLib, SelfContained, OutputType, CustomNativeMain) as explicit Properties on the MSBuild call, so the inner build sees them at evaluation time. Apply to both AuthoringConsumptionTest and the new AuthoringConsumptionTest2 CsWinRTLink targets. 2. AuthoringConsumptionTest2.AOT.csproj had explicit on top of the SDK's default *.cs discovery, producing NETSDK1022 duplicate-Compile-item. Drop the explicit include. 3. Add Win32 (x86) Debug + Release configurations to AuthoringConsumptionTest2.vcxproj (mirrors AuthoringConsumptionTest; non-AOT JIT path, no trimming - matches AuthoringConsumptionTest's shape). Update _WinMDPlatform Win32 -> x86. Drop the slnx Platform overrides that previously pinned other platforms to x64. Wire the x86 run into CsWinRT-Test-Steps.yml and src/build.cmd alongside the existing x64 invocation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../CsWinRT-Test-Steps.yml | 2 +- .../AuthoringConsumptionTest.vcxproj | 10 +++- .../AuthoringConsumptionTest2.AOT.csproj | 1 - .../AuthoringConsumptionTest2.vcxproj | 46 ++++++++++++++++++- src/build.cmd | 9 ++++ src/cswinrt.slnx | 7 +-- 6 files changed, 64 insertions(+), 11 deletions(-) diff --git a/build/AzurePipelineTemplates/CsWinRT-Test-Steps.yml b/build/AzurePipelineTemplates/CsWinRT-Test-Steps.yml index 53f7f769b..e9a909b82 100644 --- a/build/AzurePipelineTemplates/CsWinRT-Test-Steps.yml +++ b/build/AzurePipelineTemplates/CsWinRT-Test-Steps.yml @@ -74,7 +74,7 @@ steps: - task: CmdLine@2 displayName: Run Multi-Component Authoring Consumption Tests enabled: true - condition: and(succeeded(), eq(variables['BuildPlatform'], 'x64')) + condition: and(succeeded(), or(eq(variables['BuildPlatform'], 'x86'), eq(variables['BuildPlatform'], 'x64'))) continueOnError: True inputs: workingDirectory: $(Build.SourcesDirectory)\src diff --git a/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj b/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj index d4f5a2ab0..2aa99bccd 100644 --- a/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj +++ b/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj @@ -119,8 +119,14 @@ Condition="'$(Configuration)' == 'Release' and '$(Platform)' == 'x64'" Inputs="$(NativeLibraryDllPath)" Outputs="@(ReferenceCopyLocalPaths)"> - - + + diff --git a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj index a2d4800bb..f9abf76f9 100644 --- a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj +++ b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj @@ -19,7 +19,6 @@ - diff --git a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj index fcbd634c7..b1b946732 100644 --- a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj +++ b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj @@ -8,6 +8,14 @@ + + Debug + Win32 + + + Release + Win32 + Debug x64 @@ -26,6 +34,7 @@ v142 Unicode <_WinMDPlatform>$(Platform) + <_WinMDPlatform Condition="'$(Platform)' == 'Win32'">x86 false true @@ -102,9 +111,11 @@ Condition="'$(Configuration)' == 'Release' and '$(Platform)' == 'x64'" Inputs="$(NativeLibraryProjectFilePath)" Outputs="$(NativeLibraryPublishedDllPath)"> + + Properties="Configuration=$(Configuration);Platform=$(Platform);RuntimeIdentifier=win-$(Platform);TargetFramework=net10.0-windows10.0.26100.1;PublishAot=true;NativeLib=Shared;SelfContained=true;OutputType=Exe;CustomNativeMain=true" /> @@ -187,6 +198,39 @@ Console + + + Use + pch.h + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level3 + + + true + Console + + + + + Use + pch.h + MaxSpeed + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + true + MultiThreadedDLL + Level3 + + + true + true + true + Console + + diff --git a/src/build.cmd b/src/build.cmd index d723b43bb..d61ac8ccd 100644 --- a/src/build.cmd +++ b/src/build.cmd @@ -237,6 +237,15 @@ if /I "%cswinrt_platform%"=="x64" ( rem exit /b !ErrorLevel! ) ) +if /I "%cswinrt_platform%"=="x86" ( + call :exec %this_dir%_build\%cswinrt_platform%\%cswinrt_configuration%\AuthoringConsumptionTest2\bin\AuthoringConsumptionTest2.exe --gtest_output=xml:%this_dir%authoringtest2_%cswinrt_version_string%.xml + if ErrorLevel 1 ( + echo. + rem Not skipping due to known issue. + rem echo ERROR: Multi-component authoring test failed, skipping NuGet pack + rem exit /b !ErrorLevel! + ) +) :functionaltest rem Run functional tests diff --git a/src/cswinrt.slnx b/src/cswinrt.slnx index 2dc9b5773..0e83e8040 100644 --- a/src/cswinrt.slnx +++ b/src/cswinrt.slnx @@ -178,14 +178,9 @@ - - - - + - - From 892108e90fc6d7c1ccc5e6ed1b197c56d7de4b90 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 9 May 2026 18:28:04 -0700 Subject: [PATCH 070/105] Remove AuthoringConsumptionTest2.AOT.csproj from slnx default build Adding the .AOT csproj to slnx (with Build=true for Release|x64) caused slnx to pre-build it as part of default targets. That triggered an inner build of AuthoringTest.csproj (its ProjectReference) WITHOUT the PublishAot=true property propagating - PublishAot is set on the .AOT csproj itself, but ProjectReference resolution doesn't carry it through. AuthoringTest's evaluation got cached with TFM net10.0-windows10.0.26100.1 without PublishAot=true. When AuthoringConsumptionTest's CsWinRTLink later invoked Publish on AuthoringTest, the cached state caused the SDK to skip TFM normalization for AOT and fall through to ILLink-trim publish (manifesting as IL1012). Working build (commit 6550824c, no .AOT csproj) had AuthoringTest publishing to bin/x64/Release/net10.0/ - the AOT-normalized path; failing build had it at bin/x64/Release/net10.0-windows10.0.26100.1/ - the non-AOT trim path. Take .AOT out of slnx. AuthoringConsumptionTest2.vcxproj's CsWinRTLink target invokes Publish on the .AOT csproj directly via task, which doesn't need slnx pre-build wireup. AuthoringTest's standalone state is no longer contaminated by .AOT's ProjectReference. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/cswinrt.slnx | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/cswinrt.slnx b/src/cswinrt.slnx index 0e83e8040..5729ff62c 100644 --- a/src/cswinrt.slnx +++ b/src/cswinrt.slnx @@ -177,22 +177,10 @@ - - - - - - - - - - - - From 804b6c1f5951681c8358740021e2e0cc2d75b066 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 9 May 2026 18:36:47 -0700 Subject: [PATCH 071/105] Revert speculative AOT property forcing in CsWinRTLink Commit d40bf02c added explicit PublishAot=true; NativeLib=Shared; SelfContained=true; OutputType=Exe; CustomNativeMain=true to the calls in both vcxproj CsWinRTLink targets, on the theory that Directory.Build.props evaluation wasn't reaching the inner Publish in time. The actual root cause was different: AuthoringConsumptionTest2.AOT.csproj being in slnx caused slnx to pre-build it, which resolved its ProjectReference to AuthoringTest WITHOUT PublishAot propagating, caching AuthoringTest's evaluated state without AOT TFM normalization. That fix is in 892108e9 (slnx removal). Roll back the property forcing here so it's tested in isolation. Keep the unrelated parts of d40bf02c: dropped duplicate Compile of EntryPoint.cs, x86 configs on AuthoringConsumptionTest2.vcxproj, build.cmd / pipeline x86 wireup. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AuthoringConsumptionTest.vcxproj | 10 ++-------- .../AuthoringConsumptionTest2.vcxproj | 4 +--- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj b/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj index 2aa99bccd..d4f5a2ab0 100644 --- a/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj +++ b/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj @@ -119,14 +119,8 @@ Condition="'$(Configuration)' == 'Release' and '$(Platform)' == 'x64'" Inputs="$(NativeLibraryDllPath)" Outputs="@(ReferenceCopyLocalPaths)"> - - + + diff --git a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj index b1b946732..5408ae70d 100644 --- a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj +++ b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj @@ -111,11 +111,9 @@ Condition="'$(Configuration)' == 'Release' and '$(Platform)' == 'x64'" Inputs="$(NativeLibraryProjectFilePath)" Outputs="$(NativeLibraryPublishedDllPath)"> - + Properties="Configuration=$(Configuration);Platform=$(Platform);RuntimeIdentifier=win-$(Platform);TargetFramework=net10.0-windows10.0.26100.1" /> From cbe1ac7a23591f26a43fb2597fc9e6abad4dcd04 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 9 May 2026 19:21:03 -0700 Subject: [PATCH 072/105] AuthoringConsumptionTest2 Release|x64: PR components for build ordering Release|x64 had no ProjectReference to AuthoringTest / AuthoringTest2 csprojs (gated out by ad69028c since the AOT-merged host doesn't need their managed assemblies as JIT references). cppwinrt projection generation for AuthoringTest2 then failed at compile time: pch.h(20,10): error C1083: Cannot open include file: 'winrt/AuthoringTest2.h': No such file or directory The IsWinMDFile HintPath points at the AuthoringTest2.csproj output, but nothing inside the vcxproj's MSBuild evaluation was actually triggering AuthoringTest2.csproj to build. slnx BuildDependency wires Build ordering at solution-graph time, but doesn't drive a sub-build inside the vcxproj's own evaluation, so the .winmd may not exist when cppwinrt's GenerateProjection target runs. Re-add ProjectReference to both component csprojs in Release|x64 with: - ReferenceOutputAssembly=false / Private=false: build ordering only, don't pull the managed assemblies into the native vcxproj's reference closure (cppwinrt consumes only the explicit IsWinMDFile References) - UndefineProperties=PublishAot: belt-and-suspenders against the cache-contamination scenario fixed in 892108e9. Vcxproj evaluation doesn't have PublishAot=true set, so this is mostly defensive. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AuthoringConsumptionTest2.vcxproj | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj index 5408ae70d..4177dc758 100644 --- a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj +++ b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj @@ -94,6 +94,28 @@ TargetFramework=net10.0-windows10.0.26100.1 + + + + {41e2a272-150f-42f5-ad40-047aad9088a0} + TargetFramework=net10.0-windows10.0.26100.1 + false + false + PublishAot + + + TargetFramework=net10.0-windows10.0.26100.1 + false + false + PublishAot + + - - - {41e2a272-150f-42f5-ad40-047aad9088a0} - TargetFramework=net10.0-windows10.0.26100.1 - false - false - PublishAot - - - TargetFramework=net10.0-windows10.0.26100.1 - false - false - PublishAot - - + + + {41e2a272-150f-42f5-ad40-047aad9088a0} + TargetFramework=net10.0-windows10.0.26100.1 + RuntimeIdentifier=win-$(Platform) + false + false + PublishAot + + + TargetFramework=net10.0-windows10.0.26100.1 + RuntimeIdentifier=win-$(Platform) + false + false + PublishAot + + AuthoringConsumptionTest2.AOT $([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\$(NativeLibraryProjectName)'))\ From 7bc8269dd9ea3fb46168789d9934fdc649f0c819 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 9 May 2026 20:00:08 -0700 Subject: [PATCH 075/105] Simplify Release|x64 component PR comment Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AuthoringConsumptionTest2.vcxproj | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj index 207e62e22..1daac41b4 100644 --- a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj +++ b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj @@ -100,13 +100,10 @@ DllGetActivationFactory. CsWinRTLink target below invokes Publish on it; the resulting dll is added to ReferenceCopyLocalPaths so it lands next to the test exe. - Even though we don't reference the JIT-side projections, runtime, or host shim, we still - need both component csprojs built with RuntimeIdentifier set so their .winmd files land - at bin\x64\Release\\win-x64\ (matching the IsWinMDFile HintPath). slnx - BuildDependency builds them but doesn't propagate RID, so the winmd lands one folder up. - Add ProjectReferences with ReferenceOutputAssembly=false (build ordering only, no managed - closure pull-in) and explicit RuntimeIdentifier propagation. UndefineProperties=PublishAot - is defensive against the cache-contamination scenario fixed in 892108e9. + Build the two component csprojs with RuntimeIdentifier propagated, so their .winmd files + land at bin\\\\win-\ (matching the IsWinMDFile + HintPath below). ReferenceOutputAssembly=false drives build ordering only - cppwinrt + consumes the explicit IsWinMDFile items, not the managed assembly closure. --> @@ -115,14 +112,12 @@ RuntimeIdentifier=win-$(Platform) false false - PublishAot TargetFramework=net10.0-windows10.0.26100.1 RuntimeIdentifier=win-$(Platform) false false - PublishAot From 4191b93a51e64c979d9ec27257ede733aaffe942 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 9 May 2026 20:14:43 -0700 Subject: [PATCH 076/105] Restore AuthoringConsumptionTest2.AOT before Publish The .AOT csproj is invoked from CsWinRTLink only and is not in slnx, so slnx-level Restore doesn't generate its project.assets.json. Invoke Restore explicitly before Publish. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AuthoringConsumptionTest2.vcxproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj index 1daac41b4..9105b5858 100644 --- a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj +++ b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj @@ -131,6 +131,9 @@ Condition="'$(Configuration)' == 'Release' and '$(Platform)' == 'x64'" Inputs="$(NativeLibraryProjectFilePath)" Outputs="$(NativeLibraryPublishedDllPath)"> + From b39e69957b5683f949c601ac8feff50363fbbb38 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 9 May 2026 20:19:44 -0700 Subject: [PATCH 077/105] Merge Restore;Publish into one MSBuild call Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AuthoringConsumptionTest2.vcxproj | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj index 9105b5858..803300cc4 100644 --- a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj +++ b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj @@ -132,10 +132,7 @@ Inputs="$(NativeLibraryProjectFilePath)" Outputs="$(NativeLibraryPublishedDllPath)"> - From 3fce2af94d97896cff5d35c8f61248822668b506 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 9 May 2026 20:50:04 -0700 Subject: [PATCH 078/105] Override AuthoringTest AOT props in .AOT csproj PR AuthoringTest's Directory.Build.props sets PublishAot=true; SelfContained=true for Release|x64 (so the single-component AuthoringConsumptionTest can publish it as a self-contained native dll). When AuthoringConsumptionTest2.AOT.csproj PRs AuthoringTest, that block fires too, and AuthoringTest copies the WindowsAppSDK runtime payload to its bin. .AOT then publishes itself self-contained, pulling those runtimes from both AuthoringTest's bin and its own NuGet restore - NETSDK1152 duplicate publish output errors. Pass PublishAot=false; SelfContained=false; NativeLib=; OutputType=Library; CustomNativeMain=false as global properties on the PR. Globals override the Directory.Build.props PropertyGroup, so AuthoringTest builds as a plain managed library here. The merged AOT host handles all AOT linking. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AuthoringConsumptionTest2.AOT.csproj | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj index f9abf76f9..6bd4fcac4 100644 --- a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj +++ b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj @@ -19,7 +19,15 @@ - + + + PublishAot=false;SelfContained=false;NativeLib=;OutputType=Library;CustomNativeMain=false + From 49f4422419b572631a573f2f44b59d7b43b14f74 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 9 May 2026 20:52:01 -0700 Subject: [PATCH 079/105] Also pass WindowsAppSDKSelfContained=false on AuthoringTest PR WinAppSDK has its own self-contained mode property separate from .NET's SelfContained. Setting OutputType=Library already suppresses the WinAppSDK default, but pass WindowsAppSDKSelfContained=false explicitly as defense in depth. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AuthoringConsumptionTest2.AOT.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj index 6bd4fcac4..bf9900116 100644 --- a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj +++ b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj @@ -26,7 +26,7 @@ a managed input. Without this, AuthoringTest copies WinAppSDK runtimes to its bin and we hit NETSDK1152 duplicate publish output errors. --> - PublishAot=false;SelfContained=false;NativeLib=;OutputType=Library;CustomNativeMain=false + PublishAot=false;SelfContained=false;WindowsAppSDKSelfContained=false;NativeLib=;OutputType=Library;CustomNativeMain=false From fe1e1284d3b64589b481f7773ef8a5134b3b6748 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 9 May 2026 20:52:38 -0700 Subject: [PATCH 080/105] Revert "Also pass WindowsAppSDKSelfContained=false on AuthoringTest PR" This reverts commit 49f4422419b572631a573f2f44b59d7b43b14f74. --- .../AuthoringConsumptionTest2.AOT.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj index bf9900116..6bd4fcac4 100644 --- a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj +++ b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj @@ -26,7 +26,7 @@ a managed input. Without this, AuthoringTest copies WinAppSDK runtimes to its bin and we hit NETSDK1152 duplicate publish output errors. --> - PublishAot=false;SelfContained=false;WindowsAppSDKSelfContained=false;NativeLib=;OutputType=Library;CustomNativeMain=false + PublishAot=false;SelfContained=false;NativeLib=;OutputType=Library;CustomNativeMain=false From 0ca4880de3e94c20bc7ba602f118f1e74a167169 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 9 May 2026 21:32:01 -0700 Subject: [PATCH 081/105] Drop OutputType=Library override; use WindowsAppSDKSelfContained=false OutputType=Library passed as a global propagated transitively through AuthoringTest's PRs (Projections/Windows -> WinRT.Impl.Generator etc.), overriding those projects' OutputType=Exe and breaking compilation with CS8805 (top-level statements require executable). The duplicate publish output payload was the WinAppSDK runtime files, copied into AuthoringTest's bin because WinAppSDK auto-defaults WindowsAppSDKSelfContained=true when OutputType != Library. Set WindowsAppSDKSelfContained=false directly instead - same effect, no collateral damage to descendant project builds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AuthoringConsumptionTest2.AOT.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj index 6bd4fcac4..d3e0c577e 100644 --- a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj +++ b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj @@ -26,7 +26,7 @@ a managed input. Without this, AuthoringTest copies WinAppSDK runtimes to its bin and we hit NETSDK1152 duplicate publish output errors. --> - PublishAot=false;SelfContained=false;NativeLib=;OutputType=Library;CustomNativeMain=false + PublishAot=false;SelfContained=false;WindowsAppSDKSelfContained=false;NativeLib=;CustomNativeMain=false From 9d7eac48fa2ad8ca763e06a51396cd94e374cbdc Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 9 May 2026 22:08:58 -0700 Subject: [PATCH 082/105] Gate AuthoringTest AOT publish block on opt-out property AuthoringTest's Directory.Build.props sets PublishAot=true; OutputType=Exe; SelfContained=true; etc for Release|x64 - that's what makes the standalone single-component AOT publish in AuthoringConsumptionTest work. When AuthoringConsumptionTest2.AOT.csproj PRs AuthoringTest as a managed input for the merged AOT host, that block fights us. Trying to override the props as PR globals doesn't work cleanly: - OutputType=Library global propagates to AuthoringTest's transitive PRs (Projections/Windows -> WinRT.Impl.Generator etc.), overriding their OutputType=Exe and breaking compile with CS8805. - Without OutputType=Library, WinAppSDK either pulls its runtime payload into AuthoringTest's bin (NETSDK1152 dupes) or errors out demanding the Microsoft.WindowsAppSDK.Runtime PackageReference. Add an opt-out property _AuthoringTestSkipAotPublishConfig to the gating Condition. The merged AOT csproj sets that single property as a global on its PR, suppressing the AOT block entirely. AuthoringTest stays a plain CsWinRT component library - exactly what the merged host wants. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AuthoringConsumptionTest2.AOT.csproj | 2 +- src/Tests/AuthoringTest/Directory.Build.props | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj index d3e0c577e..a9cd8a062 100644 --- a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj +++ b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj @@ -26,7 +26,7 @@ a managed input. Without this, AuthoringTest copies WinAppSDK runtimes to its bin and we hit NETSDK1152 duplicate publish output errors. --> - PublishAot=false;SelfContained=false;WindowsAppSDKSelfContained=false;NativeLib=;CustomNativeMain=false + _AuthoringTestSkipAotPublishConfig=true diff --git a/src/Tests/AuthoringTest/Directory.Build.props b/src/Tests/AuthoringTest/Directory.Build.props index 296bd1cf8..48bf510a9 100644 --- a/src/Tests/AuthoringTest/Directory.Build.props +++ b/src/Tests/AuthoringTest/Directory.Build.props @@ -12,9 +12,14 @@ In Release x64, we publish with NativeAOT to test the self-contained WinRT component mode. When we do this, we also skip bundling the activation manifest in the C++ consumer. That is only needed when the implementation .dll is not the native .dll being loaded. So by dropping - it we can also further validate that the self-contained authoring scenario works correctly + it we can also further validate that the self-contained authoring scenario works correctly. + + Consumers that pull AuthoringTest in as a managed-only ProjectReference (e.g. the merged + AOT host AuthoringConsumptionTest2.AOT.csproj) set _AuthoringTestSkipAotPublishConfig=true + to suppress this block, so AuthoringTest stays a plain CsWinRT component library instead + of an exe pulling the WindowsAppSDK runtime payload into its bin. --> - + true Shared true From 3c854f0e0668444f338f320d51256db91ace1e00 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 9 May 2026 23:28:18 -0700 Subject: [PATCH 083/105] Pass PublishAot=true global on .AOT.csproj Restore;Publish The .AOT.csproj has true in its PropertyGroup, but NuGet's Restore phase invoked via didn't see it as a global property and didn't pull runtime.win-x64. microsoft.dotnet.ilcompiler into the restore graph. Publish then ran as a plain self-contained JIT publish, copying the whole .NET 10 framework plus clrjit.dll to bin\publish, producing a 16KB managed .AOT.dll instead of an AOT-compiled native dll. Tests crashed at activation because the manifest pointed at a managed library RoActivateInstance couldn't activate. Pass PublishAot=true explicitly as a global property on the call so both Restore and Publish phases see it. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj index 803300cc4..3c1aa9ad2 100644 --- a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj +++ b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj @@ -133,7 +133,7 @@ Outputs="$(NativeLibraryPublishedDllPath)"> + Properties="Configuration=$(Configuration);Platform=$(Platform);RuntimeIdentifier=win-$(Platform);TargetFramework=net10.0-windows10.0.26100.1;PublishAot=true" /> From 523473eb8da89aaa5697fc2530b86cc23b2b9db3 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 10 May 2026 00:11:42 -0700 Subject: [PATCH 084/105] UndefineProperties=PublishAot on .AOT csproj PRs Passing PublishAot=true as a global from CsWinRTLink (so NuGet Restore pulls the ILC package) propagates transitively to managed-only PRs (Projections/Windows -> WinRT.Generator.Tasks targeting netstandard2.0) and triggers NETSDK1207 'Ahead-of-time compilation is not supported for the target framework'. Add PublishAot on each PR so the global is stripped at the boundary. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AuthoringConsumptionTest2.AOT.csproj | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj index a9cd8a062..c3f6df6ec 100644 --- a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj +++ b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj @@ -19,19 +19,34 @@ + _AuthoringTestSkipAotPublishConfig=true + PublishAot + + + PublishAot + + + PublishAot + + + PublishAot + + + PublishAot - - - - From 4e66643f18913c17d116956d12fb19292f8e8ec8 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 10 May 2026 01:03:46 -0700 Subject: [PATCH 085/105] Move AuthoringConsumptionTest2.AOT.csproj back into slnx as a top-level project Previous attempt invoked the .AOT csproj from CsWinRTLink via with custom globals (PublishAot=true, RuntimeIdentifier=win-x64). Those globals propagated transitively through the .AOT csproj's PR closure (Projections/Windows -> WinRT.Generator.Tasks), caused MSBuild to see different project instance hashes than the slnx-level invocations of the same projects, and ran a second concurrent build that raced for shared bin\Release\\.dll outputs (file lock errors). Patching with per global was unmaintainable - every divergent global at every PR boundary needed enumeration. Move .AOT.csproj back into slnx as a top-level project, BuildDependency on AuthoringTest + AuthoringTest2, gated to build only for x64 Release. This way: - .AOT.csproj's evaluation uses the same slnx-level globals as everything else; descendants reuse the slnx-level project instances; no race. - Original contamination (commit ad69028c) is avoided because .AOT.csproj's PR to AuthoringTest passes _AuthoringTestSkipAotPublishConfig=true, which suppresses AuthoringTest's Directory.Build.props PublishAot block. AuthoringTest evaluates as a plain library here (different instance from AuthoringConsumptionTest's PublishAot-fired Publish-time instance, but different bin output paths so no race). CsWinRTLink target in AuthoringConsumptionTest2.vcxproj now just picks up the .AOT.dll from its publish folder and adds it to ReferenceCopyLocalPaths. No sub-invocation, no Restore/Publish from inside the vcxproj. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AuthoringConsumptionTest2.AOT.csproj | 33 ++++++------------- .../AuthoringConsumptionTest2.vcxproj | 15 ++++++--- src/cswinrt.slnx | 19 +++++++++++ 3 files changed, 39 insertions(+), 28 deletions(-) diff --git a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj index c3f6df6ec..17f0da9e7 100644 --- a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj +++ b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj @@ -20,33 +20,20 @@ - _AuthoringTestSkipAotPublishConfig=true - PublishAot - - - PublishAot - - - PublishAot - - - PublishAot - - - PublishAot + + + + diff --git a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj index 3c1aa9ad2..56ba44dc1 100644 --- a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj +++ b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj @@ -129,11 +129,16 @@ - + Inputs="$(NativeLibraryPublishedDllPath)" + Outputs="@(ReferenceCopyLocalPaths)"> + + diff --git a/src/cswinrt.slnx b/src/cswinrt.slnx index 5729ff62c..e56db7d7a 100644 --- a/src/cswinrt.slnx +++ b/src/cswinrt.slnx @@ -177,10 +177,29 @@ + + + + + + + + + + + + + From 211559d3ee4adf17f15856ee20906d11f3957a69 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 10 May 2026 09:28:18 -0700 Subject: [PATCH 086/105] Add explicit Platform=x64 mapping for .AOT.csproj in slnx Without , slnx defaulted .AOT.csproj to AnyCPU for Solution=Release|x64. AnyCPU propagated through its PR to AuthoringTest, which then tried to locate cswinrt.exe at _build\AnyCPU\Release\ (does not exist - cswinrt is built for x64). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/cswinrt.slnx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cswinrt.slnx b/src/cswinrt.slnx index e56db7d7a..9785ba246 100644 --- a/src/cswinrt.slnx +++ b/src/cswinrt.slnx @@ -192,6 +192,7 @@ + From 73e1cd9b54ebd4954b6abf4d72e410fe9a9ba3b5 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 10 May 2026 10:43:55 -0700 Subject: [PATCH 087/105] TreatAsLocalProperty _AuthoringTestSkipAotPublishConfig on AuthoringTest When AuthoringConsumptionTest2.AOT.csproj's ProjectReference to AuthoringTest sets _AuthoringTestSkipAotPublishConfig=true, that global property propagates through AuthoringTest's PR closure - including its PR to Projections/Windows.csproj. That gives Projections/Windows a different global-property hash than its slnx-level invocation, so MSBuild creates a SECOND project instance and runs a parallel build. Both instances write to the same bin\x64\Release\net10.0\Microsoft.Windows.SDK.NET.dll, so the assembly version embedded in AuthoringTest.dll's compile-time reference can disagree with the version .AOT.csproj's RAR resolves at link time -> NETSDK1148. Confirmed via binlog (cswinrt (13).binlog): two Windows.csproj instances, one with no special globals (Id=2095), another with _AuthoringTestSkipAotPublishConfig=true in its global property set (Id=2470). TreatAsLocalProperty on the element makes MSBuild treat the property as local within AuthoringTest's evaluation only - the gating Condition in Directory.Build.props still sees it, but it is NOT propagated as a global to AuthoringTest's ProjectReferences. Single Projections/Windows instance, no race, single SDK.NET version. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Tests/AuthoringTest/AuthoringTest.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tests/AuthoringTest/AuthoringTest.csproj b/src/Tests/AuthoringTest/AuthoringTest.csproj index 6d0747e6c..1c30c0ccd 100644 --- a/src/Tests/AuthoringTest/AuthoringTest.csproj +++ b/src/Tests/AuthoringTest/AuthoringTest.csproj @@ -1,4 +1,4 @@ - + net10.0-windows10.0.26100.1 From f083fa796a0d0bc81ca40237914703b2b7856c65 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 10 May 2026 10:51:28 -0700 Subject: [PATCH 088/105] Revert "TreatAsLocalProperty _AuthoringTestSkipAotPublishConfig on AuthoringTest" This reverts commit 73e1cd9b54ebd4954b6abf4d72e410fe9a9ba3b5. --- src/Tests/AuthoringTest/AuthoringTest.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tests/AuthoringTest/AuthoringTest.csproj b/src/Tests/AuthoringTest/AuthoringTest.csproj index 1c30c0ccd..6d0747e6c 100644 --- a/src/Tests/AuthoringTest/AuthoringTest.csproj +++ b/src/Tests/AuthoringTest/AuthoringTest.csproj @@ -1,4 +1,4 @@ - + net10.0-windows10.0.26100.1 From fb428a0c0e95439c3cddd33282676631663769b4 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 10 May 2026 10:52:04 -0700 Subject: [PATCH 089/105] Exclude Microsoft.Web.WebView2 in .AOT.csproj closure Real root cause of NETSDK1148 (from binlog cswinrt (13).binlog ResolveAssemblyReferenceUnresolvedAssemblyConflicts entry): Conflict: Microsoft.Windows.SDK.NET, Version=1.0.0.0, PublicKeyToken=null (locally built from Projections/Windows.csproj) vs Microsoft.Windows.SDK.NET, Version=10.0.17763.38, PublicKeyToken=31bf3856ad364e35 (official signed) Source of the official ref: microsoft.web.webview2/1.0.3179.45/lib_manual/net8.0-windows10.0.17763.0/ Microsoft.Web.WebView2.Core.Projection.dll WebView2.Core.Projection.dll was compiled against the official Windows SDK projection assembly. AuthoringTest's csproj has for WebView2 with ExcludeAssets='all' which excludes WebView2 from AuthoringTest's own compile, but does NOT block transitive flow (PrivateAssets default is not 'all'). When .AOT.csproj resolves AuthoringTest's transitive package graph, WebView2.Core.Projection.dll flows in, RAR cannot unify the two SDK.NET versions, NETSDK1148 fires. Add the same at the .AOT.csproj level so this csproj also excludes WebView2 from its compile/runtime closure. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AuthoringConsumptionTest2.AOT.csproj | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj index 17f0da9e7..50968a528 100644 --- a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj +++ b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj @@ -36,4 +36,21 @@ + + + + all + + + From 3622ba09288eda6c864bd7c65f5832449220bb73 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 10 May 2026 10:54:16 -0700 Subject: [PATCH 090/105] Trim verbose comments in test project files Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AuthoringConsumptionTest2.AOT.csproj | 25 +++++-------------- .../AuthoringConsumptionTest2.vcxproj | 22 ++++------------ src/cswinrt.slnx | 8 +----- 3 files changed, 12 insertions(+), 43 deletions(-) diff --git a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj index 50968a528..57d6fb143 100644 --- a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj +++ b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj @@ -19,14 +19,8 @@ - + _AuthoringTestSkipAotPublishConfig=true @@ -37,17 +31,10 @@ - + all diff --git a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj index 56ba44dc1..55a344f3d 100644 --- a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj +++ b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj @@ -94,17 +94,10 @@ TargetFramework=net10.0-windows10.0.26100.1 - + {41e2a272-150f-42f5-ad40-047aad9088a0} @@ -127,16 +120,11 @@ $(NativeLibraryProjectDirectory)bin\$(Platform)\$(Configuration)\net10.0-windows10.0.26100.1\win-$(Platform)\publish\ $(NativeLibraryPublishFolder)$(NativeLibraryProjectName).dll + - diff --git a/src/cswinrt.slnx b/src/cswinrt.slnx index 9785ba246..10eee8a3c 100644 --- a/src/cswinrt.slnx +++ b/src/cswinrt.slnx @@ -182,13 +182,7 @@ - + From 85206d33d90b8a4dee08db329df167eea9c426a3 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 10 May 2026 10:55:51 -0700 Subject: [PATCH 091/105] Trim version/PKT details from WebView2 exclusion comment Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AuthoringConsumptionTest2.AOT.csproj | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj index 57d6fb143..8b761af14 100644 --- a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj +++ b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj @@ -31,10 +31,9 @@ - + all From 07f71bb9ed254920afe621883589b59b86a857b9 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 10 May 2026 13:24:03 -0700 Subject: [PATCH 092/105] DefaultTargets=Publish on .AOT.csproj so slnx Build runs AOT publish Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AuthoringConsumptionTest2.AOT.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj index 8b761af14..e73ad1e51 100644 --- a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj +++ b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj @@ -1,4 +1,4 @@ - + net10.0-windows10.0.26100.1 From facf4017554b3361f47caee69c8abe7c94435fb7 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 10 May 2026 14:54:22 -0700 Subject: [PATCH 093/105] Chain Publish AfterTargets=Build on .AOT.csproj slnx's metaproj passes Targets='Build' to top-level projects regardless of DefaultTargets, so DefaultTargets='Publish' was ignored and ILC never ran on .AOT.csproj - confirmed via binlog. Add a target that runs Publish AfterTargets=Build so the AOT pipeline fires inside slnx-level Build. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AuthoringConsumptionTest2.AOT.csproj | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj index e73ad1e51..fae269594 100644 --- a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj +++ b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj @@ -1,4 +1,4 @@ - + net10.0-windows10.0.26100.1 @@ -39,4 +39,7 @@ + + + From 19ecd11ce0c4af98c259145d063a0d5e761b030e Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 10 May 2026 15:01:22 -0700 Subject: [PATCH 094/105] Revert "Chain Publish AfterTargets=Build on .AOT.csproj" This reverts commit facf4017554b3361f47caee69c8abe7c94435fb7. --- .../AuthoringConsumptionTest2.AOT.csproj | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj index fae269594..e73ad1e51 100644 --- a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj +++ b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj @@ -1,4 +1,4 @@ - + net10.0-windows10.0.26100.1 @@ -39,7 +39,4 @@ - - - From e91c467f6b2e15394ad42afb82ad6bc94df2de8b Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 10 May 2026 16:53:43 -0700 Subject: [PATCH 095/105] Add AuthoringTest3 and switch .AOT host to AuthoringTest2 + AuthoringTest3 AuthoringTest has a special Directory.Build.props block for Release|x64 that turns it into a self-contained AOT-publish executable (used by the single-component AOT scenario AuthoringConsumptionTest). Pulling it as a managed-only ProjectReference into the merged-AOT host required an opt-out global (_AuthoringTestSkipAotPublishConfig=true) to suppress that block, but the global propagated transitively, creating duplicate MSBuild project instances for transitive references and causing brittle build behavior locally (winmd path mismatch). Sidestep entirely: add AuthoringTest3, a plain CsWinRT component identical in shape to AuthoringTest2 (no AOT-publish block). The .AOT host now PRs AuthoringTest2 + AuthoringTest3. AuthoringTest stays untouched and continues to serve the single-component AOT test. Revert _AuthoringTestSkipAotPublishConfig gate on AuthoringTest's Directory.Build.props. Update tests/pch/manifests/vcxproj/slnx to reference AuthoringTest3 instead of AuthoringTest. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AuthoringConsumptionTest2.AOT.csproj | 11 +++---- ...AuthoringConsumptionTest2.AOT.exe.manifest | 2 +- .../AuthoringConsumptionTest2.exe.manifest | 2 +- .../AuthoringConsumptionTest2.vcxproj | 16 +++++----- src/Tests/AuthoringConsumptionTest2/pch.h | 2 +- src/Tests/AuthoringConsumptionTest2/test.cpp | 19 ++++++------ src/Tests/AuthoringTest/Directory.Build.props | 9 ++---- .../AuthoringTest3/AuthoringTest3.csproj | 18 ++++++++++++ src/Tests/AuthoringTest3/Calculator.cs | 29 +++++++++++++++++++ .../AuthoringTest3/Directory.Build.props | 9 ++++++ src/Tests/AuthoringTest3/Module.cs | 12 ++++++++ src/cswinrt.slnx | 12 ++++++-- 12 files changed, 104 insertions(+), 37 deletions(-) create mode 100644 src/Tests/AuthoringTest3/AuthoringTest3.csproj create mode 100644 src/Tests/AuthoringTest3/Calculator.cs create mode 100644 src/Tests/AuthoringTest3/Directory.Build.props create mode 100644 src/Tests/AuthoringTest3/Module.cs diff --git a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj index e73ad1e51..f3dbed438 100644 --- a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj +++ b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj @@ -16,14 +16,11 @@ Exe true true + true - - - _AuthoringTestSkipAotPublishConfig=true - + @@ -32,8 +29,8 @@ + which conflicts with our locally-built unsigned one. Exclude WebView2 from this csproj's + compile/runtime closure to avoid NETSDK1148. --> all diff --git a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.AOT.exe.manifest b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.AOT.exe.manifest index 83938fbd5..33eb96548 100644 --- a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.AOT.exe.manifest +++ b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.AOT.exe.manifest @@ -3,7 +3,7 @@ {25244ced-966e-45f2-9711-1f51e951ff89} TargetFramework=net10.0 - - {41e2a272-150f-42f5-ad40-047aad9088a0} + TargetFramework=net10.0-windows10.0.26100.1 @@ -99,8 +98,7 @@ win-\ subfolder the IsWinMDFile HintPath expects. ReferenceOutputAssembly=false drives build ordering only; cppwinrt consumes only the explicit IsWinMDFile References. --> - - {41e2a272-150f-42f5-ad40-047aad9088a0} + TargetFramework=net10.0-windows10.0.26100.1 RuntimeIdentifier=win-$(Platform) false @@ -132,8 +130,8 @@ - - ..\AuthoringTest\bin\$(_WinMDPlatform)\$(Configuration)\net10.0-windows10.0.26100.1\win-$(Platform)\AuthoringTest.winmd + + ..\AuthoringTest3\bin\$(_WinMDPlatform)\$(Configuration)\net10.0-windows10.0.26100.1\win-$(Platform)\AuthoringTest3.winmd true @@ -141,11 +139,11 @@ true - - - ..\AuthoringTest\bin\$(_WinMDPlatform)\$(Configuration)\net10.0-windows10.0.26100.1\win-$(Platform)\AuthoringTest.winmd + + ..\AuthoringTest3\bin\$(_WinMDPlatform)\$(Configuration)\net10.0-windows10.0.26100.1\win-$(Platform)\AuthoringTest3.winmd true AuthoringConsumptionTest2.AOT.dll diff --git a/src/Tests/AuthoringConsumptionTest2/pch.h b/src/Tests/AuthoringConsumptionTest2/pch.h index e156e8485..ce364f2e6 100644 --- a/src/Tests/AuthoringConsumptionTest2/pch.h +++ b/src/Tests/AuthoringConsumptionTest2/pch.h @@ -16,7 +16,7 @@ #pragma pop_macro("X64") #pragma pop_macro("X86") -#include +#include #include #include "gtest/gtest.h" diff --git a/src/Tests/AuthoringConsumptionTest2/test.cpp b/src/Tests/AuthoringConsumptionTest2/test.cpp index 658f029ca..242dfc49a 100644 --- a/src/Tests/AuthoringConsumptionTest2/test.cpp +++ b/src/Tests/AuthoringConsumptionTest2/test.cpp @@ -4,15 +4,15 @@ using namespace winrt; using namespace Windows::Foundation; using namespace Windows::Foundation::Collections; -// Activation tests across two CsWinRT components aggregated into one WinRT.Component.dll. +// Activation tests across two CsWinRT components aggregated into one merged AOT host. -TEST(MultiComponent, AuthoringTestStatics) +TEST(MultiComponent, CalculatorStatics) { - EXPECT_EQ(AuthoringTest::TestClass::GetDefaultFactor(), 1); - EXPECT_EQ(AuthoringTest::TestClass::GetDefaultNumber(), 2); + EXPECT_EQ(AuthoringTest3::Calculator::GetDefaultFactor(), 1); + EXPECT_EQ(AuthoringTest3::Calculator::GetDefaultNumber(), 2); } -TEST(MultiComponent, AuthoringTest2Greeter) +TEST(MultiComponent, GreeterMethods) { AuthoringTest2::Greeter greeter; EXPECT_EQ(greeter.Greet(L"world"), hstring(L"Hello, world!")); @@ -21,14 +21,14 @@ TEST(MultiComponent, AuthoringTest2Greeter) TEST(MultiComponent, BothComponentsActivateInOneProcess) { - AuthoringTest::TestClass first; + AuthoringTest3::Calculator first; AuthoringTest2::Greeter second; EXPECT_EQ(first.GetFactor(), 1); EXPECT_EQ(second.Add(10, 20), 30); } -// Generic instantiations from both components flow through the merged WinRT.Interop.dll. +// Generic instantiations from both components flow through the merged interop closure. // If per-component interop generation had run independently, type-map registration would // fail at publish time or these calls would fail at runtime. @@ -40,10 +40,11 @@ TEST(MultiComponent, GenericCollectionsFromBothComponents) EXPECT_EQ(numbers.GetAt(0), 1); EXPECT_EQ(numbers.GetAt(5), 13); - auto bools = AuthoringTest::TestClass::GetBools(); + AuthoringTest3::Calculator calculator; + auto bools = calculator.GetBools(); EXPECT_GT(bools.Size(), 0u); - auto uris = AuthoringTest::TestClass::GetUris(); + auto uris = calculator.GetUris(); EXPECT_GT(uris.Size(), 0u); } diff --git a/src/Tests/AuthoringTest/Directory.Build.props b/src/Tests/AuthoringTest/Directory.Build.props index 48bf510a9..296bd1cf8 100644 --- a/src/Tests/AuthoringTest/Directory.Build.props +++ b/src/Tests/AuthoringTest/Directory.Build.props @@ -12,14 +12,9 @@ In Release x64, we publish with NativeAOT to test the self-contained WinRT component mode. When we do this, we also skip bundling the activation manifest in the C++ consumer. That is only needed when the implementation .dll is not the native .dll being loaded. So by dropping - it we can also further validate that the self-contained authoring scenario works correctly. - - Consumers that pull AuthoringTest in as a managed-only ProjectReference (e.g. the merged - AOT host AuthoringConsumptionTest2.AOT.csproj) set _AuthoringTestSkipAotPublishConfig=true - to suppress this block, so AuthoringTest stays a plain CsWinRT component library instead - of an exe pulling the WindowsAppSDK runtime payload into its bin. + it we can also further validate that the self-contained authoring scenario works correctly --> - + true Shared true diff --git a/src/Tests/AuthoringTest3/AuthoringTest3.csproj b/src/Tests/AuthoringTest3/AuthoringTest3.csproj new file mode 100644 index 000000000..3de365851 --- /dev/null +++ b/src/Tests/AuthoringTest3/AuthoringTest3.csproj @@ -0,0 +1,18 @@ + + + + net10.0-windows10.0.26100.1 + x64;x86 + true + true + 10.0.18362.0 + win-x86;win-x64;win-arm64 + + + + + + + + + diff --git a/src/Tests/AuthoringTest3/Calculator.cs b/src/Tests/AuthoringTest3/Calculator.cs new file mode 100644 index 000000000..0bfb64c71 --- /dev/null +++ b/src/Tests/AuthoringTest3/Calculator.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; + +namespace AuthoringTest3; + +public sealed class Calculator +{ + public static int GetDefaultFactor() => 1; + public static int GetDefaultNumber() => 2; + + public int GetFactor() => 1; + + public int Multiply(int a, int b) => a * b; + + // Generic collection returns; exercise the merged interop's marshalling closure. + public IList GetBools() + { + return new List { true, false, true }; + } + + public IList GetUris() + { + return new List + { + new Uri("https://example.com/a"), + new Uri("https://example.com/b"), + }; + } +} diff --git a/src/Tests/AuthoringTest3/Directory.Build.props b/src/Tests/AuthoringTest3/Directory.Build.props new file mode 100644 index 000000000..6a86d69f2 --- /dev/null +++ b/src/Tests/AuthoringTest3/Directory.Build.props @@ -0,0 +1,9 @@ + + + + true + + + + + diff --git a/src/Tests/AuthoringTest3/Module.cs b/src/Tests/AuthoringTest3/Module.cs new file mode 100644 index 000000000..2a778079f --- /dev/null +++ b/src/Tests/AuthoringTest3/Module.cs @@ -0,0 +1,12 @@ +using System.Reflection; + +[assembly: global::System.Runtime.Versioning.SupportedOSPlatform("Windows")] + +namespace AuthoringTest3; + +internal class Program +{ + static void Main(string[] args) + { + } +} diff --git a/src/cswinrt.slnx b/src/cswinrt.slnx index 10eee8a3c..81a6f2d1c 100644 --- a/src/cswinrt.slnx +++ b/src/cswinrt.slnx @@ -175,7 +175,7 @@ - + @@ -184,7 +184,7 @@ - + @@ -211,6 +211,14 @@ + + + + + + + + From 4399e7d6b10130acffe3fe399f354ae1037625ec Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 10 May 2026 18:41:22 -0700 Subject: [PATCH 096/105] Expose PublishAot as CompilerVisibleProperty unconditionally AuthoringExportTypesGenerator.ShouldEmitNativeExports requires PublishAot=true to emit the unmanaged [UnmanagedCallersOnly] DllGetActivationFactory export. That property was exposed only via Microsoft.Windows.CsWinRT.Authoring.targets, which is imported only when CsWinRTComponent=true. A merged AOT host like AuthoringConsumptionTest2.AOT.csproj is NOT a component (it sets CsWinRTMergeReferencedActivationFactories=true but not CsWinRTComponent =true), so Authoring.targets isn't imported, PublishAot isn't visible to the source generator, ShouldEmitNativeExports() returns false, NativeExports.g.cs isn't generated, and the published native dll has no DllGetActivationFactory export. Activation fails at runtime with check_hresult throwing. Expose PublishAot unconditionally in the main CsWinRT.targets so the source generator sees it for both components and merged-aggregator hosts. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- nuget/Microsoft.Windows.CsWinRT.targets | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nuget/Microsoft.Windows.CsWinRT.targets b/nuget/Microsoft.Windows.CsWinRT.targets index cef8f7033..29f28e297 100644 --- a/nuget/Microsoft.Windows.CsWinRT.targets +++ b/nuget/Microsoft.Windows.CsWinRT.targets @@ -69,6 +69,10 @@ Copyright (C) Microsoft Corporation. All rights reserved. + + From a243e46bc96f672bc4f5a99e49c40622efa4551a Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 10 May 2026 20:35:51 -0700 Subject: [PATCH 097/105] Drop win-x64 subfolder from AuthoringTest2/Test3 winmd HintPath AuthoringTest2/AuthoringTest3 are plain CsWinRT components (no AOT publish block in their Directory.Build.props), so their winmd output naturally lands at bin\\\\.winmd (no RID subfolder). The old HintPath inherited the AuthoringTest pattern that expected the AOT publish RID-appended location, which fails locally where the VS build doesn't propagate RuntimeIdentifier through the PR Properties. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AuthoringConsumptionTest2.vcxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj index f7e700d6b..cf00d96d7 100644 --- a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj +++ b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj @@ -131,11 +131,11 @@ - ..\AuthoringTest3\bin\$(_WinMDPlatform)\$(Configuration)\net10.0-windows10.0.26100.1\win-$(Platform)\AuthoringTest3.winmd + ..\AuthoringTest3\bin\$(_WinMDPlatform)\$(Configuration)\net10.0-windows10.0.26100.1\AuthoringTest3.winmd true - ..\AuthoringTest2\bin\$(_WinMDPlatform)\$(Configuration)\net10.0-windows10.0.26100.1\win-$(Platform)\AuthoringTest2.winmd + ..\AuthoringTest2\bin\$(_WinMDPlatform)\$(Configuration)\net10.0-windows10.0.26100.1\AuthoringTest2.winmd true @@ -143,12 +143,12 @@ AuthoringTest2 winmds at compile time (it consumes the C++ projected types). --> - ..\AuthoringTest3\bin\$(_WinMDPlatform)\$(Configuration)\net10.0-windows10.0.26100.1\win-$(Platform)\AuthoringTest3.winmd + ..\AuthoringTest3\bin\$(_WinMDPlatform)\$(Configuration)\net10.0-windows10.0.26100.1\AuthoringTest3.winmd true AuthoringConsumptionTest2.AOT.dll - ..\AuthoringTest2\bin\$(_WinMDPlatform)\$(Configuration)\net10.0-windows10.0.26100.1\win-$(Platform)\AuthoringTest2.winmd + ..\AuthoringTest2\bin\$(_WinMDPlatform)\$(Configuration)\net10.0-windows10.0.26100.1\AuthoringTest2.winmd true AuthoringConsumptionTest2.AOT.dll From a1ad50eda2f08caf02e47ba6a7efdec2238fb962 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 10 May 2026 20:45:44 -0700 Subject: [PATCH 098/105] Hook Publish onto Build for .AOT.csproj DefaultTargets='Publish' is honored only when the project is invoked with default targets (no explicit /t:). slnx via msbuild does that, but VS solution build passes Targets='Build' explicitly, so Publish never runs locally and the AOT pipeline doesn't fire. Hook Publish AfterTargets =Build so it runs in both invocation modes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AuthoringConsumptionTest2.AOT.csproj | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj index f3dbed438..701287215 100644 --- a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj +++ b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj @@ -1,4 +1,4 @@ - + net10.0-windows10.0.26100.1 @@ -36,4 +36,8 @@ + + + From 0c0955494f7b3b32733be6c54fa6f9b2dd5b790b Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 10 May 2026 20:58:04 -0700 Subject: [PATCH 099/105] Skip WinRT.Host.dll CopyTestAssets in Release|x64 (AOT scenario) Release|x64 uses the merged AOT host, not WinRT.Host. The CopyTestAssets target tries to copy WinRT.Host.dll which isn't built in the AOT-only config. Gate the same way AuthoringConsumptionTest does. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Tests/AuthoringConsumptionTest2/Directory.Build.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tests/AuthoringConsumptionTest2/Directory.Build.targets b/src/Tests/AuthoringConsumptionTest2/Directory.Build.targets index 07d00c59d..855c176a6 100644 --- a/src/Tests/AuthoringConsumptionTest2/Directory.Build.targets +++ b/src/Tests/AuthoringConsumptionTest2/Directory.Build.targets @@ -2,7 +2,7 @@ $(MSBuildProjectDirectory)/DoNotImport_MsAppxPackageTargets.targets - CopyTestAssets;$(PrepareForRunDependsOn) + CopyTestAssets;$(PrepareForRunDependsOn) From 0a5fa4ce2b48896e5ef3473692f34d50e3c29ce4 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 10 May 2026 21:14:35 -0700 Subject: [PATCH 100/105] Root WinRT.Component assembly to prevent trimmer drop Activation crash root cause: the components' ABI.{Name}.ManagedExports. GetActivationFactory bodies use [UnsafeAccessor] to delegate to a same named type in WinRT.Component.dll (where the actual activation logic with class-name -> ServerActivationFactory lookup lives). ILC's trimmer doesn't follow that cross-assembly string-typed UnsafeAccessor reference, so it drops the methods holding the activation logic. Verified by inspecting the AOT.dll: GreeterServerActivationFactory class names survive, but the string literals 'AuthoringTest2.Greeter' and 'AuthoringTest3.Calculator' (used inside the trimmed methods) do not. DllGetActivationFactory then returns 0x80131534 (COR_E_TYPELOAD) at activation -> cppwinrt's check_hresult throws. Root the WinRT.Component assembly so all its types/methods survive. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AuthoringConsumptionTest2.AOT.csproj | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj index 701287215..25da853f5 100644 --- a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj +++ b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj @@ -36,6 +36,14 @@ + + + + + From 7affc9df511f842131ffb30914612c99c44144b4 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 10 May 2026 21:23:23 -0700 Subject: [PATCH 101/105] Revert "Root WinRT.Component assembly to prevent trimmer drop" This reverts commit 0a5fa4ce2b48896e5ef3473692f34d50e3c29ce4. --- .../AuthoringConsumptionTest2.AOT.csproj | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj index 25da853f5..701287215 100644 --- a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj +++ b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj @@ -36,14 +36,6 @@ - - - - - From d1b614bd95ba5a559ff726256fe6ba4703d346a0 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 10 May 2026 23:37:01 -0700 Subject: [PATCH 102/105] Fix TypeMapAssemblyTargetGenerator: don't emit WinRT.Projection target for component-only references The merged projection dll (WinRT.Projection.dll) is only produced when there are non-component reference projections (3rd-party libs with [WindowsRuntimeReferenceAssembly]). Components are projected into WinRT.Component.dll instead. Emitting [TypeMapAssemblyTarget("WinRT.Projection")] when only components are referenced caused WindowsRuntimeMarshallingInfo's static cctor to throw FileNotFoundException for the missing assembly, surfacing as 0x80131534 / COR_E_TYPELOAD at every WinRT activation site in merged-AOT consumers. Fix: derive hasMergedProjection from non-SDK reference assemblies only, excluding component assemblies. The combined list is still used for the per-assembly PrivateProjections entries. Also remove a stray EmitCompilerGeneratedFiles property from AuthoringConsumptionTest2.AOT.csproj. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../TypeMapAssemblyTargetGenerator.cs | 15 ++++++++++----- .../AuthoringConsumptionTest2.AOT.csproj | 1 - 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Authoring/WinRT.SourceGenerator2/TypeMapAssemblyTargetGenerator.cs b/src/Authoring/WinRT.SourceGenerator2/TypeMapAssemblyTargetGenerator.cs index 37999224c..cb0945271 100644 --- a/src/Authoring/WinRT.SourceGenerator2/TypeMapAssemblyTargetGenerator.cs +++ b/src/Authoring/WinRT.SourceGenerator2/TypeMapAssemblyTargetGenerator.cs @@ -82,12 +82,16 @@ public void Initialize(IncrementalGeneratorInitializationContext context) .Select(static (name, _) => name!) .Collect(); - // Combine all matching assembly names (reference + component) and filter out the Windows SDK ones - IncrementalValueProvider> filteredAssemblyNames = + // Collect non-Windows-SDK reference assembly names. These feed the merged projection (WinRT.Projection.dll). + IncrementalValueProvider> nonSdkReferenceAssemblyNames = referenceAssemblyNames .Where(static name => name is not null and not "Microsoft.Windows.SDK.NET" and not "Microsoft.Windows.UI.Xaml") .Select(static (name, _) => name!) - .Collect() + .Collect(); + + // Combine reference and component assembly names for the per-assembly '[TypeMapAssemblyTarget]' entries. + IncrementalValueProvider> filteredAssemblyNames = + nonSdkReferenceAssemblyNames .Combine(collectedComponentAssemblyNames) .Select(static (pair, token) => pair.Left.AddRange(pair.Right)); @@ -96,9 +100,10 @@ public void Initialize(IncrementalGeneratorInitializationContext context) filteredAssemblyNames .Select(static (names, token) => names.Sort(StringComparer.Ordinal).AsEquatableArray()); - // Whether the merged projection will be generated + // Whether the merged projection will be generated. Only non-Windows-SDK reference assemblies feed + // WinRT.Projection.dll; component assemblies are projected into WinRT.Component.dll instead. IncrementalValueProvider hasMergedProjection = - filteredAssemblyNames + nonSdkReferenceAssemblyNames .Select(static (assemblyNames, token) => !assemblyNames.IsDefaultOrEmpty); // Generate the attributes for all matching assemblies diff --git a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj index 701287215..631252928 100644 --- a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj +++ b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj @@ -16,7 +16,6 @@ Exe true true - true From 57c151501b7e60e308d41af145c4064af709a8f6 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Mon, 11 May 2026 00:09:47 -0700 Subject: [PATCH 103/105] Trim verbose comments in AuthoringConsumptionTest2.AOT.csproj Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../AuthoringConsumptionTest2.AOT.csproj | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj index 631252928..6d39f286d 100644 --- a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj +++ b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj @@ -5,11 +5,8 @@ x64 win-x64 - true - true Shared true @@ -27,16 +24,12 @@ - all - + From 4166881650c4b90746628d4415d9da8ce8a2a689 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Tue, 26 May 2026 09:37:50 -0700 Subject: [PATCH 104/105] Add CsWinRTEmitEntryPointInitializer property Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- nuget/Microsoft.Windows.CsWinRT.CsWinRTGen.targets | 6 ++++++ nuget/native/Microsoft.Windows.CsWinRT.targets | 1 + .../RunCsWinRTMergedProjectionGenerator.cs | 12 ++++++++++++ .../ProjectionGenerator.WinRTComponentSources.cs | 6 +++++- .../Generation/ProjectionGeneratorArgs.Parsing.cs | 1 + .../Generation/ProjectionGeneratorArgs.cs | 10 ++++++++++ 6 files changed, 35 insertions(+), 1 deletion(-) diff --git a/nuget/Microsoft.Windows.CsWinRT.CsWinRTGen.targets b/nuget/Microsoft.Windows.CsWinRT.CsWinRTGen.targets index 5dbdf5007..f2cff4f63 100644 --- a/nuget/Microsoft.Windows.CsWinRT.CsWinRTGen.targets +++ b/nuget/Microsoft.Windows.CsWinRT.CsWinRTGen.targets @@ -45,6 +45,11 @@ Copyright (C) Microsoft Corporation. All rights reserved. High true + + false + <_CsWinRTGeneratorInteropAssemblyName>WinRT.Interop <_CsWinRTGeneratorInteropAssemblyFileName>$(_CsWinRTGeneratorInteropAssemblyName).dll @@ -409,6 +414,7 @@ Copyright (C) Microsoft Corporation. All rights reserved. AssemblyName="WinRT.Component" CsWinRTToolsDirectory="$(CsWinRTMergedProjectionEffectiveToolsDirectory)" CsWinRTToolsArchitecture="$(CsWinRTToolsArchitecture)" + EmitEntryPointInitializer="$(CsWinRTEmitEntryPointInitializer)" StandardOutputImportance="$(CsWinRTGeneratorStandardOutputImportance)" StandardErrorImportance="$(CsWinRTGeneratorStandardErrorImportance)" LogStandardErrorAsError="$(CsWinRTGeneratorLogStandardErrorAsError)" /> diff --git a/nuget/native/Microsoft.Windows.CsWinRT.targets b/nuget/native/Microsoft.Windows.CsWinRT.targets index 843bdefdc..6fad7ca26 100644 --- a/nuget/native/Microsoft.Windows.CsWinRT.targets +++ b/nuget/native/Microsoft.Windows.CsWinRT.targets @@ -168,6 +168,7 @@ Properties consumers may set on the vcxproj: <_CsWinRTTempProjectLines Include=" <BaseIntermediateOutputPath>$(_CsWinRTTempProjectBaseIntermediateDir)</BaseIntermediateOutputPath>" /> <_CsWinRTTempProjectLines Include=" <IntermediateOutputPath>$(_CsWinRTTempProjectIntermediateConfigDir)</IntermediateOutputPath>" /> <_CsWinRTTempProjectLines Include=" <CsWinRTBuildForNativeConsumer>true</CsWinRTBuildForNativeConsumer>" /> + <_CsWinRTTempProjectLines Include=" <CsWinRTEmitEntryPointInitializer>true</CsWinRTEmitEntryPointInitializer>" /> <_CsWinRTTempProjectLines Include=" <CsWinRTGenerateInteropAssembly>true</CsWinRTGenerateInteropAssembly>" /> <_CsWinRTTempProjectLines Include=" <CsWinRTGenerateProjection>false</CsWinRTGenerateProjection>" /> <_CsWinRTTempProjectLines Include=" <EnableDefaultItems>false</EnableDefaultItems>" /> diff --git a/src/WinRT.Generator.Tasks/RunCsWinRTMergedProjectionGenerator.cs b/src/WinRT.Generator.Tasks/RunCsWinRTMergedProjectionGenerator.cs index 307304eda..15c9eb422 100644 --- a/src/WinRT.Generator.Tasks/RunCsWinRTMergedProjectionGenerator.cs +++ b/src/WinRT.Generator.Tasks/RunCsWinRTMergedProjectionGenerator.cs @@ -86,6 +86,13 @@ public sealed class RunCsWinRTMergedProjectionGenerator : ToolTask /// public bool WindowsUIXamlProjection { get; set; } + /// + /// Gets or sets whether to emit the 'ProjectionTypesInitializer' module initializer + /// (Assembly.SetEntryAssembly) into 'WinRT.Component.dll'. Only needed under JIT to + /// enable TypeMap discovery; AOT uses a separate exe-project workaround. + /// + public bool EmitEntryPointInitializer { get; set; } + /// protected override string ToolName => "cswinrtprojectiongen.exe"; @@ -208,6 +215,11 @@ protected override string GenerateResponseFileCommands() AppendResponseFileCommand(args, "--windows-ui-xaml-projection", "true"); } + if (EmitEntryPointInitializer) + { + AppendResponseFileCommand(args, "--emit-entry-point-initializer", "true"); + } + // Add any additional arguments that are not statically known foreach (ITaskItem additionalArgument in AdditionalArguments ?? []) { diff --git a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.WinRTComponentSources.cs b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.WinRTComponentSources.cs index 48e1e1ebd..027cda92b 100644 --- a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.WinRTComponentSources.cs +++ b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.WinRTComponentSources.cs @@ -39,7 +39,11 @@ private static void EmitWinRTComponentSources(ProjectionGeneratorArgs args, Proj return; } - WriteProjectionTypesInitializer(processingState); + if (args.EmitEntryPointInitializer) + { + WriteProjectionTypesInitializer(processingState); + } + WriteTypeMapAssemblyTargets(args, processingState); WriteMergedManagedExports(processingState); } diff --git a/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorArgs.Parsing.cs b/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorArgs.Parsing.cs index 7f90150ca..35c928d1c 100644 --- a/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorArgs.Parsing.cs +++ b/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorArgs.Parsing.cs @@ -82,6 +82,7 @@ public static ProjectionGeneratorArgs ParseFromResponseFile(string path, Cancell AssemblyName = GetOptionalStringArgument(argsMap, nameof(AssemblyName), "WinRT.Projection"), WindowsSdkOnly = GetOptionalBoolArgument(argsMap, nameof(WindowsSdkOnly)), WindowsUIXamlProjection = GetOptionalBoolArgument(argsMap, nameof(WindowsUIXamlProjection)), + EmitEntryPointInitializer = GetOptionalBoolArgument(argsMap, nameof(EmitEntryPointInitializer)), Token = token }; } diff --git a/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorArgs.cs b/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorArgs.cs index 2b8e4e6f2..2a1e814b7 100644 --- a/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorArgs.cs +++ b/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorArgs.cs @@ -54,6 +54,16 @@ internal sealed partial class ProjectionGeneratorArgs [CommandLineArgumentName("--windows-ui-xaml-projection")] public bool WindowsUIXamlProjection { get; init; } + /// + /// Gets whether to emit the ProjectionTypesInitializer module initializer + /// (calls Assembly.SetEntryAssembly) into WinRT.Component.dll. Only + /// needed under JIT to enable [TypeMapAssemblyTarget] discovery at the merged + /// component dll; AOT uses a separate exe-project workaround. Will become + /// unnecessary once the TypeMappingEntryAssembly MSBuild property is available. + /// + [CommandLineArgumentName("--emit-entry-point-initializer")] + public bool EmitEntryPointInitializer { get; init; } + /// Gets the token for the operation. public required CancellationToken Token { get; init; } } \ No newline at end of file From 9855558cf8745c19fa639ca89be5b38ca94b520f Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Tue, 26 May 2026 09:42:16 -0700 Subject: [PATCH 105/105] Fix comment --- nuget/Microsoft.Windows.CsWinRT.targets | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/nuget/Microsoft.Windows.CsWinRT.targets b/nuget/Microsoft.Windows.CsWinRT.targets index 29f28e297..dbdb1187f 100644 --- a/nuget/Microsoft.Windows.CsWinRT.targets +++ b/nuget/Microsoft.Windows.CsWinRT.targets @@ -69,9 +69,12 @@ Copyright (C) Microsoft Corporation. All rights reserved. - + +