diff --git a/build/AzurePipelineTemplates/CsWinRT-Build-Steps.yml b/build/AzurePipelineTemplates/CsWinRT-Build-Steps.yml
index e426c86bdd..64b692a3bb 100644
--- a/build/AzurePipelineTemplates/CsWinRT-Build-Steps.yml
+++ b/build/AzurePipelineTemplates/CsWinRT-Build-Steps.yml
@@ -244,8 +244,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: |
@@ -284,6 +282,26 @@ steps:
cswinrtprojectiongen.pdb
TargetFolder: $(StagingFolder)\net10.0\native
+ - task: CopyFiles@2
+ displayName: Stage cswinrtprojectionrefgen
+ condition: and(succeeded(), or(eq(variables['BuildPlatform'], 'x64'), eq(variables['BuildPlatform'], 'arm64')), eq(variables['BuildConfiguration'], 'release'))
+ inputs:
+ SourceFolder: $(Build.SourcesDirectory)\src\WinRT.Projection.Ref.Generator\bin\$(BuildConfiguration)\net10.0\win-$(BuildPlatform)\publish
+ Contents: |
+ cswinrtprojectionrefgen.exe
+ cswinrtprojectionrefgen.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 cac7e4ae89..adf3ba1190 100644
--- a/build/AzurePipelineTemplates/CsWinRT-BuildAndTest-Stage-OneBranch.yml
+++ b/build/AzurePipelineTemplates/CsWinRT-BuildAndTest-Stage-OneBranch.yml
@@ -72,6 +72,8 @@ jobs:
net10.0/native/cswinrtinteropgen.exe;
net10.0/native/cswinrtimplgen.exe;
net10.0/native/cswinrtprojectiongen.exe;
+ net10.0/native/cswinrtprojectionrefgen.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 b9f73b43ae..c19ab5179f 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);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);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;cswinrtprojectionrefgen_x64=$(Build.SourcesDirectory)\release_x64\net10.0\native\cswinrtprojectionrefgen.exe;cswinrtprojectionrefgen_arm64=$(Build.SourcesDirectory)\release_arm64\net10.0\native\cswinrtprojectionrefgen.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/build/AzurePipelineTemplates/CsWinRT-Test-Steps.yml b/build/AzurePipelineTemplates/CsWinRT-Test-Steps.yml
index 01a55b79f3..e9a909b82f 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(), or(eq(variables['BuildPlatform'], 'x86'), 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/Microsoft.Windows.CsWinRT.Authoring.targets b/nuget/Microsoft.Windows.CsWinRT.Authoring.targets
index d33ee6e931..728341b378 100644
--- a/nuget/Microsoft.Windows.CsWinRT.Authoring.targets
+++ b/nuget/Microsoft.Windows.CsWinRT.Authoring.targets
@@ -67,7 +67,7 @@ Copyright (C) Microsoft Corporation. All rights reserved.
-->
-
+
WinRT.Host.Shim.dll
PreserveNewest
@@ -171,6 +171,9 @@ Copyright (C) Microsoft Corporation. All rights reserved.
true
$(TargetFramework)
+
+ $(WindowsSdkPackageVersion)
@@ -293,7 +296,7 @@ Copyright (C) Microsoft Corporation. All rights reserved.
-->
-
+
true
lib\$(TargetFramework)
diff --git a/nuget/Microsoft.Windows.CsWinRT.CsWinRTGen.targets b/nuget/Microsoft.Windows.CsWinRT.CsWinRTGen.targets
index 05a56e97b7..bf683b9dff 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
@@ -352,8 +357,9 @@ Copyright (C) Microsoft Corporation. All rights reserved.
MaxDegreesOfParallelism="$(CsWinRTGeneratorMaxDegreesOfParallelism)"
LogStandardErrorAsError="$(CsWinRTGeneratorLogStandardErrorAsError)" />
-
-
+
+
WinRT.Projection
.NETCoreApp
@@ -409,6 +415,7 @@ Copyright (C) Microsoft Corporation. All rights reserved.
AssemblyName="WinRT.Component"
CsWinRTToolsDirectory="$(CsWinRTMergedProjectionEffectiveToolsDirectory)"
CsWinRTToolsArchitecture="$(CsWinRTToolsArchitecture)"
+ EmitEntryPointInitializer="$(CsWinRTEmitEntryPointInitializer)"
StandardOutputImportance="$(CsWinRTGeneratorStandardOutputImportance)"
StandardErrorImportance="$(CsWinRTGeneratorStandardErrorImportance)"
MaxDegreesOfParallelism="$(CsWinRTGeneratorMaxDegreesOfParallelism)"
diff --git a/nuget/Microsoft.Windows.CsWinRT.Embedded.targets b/nuget/Microsoft.Windows.CsWinRT.Embedded.targets
deleted file mode 100644
index ff8015f1f1..0000000000
--- 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 640a3a4b7e..0000000000
--- 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/nuget/Microsoft.Windows.CsWinRT.Native.targets b/nuget/Microsoft.Windows.CsWinRT.Native.targets
deleted file mode 100644
index 6542a26038..0000000000
--- a/nuget/Microsoft.Windows.CsWinRT.Native.targets
+++ /dev/null
@@ -1,133 +0,0 @@
-
-
-
-
- <_CsWinRTNativeConsumerIntermediateDir>$(IntDir)cswinrt\
-
-
-
-
-
-
-
- <_CsWinRTComponentProjectPaths Include="%(_ResolvedProjectReferencePaths.MSBuildSourceProjectFile)"
- Condition="'%(_ResolvedProjectReferencePaths.CsWinRTComponent)' == 'true'" />
-
-
-
-
- <_CsWinRTComponentTargetFramework>%(_ResolvedProjectReferencePaths.CsWinRTComponentTargetFramework)
- <_CsWinRTComponentTargetFramework Condition="'$(_CsWinRTComponentTargetFramework)' == ''">net10.0-windows10.0.26100.1
-
-
-
-
-
-
-
-
-
- <_CsWinRTHasComponentReferences Condition="'@(_CsWinRTComponentProjectPaths)' != ''">true
-
-
-
-
-
-
- <_CsWinRTTempProjectDir>$(_CsWinRTNativeConsumerIntermediateDir)
- <_CsWinRTTempProjectPath>$(_CsWinRTTempProjectDir)CsWinRT.NativeConsumer.csproj
-
- <_CsWinRTTempProjectTFMDir>$(_CsWinRTComponentTargetFramework)
-
-
-
-
-
- <_CsWinRTTempProjectLines Include="<Project Sdk="Microsoft.NET.Sdk">" />
- <_CsWinRTTempProjectLines Include=" <PropertyGroup>" />
- <_CsWinRTTempProjectLines Include=" <TargetFramework>$(_CsWinRTComponentTargetFramework)</TargetFramework>" />
- <_CsWinRTTempProjectLines Include=" <Platforms>x64%3Bx86%3BARM64</Platforms>" />
- <_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=" <NoWarn>$(NoWarn)%3BNETSDK1130</NoWarn>" />
- <_CsWinRTTempProjectLines Include=" </PropertyGroup>" />
- <_CsWinRTTempProjectLines Include=" <ItemGroup>" />
- <_CsWinRTTempProjectLines Include=" <ProjectReference Include="%(_CsWinRTComponentProjectPaths.Identity)" />" />
- <_CsWinRTTempProjectLines Include=" </ItemGroup>" />
- <_CsWinRTTempProjectLines Include="</Project>" />
-
-
-
-
-
-
-
-
-
-
-
- <_CsWinRTTempProjectIntermediateDir>$(_CsWinRTTempProjectDir)obj\$(Configuration)\$(_CsWinRTTempProjectTFMDir)\
-
-
-
- <_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')" />
-
-
-
-
-
-
-
diff --git a/nuget/Microsoft.Windows.CsWinRT.nuspec b/nuget/Microsoft.Windows.CsWinRT.nuspec
index 44bf5c8952..28a6113f82 100644
--- a/nuget/Microsoft.Windows.CsWinRT.nuspec
+++ b/nuget/Microsoft.Windows.CsWinRT.nuspec
@@ -24,11 +24,13 @@
-
+
+
+
-
+
@@ -37,7 +39,7 @@
-
+
+ $([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)', '..\metadata\WindowsRuntime.Internal.winmd'))
+
+
@@ -127,22 +143,6 @@ Copyright (C) Microsoft Corporation. All rights reserved.
-
-
-
- $(CsWinRTPath)lib\net10.0
- $(CsWinRTPath)runtimes\**\native
-
-
-
-
-
-
-
-
-
-
-
@@ -150,6 +150,23 @@ Copyright (C) Microsoft Corporation. All rights reserved.
+
+
+
+
+
+
+
diff --git a/nuget/native/Microsoft.Windows.CsWinRT.targets b/nuget/native/Microsoft.Windows.CsWinRT.targets
new file mode 100644
index 0000000000..6fad7ca266
--- /dev/null
+++ b/nuget/native/Microsoft.Windows.CsWinRT.targets
@@ -0,0 +1,262 @@
+
+
+
+
+ <_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)' != ''" />
+
+
+
+ <_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)' == ''">@(_CsWinRTComponentSdkPackageVersionValues->Distinct())
+
+
+
+
+ <_CsWinRTAggregatorInputs Include="@(_ResolvedProjectReferencePaths)"
+ Condition="'%(_ResolvedProjectReferencePaths.CsWinRTComponent)' == 'true'" />
+ <_CsWinRTAggregatorInputs Include="@(CsWinRTNativeComponent)" />
+ <_CsWinRTAggregatorInputs Include="$(MSBuildThisFileFullPath)" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_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>" />
+ <_CsWinRTTempProjectLines Include=" <CsWinRTEmitEntryPointInitializer>true</CsWinRTEmitEntryPointInitializer>" />
+ <_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 Condition="'@(_CsWinRTComponentProjectPaths)' != ''"
+ Include=" <ProjectReference Include="%(_CsWinRTComponentProjectPaths.Identity)" />" />
+
+ <_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)" />" />
+ <_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')" />
+ <_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')" />
+
+
+
+
+
+
+
+
+
+
+ <_CsWinRTHostDllPath>$(MSBuildThisFileDirectory)..\..\hosting\$(_CsWinRTNormalizedPlatform)\native\WinRT.Host.dll
+ <_CsWinRTHostMuiPath>$(MSBuildThisFileDirectory)..\..\hosting\$(_CsWinRTNormalizedPlatform)\native\en-US\WinRT.Host.dll.mui
+
+
+
+ <_CsWinRTHostingItemsToReplace 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 fa9f165dad..e74e375d69 100644
--- a/nuget/readme.md
+++ b/nuget/readme.md
@@ -76,6 +76,62 @@ 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. |
+| `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
+
+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/Authoring/WinRT.Host/WinRT.Host.cpp b/src/Authoring/WinRT.Host/WinRT.Host.cpp
index 82566f5995..aa738ad080 100644
--- a/src/Authoring/WinRT.Host/WinRT.Host.cpp
+++ b/src/Authoring/WinRT.Host/WinRT.Host.cpp
@@ -376,16 +376,6 @@ void GetActivationFactory(void* hstr_class_id, void** activation_factory)
init_runtime(host_module.wstring().c_str(), host_config.c_str());
- // If no explicit target assembly mapping found, probe for it by naming convention
- if (target_path.empty())
- {
- target_path = probe_for_target_assembly(host_module, class_id);
- if (target_path.empty() || !std::filesystem::exists(target_path))
- {
- winrt::throw_hresult(HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND));
- }
- }
-
// Load shim (managed portion of host) and retrieve get_activation_factory pointer
if (::get_activation_factory == nullptr)
{
@@ -395,11 +385,57 @@ void GetActivationFactory(void* hstr_class_id, void** activation_factory)
shim_path.wstring().c_str(),
L"WinRT.Host.Shim, WinRT.Host.Shim",
L"GetActivationFactory",
- L"WinRT.Host.Shim+GetActivationFactoryDelegate, WinRT.Host.Shim",
+ L"WinRT.Host.Shim+GetActivationFactoryDelegate, WinRT.Host.Shim",
nullptr,
(void**)&::get_activation_factory));
}
+ // If no explicit target assembly mapping was supplied via runtimeconfig, prefer a deployed
+ // 'WinRT.Component.dll'. This is the merged-projection / merged-activation dll produced by
+ // the aggregator's projection generator for native-consumer scenarios with one or more
+ // CsWinRT components. Its merged 'ABI.WinRT.Component.ManagedExports.GetActivationFactory'
+ // dispatches across each input component. A 'CLASS_E_CLASSNOTAVAILABLE' from the shim
+ // means the merged dll didn't aggregate that runtime class, so we fall through to the
+ // existing per-component prefix probe below. Any other failing HRESULT is fatal.
+ if (target_path.empty())
+ {
+ auto winrt_component_path = host_module;
+ winrt_component_path.replace_filename(L"WinRT.Component.dll");
+
+ if (std::filesystem::exists(winrt_component_path))
+ {
+ winrt::hstring hstr_winrt_component_path(winrt_component_path.c_str());
+ *activation_factory = nullptr;
+
+ HRESULT hr = ::get_activation_factory(
+ winrt::get_abi(hstr_winrt_component_path), hstr_class_id, activation_factory);
+
+ if (SUCCEEDED(hr))
+ {
+ return;
+ }
+
+ if (hr != CLASS_E_CLASSNOTAVAILABLE)
+ {
+ check_hostfxr_hresult(hr);
+ }
+
+ // 'WinRT.Component.dll' did not aggregate this runtime class; fall through
+ // to the existing per-component probing logic below.
+ *activation_factory = nullptr;
+ }
+ }
+
+ // If no explicit target assembly mapping found, probe for it by naming convention
+ if (target_path.empty())
+ {
+ target_path = probe_for_target_assembly(host_module, class_id);
+ if (target_path.empty() || !std::filesystem::exists(target_path))
+ {
+ winrt::throw_hresult(HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND));
+ }
+ }
+
// Load target assembly and get managed runtime class activation factory
winrt::hstring hstr_target_path(target_path.c_str());
check_hostfxr_hresult(::get_activation_factory(
diff --git a/src/Authoring/WinRT.SourceGenerator2/TypeMapAssemblyTargetGenerator.cs b/src/Authoring/WinRT.SourceGenerator2/TypeMapAssemblyTargetGenerator.cs
index 0fc02a3df8..cb09452714 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
@@ -80,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));
@@ -94,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
@@ -108,12 +115,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
diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets
index 056a8ddd2e..10c00ed6ea 100644
--- a/src/Directory.Build.targets
+++ b/src/Directory.Build.targets
@@ -21,11 +21,21 @@
+
+
+
+
+
+
+
@@ -103,7 +113,7 @@
diff --git a/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj b/src/Tests/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj
index 8d55f37bf5..d4f5a2ab0e 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
-
+
-
-
- <_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
+ ..\AuthoringTest\bin\$(_WinMDPlatform)\$(Configuration)\net10.0-windows10.0.26100.1\win-$(Platform)\AuthoringTest.winmd
true
-
+
-
-
+
+
diff --git a/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj
new file mode 100644
index 0000000000..6d39f286da
--- /dev/null
+++ b/src/Tests/AuthoringConsumptionTest2.AOT/AuthoringConsumptionTest2.AOT.csproj
@@ -0,0 +1,35 @@
+
+
+
+ net10.0-windows10.0.26100.1
+ x64
+ win-x64
+
+ true
+
+ true
+ Shared
+ true
+ Exe
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+
+
+
+
+
+
+
diff --git a/src/Tests/AuthoringConsumptionTest2.AOT/Directory.Build.props b/src/Tests/AuthoringConsumptionTest2.AOT/Directory.Build.props
new file mode 100644
index 0000000000..6a86d69f2e
--- /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 0000000000..ae24a069c0
--- /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 0000000000..33eb965487
--- /dev/null
+++ b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.AOT.exe.manifest
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
diff --git a/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.exe.manifest b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.exe.manifest
new file mode 100644
index 0000000000..e4fbe38c96
--- /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 0000000000..cf00d96d7d
--- /dev/null
+++ b/src/Tests/AuthoringConsumptionTest2/AuthoringConsumptionTest2.vcxproj
@@ -0,0 +1,247 @@
+
+
+
+
+
+
+
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ {8a4b1f2a-9c2e-4d3a-bf68-2a4f5b7c8d9e}
+ Win32Proj
+ AuthoringConsumptionTest2
+ Application
+ v143
+ v142
+ Unicode
+ <_WinMDPlatform>$(Platform)
+ <_WinMDPlatform Condition="'$(Platform)' == 'Win32'">x86
+ 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
+
+
+ TargetFramework=net10.0-windows10.0.26100.1
+
+
+ TargetFramework=net10.0-windows10.0.26100.1
+
+
+
+
+
+ TargetFramework=net10.0-windows10.0.26100.1
+ RuntimeIdentifier=win-$(Platform)
+ false
+ false
+
+
+ TargetFramework=net10.0-windows10.0.26100.1
+ RuntimeIdentifier=win-$(Platform)
+ false
+ false
+
+
+
+ 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
+
+
+
+
+
+
+
+
+
+
+ ..\AuthoringTest3\bin\$(_WinMDPlatform)\$(Configuration)\net10.0-windows10.0.26100.1\AuthoringTest3.winmd
+ true
+
+
+ ..\AuthoringTest2\bin\$(_WinMDPlatform)\$(Configuration)\net10.0-windows10.0.26100.1\AuthoringTest2.winmd
+ true
+
+
+
+
+
+ ..\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\AuthoringTest2.winmd
+ true
+ AuthoringConsumptionTest2.AOT.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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
+
+
+
+
+ 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/Tests/AuthoringConsumptionTest2/Directory.Build.targets b/src/Tests/AuthoringConsumptionTest2/Directory.Build.targets
new file mode 100644
index 0000000000..855c176a63
--- /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 0000000000..74f0916e0a
--- /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 0000000000..88b184e831
--- /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"
+ }
+ }
+}
diff --git a/src/Tests/AuthoringConsumptionTest2/packages.config b/src/Tests/AuthoringConsumptionTest2/packages.config
new file mode 100644
index 0000000000..0470fd6c7d
--- /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 0000000000..1d9f38c57d
--- /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 0000000000..ce364f2e67
--- /dev/null
+++ b/src/Tests/AuthoringConsumptionTest2/pch.h
@@ -0,0 +1,22 @@
+#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
+
+#include "gtest/gtest.h"
diff --git a/src/Tests/AuthoringConsumptionTest2/test.cpp b/src/Tests/AuthoringConsumptionTest2/test.cpp
new file mode 100644
index 0000000000..242dfc49a0
--- /dev/null
+++ b/src/Tests/AuthoringConsumptionTest2/test.cpp
@@ -0,0 +1,67 @@
+#include "pch.h"
+
+using namespace winrt;
+using namespace Windows::Foundation;
+using namespace Windows::Foundation::Collections;
+
+// Activation tests across two CsWinRT components aggregated into one merged AOT host.
+
+TEST(MultiComponent, CalculatorStatics)
+{
+ EXPECT_EQ(AuthoringTest3::Calculator::GetDefaultFactor(), 1);
+ EXPECT_EQ(AuthoringTest3::Calculator::GetDefaultNumber(), 2);
+}
+
+TEST(MultiComponent, GreeterMethods)
+{
+ AuthoringTest2::Greeter greeter;
+ EXPECT_EQ(greeter.Greet(L"world"), hstring(L"Hello, world!"));
+ EXPECT_EQ(greeter.Add(2, 3), 5);
+}
+
+TEST(MultiComponent, BothComponentsActivateInOneProcess)
+{
+ 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 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.
+
+TEST(MultiComponent, GenericCollectionsFromBothComponents)
+{
+ AuthoringTest2::Greeter greeter;
+ auto numbers = greeter.GetNumbers();
+ ASSERT_EQ(numbers.Size(), 6u);
+ EXPECT_EQ(numbers.GetAt(0), 1);
+ EXPECT_EQ(numbers.GetAt(5), 13);
+
+ AuthoringTest3::Calculator calculator;
+ auto bools = calculator.GetBools();
+ EXPECT_GT(bools.Size(), 0u);
+
+ auto uris = calculator.GetUris();
+ EXPECT_GT(uris.Size(), 0u);
+}
+
+TEST(MultiComponent, GenericMapFromComponent2)
+{
+ 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();
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/src/Tests/AuthoringTest/AuthoringTest.csproj b/src/Tests/AuthoringTest/AuthoringTest.csproj
index 5b12ed3449..debc0ac945 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
@@ -41,7 +41,10 @@
-
+
+
+ compile;runtime
+
all
diff --git a/src/Tests/AuthoringTest/Module.cs b/src/Tests/AuthoringTest/Module.cs
index 1bc22ba3d2..c909bfc470 100644
--- a/src/Tests/AuthoringTest/Module.cs
+++ b/src/Tests/AuthoringTest/Module.cs
@@ -4,22 +4,6 @@
namespace AuthoringTest;
-// CsWinRT makes use of the .NET typemap to register all the projected types.
-// As part of this, .NET uses TypeMapAssemblyTarget to discover the assemblies with the type map.
-// But this needs to be on the launching executable for it to discover them by default or use the
-// RuntimeHostConfiguration which isn't available on current builds. Due to this,
-// we manually set the entry assembly which allows .NET to discover it.
-internal static class ProjectionTypesInitializer
-{
-#pragma warning disable CA2255 // The 'ModuleInitializer' attribute should not be used in libraries
- [System.Runtime.CompilerServices.ModuleInitializer]
-#pragma warning restore CA2255 // The 'ModuleInitializer' attribute should not be used in libraries
- internal static void InitializeProjectionTypes()
- {
- Assembly.SetEntryAssembly(typeof(ProjectionTypesInitializer).Assembly);
- }
-}
-
internal class Program
{
static void Main(string[] args)
diff --git a/src/Tests/AuthoringTest2/AuthoringTest2.csproj b/src/Tests/AuthoringTest2/AuthoringTest2.csproj
new file mode 100644
index 0000000000..3de3658513
--- /dev/null
+++ b/src/Tests/AuthoringTest2/AuthoringTest2.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/AuthoringTest2/Directory.Build.props b/src/Tests/AuthoringTest2/Directory.Build.props
new file mode 100644
index 0000000000..6a86d69f2e
--- /dev/null
+++ b/src/Tests/AuthoringTest2/Directory.Build.props
@@ -0,0 +1,9 @@
+
+
+
+ true
+
+
+
+
+
diff --git a/src/Tests/AuthoringTest2/Greeter.cs b/src/Tests/AuthoringTest2/Greeter.cs
new file mode 100644
index 0000000000..2895b53c78
--- /dev/null
+++ b/src/Tests/AuthoringTest2/Greeter.cs
@@ -0,0 +1,32 @@
+using System.Collections.Generic;
+
+namespace AuthoringTest2;
+
+public sealed class Greeter
+{
+ public string Greet(string name)
+ {
+ return $"Hello, {name}!";
+ }
+
+ public int Add(int a, int b)
+ {
+ return a + b;
+ }
+
+ // Generic collection returns; exercise the merged interop's marshalling closure.
+ public IList GetNumbers()
+ {
+ return new List { 1, 2, 3, 5, 8, 13 };
+ }
+
+ public IDictionary GetCounts()
+ {
+ return new Dictionary
+ {
+ { "alpha", 1 },
+ { "beta", 2 },
+ { "gamma", 3 },
+ };
+ }
+}
diff --git a/src/Tests/AuthoringTest2/Module.cs b/src/Tests/AuthoringTest2/Module.cs
new file mode 100644
index 0000000000..56fd158d77
--- /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/Tests/AuthoringTest3/AuthoringTest3.csproj b/src/Tests/AuthoringTest3/AuthoringTest3.csproj
new file mode 100644
index 0000000000..3de3658513
--- /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 0000000000..0bfb64c716
--- /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 0000000000..6a86d69f2e
--- /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 0000000000..2a778079f1
--- /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/WinRT.Generator.Tasks/RunCsWinRTMergedProjectionGenerator.cs b/src/WinRT.Generator.Tasks/RunCsWinRTMergedProjectionGenerator.cs
index fd066319a6..ccc1b15585 100644
--- a/src/WinRT.Generator.Tasks/RunCsWinRTMergedProjectionGenerator.cs
+++ b/src/WinRT.Generator.Tasks/RunCsWinRTMergedProjectionGenerator.cs
@@ -93,6 +93,13 @@ public sealed class RunCsWinRTMergedProjectionGenerator : ToolTask
/// If not set, no debug repro will be produced.
public string? DebugReproDirectory { 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";
@@ -223,6 +230,11 @@ protected override string GenerateResponseFileCommands()
AppendResponseFileCommand(args, "--max-degrees-of-parallelism", MaxDegreesOfParallelism.ToString());
AppendResponseFileOptionalCommand(args, "--debug-repro-directory", DebugReproDirectory);
+ 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.Generate.cs b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.Generate.cs
index 58e6fba9ee..b64717ab0e 100644
--- a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.Generate.cs
+++ b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.Generate.cs
@@ -51,11 +51,17 @@ private static ProjectionGeneratorProcessingState ProcessReferences(ProjectionGe
out string outputFolder,
out HashSet projectionReferenceAssemblies,
out bool hasTypesToProject,
- out ProjectionWriterOptions writerOptions);
+ out ProjectionWriterOptions writerOptions,
+ out List componentAssemblyNames);
string[] referencesWithoutProjections = [.. args.ReferenceAssemblyPaths.Where(r => !projectionReferenceAssemblies.Contains(r))];
- return new ProjectionGeneratorProcessingState(outputFolder, referencesWithoutProjections, writerOptions, hasTypesToProject);
+ return new ProjectionGeneratorProcessingState(
+ outputFolder,
+ referencesWithoutProjections,
+ writerOptions,
+ hasTypesToProject,
+ componentAssemblyNames);
}
///
@@ -83,18 +89,21 @@ private static void GenerateSources(ProjectionGeneratorProcessingState processin
/// The projection reference assemblies which were used.
/// Whether any types were found to include in the projection.
/// The resulting writer options.
+ /// Sorted simple names of input [WindowsRuntimeComponentAssembly] references (populated only in component mode).
private static void BuildWriterOptions(
ProjectionGeneratorArgs args,
out string outputFolder,
out HashSet projectionReferenceAssemblies,
out bool hasTypesToProject,
- out ProjectionWriterOptions writerOptions)
+ out ProjectionWriterOptions writerOptions,
+ out List componentAssemblyNames)
{
args.Token.ThrowIfCancellationRequested();
outputFolder = GetTempFolder();
projectionReferenceAssemblies = [];
hasTypesToProject = false;
+ componentAssemblyNames = [];
List includes = [];
List excludes = [];
@@ -117,7 +126,7 @@ private static void BuildWriterOptions(
if (isComponentMode)
{
// Collect the names of all component assemblies from the references
- HashSet componentAssemblyNames = [];
+ HashSet componentAssemblyNameSet = [];
foreach (string refPath in args.ReferenceAssemblyPaths)
{
@@ -130,16 +139,20 @@ private static void BuildWriterOptions(
if (IsComponentAssembly(refModule) && refModule.Assembly?.Name is Utf8String name)
{
- _ = componentAssemblyNames.Add(name.Value);
+ _ = componentAssemblyNameSet.Add(name.Value);
}
}
+ // Sort for stable codegen output
+ componentAssemblyNames = [.. componentAssemblyNameSet];
+ componentAssemblyNames.Sort(StringComparer.Ordinal);
+
// Scan WinMD files matching component assembly names (e.g. 'MyComponent.winmd')
foreach (string winmdPath in args.WinMDPaths)
{
string winmdFileName = Path.GetFileNameWithoutExtension(winmdPath);
- if (!componentAssemblyNames.Contains(winmdFileName))
+ if (!componentAssemblyNameSet.Contains(winmdFileName))
{
continue;
}
diff --git a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.WinRTComponentSources.cs b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.WinRTComponentSources.cs
new file mode 100644
index 0000000000..58d13a77ab
--- /dev/null
+++ b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.WinRTComponentSources.cs
@@ -0,0 +1,304 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using AsmResolver.DotNet;
+using WindowsRuntime.ProjectionWriter.Writers;
+
+namespace WindowsRuntime.ProjectionGenerator.Generation;
+
+///
+internal partial class ProjectionGenerator
+{
+ ///
+ /// Component-mode only. Emits the supporting source files that make WinRT.Component.dll
+ /// the merged aggregator dll:
+ ///
+ /// - A module initializer that designates this assembly as the entry assembly for .NET interop type map discovery.
+ /// -
+ /// A
+ /// union covering each component plus shared infrastructure assemblies.
+ ///
+ /// -
+ /// A merged ABI.WinRT.Component.ManagedExports.GetActivationFactory that WinRT.Host.Shim reflects on.
+ ///
+ ///
+ ///
+ ///
+ /// These emissions write directly into
+ /// (the same folder cswinrt.exe targets), so they are picked up automatically by the Roslyn compile
+ /// step in .
+ ///
+ private static void EmitWinRTComponentSources(ProjectionGeneratorArgs args, ProjectionGeneratorProcessingState processingState)
+ {
+ // Only emit these files when producing 'WinRT.Component.dll'
+ if (args.AssemblyName != "WinRT.Component")
+ {
+ return;
+ }
+
+ // Nothing to merge if there are no input components. In this case, the
+ // projection generator invocation in component mode would not have produced
+ // any 'ABI.{ComponentName}.ManagedExports' types either.
+ if (processingState.ComponentAssemblyNames.Count == 0)
+ {
+ return;
+ }
+
+ if (args.EmitEntryPointInitializer)
+ {
+ WriteProjectionTypesInitializer(processingState);
+ }
+
+ WriteTypeMapAssemblyTargets(args, processingState);
+ WriteMergedManagedExports(processingState);
+ }
+
+ ///
+ /// Emits a -driven call
+ /// to in WinRT.Component.dll.
+ /// This designates WinRT.Component.dll as the entry assembly the .NET runtime uses
+ /// to root
+ /// discovery. This method is idempotent: skipped if the host has already set an entry assembly.
+ /// Per-component '.dll'-s intentionally do not emit a similar initializer. Consumers using a single
+ /// component '.dll' directly must call
+ /// themselves if they need interop type map discovery rooted there.
+ ///
+ private static void WriteProjectionTypesInitializer(ProjectionGeneratorProcessingState processingState)
+ {
+ const string source = """
+ //
+ #pragma warning disable
+
+ namespace ABI.WinRT.Component;
+
+ ///
+ /// Designates WinRT.Component.dll as the entry assembly for the hosted .NET
+ /// runtime so that [TypeMapAssemblyTarget] discovery (rooted at the entry
+ /// assembly) sees the union assembly attributes emitted on this dll.
+ ///
+ [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);
+ }
+ }
+ }
+ """;
+
+ string destinationPath = Path.Combine(processingState.SourcesFolder, "ProjectionTypesInitializer.g.cs");
+
+ File.WriteAllText(destinationPath, source);
+ }
+
+ ///
+ /// Emits the union [TypeMapAssemblyTarget] assembly attributes on
+ /// WinRT.Component.dll. The union covers each input component, the shared CsWinRT
+ /// infrastructure assemblies (WinRT.Interop, WinRT.Runtime,
+ /// WinRT.Sdk.Projection), and (when applicable) WinRT.Sdk.Xaml.Projection
+ /// and WinRT.Projection.
+ ///
+ ///
+ /// Only assemblies that will actually be deployed alongside WinRT.Component.dll are
+ /// included. The .NET runtime fails with when it tries
+ /// to enumerate a target assembly that doesn't exist, which would in turn fail the static
+ /// constructor of any type that depends on the type map (e.g. WindowsRuntimeComWrappers).
+ ///
+ private static void WriteTypeMapAssemblyTargets(ProjectionGeneratorArgs args, ProjectionGeneratorProcessingState processingState)
+ {
+ // Build the list of target assembly simple names. Order is deterministic for stable
+ // codegen output. The runtime treats the order as irrelevant for discovery.
+ List targetAssemblyNames =
+ [
+ "WinRT.Interop",
+ "WinRT.Runtime",
+ "WinRT.Sdk.Projection",
+ ];
+
+ if (args.WindowsUIXamlProjection)
+ {
+ targetAssemblyNames.Add("WinRT.Sdk.Xaml.Projection");
+ }
+
+ // 'WinRT.Projection.dll' is generated only when there are non-Windows-SDK, non-component
+ // 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))
+ {
+ targetAssemblyNames.Add("WinRT.Projection");
+ }
+
+ // Per-component targets
+ targetAssemblyNames.AddRange(processingState.ComponentAssemblyNames);
+
+ StringBuilder builder = new();
+
+ _ = builder.AppendLine("// ");
+ _ = builder.AppendLine("#pragma warning disable");
+ _ = builder.AppendLine();
+
+ // Append all interop type map entries for each target assembly we discovered
+ foreach (string targetTypeMapGroup in (ReadOnlySpan)[
+ "global::WindowsRuntime.InteropServices.WindowsRuntimeComWrappersTypeMapGroup",
+ "global::WindowsRuntime.InteropServices.WindowsRuntimeMetadataTypeMapGroup",
+ "global::WindowsRuntime.InteropServices.DynamicInterfaceCastableImplementationTypeMapGroup"])
+ {
+ foreach (string targetAssembly in targetAssemblyNames)
+ {
+ _ = builder.AppendLine($"[assembly: global::System.Runtime.InteropServices.TypeMapAssemblyTarget<{targetTypeMapGroup}>(\"{targetAssembly}\")]");
+ }
+ }
+
+ string destinationPath = Path.Combine(processingState.SourcesFolder, "TypeMapAssemblyTargets.g.cs");
+
+ File.WriteAllText(destinationPath, builder.ToString());
+ }
+
+ ///
+ /// Returns true if there is at least one non-Windows-SDK, non-component Windows Runtime
+ /// 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)
+ {
+ string[] resolverPaths = [.. args.ReferenceAssemblyPaths.Where(p => !p.EndsWith(".winmd", StringComparison.OrdinalIgnoreCase))];
+
+ PathAssemblyResolver resolver = new(resolverPaths);
+
+ foreach (string refPath in args.ReferenceAssemblyPaths)
+ {
+ if (refPath.EndsWith(".winmd", StringComparison.OrdinalIgnoreCase))
+ {
+ continue;
+ }
+
+ ModuleDefinition refModule;
+
+ try
+ {
+ refModule = ModuleDefinition.FromFile(refPath, resolver.ReaderParameters);
+ }
+ catch
+ {
+ continue;
+ }
+
+ // Skip non-projection references (only WinRT projection .dll-s are interesting)
+ if (!IsReferenceAssembly(refModule) || !IsWindowsRuntimeReferenceAssembly(refModule))
+ {
+ continue;
+ }
+
+ // Windows SDK projections ('Microsoft.Windows.SDK.NET' and 'Microsoft.Windows.UI.Xaml') go into
+ // 'WinRT.Sdk.Projection.dll' and 'WinRT.Sdk.Xaml.Projection.dll', not 'WinRT.Projection.dll'.
+ if (IsWindowsSdkAssembly(refModule))
+ {
+ continue;
+ }
+
+ // Component reference projections also don't go into 'WinRT.Projection.dll'
+ // (they are listed separately in the per-component target group above).
+ if (IsComponentAssembly(refModule))
+ {
+ continue;
+ }
+
+ // A third-party Windows Runtime reference projection, 'WinRT.Projection.dll'
+ // will be generated by '_RunCsWinRTMergedProjectionGenerator' for these.
+ return true;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Emits ABI.WinRT.Component.ManagedExports.GetActivationFactory, a merged dispatcher
+ /// that walks each per-component ABI.{ComponentName}.ManagedExports.GetActivationFactory
+ /// (already emitted by the projection generator invocation in component mode) and returns the
+ /// first non- factory.
+ ///
+ ///
+ /// This type is what WinRT.Host.Shim.GetActivationFactory reflects on when the
+ /// loaded target assembly is WinRT.Component.dll (the moduleName the shim
+ /// computes from the '.dll' filename is "WinRT.Component", so it looks up
+ /// ABI.WinRT.Component.ManagedExports).
+ ///
+ private static void WriteMergedManagedExports(ProjectionGeneratorProcessingState processingState)
+ {
+ IndentedTextWriter writer = new();
+
+ // Writes the invocations to all available components for the current type being activated
+ void WriteActivationFactoryInvocations(IndentedTextWriter writer)
+ {
+ foreach (string componentAssemblyName in processingState.ComponentAssemblyNames)
+ {
+ writer.WriteLine($$"""
+ factory = global::ABI.{{componentAssemblyName}}.ManagedExports.GetActivationFactory(activatableClassId);
+ if (factory is not null)
+ {
+ return factory;
+ }
+ """);
+ }
+ }
+
+ // Write the managed exports for 'GetActivationFactory'
+ writer.WriteLine($$"""
+ //
+ #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 if no component handles the class.
+ public static void* GetActivationFactory(global::System.ReadOnlySpan activatableClassId)
+ {
+ void* factory;
+
+ {{WriteActivationFactoryInvocations}}
+
+ return null;
+ }
+
+ ///
+ /// Reflection-friendly overload used by managed runtime hosts (e.g. WinRT.Host.Shim).
+ ///
+ /// The runtime class identifier.
+ /// A pointer to the factory, or if no component handles the class.
+ public static nint GetActivationFactory(string activatableClassId)
+ {
+ return (nint)GetActivationFactory(global::System.MemoryExtensions.AsSpan(activatableClassId));
+ }
+ }
+ """);
+
+ string destinationPath = Path.Combine(processingState.SourcesFolder, "MergedManagedExports.g.cs");
+
+ writer.FlushToFile(destinationPath);
+ }
+}
diff --git a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.cs b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.cs
index 7bb3a9ffb1..7b642cb3c5 100644
--- a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.cs
+++ b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.cs
@@ -58,6 +58,14 @@ public static void Run([Argument] string inputFilePath, CancellationToken token)
logMessage: "Generating projection code",
body: _ => GenerateSources(processingState));
+ // In component mode (i.e. producing 'WinRT.Component.dll'), emit the supporting source files
+ // alongside the projection writer's output so the merged '.dll' plays the entry-assembly and
+ // merged-activation roles (interop type map union, 'SetEntryAssembly' module init, merged
+ // 'ABI.WinRT.Component.ManagedExports.GetActivationFactory', and AOT native export).
+ runner.RunPhase(
+ phaseName: "winrt-component-sources",
+ body: args => EmitWinRTComponentSources(args, processingState));
+
// Invoke Roslyn to compile the generated sources into 'WinRT.Projection.dll'
runner.RunPhase(
phaseName: "emit",
diff --git a/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorArgs.cs b/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorArgs.cs
index e01fb8d7fa..905274ceaa 100644
--- a/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorArgs.cs
+++ b/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorArgs.cs
@@ -57,6 +57,16 @@ internal sealed class ProjectionGeneratorArgs : IGeneratorArgs
[CommandLineArgumentName("--max-degrees-of-parallelism")]
public required int MaxDegreesOfParallelism { 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; }
+
///
public required CancellationToken Token { get; init; }
diff --git a/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorProcessingState.cs b/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorProcessingState.cs
index b4c09a58bb..5e16600992 100644
--- a/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorProcessingState.cs
+++ b/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorProcessingState.cs
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
+using System.Collections.Generic;
using WindowsRuntime.ProjectionWriter;
namespace WindowsRuntime.ProjectionGenerator.Generation;
@@ -12,11 +13,13 @@ namespace WindowsRuntime.ProjectionGenerator.Generation;
/// The reference assembly paths excluding projection assemblies.
/// The options to pass to .
/// Whether any types were found to project.
+/// Sorted simple names of all input [WindowsRuntimeComponentAssembly] references (component-mode only).
internal sealed class ProjectionGeneratorProcessingState(
string sourcesFolder,
string[] referencesWithoutProjections,
ProjectionWriterOptions writerOptions,
- bool hasTypesToProject = true)
+ bool hasTypesToProject = true,
+ IReadOnlyList? componentAssemblyNames = null)
{
///
/// Gets the path to the folder where sources will be generated.
@@ -38,5 +41,12 @@ internal sealed class ProjectionGeneratorProcessingState(
/// and emit phases should be skipped (no DLL will be produced).
///
public bool HasTypesToProject { get; } = hasTypesToProject;
+
+ ///
+ /// Gets the simple names of all input assemblies marked with
+ /// [WindowsRuntimeComponentAssembly]. Empty unless this is a component-mode run
+ /// (i.e. producing WinRT.Component.dll).
+ ///
+ public IReadOnlyList ComponentAssemblyNames { get; } = componentAssemblyNames ?? [];
}
diff --git a/src/WinRT.Projection.Writer/Writers/IndentedTextWriter.AppendIfInterpolatedStringHandler.cs b/src/WinRT.Projection.Writer/Writers/IndentedTextWriter.AppendIfInterpolatedStringHandler.cs
index 5e93bff165..a3627d8eac 100644
--- a/src/WinRT.Projection.Writer/Writers/IndentedTextWriter.AppendIfInterpolatedStringHandler.cs
+++ b/src/WinRT.Projection.Writer/Writers/IndentedTextWriter.AppendIfInterpolatedStringHandler.cs
@@ -11,7 +11,7 @@
namespace WindowsRuntime.ProjectionWriter.Writers;
///
-internal partial class IndentedTextWriter
+public partial class IndentedTextWriter
{
///
/// Provides a handler used by the language compiler to conditionally append interpolated strings into instances.
diff --git a/src/WinRT.Projection.Writer/Writers/IndentedTextWriter.AppendInterpolatedStringHandler.cs b/src/WinRT.Projection.Writer/Writers/IndentedTextWriter.AppendInterpolatedStringHandler.cs
index b04ac0a3cf..cb87dbe065 100644
--- a/src/WinRT.Projection.Writer/Writers/IndentedTextWriter.AppendInterpolatedStringHandler.cs
+++ b/src/WinRT.Projection.Writer/Writers/IndentedTextWriter.AppendInterpolatedStringHandler.cs
@@ -11,7 +11,7 @@
namespace WindowsRuntime.ProjectionWriter.Writers;
///
-internal partial class IndentedTextWriter
+public partial class IndentedTextWriter
{
///
/// Provides a handler used by the language compiler to append interpolated strings into instances.
diff --git a/src/WinRT.Projection.Writer/Writers/IndentedTextWriter.cs b/src/WinRT.Projection.Writer/Writers/IndentedTextWriter.cs
index 77a8b2e16e..fe151d6fd9 100644
--- a/src/WinRT.Projection.Writer/Writers/IndentedTextWriter.cs
+++ b/src/WinRT.Projection.Writer/Writers/IndentedTextWriter.cs
@@ -30,7 +30,7 @@ namespace WindowsRuntime.ProjectionWriter.Writers;
/// indentation, so raw multi-line literals with blank lines do not gain trailing whitespace.
///
///
-internal sealed partial class IndentedTextWriter
+public sealed partial class IndentedTextWriter
{
///
/// The default indentation (4 spaces).
@@ -696,38 +696,15 @@ public void Clear()
}
///
- /// Flushes the current buffer to (skipping the write if the file
- /// already exists with identical content), then clears the buffer.
+ /// Flushes the current buffer to , then clears the buffer.
///
- ///
- /// If the destination file exists but cannot be read (e.g. due to a transient I/O failure or
- /// access denial), the catch block silently falls through to a fresh write. This is the
- /// intended behavior for a build tool: the worst case is an extra write of identical content
- /// that the OS will then re-permit; the alternative (failing the build) would create
- /// brittleness around incidental file-system noise.
- ///
/// The destination file path.
public void FlushToFile(string path)
{
string content = _buffer.ToString();
- if (File.Exists(path))
- {
- try
- {
- if (File.ReadAllText(path) == content)
- {
- _ = _buffer.Clear();
- return;
- }
- }
- catch (Exception e) when (e is IOException or UnauthorizedAccessException)
- {
- // Intentional: see -- a failed read falls through to a fresh write.
- }
- }
-
File.WriteAllText(path, content);
+
_ = _buffer.Clear();
}
diff --git a/src/WinRT.Projection.Writer/Writers/IndentedTextWriterCallback.cs b/src/WinRT.Projection.Writer/Writers/IndentedTextWriterCallback.cs
index 175abfccea..a3ed960f5e 100644
--- a/src/WinRT.Projection.Writer/Writers/IndentedTextWriterCallback.cs
+++ b/src/WinRT.Projection.Writer/Writers/IndentedTextWriterCallback.cs
@@ -19,4 +19,4 @@ namespace WindowsRuntime.ProjectionWriter.Writers;
///
///
/// The writer to emit content to at its current position and indentation level.
-internal delegate void IndentedTextWriterCallback(IndentedTextWriter writer);
+public delegate void IndentedTextWriterCallback(IndentedTextWriter writer);
diff --git a/src/WinRT.Projection.Writer/Writers/IndentedTextWriterCallbackExtensions.cs b/src/WinRT.Projection.Writer/Writers/IndentedTextWriterCallbackExtensions.cs
index df7756fdd5..31e41779ef 100644
--- a/src/WinRT.Projection.Writer/Writers/IndentedTextWriterCallbackExtensions.cs
+++ b/src/WinRT.Projection.Writer/Writers/IndentedTextWriterCallbackExtensions.cs
@@ -6,7 +6,7 @@ namespace WindowsRuntime.ProjectionWriter.Writers;
///
/// Extension methods for .
///
-internal static class IndentedTextWriterCallbackExtensions
+public static class IndentedTextWriterCallbackExtensions
{
///
/// Writes the delegate's content into a pooled at indent
diff --git a/src/WinRT.Projection.Writer/Writers/IndentedTextWriterPool.cs b/src/WinRT.Projection.Writer/Writers/IndentedTextWriterPool.cs
index 328c12f006..e081838134 100644
--- a/src/WinRT.Projection.Writer/Writers/IndentedTextWriterPool.cs
+++ b/src/WinRT.Projection.Writer/Writers/IndentedTextWriterPool.cs
@@ -29,7 +29,7 @@ namespace WindowsRuntime.ProjectionWriter.Writers;
/// parallel load the pool naturally caps at the worker-thread high-water mark.
///
///
-internal static class IndentedTextWriterPool
+public static class IndentedTextWriterPool
{
///
/// The backing pool. is the right primitive for thread-local
@@ -54,7 +54,8 @@ public static IndentedTextWriterOwner GetOrCreate()
writer.Clear();
return new IndentedTextWriterOwner(writer);
}
- return new IndentedTextWriterOwner(new IndentedTextWriter());
+
+ return new(new IndentedTextWriter());
}
///
@@ -82,7 +83,7 @@ internal static void Return(IndentedTextWriter writer)
/// property throws .
///
///
-internal ref struct IndentedTextWriterOwner : IDisposable
+public ref struct IndentedTextWriterOwner : IDisposable
{
private IndentedTextWriter? _writer;
diff --git a/src/build.cmd b/src/build.cmd
index d94c32c817..51f471e172 100644
--- a/src/build.cmd
+++ b/src/build.cmd
@@ -228,6 +228,25 @@ 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!
+ )
+)
+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
if "%run_functional_tests%" EQU "true" (
@@ -262,11 +281,12 @@ set cswinrtinteropgen_%cswinrt_platform%=%this_dir%WinRT.Interop.Generator\bin\%
set cswinrtimplgen_%cswinrt_platform%=%this_dir%WinRT.Impl.Generator\bin\%cswinrt_configuration%\net10.0\win-%cswinrt_platform%\publish\cswinrtimplgen.exe
set cswinrtprojectiongen_%cswinrt_platform%=%this_dir%WinRT.Projection.Generator\bin\%cswinrt_configuration%\net10.0\win-%cswinrt_platform%\publish\cswinrtprojectiongen.exe
set cswinrtprojectionrefgen_%cswinrt_platform%=%this_dir%WinRT.Projection.Ref.Generator\bin\%cswinrt_configuration%\net10.0\win-%cswinrt_platform%\publish\cswinrtprojectionrefgen.exe
+set cswinrtwinmdgen_%cswinrt_platform%=%this_dir%WinRT.WinMD.Generator\bin\%cswinrt_configuration%\net10.0\win-%cswinrt_platform%\publish\cswinrtwinmdgen.exe
set run_cswinrt_generator_task=%this_dir%WinRT.Generator.Tasks\bin\%cswinrt_configuration%\netstandard2.0\WinRT.Generator.Tasks.dll
rem Now call pack
echo Creating nuget package
-call :exec %nuget_dir%\nuget pack %this_dir%..\nuget\Microsoft.Windows.CsWinRT.nuspec -Properties interop_winmd=%interop_winmd%;net10_runtime=%net10_runtime%;net10_runtime_xml=%net10_runtime_xml%;source_generator=%source_generator%;cswinrt_nuget_version=%cswinrt_version_string%;winrt_host_x86=%winrt_host_x86%;winrt_host_x64=%winrt_host_x64%;winrt_host_arm=%winrt_host_arm%;winrt_host_arm64=%winrt_host_arm64%;winrt_host_resource_x86=%winrt_host_resource_x86%;winrt_host_resource_x64=%winrt_host_resource_x64%;winrt_host_resource_arm=%winrt_host_resource_arm%;winrt_host_resource_arm64=%winrt_host_resource_arm64%;winrt_shim=%winrt_shim%;cswinrtinteropgen_x64=%cswinrtinteropgen_x64%;cswinrtinteropgen_arm64=%cswinrtinteropgen_arm64%;cswinrtimplgen_x64=%cswinrtimplgen_x64%;cswinrtimplgen_arm64=%cswinrtimplgen_arm64%;cswinrtprojectiongen_x64=%cswinrtprojectiongen_x64%;cswinrtprojectiongen_arm64=%cswinrtprojectiongen_arm64%;cswinrtprojectionrefgen_x64=%cswinrtprojectionrefgen_x64%;cswinrtprojectionrefgen_arm64=%cswinrtprojectionrefgen_arm64%;run_cswinrt_generator_task=%run_cswinrt_generator_task%; -OutputDirectory %cswinrt_bin_dir% -NonInteractive -Verbosity Detailed -NoPackageAnalysis
+call :exec %nuget_dir%\nuget pack %this_dir%..\nuget\Microsoft.Windows.CsWinRT.nuspec -Properties interop_winmd=%interop_winmd%;net10_runtime=%net10_runtime%;net10_runtime_xml=%net10_runtime_xml%;source_generator=%source_generator%;cswinrt_nuget_version=%cswinrt_version_string%;winrt_host_x86=%winrt_host_x86%;winrt_host_x64=%winrt_host_x64%;winrt_host_arm=%winrt_host_arm%;winrt_host_arm64=%winrt_host_arm64%;winrt_host_resource_x86=%winrt_host_resource_x86%;winrt_host_resource_x64=%winrt_host_resource_x64%;winrt_host_resource_arm=%winrt_host_resource_arm%;winrt_host_resource_arm64=%winrt_host_resource_arm64%;winrt_shim=%winrt_shim%;cswinrtinteropgen_x64=%cswinrtinteropgen_x64%;cswinrtinteropgen_arm64=%cswinrtinteropgen_arm64%;cswinrtimplgen_x64=%cswinrtimplgen_x64%;cswinrtimplgen_arm64=%cswinrtimplgen_arm64%;cswinrtprojectiongen_x64=%cswinrtprojectiongen_x64%;cswinrtprojectiongen_arm64=%cswinrtprojectiongen_arm64%;cswinrtprojectionrefgen_x64=%cswinrtprojectionrefgen_x64%;cswinrtprojectionrefgen_arm64=%cswinrtprojectionrefgen_arm64%;cswinrtwinmdgen_x64=%cswinrtwinmdgen_x64%;cswinrtwinmdgen_arm64=%cswinrtwinmdgen_arm64%;run_cswinrt_generator_task=%run_cswinrt_generator_task%; -OutputDirectory %cswinrt_bin_dir% -NonInteractive -Verbosity Detailed -NoPackageAnalysis
goto :eof
:exec
diff --git a/src/cswinrt.slnx b/src/cswinrt.slnx
index 08bde562fe..27e04f3c4e 100644
--- a/src/cswinrt.slnx
+++ b/src/cswinrt.slnx
@@ -77,10 +77,9 @@
+
-
-
@@ -183,6 +182,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -191,6 +211,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+