diff --git a/build/AzurePipelineTemplates/CsWinRT-Build-Steps.yml b/build/AzurePipelineTemplates/CsWinRT-Build-Steps.yml
index 17314a9c01..dca90bf22d 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 12dcc49074..1722e98bf6 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 22fe1c4931..c2c5b3c943 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/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 0dd2544db8..1d416861cb 100644
--- a/nuget/Microsoft.Windows.CsWinRT.Authoring.targets
+++ b/nuget/Microsoft.Windows.CsWinRT.Authoring.targets
@@ -68,7 +68,7 @@ Copyright (C) Microsoft Corporation. All rights reserved.
-->
-
+
WinRT.Host.Shim.dll
PreserveNewest
@@ -172,6 +172,9 @@ Copyright (C) Microsoft Corporation. All rights reserved.
true
$(TargetFramework)
+
+ $(WindowsSdkPackageVersion)
@@ -294,7 +297,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 2dfc975f16..f2cff4f636 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
@@ -350,8 +355,9 @@ Copyright (C) Microsoft Corporation. All rights reserved.
StandardErrorImportance="$(CsWinRTGeneratorStandardErrorImportance)"
LogStandardErrorAsError="$(CsWinRTGeneratorLogStandardErrorAsError)" />
-
-
+
+
WinRT.Projection
.NETCoreApp
@@ -408,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/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 1b9f18d74a..738ef0f911 100644
--- a/nuget/Microsoft.Windows.CsWinRT.nuspec
+++ b/nuget/Microsoft.Windows.CsWinRT.nuspec
@@ -25,10 +25,12 @@
-
+
+
+
-
+
@@ -37,7 +39,7 @@
-
+
+ $([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)', '..\metadata\WindowsRuntime.Internal.winmd'))
+
+
@@ -128,22 +144,6 @@ Copyright (C) Microsoft Corporation. All rights reserved.
-
-
-
- $(CsWinRTPath)lib\net10.0
- $(CsWinRTPath)runtimes\**\native
-
-
-
-
-
-
-
-
-
-
-
@@ -151,6 +151,23 @@ Copyright (C) Microsoft Corporation. All rights reserved.
+
+
+
+
+
+
+
@@ -267,7 +284,6 @@ Copyright (C) Microsoft Corporation. All rights reserved.
@(CsWinRTIncludeItems->'-include %(Identity)', '
')
- $([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)', '..\metadata\WindowsRuntime.Internal.winmd'))
-input $(CsWinRTInteropMetadata)
-include WindowsRuntime.Internal
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 392c45f1af..094a256562 100644
--- a/nuget/readme.md
+++ b/nuget/readme.md
@@ -84,6 +84,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..5a10c6a6d5 100644
--- a/src/Directory.Build.targets
+++ b/src/Directory.Build.targets
@@ -21,9 +21,13 @@
+
+
+
@@ -103,7 +107,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 24afdfea4b..7a5f332d59 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 307304eda4..15c9eb4224 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.Generate.cs b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.Generate.cs
index ca9c572266..960098b3cd 100644
--- a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.Generate.cs
+++ b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.Generate.cs
@@ -45,11 +45,22 @@ private static ProjectionGeneratorProcessingState ProcessReferences(ProjectionGe
{
args.Token.ThrowIfCancellationRequested();
- GenerateRspFile(args, out string outputFolder, out string rspFile, out HashSet projectionReferenceAssemblies, out bool hasTypesToProject);
+ GenerateRspFile(
+ args,
+ out string outputFolder,
+ out string rspFile,
+ out HashSet projectionReferenceAssemblies,
+ out bool hasTypesToProject,
+ out List componentAssemblyNames);
string[] referencesWithoutProjections = [.. args.ReferenceAssemblyPaths.Where(r => !projectionReferenceAssemblies.Contains(r))];
- return new ProjectionGeneratorProcessingState(outputFolder, rspFile, referencesWithoutProjections, hasTypesToProject);
+ return new ProjectionGeneratorProcessingState(
+ outputFolder,
+ rspFile,
+ referencesWithoutProjections,
+ hasTypesToProject,
+ componentAssemblyNames);
}
///
@@ -111,12 +122,14 @@ private static void GenerateSources(ProjectionGeneratorArgs args, ProjectionGene
/// The generated response file for running cswinrt.exe.
/// The projection reference assemblies which were used to generate the response file.
/// Whether any types were found to include in the projection.
+ /// Sorted simple names of input [WindowsRuntimeComponentAssembly] references (populated only in component mode).
private static void GenerateRspFile(
ProjectionGeneratorArgs args,
out string outputFolder,
out string rspFile,
out HashSet projectionReferenceAssemblies,
- out bool hasTypesToProject)
+ out bool hasTypesToProject,
+ out List componentAssemblyNames)
{
args.Token.ThrowIfCancellationRequested();
@@ -124,6 +137,7 @@ private static void GenerateRspFile(
rspFile = Path.Combine(outputFolder, "ProjectionGenerator.rsp");
projectionReferenceAssemblies = [];
hasTypesToProject = false;
+ componentAssemblyNames = [];
using StreamWriter fileStream = new(rspFile);
@@ -144,7 +158,7 @@ private static void GenerateRspFile(
if (isComponentMode)
{
// Collect the names of all component assemblies from the references
- HashSet componentAssemblyNames = [];
+ HashSet componentAssemblyNameSet = [];
foreach (string refPath in args.ReferenceAssemblyPaths)
{
@@ -157,16 +171,20 @@ private static void GenerateRspFile(
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;
}
@@ -254,6 +272,8 @@ private static void GenerateRspFile(
if (isWindowsSdkMode && projectionReferenceAssemblies.Count == 0)
{
WriteWindowsSdkFilters(fileStream, args.WindowsUIXamlProjection);
+
+ hasTypesToProject = true;
}
// If we're not in Windows SDK mode, we exclude the Windows namespace to avoid
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..027cda92b6
--- /dev/null
+++ b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.WinRTComponentSources.cs
@@ -0,0 +1,282 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.IO;
+using System.Text;
+using AsmResolver.DotNet;
+
+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) 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, and (c) a merged
+ /// ABI.WinRT.Component.ManagedExports.GetActivationFactory that the
+ /// 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. cswinrt.exe -component 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 [ModuleInitializer]-driven SetEntryAssembly in WinRT.Component.dll.
+ /// This designates WinRT.Component.dll as the entry assembly the .NET runtime uses
+ /// 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)
+ {
+ 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);
+ }
+ }
+ }
+ """;
+
+ File.WriteAllText(Path.Combine(processingState.SourcesFolder, "ProjectionTypesInitializer.g.cs"), 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.
+ System.Collections.Generic.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 sb = new();
+ _ = sb.AppendLine("// ");
+ _ = sb.AppendLine("#pragma warning disable");
+ _ = sb.AppendLine();
+
+ foreach (string targetTypeMapGroup in (string[])
+ [
+ "global::WindowsRuntime.InteropServices.WindowsRuntimeComWrappersTypeMapGroup",
+ "global::WindowsRuntime.InteropServices.WindowsRuntimeMetadataTypeMapGroup",
+ "global::WindowsRuntime.InteropServices.DynamicInterfaceCastableImplementationTypeMapGroup",
+ ])
+ {
+ foreach (string targetAssembly in targetAssemblyNames)
+ {
+ _ = sb.AppendLine($"[assembly: global::System.Runtime.InteropServices.TypeMapAssemblyTarget<{targetTypeMapGroup}>(\"{targetAssembly}\")]");
+ }
+
+ _ = sb.AppendLine();
+ }
+
+ File.WriteAllText(Path.Combine(processingState.SourcesFolder, "TypeMapAssemblyTargets.g.cs"), sb.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 = [.. System.Linq.Enumerable.Where(args.ReferenceAssemblyPaths,
+ 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 / Microsoft.Windows.UI.Xaml)
+ // go into 'WinRT.Sdk.Projection.dll' / '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 cswinrt.exe in -component mode) and returns the first
+ /// non-null 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)
+ {
+ StringBuilder dispatchCases = new();
+
+ foreach (string componentAssemblyName in processingState.ComponentAssemblyNames)
+ {
+ _ = dispatchCases.AppendLine($$"""
+
+ factory = global::ABI.{{componentAssemblyName}}.ManagedExports.GetActivationFactory(activatableClassId);
+ if (factory is not null)
+ {
+ return factory;
+ }
+ """);
+ }
+
+ 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);
+ }
+}
diff --git a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.cs b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.cs
index 2119605ee2..7ec3baff8e 100644
--- a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.cs
+++ b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.cs
@@ -80,6 +80,21 @@ public static void Run([Argument] string responseFilePath, CancellationToken tok
args.Token.ThrowIfCancellationRequested();
+ // 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
+ {
+ EmitWinRTComponentSources(args, processingState);
+ }
+ catch (Exception e) when (!e.IsWellKnown)
+ {
+ throw new UnhandledProjectionGeneratorException("winrt-component-sources", e);
+ }
+
+ args.Token.ThrowIfCancellationRequested();
+
// Invoke Roslyn to compile the generated sources into 'WinRT.Projection.dll'
try
{
diff --git a/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorArgs.Parsing.cs b/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorArgs.Parsing.cs
index 7f90150ca2..35c928d1c3 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 2b8e4e6f2b..2a1e814b7b 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
diff --git a/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorProcessingState.cs b/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorProcessingState.cs
index 6d570ac04f..3422657346 100644
--- a/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorProcessingState.cs
+++ b/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorProcessingState.cs
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
+using System.Collections.Generic;
+
namespace WindowsRuntime.ProjectionGenerator.Generation;
///
@@ -10,7 +12,13 @@ namespace WindowsRuntime.ProjectionGenerator.Generation;
/// The path to the generated response file for CsWinRT.
/// The reference assembly paths excluding projection assemblies.
/// Whether any types were found to project.
-internal sealed class ProjectionGeneratorProcessingState(string sourcesFolder, string rspFilePath, string[] referencesWithoutProjections, bool hasTypesToProject = true)
+/// Sorted simple names of all input [WindowsRuntimeComponentAssembly] references (component-mode only).
+internal sealed class ProjectionGeneratorProcessingState(
+ string sourcesFolder,
+ string rspFilePath,
+ string[] referencesWithoutProjections,
+ bool hasTypesToProject = true,
+ IReadOnlyList? componentAssemblyNames = null)
{
///
/// Gets the path to the folder where sources will be generated.
@@ -32,4 +40,11 @@ internal sealed class ProjectionGeneratorProcessingState(string sourcesFolder, s
/// 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/build.cmd b/src/build.cmd
index 35d7b9ad16..d61ac8ccd8 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 winrt_shim=%this_dir%Authoring\WinRT.Host.Shim\bin\%cswinrt_configuration%\n
set cswinrtinteropgen_%cswinrt_platform%=%this_dir%WinRT.Interop.Generator\bin\%cswinrt_configuration%\net10.0\win-%cswinrt_platform%\publish\cswinrtinteropgen.exe
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 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 cswinrt_exe=%cswinrt_exe%;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%;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 cswinrt_exe=%cswinrt_exe%;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%;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 8c2dc47d6d..81a6f2d1c1 100644
--- a/src/cswinrt.slnx
+++ b/src/cswinrt.slnx
@@ -79,9 +79,8 @@
+
-
-
@@ -175,6 +174,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -183,6 +203,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+