From c5d389a76b2d8b53450b6637e171bdd6c512b390 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Jun 2026 12:20:59 -0700 Subject: [PATCH 01/42] Add isolated infrastructure for end-to-end smoke tests Adds blank Directory.Build.props/.targets and a Directory.Packages.props that disables central package management, so the smoke tests can consume the real CsWinRT NuGet package in full isolation from the repository build infrastructure. A .gitignore keeps their default bin/obj output out of source control. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Tests/SmokeTests/.gitignore | 5 +++++ src/Tests/SmokeTests/Directory.Build.props | 13 +++++++++++++ src/Tests/SmokeTests/Directory.Build.targets | 11 +++++++++++ src/Tests/SmokeTests/Directory.Packages.props | 15 +++++++++++++++ 4 files changed, 44 insertions(+) create mode 100644 src/Tests/SmokeTests/.gitignore create mode 100644 src/Tests/SmokeTests/Directory.Build.props create mode 100644 src/Tests/SmokeTests/Directory.Build.targets create mode 100644 src/Tests/SmokeTests/Directory.Packages.props diff --git a/src/Tests/SmokeTests/.gitignore b/src/Tests/SmokeTests/.gitignore new file mode 100644 index 000000000..3f4be6546 --- /dev/null +++ b/src/Tests/SmokeTests/.gitignore @@ -0,0 +1,5 @@ +# The smoke tests are isolated from the repository build infrastructure and use the default +# project-relative build output folders (rather than the repo's '_build' output), so ignore +# them here to keep build artifacts out of source control. +bin/ +obj/ diff --git a/src/Tests/SmokeTests/Directory.Build.props b/src/Tests/SmokeTests/Directory.Build.props new file mode 100644 index 000000000..f9c13339f --- /dev/null +++ b/src/Tests/SmokeTests/Directory.Build.props @@ -0,0 +1,13 @@ + + + + + diff --git a/src/Tests/SmokeTests/Directory.Build.targets b/src/Tests/SmokeTests/Directory.Build.targets new file mode 100644 index 000000000..2f904f902 --- /dev/null +++ b/src/Tests/SmokeTests/Directory.Build.targets @@ -0,0 +1,11 @@ + + + + + diff --git a/src/Tests/SmokeTests/Directory.Packages.props b/src/Tests/SmokeTests/Directory.Packages.props new file mode 100644 index 000000000..813a33d8f --- /dev/null +++ b/src/Tests/SmokeTests/Directory.Packages.props @@ -0,0 +1,15 @@ + + + + + + false + + + From 4fdad947e165bea8ad428adbe523cc62a1df508e Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Jun 2026 12:21:06 -0700 Subject: [PATCH 02/42] Add consumption end-to-end smoke test A .NET app that parses a JSON object from Windows.Data.Json and round-trips it via Stringify, exercising the Windows SDK projection, the interop generator, and the WinRT.Runtime ref/impl assemblies against the real NuGet package. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../SmokeTests/Consumption/Consumption.csproj | 53 +++++++++++++++++++ src/Tests/SmokeTests/Consumption/Program.cs | 16 ++++++ 2 files changed, 69 insertions(+) create mode 100644 src/Tests/SmokeTests/Consumption/Consumption.csproj create mode 100644 src/Tests/SmokeTests/Consumption/Program.cs diff --git a/src/Tests/SmokeTests/Consumption/Consumption.csproj b/src/Tests/SmokeTests/Consumption/Consumption.csproj new file mode 100644 index 000000000..3a939963a --- /dev/null +++ b/src/Tests/SmokeTests/Consumption/Consumption.csproj @@ -0,0 +1,53 @@ + + + + + + Exe + + + net10.0-windows10.0.26100.1 + 10.0.17763.0 + 10.0.26100.85-preview + + + + + 0.0.0-private.0 + $([MSBuild]::NormalizeDirectory('$(MSBuildThisFileDirectory)', '..', '..', '..', '_build', 'x64', 'Release', 'cswinrt', 'bin')) + + + https://api.nuget.org/v3/index.json + + + $(CsWinRTPackageSource);$(PublicNuGetSource) + + + + + + + diff --git a/src/Tests/SmokeTests/Consumption/Program.cs b/src/Tests/SmokeTests/Consumption/Program.cs new file mode 100644 index 000000000..038ec9ce1 --- /dev/null +++ b/src/Tests/SmokeTests/Consumption/Program.cs @@ -0,0 +1,16 @@ +using System; +using Windows.Data.Json; + +// Parse a JSON object from a string literal (a static projected method that also creates +// an RCW), then round-trip it back to a string with Stringify (an instance projected +// method). This exercises the generated Windows SDK projection and interop assemblies, and +// the WinRT.Runtime ref/impl assemblies, end-to-end against the real NuGet package. +JsonObject json = JsonObject.Parse("""{ "a": 42 }"""); + +string stringified = json.Stringify(); + +Console.WriteLine($"Round-tripped JSON: {stringified}"); + +// A successful round-trip must preserve the original value. Returning a non-zero exit code +// (or throwing) signals failure to the smoke test runner. +return stringified.Contains("42") ? 0 : 1; From 7feaf7044e7adb99fbb14ac99b142d2ad4c3291c Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Jun 2026 12:21:16 -0700 Subject: [PATCH 03/42] Add authoring end-to-end smoke test A Windows Runtime component library exposing a minimal class, exercising WinMD generation, the reference projection, and the forwarder assembly against the real NuGet package. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../SmokeTests/Authoring/Authoring.csproj | 54 +++++++++++++++++++ src/Tests/SmokeTests/Authoring/Greeter.cs | 19 +++++++ 2 files changed, 73 insertions(+) create mode 100644 src/Tests/SmokeTests/Authoring/Authoring.csproj create mode 100644 src/Tests/SmokeTests/Authoring/Greeter.cs diff --git a/src/Tests/SmokeTests/Authoring/Authoring.csproj b/src/Tests/SmokeTests/Authoring/Authoring.csproj new file mode 100644 index 000000000..61fd7c44a --- /dev/null +++ b/src/Tests/SmokeTests/Authoring/Authoring.csproj @@ -0,0 +1,54 @@ + + + + + + + net10.0-windows10.0.26100.1 + 10.0.17763.0 + 10.0.26100.85-preview + + + true + + + + + 0.0.0-private.0 + $([MSBuild]::NormalizeDirectory('$(MSBuildThisFileDirectory)', '..', '..', '..', '_build', 'x64', 'Release', 'cswinrt', 'bin')) + + + https://api.nuget.org/v3/index.json + + + $(CsWinRTPackageSource);$(PublicNuGetSource) + + + + + + + diff --git a/src/Tests/SmokeTests/Authoring/Greeter.cs b/src/Tests/SmokeTests/Authoring/Greeter.cs new file mode 100644 index 000000000..f1f8b0ae0 --- /dev/null +++ b/src/Tests/SmokeTests/Authoring/Greeter.cs @@ -0,0 +1,19 @@ +namespace Authoring; + +/// +/// A minimal Windows Runtime class used to smoke-test the C#/WinRT authoring pipeline +/// (WinMD generation, the reference projection, and the forwarder assembly) against the +/// real NuGet package. +/// +public sealed class Greeter +{ + /// + /// Returns a greeting for the given name. + /// + /// The name to greet. + /// A greeting message. + public string Greet(string name) + { + return $"Hello, {name}!"; + } +} From 2e00052cb7d182f7a2a8c5dfa68a3a9dd362dc23 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Jun 2026 12:21:29 -0700 Subject: [PATCH 04/42] Build and run smoke tests in local and CI builds Adds a runner that builds and runs the consumption test and builds the authoring test against a given package source and version, and wires it into build.cmd (after the pack step, on x64) and the PublishToNuGet CI steps (after packing). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../CsWinRT-PublishToNuGet-Steps.yml | 19 ++++ src/Tests/SmokeTests/run-smoke-tests.ps1 | 96 +++++++++++++++++++ src/build.cmd | 17 ++++ 3 files changed, 132 insertions(+) create mode 100644 src/Tests/SmokeTests/run-smoke-tests.ps1 diff --git a/build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml b/build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml index 4fb62c648..d4b648a94 100644 --- a/build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml +++ b/build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml @@ -124,6 +124,25 @@ steps: commit=$(Build.SourceVersion)" packDestination: $(ob_outputDirectory)\packages + # Build and run the end-to-end smoke tests against the freshly packed NuGet package. These + # verify that the real package (ref/lib assemblies, generators, and build targets) works for + # a consuming app and a component author, fully isolated from the repo build infrastructure. + # The smoke tests restore the package being tested from the packed output above, and all other + # dependencies (notably the preview Windows SDK ref pack) from public NuGet. + - task: UseDotNet@2 + displayName: Use .NET SDK for smoke tests + inputs: + packageType: sdk + version: $(_DotnetVersion) + + - task: PowerShell@2 + displayName: Run smoke tests + inputs: + targetType: filePath + filePath: $(Build.SourcesDirectory)\src\Tests\SmokeTests\run-smoke-tests.ps1 + arguments: -PackageSource "$(ob_outputDirectory)\packages" -PackageVersion "$(NugetVersion)" + workingDirectory: $(Build.SourcesDirectory) + - ${{ if eq(parameters.IsGitHub, false) }}: # NuGet signing diff --git a/src/Tests/SmokeTests/run-smoke-tests.ps1 b/src/Tests/SmokeTests/run-smoke-tests.ps1 new file mode 100644 index 000000000..c340e9414 --- /dev/null +++ b/src/Tests/SmokeTests/run-smoke-tests.ps1 @@ -0,0 +1,96 @@ +#!/usr/bin/env pwsh + +<# +.SYNOPSIS + Builds and runs the C#/WinRT end-to-end smoke tests against a real + 'Microsoft.Windows.CsWinRT' NuGet package. + +.DESCRIPTION + These smoke tests verify that the real NuGet package works for the two main consumer + scenarios, in isolation from the CsWinRT repository build infrastructure: + + * Consumption: a .NET app that uses a Windows SDK projection ('Windows.Data.Json') is + built and run, validating that the generated projection and interop assemblies, and + the 'WinRT.Runtime' ref/impl assemblies, are wired up correctly. + + * Authoring: a Windows Runtime component library is built, validating WinMD + generation, the reference projection, and the forwarder assembly. + + The smoke tests reference the package via 'RestoreSources' (see the '.csproj' files), so + no global NuGet configuration changes are required. + +.PARAMETER PackageSource + Folder containing the built 'Microsoft.Windows.CsWinRT' NuGet package. + +.PARAMETER PackageVersion + Version of the 'Microsoft.Windows.CsWinRT' package to consume. + +.PARAMETER Configuration + Build configuration to use (defaults to 'Release'). + +.EXAMPLE + ./run-smoke-tests.ps1 -PackageSource ../../_build/x64/Release/cswinrt/bin -PackageVersion 0.0.0-private.0 +#> + +[CmdletBinding()] +param ( + [Parameter(Mandatory = $true)] + [string] $PackageSource, + + [Parameter(Mandatory = $true)] + [string] $PackageVersion, + + [string] $Configuration = 'Release' +) + +$ErrorActionPreference = 'Stop' + +$smokeTestsRoot = $PSScriptRoot +$consumptionProject = [IO.Path]::Combine($smokeTestsRoot, 'Consumption', 'Consumption.csproj') +$authoringProject = [IO.Path]::Combine($smokeTestsRoot, 'Authoring', 'Authoring.csproj') + +# Resolve the package source to an absolute path (NuGet rejects relative '--source' values). +$resolvedPackageSource = (Resolve-Path -Path $PackageSource).Path + +Write-Host "Smoke tests: consuming CsWinRT package '$PackageVersion' from '$resolvedPackageSource'" -ForegroundColor Cyan + +$commonBuildArgs = @( + '--configuration', $Configuration + "-p:CsWinRTPackageSource=$resolvedPackageSource" + "-p:CsWinRTPackageVersion=$PackageVersion" +) + +function Invoke-Dotnet { + param ([string[]] $Arguments) + + Write-Host "> dotnet $($Arguments -join ' ')" -ForegroundColor DarkGray + & dotnet @Arguments + if ($LASTEXITCODE -ne 0) { + throw "Command 'dotnet $($Arguments -join ' ')' failed with exit code $LASTEXITCODE." + } +} + +# ---- Consumption: build and run (must not crash) ---- +Write-Host "`n=== Consumption smoke test ===" -ForegroundColor Green +Invoke-Dotnet (@('build', $consumptionProject) + $commonBuildArgs) + +# Locate and run the freshly built app, asserting a clean (zero) exit code. +$consumptionExe = Get-ChildItem -Path ([IO.Path]::Combine($smokeTestsRoot, 'Consumption', 'bin')) -Filter 'Consumption.exe' -Recurse | + Sort-Object LastWriteTime -Descending | + Select-Object -First 1 + +if ($null -eq $consumptionExe) { + throw "Could not find the built 'Consumption.exe'." +} + +Write-Host "Running '$($consumptionExe.FullName)'" -ForegroundColor DarkGray +& $consumptionExe.FullName +if ($LASTEXITCODE -ne 0) { + throw "Consumption smoke test crashed or failed with exit code $LASTEXITCODE." +} + +# ---- Authoring: build only ---- +Write-Host "`n=== Authoring smoke test ===" -ForegroundColor Green +Invoke-Dotnet (@('build', $authoringProject) + $commonBuildArgs) + +Write-Host "`nAll smoke tests passed." -ForegroundColor Green diff --git a/src/build.cmd b/src/build.cmd index ab4c18a5e..e8a5f892d 100644 --- a/src/build.cmd +++ b/src/build.cmd @@ -314,6 +314,23 @@ set run_cswinrt_generator_task=%this_dir%WinRT.Generator.Tasks\bin\%cswinrt_conf 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_ref=%net10_runtime_ref%;net10_runtime_ref_xml=%net10_runtime_ref_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 + +:smoketest +rem Build and run the end-to-end smoke tests against the just-built NuGet package. These +rem verify that the real package (ref/lib assemblies, generators, and build targets) works +rem for a consuming app and a component author, fully isolated from the repo build +rem infrastructure. They run only on x64 (matching the native build tools packaged for the +rem host architecture) and can be skipped by setting 'cswinrt_run_smoke_tests=false'. +if /I not "%cswinrt_platform%"=="x64" goto :eof +if /I "%cswinrt_run_smoke_tests%"=="false" goto :eof + +echo Running smoke tests for %cswinrt_platform% %cswinrt_configuration% +call :exec powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%this_dir%Tests\SmokeTests\run-smoke-tests.ps1" -PackageSource "%cswinrt_bin_dir%" -PackageVersion %cswinrt_version_string% -Configuration %cswinrt_configuration% +if ErrorLevel 1 ( + echo. + echo ERROR: Smoke tests failed + exit /b !ErrorLevel! +) goto :eof :exec From 06ce13f19e798d18acb6a17743cd4807dc0ab949 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Jun 2026 13:40:39 -0700 Subject: [PATCH 05/42] Verify the authoring smoke test produces a .winmd defining the expected type After building the component, the runner now locates the generated Authoring.winmd and asserts it is a Windows Runtime metadata file that defines the Authoring.Greeter type, using a dependency-free inspection that works in any PowerShell host. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Tests/SmokeTests/run-smoke-tests.ps1 | 40 +++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/Tests/SmokeTests/run-smoke-tests.ps1 b/src/Tests/SmokeTests/run-smoke-tests.ps1 index c340e9414..0f20a2deb 100644 --- a/src/Tests/SmokeTests/run-smoke-tests.ps1 +++ b/src/Tests/SmokeTests/run-smoke-tests.ps1 @@ -70,6 +70,32 @@ function Invoke-Dotnet { } } +function Assert-WinMDDefinesType { + param ( + [Parameter(Mandatory = $true)] [string] $Path, + [Parameter(Mandatory = $true)] [string] $Namespace, + [Parameter(Mandatory = $true)] [string] $TypeName + ) + + # Deliberately lightweight inspection (no managed-metadata dependencies, works in any + # PowerShell host): a Windows Runtime metadata file carries the 'WindowsRuntime 1.4' + # metadata version, and a type's namespace and name are stored as separate, null-terminated + # entries in the metadata strings heap. + $text = [Text.Encoding]::ASCII.GetString([IO.File]::ReadAllBytes($Path)) + + if (-not $text.Contains('WindowsRuntime 1.4')) { + throw "'$Path' is not a Windows Runtime metadata (.winmd) file." + } + + foreach ($name in @($Namespace, $TypeName)) { + if (-not $text.Contains("$name`0")) { + throw "'$Path' does not define '$Namespace.$TypeName' (missing '$name')." + } + } + + Write-Host "Verified '$([IO.Path]::GetFileName($Path))' defines '$Namespace.$TypeName'." -ForegroundColor DarkGray +} + # ---- Consumption: build and run (must not crash) ---- Write-Host "`n=== Consumption smoke test ===" -ForegroundColor Green Invoke-Dotnet (@('build', $consumptionProject) + $commonBuildArgs) @@ -89,8 +115,20 @@ if ($LASTEXITCODE -ne 0) { throw "Consumption smoke test crashed or failed with exit code $LASTEXITCODE." } -# ---- Authoring: build only ---- +# ---- Authoring: build, then verify the generated Windows Runtime metadata ---- Write-Host "`n=== Authoring smoke test ===" -ForegroundColor Green Invoke-Dotnet (@('build', $authoringProject) + $commonBuildArgs) +# The authoring build emits a '.winmd' next to the component assembly. Verify it was produced +# and that it defines the expected Windows Runtime type. +$authoringWinMD = Get-ChildItem -Path ([IO.Path]::Combine($smokeTestsRoot, 'Authoring', 'bin')) -Filter 'Authoring.winmd' -Recurse -ErrorAction SilentlyContinue | + Sort-Object LastWriteTime -Descending | + Select-Object -First 1 + +if ($null -eq $authoringWinMD) { + throw "The authoring build did not produce 'Authoring.winmd'." +} + +Assert-WinMDDefinesType -Path $authoringWinMD.FullName -Namespace 'Authoring' -TypeName 'Greeter' + Write-Host "`nAll smoke tests passed." -ForegroundColor Green From 73e8523b02f503aed0d1f9c82e601627fc6233d7 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Jun 2026 13:44:18 -0700 Subject: [PATCH 06/42] Trim comments and whitespace in smoke tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove explanatory comments and extra blank lines from SmokeTests projects and source files to reduce noise. Changes touch Authoring.csproj, Greeter.cs, Consumption.csproj, Program.cs, Directory.Build.props, Directory.Build.targets, and Directory.Packages.props. No functional code changes — only formatting and comment cleanup to keep the smoke test files minimal. --- .../SmokeTests/Authoring/Authoring.csproj | 27 ++----------------- src/Tests/SmokeTests/Authoring/Greeter.cs | 10 ------- .../SmokeTests/Consumption/Consumption.csproj | 26 +----------------- src/Tests/SmokeTests/Consumption/Program.cs | 8 ------ src/Tests/SmokeTests/Directory.Build.props | 1 - src/Tests/SmokeTests/Directory.Build.targets | 1 - src/Tests/SmokeTests/Directory.Packages.props | 1 - 7 files changed, 3 insertions(+), 71 deletions(-) diff --git a/src/Tests/SmokeTests/Authoring/Authoring.csproj b/src/Tests/SmokeTests/Authoring/Authoring.csproj index 61fd7c44a..5f6be48ed 100644 --- a/src/Tests/SmokeTests/Authoring/Authoring.csproj +++ b/src/Tests/SmokeTests/Authoring/Authoring.csproj @@ -1,28 +1,10 @@ - - - - net10.0-windows10.0.26100.1 10.0.17763.0 10.0.26100.85-preview - + true @@ -39,16 +21,11 @@ https://api.nuget.org/v3/index.json - + $(CsWinRTPackageSource);$(PublicNuGetSource) - diff --git a/src/Tests/SmokeTests/Authoring/Greeter.cs b/src/Tests/SmokeTests/Authoring/Greeter.cs index f1f8b0ae0..12a1de64d 100644 --- a/src/Tests/SmokeTests/Authoring/Greeter.cs +++ b/src/Tests/SmokeTests/Authoring/Greeter.cs @@ -1,17 +1,7 @@ namespace Authoring; -/// -/// A minimal Windows Runtime class used to smoke-test the C#/WinRT authoring pipeline -/// (WinMD generation, the reference projection, and the forwarder assembly) against the -/// real NuGet package. -/// public sealed class Greeter { - /// - /// Returns a greeting for the given name. - /// - /// The name to greet. - /// A greeting message. public string Greet(string name) { return $"Hello, {name}!"; diff --git a/src/Tests/SmokeTests/Consumption/Consumption.csproj b/src/Tests/SmokeTests/Consumption/Consumption.csproj index 3a939963a..918efa366 100644 --- a/src/Tests/SmokeTests/Consumption/Consumption.csproj +++ b/src/Tests/SmokeTests/Consumption/Consumption.csproj @@ -1,25 +1,6 @@ - - - Exe - - net10.0-windows10.0.26100.1 10.0.17763.0 10.0.26100.85-preview @@ -38,16 +19,11 @@ https://api.nuget.org/v3/index.json - + $(CsWinRTPackageSource);$(PublicNuGetSource) - diff --git a/src/Tests/SmokeTests/Consumption/Program.cs b/src/Tests/SmokeTests/Consumption/Program.cs index 038ec9ce1..81318c24f 100644 --- a/src/Tests/SmokeTests/Consumption/Program.cs +++ b/src/Tests/SmokeTests/Consumption/Program.cs @@ -1,16 +1,8 @@ using System; using Windows.Data.Json; -// Parse a JSON object from a string literal (a static projected method that also creates -// an RCW), then round-trip it back to a string with Stringify (an instance projected -// method). This exercises the generated Windows SDK projection and interop assemblies, and -// the WinRT.Runtime ref/impl assemblies, end-to-end against the real NuGet package. JsonObject json = JsonObject.Parse("""{ "a": 42 }"""); string stringified = json.Stringify(); -Console.WriteLine($"Round-tripped JSON: {stringified}"); - -// A successful round-trip must preserve the original value. Returning a non-zero exit code -// (or throwing) signals failure to the smoke test runner. return stringified.Contains("42") ? 0 : 1; diff --git a/src/Tests/SmokeTests/Directory.Build.props b/src/Tests/SmokeTests/Directory.Build.props index f9c13339f..f233f9ca7 100644 --- a/src/Tests/SmokeTests/Directory.Build.props +++ b/src/Tests/SmokeTests/Directory.Build.props @@ -9,5 +9,4 @@ smoke tests fully isolated from how CsWinRT itself is built. All project configuration lives in the individual '.csproj' files. --> - diff --git a/src/Tests/SmokeTests/Directory.Build.targets b/src/Tests/SmokeTests/Directory.Build.targets index 2f904f902..9751b5521 100644 --- a/src/Tests/SmokeTests/Directory.Build.targets +++ b/src/Tests/SmokeTests/Directory.Build.targets @@ -7,5 +7,4 @@ importing the repository's 'src/Directory.Build.targets', keeping the smoke tests fully isolated from how CsWinRT itself is built. --> - diff --git a/src/Tests/SmokeTests/Directory.Packages.props b/src/Tests/SmokeTests/Directory.Packages.props index 813a33d8f..4a03f634e 100644 --- a/src/Tests/SmokeTests/Directory.Packages.props +++ b/src/Tests/SmokeTests/Directory.Packages.props @@ -11,5 +11,4 @@ false - From de07e314175d51f1a56ab650982f322a3dcfd97f Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Jun 2026 13:54:22 -0700 Subject: [PATCH 07/42] Centralize shared smoke test configuration in Directory.Build.props Moves the target framework, Windows SDK ref pack pin, NuGet restore sources, CsWinRT package version/source, and the CsWinRT package reference (all previously duplicated in both smoke test projects) into the shared SmokeTests Directory.Build.props. Each project now only declares what makes it different: the consumption app's output type and the authoring library's component flag. Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com> --- .../SmokeTests/Authoring/Authoring.csproj | 30 ++++----------- .../SmokeTests/Consumption/Consumption.csproj | 28 +++----------- src/Tests/SmokeTests/Directory.Build.props | 38 ++++++++++++++++--- src/Tests/SmokeTests/Directory.Packages.props | 1 - 4 files changed, 45 insertions(+), 52 deletions(-) diff --git a/src/Tests/SmokeTests/Authoring/Authoring.csproj b/src/Tests/SmokeTests/Authoring/Authoring.csproj index 5f6be48ed..42d7c28cf 100644 --- a/src/Tests/SmokeTests/Authoring/Authoring.csproj +++ b/src/Tests/SmokeTests/Authoring/Authoring.csproj @@ -1,31 +1,15 @@ - - net10.0-windows10.0.26100.1 - 10.0.17763.0 - 10.0.26100.85-preview - - - true - - 0.0.0-private.0 - $([MSBuild]::NormalizeDirectory('$(MSBuildThisFileDirectory)', '..', '..', '..', '_build', 'x64', 'Release', 'cswinrt', 'bin')) - - https://api.nuget.org/v3/index.json - - - $(CsWinRTPackageSource);$(PublicNuGetSource) + + true - - - - diff --git a/src/Tests/SmokeTests/Consumption/Consumption.csproj b/src/Tests/SmokeTests/Consumption/Consumption.csproj index 918efa366..e473292ce 100644 --- a/src/Tests/SmokeTests/Consumption/Consumption.csproj +++ b/src/Tests/SmokeTests/Consumption/Consumption.csproj @@ -1,29 +1,13 @@ - - Exe - net10.0-windows10.0.26100.1 - 10.0.17763.0 - 10.0.26100.85-preview - - 0.0.0-private.0 - $([MSBuild]::NormalizeDirectory('$(MSBuildThisFileDirectory)', '..', '..', '..', '_build', 'x64', 'Release', 'cswinrt', 'bin')) - - - https://api.nuget.org/v3/index.json - - - $(CsWinRTPackageSource);$(PublicNuGetSource) + Exe - - - - diff --git a/src/Tests/SmokeTests/Directory.Build.props b/src/Tests/SmokeTests/Directory.Build.props index f233f9ca7..974301528 100644 --- a/src/Tests/SmokeTests/Directory.Build.props +++ b/src/Tests/SmokeTests/Directory.Build.props @@ -1,12 +1,38 @@ + + net10.0-windows10.0.26100.1 + 10.0.17763.0 + 10.0.26100.85-preview + + + + + 0.0.0-private.0 + $([MSBuild]::NormalizeDirectory('$(MSBuildThisFileDirectory)', '..', '..', '_build', 'x64', 'Release', 'cswinrt', 'bin')) + + + https://api.nuget.org/v3/index.json + + + $(CsWinRTPackageSource);$(PublicNuGetSource) + + + + + diff --git a/src/Tests/SmokeTests/Directory.Packages.props b/src/Tests/SmokeTests/Directory.Packages.props index 4a03f634e..631be2ff9 100644 --- a/src/Tests/SmokeTests/Directory.Packages.props +++ b/src/Tests/SmokeTests/Directory.Packages.props @@ -7,7 +7,6 @@ produced the package), so central package management is turned off here. This local file also shadows the repository one, so the smoke tests never inherit its versions. --> - false From 48ad594cc71a9904778e9b3a03cb34f122ce92aa Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Jun 2026 14:52:37 -0700 Subject: [PATCH 08/42] Document the smoke tests and refresh test documentation Updates the testing skill and docs/structure.md to account for the new SmokeTests projects, and fixes other outdated test documentation: expands the SourceGenerator2Test analyzer test list (now CSWINRT2009-2017), corrects the AuthoringTest status and TFM, fixes the TestComponentCSharp IDL filename and the cswinrt.slnx reference, and lists the missing test projects in the repository structure doc. Also adds a smoke-tests verification step to the update-testing-instructions skill. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/skills/testing/SKILL.md | 55 ++++++++++++++----- .../update-testing-instructions/SKILL.md | 26 ++++++--- docs/structure.md | 24 ++++++-- 3 files changed, 80 insertions(+), 25 deletions(-) diff --git a/.github/skills/testing/SKILL.md b/.github/skills/testing/SKILL.md index c735aa5d2..34e5e2ca0 100644 --- a/.github/skills/testing/SKILL.md +++ b/.github/skills/testing/SKILL.md @@ -13,7 +13,7 @@ Before adding tests, always check whether tests for the same functionality alrea ## Test project overview -CsWinRT 3.0 has 5 primary test project areas, each serving a different purpose. Additional specialized test projects also exist under `src/Tests/`: +CsWinRT 3.0 has 6 primary test project areas, each serving a different purpose. Additional specialized test projects also exist under `src/Tests/`: ### 1. Unit tests (`src/Tests/UnitTest/`) @@ -25,8 +25,8 @@ CsWinRT 3.0 has 5 primary test project areas, each serving a different purpose. - **Test framework:** MSTest (`[TestClass]`, `[TestMethod]`, `Assert.*`) - **TFM:** Variable via `$(AppBuildTFMs)`, multi-platform (x86/x64) - **Output type:** Exe, self-contained, AOT-enabled -- **Key dependencies:** MSTest.TestFramework, MSTest.Engine, MSTest.SourceGeneration, Microsoft.Windows.CsWin32, Newtonsoft.Json -- **References:** WinRT.SourceGenerator2 (as analyzer), Test/Windows/WinAppSDK projections +- **Key dependencies:** MSTest.TestFramework, MSTest.Engine, MSTest.SourceGeneration, Microsoft.Windows.CsWin32, Newtonsoft.Json, Microsoft.VCRTForwarders.140 +- **References:** WinRT.SourceGenerator2 (as analyzer), Test/TestSubset/Windows/WinAppSDK projections **Test organization:** - Single namespace: `UnitTest` @@ -132,9 +132,16 @@ return 100; | Test class | What it tests | |------------|---------------| | `Test_CustomPropertyProviderGenerator` | `CustomPropertyProviderGenerator` source generator output | -| `Test_GeneratedCustomPropertyProviderAttributeArgumentAnalyzer` | CSWINRT2004–2008 diagnostics | | `Test_GeneratedCustomPropertyProviderTargetTypeAnalyzer` | CSWINRT2000–2001 diagnostics | | `Test_GeneratedCustomPropertyProviderExistingMemberImplementationAnalyzer` | CSWINRT2003 diagnostic | +| `Test_GeneratedCustomPropertyProviderAttributeArgumentAnalyzer` | CSWINRT2004–2008 diagnostics | +| `Test_ComImportInterfaceAnalyzer` | CSWINRT2009 diagnostic (casts to `[ComImport]` interfaces) | +| `Test_ValidApiContractEnumTypeAnalyzer` | CSWINRT2010 diagnostic | +| `Test_ValidContractVersionAttributeAnalyzer` | CSWINRT2011–2013 diagnostics | +| `Test_ApiContractTypeRequiresContractVersionAnalyzer` | CSWINRT2014 diagnostic | +| `Test_PublicTypeRequiresVersioningAnalyzer` | CSWINRT2015 diagnostic | +| `Test_PublicTypeRequiresContractVersionAnalyzer` | CSWINRT2016 diagnostic | +| `Test_PublicTypeMixedVersioningAttributesAnalyzer` | CSWINRT2017 diagnostic | **Test helpers (in `Helpers/`):** - `CSharpGeneratorTest` — runs a generator on source code and compares output @@ -183,6 +190,7 @@ public async Task InvalidType_Warns() - Use `{|DIAGNOSTIC_ID:target|}` inline syntax to mark expected diagnostics - Or use explicit `expectedDiagnostics` array with `DiagnosticResult` for complex cases +- Pass `isCsWinRTComponent: true` to `VerifyAnalyzerAsync` for analyzers that only apply to authored components (e.g. the contract-versioning analyzers) - Test naming convention: `Condition_ExpectedBehavior` (e.g. `NullPropertyName_Warns`, `ValidClass_DoesNotWarn`) ### 4. Object lifetime tests (`src/Tests/ObjectLifetimeTests/`) @@ -201,18 +209,38 @@ public async Task InvalidType_Warns() - `AsyncQueue` helper for scheduling actions on UI thread and forcing GC - Tests named `BasicTestN()`, `CycleTestN()`, `LeakTestN()` -### 5. Authoring tests (`src/Tests/AuthoringTest/`) — currently disabled, WIP +### 5. Authoring tests (`src/Tests/AuthoringTest/`) -**What it tests:** Authoring a WinRT component in C# — validates that diverse type patterns (enums, structs, classes, interfaces, delegates, collections, XAML controls, async operations, data binding types) can be successfully projected as a WinRT component. +**What it tests:** Authoring a WinRT component in C# — validates that diverse type patterns (enums, structs, classes, interfaces, delegates, collections, XAML controls, async operations, data binding types, and contract-versioning attributes) can be successfully projected as a WinRT component. The component itself builds (build-time validation); the C++ consumption tests that exercise it (`AuthoringConsumptionTest*`) are not yet enabled in the solution. -**When to add tests here:** Currently disabled. When enabled, for testing new WinRT component authoring scenarios. +**When to add tests here:** For testing new WinRT component authoring scenarios — new type shapes, attributes, or versioning patterns. **Project settings:** -- **Type:** Class library with `CsWinRTComponent=true` -- **TFM:** `net10.0` -- **Release x64:** NativeAOT self-contained mode +- **Type:** `CsWinRTComponent=true` class library; Release x64 publishes as a Native AOT shared library (`OutputType=Exe`, `PublishAot=true`, `SelfContained=true`, `NativeLib=Shared`) +- **TFM:** `net10.0-windows10.0.26100.1` - Build-time validation (compilation succeeds = test passes) +### 6. Smoke tests (`src/Tests/SmokeTests/`) + +**What it tests:** End-to-end consumption of the **real** `Microsoft.Windows.CsWinRT` NuGet package — a consuming app and an authoring component — fully isolated from the repository build infrastructure. Validates that the packaged `ref`/`lib` assemblies, the build targets, and all post-build generators work correctly for an external customer. + +**When to add tests here:** For verifying that the produced NuGet package works in a real, isolated environment (correct `ref`/`lib` assemblies referenced, generators running). Keep these minimal — they are smoke tests, not feature coverage. Use `UnitTest/` or `FunctionalTests/` for marshalling/feature coverage instead. + +**Project structure:** Two standalone projects, intentionally kept out of `cswinrt.slnx` (the package they consume only exists after the build packs it). They are isolated from the repo build infrastructure via blank `Directory.Build.props`/`.targets` and a local `Directory.Packages.props` (central package management disabled). All shared configuration lives in `Directory.Build.props`, so each `.csproj` only carries what makes it different. + +**Existing tests:** +| Project | Tests | +|---------|-------| +| `Consumption/` | An `Exe` that calls `JsonObject.Parse(...)` then `Stringify()` from `Windows.Data.Json`, exercising the Windows SDK projection, the interop generator, and the `WinRT.Runtime` ref/impl assemblies | +| `Authoring/` | A `CsWinRTComponent` library exposing a minimal `Greeter` class, exercising WinMD generation, the reference projection, and the forwarder assembly | + +**Shared configuration (`Directory.Build.props`):** +- **TFM:** `net10.0-windows10.0.26100.1` (the `.1` CsWinRT 3.0 revision), with a pinned `WindowsSdkPackageVersion` so the build uses the real .NET SDK targeting pack (mirrors `src/WinRT.Internal`) +- `RestoreSources` overrides all inherited NuGet sources: the local CsWinRT build output (`CsWinRTPackageSource`) plus public NuGet (`PublicNuGetSource`) +- `CsWinRTPackageVersion`/`CsWinRTPackageSource` default to the local `build.cmd x64 Release` output and are overridden by the build/CI that produced the package + +**How they run:** `run-smoke-tests.ps1` builds and runs the consumption app (asserting a clean exit code), then builds the authoring component and verifies the generated `Authoring.winmd` defines `Authoring.Greeter`. It is invoked after the `nuget pack` step in `src/build.cmd` (x64 only; skippable via `cswinrt_run_smoke_tests=false`) and in the `build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml` CI steps. + ## Deciding where to add tests | You want to test... | Add test to... | @@ -226,14 +254,15 @@ public async Task InvalidType_Warns() | An analyzer diagnostic | `SourceGenerator2Test/` (new `Test_*Analyzer` class or add to existing) | | GC/reference tracking behavior | `ObjectLifetimeTests/` | | XAML visual tree element lifetime | `ObjectLifetimeTests/` | -| WinRT component authoring patterns | `AuthoringTest/` (when enabled) | +| WinRT component authoring patterns | `AuthoringTest/` | +| The produced NuGet package works end-to-end (real `ref`/`lib` assemblies, generators) | `SmokeTests/` (`Consumption/` or `Authoring/`) | | Generated projection code patterns or cross-ABI control flow | Update `TestComponentCSharp/` and add tests in `UnitTest/` or `FunctionalTests/` | ## Test component: TestComponentCSharp (`src/Tests/TestComponentCSharp/`) -A **WinRT test component** (defined in `class.idl`, implemented in C++) that complements the general `TestComponent` from the [TestWinRT](https://github.com/microsoft/TestWinRT/) submodule. It tests scenarios specific to the C#/WinRT language projection. +A **WinRT test component** (defined in `TestComponentCSharp.idl`, implemented in C++) that complements the general `TestComponent` from the [TestWinRT](https://github.com/microsoft/TestWinRT/) submodule. It tests scenarios specific to the C#/WinRT language projection. -**When to update this project:** When you need to validate generated projection code patterns or cross-ABI control flow — e.g. a C# type calling a method on a projected object with specific parameters, and the native implementation validating the result. New types and members can be added to `class.idl` as needed. +**When to update this project:** When you need to validate generated projection code patterns or cross-ABI control flow — e.g. a C# type calling a method on a projected object with specific parameters, and the native implementation validating the result. New types and members can be added to `TestComponentCSharp.idl` as needed. **Referenced from:** unit tests (`UnitTest/`), functional tests (`FunctionalTests/`), and projection test projects (`Projections/Test/`). diff --git a/.github/skills/update-testing-instructions/SKILL.md b/.github/skills/update-testing-instructions/SKILL.md index 6ffe5ff9c..c63f9be81 100644 --- a/.github/skills/update-testing-instructions/SKILL.md +++ b/.github/skills/update-testing-instructions/SKILL.md @@ -68,7 +68,17 @@ Launch an explore agent to verify: - **Project settings** are current: output type, TFM, `CsWinRTComponent` setting, AOT mode - **What it tests** description is accurate -### Step 7: verify TestComponentCSharp (`src/Tests/TestComponentCSharp/`) +### Step 7: verify smoke tests (`src/Tests/SmokeTests/`) + +Launch an explore agent (or inspect directly) to verify: + +- **Project list** is accurate — the `Consumption/` app and the `Authoring/` component, kept out of `cswinrt.slnx` +- **Isolation** is intact: blank `Directory.Build.props`/`.targets` and a local `Directory.Packages.props` (central package management disabled) +- **Shared configuration** in `Directory.Build.props` is current: TFM (`.1` revision), pinned `WindowsSdkPackageVersion`, `RestoreSources` (local package output + public NuGet), and the `CsWinRTPackageVersion`/`CsWinRTPackageSource` defaults +- **What each test does** is accurate (the consumption app's `JsonObject.Parse`/`Stringify` call; the authoring component's class and `.winmd` verification) +- **How they run** is current: the `run-smoke-tests.ps1` runner, and the invocations in `src/build.cmd` and `build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml` + +### Step 8: verify TestComponentCSharp (`src/Tests/TestComponentCSharp/`) Launch an explore agent to verify: @@ -76,7 +86,7 @@ Launch an explore agent to verify: - **"Referenced from" list** is current - **"When to update" guidance** is still correct -### Step 8: verify the "deciding where to add tests" table +### Step 9: verify the "deciding where to add tests" table Check every row in the routing table against the actual test projects. Verify: @@ -85,7 +95,7 @@ Check every row in the routing table against the actual test projects. Verify: - No new test project categories exist that should be added as rows - The `TestComponentCSharp` guidance is still accurate -### Step 9: verify code examples +### Step 10: verify code examples For each code example in the testing skill, verify it matches the conventions actually used in the test files: @@ -94,7 +104,7 @@ For each code example in the testing skill, verify it matches the conventions ac - **Generator test pattern**: verify the `VerifySources` call matches the actual method signature and style. Check an actual test method in `Test_CustomPropertyProviderGenerator` to confirm - **Analyzer test pattern**: verify the `VerifyAnalyzerAsync` call matches the actual method signature and style. Check an actual test method in the analyzer test files to confirm -### Step 10: update the testing instructions +### Step 11: update the testing instructions Apply surgical edits to `.github/skills/testing/SKILL.md` to fix any discrepancies found. Typical updates include: @@ -115,17 +125,17 @@ Apply surgical edits to `.github/skills/testing/SKILL.md` to fix any discrepanci - Do not add unnecessary commentary or explanation beyond what's needed for test placement guidance -### Step 11: update this skill if needed +### Step 12: update this skill if needed If significant changes to the test suite were discovered (e.g. test projects added or removed, new categories of tests, changed validation criteria), also update this skill file (`.github/skills/update-testing-instructions/SKILL.md`) to reflect those changes. In particular: -- The **per-project verification steps** (steps 2–7) must stay in sync with the actual test projects. If a test project is added or removed, add or remove its verification step accordingly. +- The **per-project verification steps** (steps 2–8) must stay in sync with the actual test projects. If a test project is added or removed, add or remove its verification step accordingly. - The **verification criteria** for each step should reflect what is actually worth checking. If a project gains new aspects worth validating (e.g. new test helper classes, new build settings), add those to the checklist. -- The **code example verification step** (step 9) should list all code examples present in the testing skill. +- The **code example verification step** (step 10) should list all code examples present in the testing skill. This ensures the skill remains useful and accurate for future runs. -### Step 12: summarize changes +### Step 13: summarize changes After editing, provide a clear summary of what was updated and why, so the user can review the changes before committing. diff --git a/docs/structure.md b/docs/structure.md index e0895712c..fa5968761 100644 --- a/docs/structure.md +++ b/docs/structure.md @@ -41,15 +41,31 @@ Contains several projects for generating and building projections from the Windo Contains various testing-related projects: -- [`TestComponentCSharp`](../src/Tests/TestComponentCSharp): This is an implementation of a WinRT test component, defined in `class.idl` and used by the UnitTest project. To complement the general TestComponent above, the TestComponentCSharp tests scenarios specific to the C#/WinRT language projection. +- [`TestComponentCSharp`](../src/Tests/TestComponentCSharp): An implementation of a WinRT test component, defined in `TestComponentCSharp.idl` and used by the UnitTest and functional test projects. To complement the general TestComponent above, the TestComponentCSharp tests scenarios specific to the C#/WinRT language projection. -- [`UnitTest`](../src/Tests/UnitTest): Unit tests for validating the Windows SDK, WinUI, and Test projections generated above. All pull requests should ensure that this project executes without errors. +- [`UnitTest`](../src/Tests/UnitTest): MSTest unit tests for validating the Windows SDK, WinUI, and Test projections generated above, plus core marshalling, COM interop, exceptions, and source-generator integration. All pull requests should ensure that this project executes without errors. -- [`HostTest`](../src/Tests/HostTest): Unit tests for WinRT.Host.dll, which provides hosting for runtime components written in C#. +- [`FunctionalTests`](../src/Tests/FunctionalTests): A collection of standalone console applications, each validating a specific interop scenario (async, collections, events, CCW, dynamic casting, structs, and more) under real publishing conditions such as trimming and Native AOT. Each test reports success with exit code `100`. + +- [`SourceGenerator2Test`](../src/Tests/SourceGenerator2Test): MSTest unit tests for the source generators and diagnostic analyzers in `WinRT.SourceGenerator2`, built on the Roslyn testing libraries. + +- [`ObjectLifetimeTests`](../src/Tests/ObjectLifetimeTests): A WinUI application-style MSTest project validating reference tracking, garbage collection behavior, and XAML element lifetime. + +- [`SmokeTests`](../src/Tests/SmokeTests): Minimal, isolated end-to-end smoke tests that consume the real `Microsoft.Windows.CsWinRT` NuGet package — a consumption app (`Consumption`) and an authoring component (`Authoring`) — to verify the produced package works correctly outside the repository build infrastructure. + +- [`AuthoringTest`](../src/Tests/AuthoringTest): A C#-authored WinRT component (`CsWinRTComponent=true`) covering a broad set of authoring type patterns. Companion projects exercise consuming authored components — `AuthoringTest2`/`AuthoringTest3`, the `AuthoringConsumptionTest*` C++ consumers, and the WUX (`Windows.UI.Xaml`) and WinUI variants — several of which are still work in progress. + +- [`HostTest`](../src/Tests/HostTest): C++ (gtest) tests for `WinRT.Host.dll`, which provides hosting for runtime components written in C#. + +- [`DiagnosticTests`](../src/Tests/DiagnosticTests): Tests for the CsWinRT diagnostic and analyzer rules, driven by positive and negative source snippets. + +- [`BuildDeterminismTest`](../src/Tests/BuildDeterminismTest): Builds a component twice and compares the hashes of the generated `WinRT.Interop.dll` to verify deterministic builds. + +- [`OOPExe`](../src/Tests/OOPExe): An out-of-process executable harness used by the authoring test scenarios. ## [`src/TestWinRT`](https://github.com/microsoft/TestWinRT/) -C#/WinRT makes use of the standalone [TestWinRT](https://github.com/microsoft/TestWinRT/) repository for general language projection test coverage. This repo is cloned into the root of the C#/WinRT repo, via `get_testwinrt.cmd`, so that `cswinrt.sln` can resolve its reference to `TestComponent.vcxproj`. The resulting `TestComponent` and `BenchmarkComponent` files are consumed by the UnitTest and Benchmarks projects above. +C#/WinRT makes use of the standalone [TestWinRT](https://github.com/microsoft/TestWinRT/) repository for general language projection test coverage. This repo is cloned into the root of the C#/WinRT repo, via `get_testwinrt.cmd`, so that `cswinrt.slnx` can resolve its reference to `TestComponent.vcxproj`. The resulting `TestComponent` and `BenchmarkComponent` files are consumed by the UnitTest and Benchmarks projects above. ## [`src/WinRT.Generator.Tasks`](../src/WinRT.Generator.Tasks) From a50f9b903ce60a5f54e45628619512ed7d2f68de Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 18 Jun 2026 17:51:31 -0700 Subject: [PATCH 09/42] Use the CsWinRTDependencies feed for smoke test restore CI agents cannot reach public NuGet (api.nuget.org), which broke the smoke test restore. Restore the preview Windows SDK ref pack from the repository's standard CsWinRTDependencies feed instead (the same feed the rest of the repo uses, e.g. src/WinRT.Internal), keeping the local CsWinRT build output as the source for the package under test. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../CsWinRT-PublishToNuGet-Steps.yml | 2 +- src/Tests/SmokeTests/Directory.Build.props | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml b/build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml index d4b648a94..53effb6ad 100644 --- a/build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml +++ b/build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml @@ -128,7 +128,7 @@ steps: # verify that the real package (ref/lib assemblies, generators, and build targets) works for # a consuming app and a component author, fully isolated from the repo build infrastructure. # The smoke tests restore the package being tested from the packed output above, and all other - # dependencies (notably the preview Windows SDK ref pack) from public NuGet. + # dependencies (notably the preview Windows SDK ref pack) from the CsWinRTDependencies feed. - task: UseDotNet@2 displayName: Use .NET SDK for smoke tests inputs: diff --git a/src/Tests/SmokeTests/Directory.Build.props b/src/Tests/SmokeTests/Directory.Build.props index 974301528..78bf543f6 100644 --- a/src/Tests/SmokeTests/Directory.Build.props +++ b/src/Tests/SmokeTests/Directory.Build.props @@ -25,11 +25,18 @@ 0.0.0-private.0 $([MSBuild]::NormalizeDirectory('$(MSBuildThisFileDirectory)', '..', '..', '_build', 'x64', 'Release', 'cswinrt', 'bin')) - - https://api.nuget.org/v3/index.json + + https://pkgs.dev.azure.com/shine-oss/CsWinRT/_packaging/CsWinRTDependencies/nuget/v3/index.json - - $(CsWinRTPackageSource);$(PublicNuGetSource) + + $(CsWinRTPackageSource);$(CsWinRTDependenciesSource) From 1a4c14e06bf8c5e02320c35d8ccdb9dd373a0f8d Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Jun 2026 10:02:51 -0700 Subject: [PATCH 10/42] Keep type map group types in the WinRT.Runtime reference assembly The type map group types (WindowsRuntimeComWrappersTypeMapGroup, WindowsRuntimeMetadataTypeMapGroup, and DynamicInterfaceCastableImplementationTypeMapGroup) were stripped from the reference assembly as implementation-only types. However, they are referenced by code the CsWinRT source generator emits into consumer assemblies (the '[assembly: TypeMapAssemblyTarget]' attributes that register assemblies for the interop type map infrastructure), which is compiled against the reference assembly. Stripping them broke consumers with CS0234. Keep these three types in the reference assembly, and instead mark them '[Obsolete]' (with the new CSWINRT3002 diagnostic) and '[EditorBrowsable(Never)]', only in the reference assembly, to discourage direct use in user code. This mirrors the reference-assembly-only obsolete pattern already used for the parameterless 'WindowsRuntimeObject' constructor (CSWINRT3001). The marker is reference-assembly-only because the implementation assembly has internal '[assembly: TypeMap]' usages that would otherwise trip the obsolete warning. The projection writer's generated-file header now also suppresses CSWINRT3002, since the generated projection code references these types. Adds the docs/diagnostics/cswinrt3002.md page. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/diagnostics/cswinrt3002.md | 28 +++++++++++++++++++ .../Extensions/ProjectionWriterExtensions.cs | 1 + ...rfaceCastableImplementationTypeMapGroup.cs | 13 ++++++++- .../WindowsRuntimeComWrappersTypeMapGroup.cs | 13 ++++++++- .../WindowsRuntimeMetadataTypeMapGroup.cs | 13 +++++++-- .../Properties/WindowsRuntimeConstants.cs | 15 ++++++++++ src/WinRT.Runtime2/WinRT.Runtime.csproj | 10 ++++++- 7 files changed, 88 insertions(+), 5 deletions(-) create mode 100644 docs/diagnostics/cswinrt3002.md diff --git a/docs/diagnostics/cswinrt3002.md b/docs/diagnostics/cswinrt3002.md new file mode 100644 index 000000000..193102af5 --- /dev/null +++ b/docs/diagnostics/cswinrt3002.md @@ -0,0 +1,28 @@ +# CsWinRT warning CSWINRT3002 + +The Windows Runtime type map group types (`WindowsRuntimeComWrappersTypeMapGroup`, `WindowsRuntimeMetadataTypeMapGroup`, and `DynamicInterfaceCastableImplementationTypeMapGroup`, all in the `WindowsRuntime.InteropServices` namespace) are a private implementation detail of `WinRT.Runtime.dll`. They are only meant to be used as type map group type arguments for the `System.Runtime.InteropServices.TypeMapping` APIs, in marshalling code generated by CsWinRT. They are exposed in the reference assembly for `WinRT.Runtime.dll` solely so that this generated code can reference them, and they are not intended for direct use in user code. + +For instance, the following sample generates CSWINRT3002: + +```csharp +using System.Runtime.InteropServices; +using WindowsRuntime.InteropServices; + +namespace MyProgram; + +// CSWINRT3002: the type map group types are a private implementation detail +[assembly: TypeMapAssemblyTarget("MyComponent")] +``` + +## Additional resources + +`CSWINRT3002` is emitted when user code references one of the Windows Runtime type map group types directly. These types act as type map group markers for the .NET interop type map infrastructure: the CsWinRT source generator emits `[assembly: TypeMapAssemblyTarget(...)]` attributes to register the assemblies that contain type map entries, and the interop generator (`cswinrtinteropgen.exe`) emits the corresponding entries. All of that generated code suppresses this diagnostic, so it never affects normal builds. + +The type map group types are not considered part of the versioned API surface of `WinRT.Runtime.dll`, and they may be modified or removed across any version change. Using them in user code is undefined behavior and not supported. + +## Recommended action + +- Do not reference the type map group types in user code, and let CsWinRT generate the type map registration for you. +- If you are authoring or consuming a Windows Runtime component, the required `[assembly: TypeMapAssemblyTarget(...)]` attributes are generated automatically; no manual registration is needed. + +Keeping the type map group types exclusive to generated code is what allows CsWinRT to evolve the interop type map infrastructure rapidly. Respecting the diagnostic ensures your applications remain stable across updates. diff --git a/src/WinRT.Projection.Writer/Extensions/ProjectionWriterExtensions.cs b/src/WinRT.Projection.Writer/Extensions/ProjectionWriterExtensions.cs index 1f04dbaf7..860263526 100644 --- a/src/WinRT.Projection.Writer/Extensions/ProjectionWriterExtensions.cs +++ b/src/WinRT.Projection.Writer/Extensions/ProjectionWriterExtensions.cs @@ -51,6 +51,7 @@ public void WriteFileHeader(ProjectionEmitContext context) #pragma warning disable CS0649 // "Field '...' is never assigned to" #pragma warning disable CA2207, CA1063, CA1033, CA1001, CA2213 #pragma warning disable CSWINRT3001 // "Type or member '...' is a private implementation detail" + #pragma warning disable CSWINRT3002 // "Type '...' is a private implementation detail" #pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type """); diff --git a/src/WinRT.Runtime2/InteropServices/TypeMapGroups/DynamicInterfaceCastableImplementationTypeMapGroup.cs b/src/WinRT.Runtime2/InteropServices/TypeMapGroups/DynamicInterfaceCastableImplementationTypeMapGroup.cs index dfddd5369..f5d212dc2 100644 --- a/src/WinRT.Runtime2/InteropServices/TypeMapGroups/DynamicInterfaceCastableImplementationTypeMapGroup.cs +++ b/src/WinRT.Runtime2/InteropServices/TypeMapGroups/DynamicInterfaceCastableImplementationTypeMapGroup.cs @@ -1,6 +1,11 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#if WINDOWS_RUNTIME_REFERENCE_ASSEMBLY +using System; +using System.ComponentModel; +#endif + namespace WindowsRuntime.InteropServices; /// @@ -10,7 +15,13 @@ namespace WindowsRuntime.InteropServices; /// /// This type is only meant to be used as type map group for APIs. /// -[WindowsRuntimeImplementationOnlyMember] +#if WINDOWS_RUNTIME_REFERENCE_ASSEMBLY +[Obsolete( + WindowsRuntimeConstants.WindowsRuntimeTypeMapGroupObsoleteMessage, + DiagnosticId = WindowsRuntimeConstants.WindowsRuntimeTypeMapGroupObsoleteDiagnosticId, + UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] +[EditorBrowsable(EditorBrowsableState.Never)] +#endif public abstract class DynamicInterfaceCastableImplementationTypeMapGroup { /// diff --git a/src/WinRT.Runtime2/InteropServices/TypeMapGroups/WindowsRuntimeComWrappersTypeMapGroup.cs b/src/WinRT.Runtime2/InteropServices/TypeMapGroups/WindowsRuntimeComWrappersTypeMapGroup.cs index b124e507a..80aab02a3 100644 --- a/src/WinRT.Runtime2/InteropServices/TypeMapGroups/WindowsRuntimeComWrappersTypeMapGroup.cs +++ b/src/WinRT.Runtime2/InteropServices/TypeMapGroups/WindowsRuntimeComWrappersTypeMapGroup.cs @@ -1,6 +1,11 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#if WINDOWS_RUNTIME_REFERENCE_ASSEMBLY +using System; +using System.ComponentModel; +#endif + namespace WindowsRuntime.InteropServices; /// @@ -9,7 +14,13 @@ namespace WindowsRuntime.InteropServices; /// /// This type is only meant to be used as type map group for APIs. /// -[WindowsRuntimeImplementationOnlyMember] +#if WINDOWS_RUNTIME_REFERENCE_ASSEMBLY +[Obsolete( + WindowsRuntimeConstants.WindowsRuntimeTypeMapGroupObsoleteMessage, + DiagnosticId = WindowsRuntimeConstants.WindowsRuntimeTypeMapGroupObsoleteDiagnosticId, + UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] +[EditorBrowsable(EditorBrowsableState.Never)] +#endif public abstract class WindowsRuntimeComWrappersTypeMapGroup { /// diff --git a/src/WinRT.Runtime2/InteropServices/TypeMapGroups/WindowsRuntimeMetadataTypeMapGroup.cs b/src/WinRT.Runtime2/InteropServices/TypeMapGroups/WindowsRuntimeMetadataTypeMapGroup.cs index 31b212175..1916754ed 100644 --- a/src/WinRT.Runtime2/InteropServices/TypeMapGroups/WindowsRuntimeMetadataTypeMapGroup.cs +++ b/src/WinRT.Runtime2/InteropServices/TypeMapGroups/WindowsRuntimeMetadataTypeMapGroup.cs @@ -1,17 +1,26 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +#if WINDOWS_RUNTIME_REFERENCE_ASSEMBLY using System; +using System.ComponentModel; +#endif namespace WindowsRuntime.InteropServices; /// -/// The type map group placeholder for all Windows Runtime types that need to support marshalling. +/// The type map group placeholder for all Windows Runtime types that need to support marshalling. /// /// /// This type is only meant to be used as type map group for APIs. /// -[WindowsRuntimeImplementationOnlyMember] +#if WINDOWS_RUNTIME_REFERENCE_ASSEMBLY +[Obsolete( + WindowsRuntimeConstants.WindowsRuntimeTypeMapGroupObsoleteMessage, + DiagnosticId = WindowsRuntimeConstants.WindowsRuntimeTypeMapGroupObsoleteDiagnosticId, + UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] +[EditorBrowsable(EditorBrowsableState.Never)] +#endif public abstract class WindowsRuntimeMetadataTypeMapGroup { /// diff --git a/src/WinRT.Runtime2/Properties/WindowsRuntimeConstants.cs b/src/WinRT.Runtime2/Properties/WindowsRuntimeConstants.cs index befb33eb0..1231ba5cc 100644 --- a/src/WinRT.Runtime2/Properties/WindowsRuntimeConstants.cs +++ b/src/WinRT.Runtime2/Properties/WindowsRuntimeConstants.cs @@ -22,6 +22,21 @@ internal static class WindowsRuntimeConstants /// public const string WindowsRuntimeObjectConstructorObsoleteDiagnosticId = "CSWINRT3001"; + /// + /// A message for the type map group types (see the WindowsRuntime.InteropServices type map group placeholders). + /// + public const string WindowsRuntimeTypeMapGroupObsoleteMessage = + "This type is a private implementation detail, and it must never be used directly. It is only meant to be used as a type map " + + "group type argument for the 'System.Runtime.InteropServices.TypeMapping' APIs, in marshalling code generated by CsWinRT " + + "(produced by 'cswinrtinteropgen.exe' and by the CsWinRT source generator). It is not considered part of the versioned API " + + "surface, and it may be modified or removed across any version change for 'WinRT.Runtime.dll'. Using it in user code is " + + "undefined behavior and not supported."; + + /// + /// The diagnostic id for the type map group types. + /// + public const string WindowsRuntimeTypeMapGroupObsoleteDiagnosticId = "CSWINRT3002"; + /// /// The URL format for all custom diagnostics for CsWinRT. /// diff --git a/src/WinRT.Runtime2/WinRT.Runtime.csproj b/src/WinRT.Runtime2/WinRT.Runtime.csproj index 74e4743a3..e5f39bb2d 100644 --- a/src/WinRT.Runtime2/WinRT.Runtime.csproj +++ b/src/WinRT.Runtime2/WinRT.Runtime.csproj @@ -173,7 +173,15 @@ - + + From ac10bd6affa1f998f40da9a17fafa0e5e799e474 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Jun 2026 14:17:30 -0700 Subject: [PATCH 11/42] Run each smoke test as its own CI step with a final failure gate Previously all smoke tests ran in a single CI step, so a failure didn't make it obvious which one failed. Following the unit test pattern in CsWinRT-Test-Steps.yml, each smoke test now runs as its own step with 'continueOnError' (an individual failure only marks the job as 'SucceededWithIssues'), and a final gate step turns any such issue into an actual failure. This makes it clear exactly which smoke test failed while still letting every test run and report. The runner script gains a '-Test' parameter (Consumption, Authoring, or All) so CI can invoke a single test per step; local builds keep using the default 'All'. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../CsWinRT-PublishToNuGet-Steps.yml | 30 +++++++- src/Tests/SmokeTests/run-smoke-tests.ps1 | 75 ++++++++++++------- 2 files changed, 77 insertions(+), 28 deletions(-) diff --git a/build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml b/build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml index 53effb6ad..690f5a2a3 100644 --- a/build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml +++ b/build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml @@ -129,6 +129,10 @@ steps: # a consuming app and a component author, fully isolated from the repo build infrastructure. # The smoke tests restore the package being tested from the packed output above, and all other # dependencies (notably the preview Windows SDK ref pack) from the CsWinRTDependencies feed. + # + # Each smoke test runs as its own step with 'continueOnError' (so a failure only marks the job + # as 'SucceededWithIssues' and makes it obvious which one failed); a final gate step below turns + # any such issue into an actual failure. This mirrors the unit test steps in CsWinRT-Test-Steps.yml. - task: UseDotNet@2 displayName: Use .NET SDK for smoke tests inputs: @@ -136,13 +140,35 @@ steps: version: $(_DotnetVersion) - task: PowerShell@2 - displayName: Run smoke tests + displayName: Run Consumption smoke test + continueOnError: true inputs: targetType: filePath filePath: $(Build.SourcesDirectory)\src\Tests\SmokeTests\run-smoke-tests.ps1 - arguments: -PackageSource "$(ob_outputDirectory)\packages" -PackageVersion "$(NugetVersion)" + arguments: -PackageSource "$(ob_outputDirectory)\packages" -PackageVersion "$(NugetVersion)" -Test Consumption workingDirectory: $(Build.SourcesDirectory) + - task: PowerShell@2 + displayName: Run Authoring smoke test + continueOnError: true + inputs: + targetType: filePath + filePath: $(Build.SourcesDirectory)\src\Tests\SmokeTests\run-smoke-tests.ps1 + arguments: -PackageSource "$(ob_outputDirectory)\packages" -PackageVersion "$(NugetVersion)" -Test Authoring + workingDirectory: $(Build.SourcesDirectory) + + # Fail the job if any smoke test above failed. Each smoke test uses 'continueOnError', so an + # individual failure only marks the job as 'SucceededWithIssues'; this turns that into a real + # failure, while still letting every smoke test run and report first. + - task: PowerShell@2 + displayName: Fail if any smoke test failed + condition: eq(variables['Agent.JobStatus'], 'SucceededWithIssues') + inputs: + targetType: inline + script: | + Write-Host "##vso[task.logissue type=error]One or more smoke tests failed. See above for details." + exit 1 + - ${{ if eq(parameters.IsGitHub, false) }}: # NuGet signing diff --git a/src/Tests/SmokeTests/run-smoke-tests.ps1 b/src/Tests/SmokeTests/run-smoke-tests.ps1 index 0f20a2deb..80bb91869 100644 --- a/src/Tests/SmokeTests/run-smoke-tests.ps1 +++ b/src/Tests/SmokeTests/run-smoke-tests.ps1 @@ -25,11 +25,19 @@ .PARAMETER PackageVersion Version of the 'Microsoft.Windows.CsWinRT' package to consume. +.PARAMETER Test + Which smoke test(s) to run: 'Consumption', 'Authoring', or 'All' (the default). The CI runs + each test as its own step (passing a single value), so an individual failure is reported in + isolation; local builds use the default 'All'. + .PARAMETER Configuration Build configuration to use (defaults to 'Release'). .EXAMPLE ./run-smoke-tests.ps1 -PackageSource ../../_build/x64/Release/cswinrt/bin -PackageVersion 0.0.0-private.0 + +.EXAMPLE + ./run-smoke-tests.ps1 -PackageSource ./packages -PackageVersion 3.0.0-preview.1 -Test Consumption #> [CmdletBinding()] @@ -40,6 +48,9 @@ param ( [Parameter(Mandatory = $true)] [string] $PackageVersion, + [ValidateSet('All', 'Consumption', 'Authoring')] + [string] $Test = 'All', + [string] $Configuration = 'Release' ) @@ -96,39 +107,51 @@ function Assert-WinMDDefinesType { Write-Host "Verified '$([IO.Path]::GetFileName($Path))' defines '$Namespace.$TypeName'." -ForegroundColor DarkGray } -# ---- Consumption: build and run (must not crash) ---- -Write-Host "`n=== Consumption smoke test ===" -ForegroundColor Green -Invoke-Dotnet (@('build', $consumptionProject) + $commonBuildArgs) +# Consumption: build and run (must not crash). +function Invoke-ConsumptionSmokeTest { + Write-Host "`n=== Consumption smoke test ===" -ForegroundColor Green + Invoke-Dotnet (@('build', $consumptionProject) + $commonBuildArgs) -# Locate and run the freshly built app, asserting a clean (zero) exit code. -$consumptionExe = Get-ChildItem -Path ([IO.Path]::Combine($smokeTestsRoot, 'Consumption', 'bin')) -Filter 'Consumption.exe' -Recurse | - Sort-Object LastWriteTime -Descending | - Select-Object -First 1 + # Locate and run the freshly built app, asserting a clean (zero) exit code. + $consumptionExe = Get-ChildItem -Path ([IO.Path]::Combine($smokeTestsRoot, 'Consumption', 'bin')) -Filter 'Consumption.exe' -Recurse | + Sort-Object LastWriteTime -Descending | + Select-Object -First 1 -if ($null -eq $consumptionExe) { - throw "Could not find the built 'Consumption.exe'." -} + if ($null -eq $consumptionExe) { + throw "Could not find the built 'Consumption.exe'." + } -Write-Host "Running '$($consumptionExe.FullName)'" -ForegroundColor DarkGray -& $consumptionExe.FullName -if ($LASTEXITCODE -ne 0) { - throw "Consumption smoke test crashed or failed with exit code $LASTEXITCODE." + Write-Host "Running '$($consumptionExe.FullName)'" -ForegroundColor DarkGray + & $consumptionExe.FullName + if ($LASTEXITCODE -ne 0) { + throw "Consumption smoke test crashed or failed with exit code $LASTEXITCODE." + } } -# ---- Authoring: build, then verify the generated Windows Runtime metadata ---- -Write-Host "`n=== Authoring smoke test ===" -ForegroundColor Green -Invoke-Dotnet (@('build', $authoringProject) + $commonBuildArgs) +# Authoring: build, then verify the generated Windows Runtime metadata. +function Invoke-AuthoringSmokeTest { + Write-Host "`n=== Authoring smoke test ===" -ForegroundColor Green + Invoke-Dotnet (@('build', $authoringProject) + $commonBuildArgs) + + # The authoring build emits a '.winmd' next to the component assembly. Verify it was produced + # and that it defines the expected Windows Runtime type. + $authoringWinMD = Get-ChildItem -Path ([IO.Path]::Combine($smokeTestsRoot, 'Authoring', 'bin')) -Filter 'Authoring.winmd' -Recurse -ErrorAction SilentlyContinue | + Sort-Object LastWriteTime -Descending | + Select-Object -First 1 + + if ($null -eq $authoringWinMD) { + throw "The authoring build did not produce 'Authoring.winmd'." + } -# The authoring build emits a '.winmd' next to the component assembly. Verify it was produced -# and that it defines the expected Windows Runtime type. -$authoringWinMD = Get-ChildItem -Path ([IO.Path]::Combine($smokeTestsRoot, 'Authoring', 'bin')) -Filter 'Authoring.winmd' -Recurse -ErrorAction SilentlyContinue | - Sort-Object LastWriteTime -Descending | - Select-Object -First 1 + Assert-WinMDDefinesType -Path $authoringWinMD.FullName -Namespace 'Authoring' -TypeName 'Greeter' +} -if ($null -eq $authoringWinMD) { - throw "The authoring build did not produce 'Authoring.winmd'." +if ($Test -in @('All', 'Consumption')) { + Invoke-ConsumptionSmokeTest } -Assert-WinMDDefinesType -Path $authoringWinMD.FullName -Namespace 'Authoring' -TypeName 'Greeter' +if ($Test -in @('All', 'Authoring')) { + Invoke-AuthoringSmokeTest +} -Write-Host "`nAll smoke tests passed." -ForegroundColor Green +Write-Host "`nSmoke tests passed." -ForegroundColor Green From dba83426031c8550bf1a020acaf30ec00415d671 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Jun 2026 15:12:21 -0700 Subject: [PATCH 12/42] Compile generated projections against the WinRT.Runtime implementation assembly The NuGet package ships WinRT.Runtime as both a reference assembly (ref/net10.0, with implementation-only types stripped) and an implementation assembly (lib/net10.0). The projection and interop generators compile and inspect generated implementation projection code that references those implementation-only types (e.g. WindowsRuntimeObjectReferenceValue, RestrictedErrorInfo, the marshallers), so they must use the implementation assembly rather than the reference assembly that MSBuild resolves for compilation. Introduce a CsWinRTRuntimeImplementationAssemblyPath property (defaulting to the package lib layout) and swap WinRT.Runtime for it in each affected generator target. Repo-internal builds override the property to point at the locally built implementation assembly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ...crosoft.Windows.CsWinRT.CsWinRTGen.targets | 47 ++++++++++++++++--- src/Directory.Build.props | 8 ++++ 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/nuget/Microsoft.Windows.CsWinRT.CsWinRTGen.targets b/nuget/Microsoft.Windows.CsWinRT.CsWinRTGen.targets index bf683b9df..ee9a73da1 100644 --- a/nuget/Microsoft.Windows.CsWinRT.CsWinRTGen.targets +++ b/nuget/Microsoft.Windows.CsWinRT.CsWinRTGen.targets @@ -81,6 +81,19 @@ Copyright (C) Microsoft Corporation. All rights reserved. --> <_CsWinRTSdkProjectionAssemblyPath>$([MSBuild]::NormalizePath('$(MSBuildProjectDirectory)', '$(IntermediateOutputPath)', 'WinRT.Sdk.Projection.dll')) + + $([MSBuild]::NormalizePath('$(CsWinRTPath)', 'lib', 'net10.0', 'WinRT.Runtime.dll')) + $(DefineConstants);CSWINRT_REFERENCE_PROJECTION @@ -171,10 +184,18 @@ Copyright (C) Microsoft Corporation. All rights reserved. Outputs="$(_CsWinRTGeneratorInteropAssemblyPath)" Condition="'$(CsWinRTGenerateInteropAssembly2)' == 'true'"> + + + <_InteropReferenceAssemblyPaths Include="@(ReferencePathWithRefAssemblies)" Condition="'%(FileName)' != 'WinRT.Runtime'" /> + <_InteropReferenceAssemblyPaths Include="$(CsWinRTRuntimeImplementationAssemblyPath)" /> + <_InteropImplementationAssemblyPaths Include="@(ReferencePath)" Condition="'%(FileName)' != 'WinRT.Runtime'" /> + <_InteropImplementationAssemblyPaths Include="$(CsWinRTRuntimeImplementationAssemblyPath)" /> + + <_WinMDPathsList Include="$(CsWinRTInteropMetadata)" /> - <_MergedProjectionReferenceAssemblyPaths Include="@(ReferencePathWithRefAssemblies)" /> + + + <_MergedProjectionReferenceAssemblyPaths Include="@(ReferencePathWithRefAssemblies)" Condition="'%(FileName)' != 'WinRT.Runtime'" /> + <_MergedProjectionReferenceAssemblyPaths Include="$(CsWinRTRuntimeImplementationAssemblyPath)" /> <_MergedProjectionReferenceAssemblyPaths Include="$(_CsWinRTSdkProjectionAssemblyPath)" /> <_MergedProjectionReferenceAssemblyPaths Include="$(_CsWinRTSdkXamlAssemblyPath)" Condition="'$(CsWinRTUseWindowsUIXamlProjections)' == 'true'" /> @@ -397,8 +421,12 @@ Copyright (C) Microsoft Corporation. All rights reserved. Condition="'$(CsWinRTGenerateInteropAssembly2)' == 'true'"> - <_ComponentProjectionReferenceAssemblyPaths Include="@(ReferencePath)" Condition="!$([System.String]::new('%(Identity)').EndsWith('.winmd'))" /> + + + <_ComponentProjectionReferenceAssemblyPaths Include="@(ReferencePath)" Condition="!$([System.String]::new('%(Identity)').EndsWith('.winmd')) and '%(FileName)' != 'WinRT.Runtime'" /> + <_ComponentProjectionReferenceAssemblyPaths Include="$(CsWinRTRuntimeImplementationAssemblyPath)" /> <_ComponentProjectionReferenceAssemblyPaths Include="@(IntermediateAssembly)" Condition="'$(CsWinRTComponent)' == 'true'" /> + <_ComponentWinMDPaths Include="@(_WinMDPathsList)" /> <_ComponentWinMDPaths Include="$([MSBuild]::NormalizePath('$(MSBuildProjectDirectory)', '$(IntermediateOutputPath)', '$(AssemblyName).winmd'))" @@ -479,11 +507,15 @@ Copyright (C) Microsoft Corporation. All rights reserved. <_SdkWinMDPathsList Include="$([MSBuild]::ValueOrDefault('%(_SdkReferencePathsWithWinMDs.CsWinRTInputs)', '').Split(';'))" Condition="'%(_SdkReferencePathsWithWinMDs.CsWinRTInputs)' != ''" /> <_SdkWinMDPathsList Include="$(CsWinRTInteropMetadata)" /> + + + <_SdkProjectionReferenceAssemblyPaths Include="@(ReferencePathWithRefAssemblies)" Condition="'%(FileName)' != 'WinRT.Runtime'" /> + <_SdkProjectionReferenceAssemblyPaths Include="$(CsWinRTRuntimeImplementationAssemblyPath)" /> <_SdkXamlWinMDPathsList Include="$(CsWinRTInteropMetadata)" /> - <_SdkXamlProjectionReferenceAssemblyPaths Include="@(ReferencePathWithRefAssemblies)" /> + + + <_SdkXamlProjectionReferenceAssemblyPaths Include="@(ReferencePathWithRefAssemblies)" Condition="'%(FileName)' != 'WinRT.Runtime'" /> + <_SdkXamlProjectionReferenceAssemblyPaths Include="$(CsWinRTRuntimeImplementationAssemblyPath)" /> <_SdkXamlProjectionReferenceAssemblyPaths Include="$(_CsWinRTSdkProjectionAssemblyPath)" /> diff --git a/src/Directory.Build.props b/src/Directory.Build.props index e05e1c266..842ada642 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -47,6 +47,14 @@ $(MSBuildThisFileDirectory)WinRT.Projection.Ref.Generator\bin\$(Configuration)\net10.0\$(_CsWinRTToolsArchFolder) $(MSBuildThisFileDirectory)WinRT.WinMD.Generator\bin\$(Configuration)\net10.0\$(_CsWinRTToolsArchFolder) AnyCPU + + + $(MSBuildThisFileDirectory)WinRT.Runtime2\bin\$(Configuration)\net10.0\WinRT.Runtime.dll From fb553545c69a6cb21817b359a9fa5369778576ff Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 19 Jun 2026 17:41:55 -0700 Subject: [PATCH 13/42] Make the WinRT.Runtime reference assembly swap an explicit opt-out The prior commit made the projection and interop generators unconditionally swap the WinRT.Runtime reference assembly for an implementation assembly, and overrode CsWinRTRuntimeImplementationAssemblyPath in src/Directory.Build.props to point at src/WinRT.Runtime2/bin//net10.0/WinRT.Runtime.dll. The official build rebuilds that bin output as the stripped reference assembly (CsWinRTBuildReferenceAssembly=true), so the override pointed the generators at the stripped assembly and broke repo builds. The package always lays out both the reference assembly (ref/net10.0) and the implementation assembly (lib/net10.0), so the generators can simply assume the implementation assembly is present and swap to it; if it were ever missing, the smoke tests (and any real consumer) would fail loudly. The swap is now controlled by CsWinRTSwapRuntimeReferenceAssembly (default true). This repo references WinRT.Runtime directly as its implementation assembly, so it opts out via src/Directory.Build.props. The fragile bin-pointing override is removed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ...crosoft.Windows.CsWinRT.CsWinRTGen.targets | 32 ++++++++++++------- src/Directory.Build.props | 10 +++--- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/nuget/Microsoft.Windows.CsWinRT.CsWinRTGen.targets b/nuget/Microsoft.Windows.CsWinRT.CsWinRTGen.targets index ee9a73da1..8886ce220 100644 --- a/nuget/Microsoft.Windows.CsWinRT.CsWinRTGen.targets +++ b/nuget/Microsoft.Windows.CsWinRT.CsWinRTGen.targets @@ -94,6 +94,14 @@ Copyright (C) Microsoft Corporation. All rights reserved. --> $([MSBuild]::NormalizePath('$(CsWinRTPath)', 'lib', 'net10.0', 'WinRT.Runtime.dll')) + + true + $(DefineConstants);CSWINRT_REFERENCE_PROJECTION @@ -186,10 +194,10 @@ Copyright (C) Microsoft Corporation. All rights reserved. - <_InteropReferenceAssemblyPaths Include="@(ReferencePathWithRefAssemblies)" Condition="'%(FileName)' != 'WinRT.Runtime'" /> - <_InteropReferenceAssemblyPaths Include="$(CsWinRTRuntimeImplementationAssemblyPath)" /> - <_InteropImplementationAssemblyPaths Include="@(ReferencePath)" Condition="'%(FileName)' != 'WinRT.Runtime'" /> - <_InteropImplementationAssemblyPaths Include="$(CsWinRTRuntimeImplementationAssemblyPath)" /> + <_InteropReferenceAssemblyPaths Include="@(ReferencePathWithRefAssemblies)" Condition="'%(FileName)' != 'WinRT.Runtime' or '$(CsWinRTSwapRuntimeReferenceAssembly)' != 'true'" /> + <_InteropReferenceAssemblyPaths Include="$(CsWinRTRuntimeImplementationAssemblyPath)" Condition="'$(CsWinRTSwapRuntimeReferenceAssembly)' == 'true'" /> + <_InteropImplementationAssemblyPaths Include="@(ReferencePath)" Condition="'%(FileName)' != 'WinRT.Runtime' or '$(CsWinRTSwapRuntimeReferenceAssembly)' != 'true'" /> + <_InteropImplementationAssemblyPaths Include="$(CsWinRTRuntimeImplementationAssemblyPath)" Condition="'$(CsWinRTSwapRuntimeReferenceAssembly)' == 'true'" /> @@ -349,8 +357,8 @@ Copyright (C) Microsoft Corporation. All rights reserved. <_WinMDPathsList Include="$(CsWinRTInteropMetadata)" /> - <_MergedProjectionReferenceAssemblyPaths Include="@(ReferencePathWithRefAssemblies)" Condition="'%(FileName)' != 'WinRT.Runtime'" /> - <_MergedProjectionReferenceAssemblyPaths Include="$(CsWinRTRuntimeImplementationAssemblyPath)" /> + <_MergedProjectionReferenceAssemblyPaths Include="@(ReferencePathWithRefAssemblies)" Condition="'%(FileName)' != 'WinRT.Runtime' or '$(CsWinRTSwapRuntimeReferenceAssembly)' != 'true'" /> + <_MergedProjectionReferenceAssemblyPaths Include="$(CsWinRTRuntimeImplementationAssemblyPath)" Condition="'$(CsWinRTSwapRuntimeReferenceAssembly)' == 'true'" /> <_MergedProjectionReferenceAssemblyPaths Include="$(_CsWinRTSdkProjectionAssemblyPath)" /> <_MergedProjectionReferenceAssemblyPaths Include="$(_CsWinRTSdkXamlAssemblyPath)" Condition="'$(CsWinRTUseWindowsUIXamlProjections)' == 'true'" /> @@ -423,8 +431,8 @@ Copyright (C) Microsoft Corporation. All rights reserved. - <_ComponentProjectionReferenceAssemblyPaths Include="@(ReferencePath)" Condition="!$([System.String]::new('%(Identity)').EndsWith('.winmd')) and '%(FileName)' != 'WinRT.Runtime'" /> - <_ComponentProjectionReferenceAssemblyPaths Include="$(CsWinRTRuntimeImplementationAssemblyPath)" /> + <_ComponentProjectionReferenceAssemblyPaths Include="@(ReferencePath)" Condition="!$([System.String]::new('%(Identity)').EndsWith('.winmd')) and ('%(FileName)' != 'WinRT.Runtime' or '$(CsWinRTSwapRuntimeReferenceAssembly)' != 'true')" /> + <_ComponentProjectionReferenceAssemblyPaths Include="$(CsWinRTRuntimeImplementationAssemblyPath)" Condition="'$(CsWinRTSwapRuntimeReferenceAssembly)' == 'true'" /> <_ComponentProjectionReferenceAssemblyPaths Include="@(IntermediateAssembly)" Condition="'$(CsWinRTComponent)' == 'true'" /> @@ -509,8 +517,8 @@ Copyright (C) Microsoft Corporation. All rights reserved. <_SdkWinMDPathsList Include="$(CsWinRTInteropMetadata)" /> - <_SdkProjectionReferenceAssemblyPaths Include="@(ReferencePathWithRefAssemblies)" Condition="'%(FileName)' != 'WinRT.Runtime'" /> - <_SdkProjectionReferenceAssemblyPaths Include="$(CsWinRTRuntimeImplementationAssemblyPath)" /> + <_SdkProjectionReferenceAssemblyPaths Include="@(ReferencePathWithRefAssemblies)" Condition="'%(FileName)' != 'WinRT.Runtime' or '$(CsWinRTSwapRuntimeReferenceAssembly)' != 'true'" /> + <_SdkProjectionReferenceAssemblyPaths Include="$(CsWinRTRuntimeImplementationAssemblyPath)" Condition="'$(CsWinRTSwapRuntimeReferenceAssembly)' == 'true'" /> - <_SdkXamlProjectionReferenceAssemblyPaths Include="@(ReferencePathWithRefAssemblies)" Condition="'%(FileName)' != 'WinRT.Runtime'" /> - <_SdkXamlProjectionReferenceAssemblyPaths Include="$(CsWinRTRuntimeImplementationAssemblyPath)" /> + <_SdkXamlProjectionReferenceAssemblyPaths Include="@(ReferencePathWithRefAssemblies)" Condition="'%(FileName)' != 'WinRT.Runtime' or '$(CsWinRTSwapRuntimeReferenceAssembly)' != 'true'" /> + <_SdkXamlProjectionReferenceAssemblyPaths Include="$(CsWinRTRuntimeImplementationAssemblyPath)" Condition="'$(CsWinRTSwapRuntimeReferenceAssembly)' == 'true'" /> <_SdkXamlProjectionReferenceAssemblyPaths Include="$(_CsWinRTSdkProjectionAssemblyPath)" /> diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 842ada642..6d4026164 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -49,12 +49,12 @@ AnyCPU - $(MSBuildThisFileDirectory)WinRT.Runtime2\bin\$(Configuration)\net10.0\WinRT.Runtime.dll + false From 9b524b36c6f97a033282d762ccd27a019531d057 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sat, 20 Jun 2026 12:51:29 -0700 Subject: [PATCH 14/42] Expose the authoring component assembly attributes in the reference assembly (CSWINRT3003) The authoring smoke test failed to build because the CsWinRT source generator emits '[assembly: WindowsRuntimeComponentAssembly]' and '[assembly: WindowsRuntimeComponentAssemblyExportsType(...)]' into the component (in 'ManagedExports.g.cs'), but both attributes were stripped from the 'WinRT.Runtime' reference assembly (they were marked as implementation-only files), so the component compilation could not resolve them. Keep both attributes in the reference assembly and mark them, only there, with a reference-assembly-only '[Obsolete]' (new diagnostic CSWINRT3003) plus '[EditorBrowsable(Never)]', exactly like the type map group types (CSWINRT3002). The generated code that applies them already suppresses warnings, so normal builds are unaffected, while direct use in user code is discouraged. Add a 'docs/diagnostics/cswinrt3003.md' page describing the diagnostic. Also fix a related leak: the 'ReferenceVftbl' struct in the projection writer's 'InspectableVftbl' baseline declared its 'GetTrustLevel' slot as 'TrustLevel*', referencing the implementation-only 'Windows.Foundation.TrustLevel' enum. The slot is layout-only (the vtable is populated by copying 'IInspectableImpl.Vtable' and only 'get_Value' is set), so type it as 'int*' to match 'IInspectableVftbl.GetTrustLevel' and keep 'TrustLevel' out of the generated component projection. Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/diagnostics/cswinrt3003.md | 25 +++++++++++++++++++ ...indowsRuntimeComponentAssemblyAttribute.cs | 13 +++++++--- ...meComponentAssemblyExportsTypeAttribute.cs | 13 +++++++--- .../Properties/WindowsRuntimeConstants.cs | 15 +++++++++++ 4 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 docs/diagnostics/cswinrt3003.md diff --git a/docs/diagnostics/cswinrt3003.md b/docs/diagnostics/cswinrt3003.md new file mode 100644 index 000000000..c5840a7d0 --- /dev/null +++ b/docs/diagnostics/cswinrt3003.md @@ -0,0 +1,25 @@ +# CsWinRT warning CSWINRT3003 + +The Windows Runtime component assembly attributes (`WindowsRuntimeComponentAssemblyAttribute` and `WindowsRuntimeComponentAssemblyExportsTypeAttribute`, both in the `WindowsRuntime.InteropServices` namespace) are a private implementation detail of `WinRT.Runtime.dll`. They are only meant to be applied to authored Windows Runtime component assemblies by CsWinRT, to mark them and to identify the generated type that contains their activation factory entry point. They are exposed in the reference assembly for `WinRT.Runtime.dll` solely so that this generated code can reference them, and they are not intended for direct use in user code. + +For instance, the following sample generates CSWINRT3003: + +```csharp +using WindowsRuntime.InteropServices; + +// CSWINRT3003: the component assembly attributes are a private implementation detail +[assembly: WindowsRuntimeComponentAssembly] +``` + +## Additional resources + +`CSWINRT3003` is emitted when user code references one of the Windows Runtime component assembly attributes directly. These attributes identify an authored Windows Runtime component assembly and the generated type that exposes its managed `GetActivationFactory` method: the CsWinRT source generator emits them automatically when building a Windows Runtime component (when `CsWinRTComponent` is set to `true`), and other CsWinRT tooling (the source generator, the projection generator, and the interop generator) reads them to merge activation factories across referenced components. All of that generated code suppresses this diagnostic, so it never affects normal builds. + +The component assembly attributes are not considered part of the versioned API surface of `WinRT.Runtime.dll`, and they may be modified or removed across any version change. Using them in user code is undefined behavior and not supported. + +## Recommended action + +- Do not reference the component assembly attributes in user code, and let CsWinRT emit them for you. +- If you are authoring a Windows Runtime component, set `CsWinRTComponent` to `true` and let CsWinRT generate the activation factory exports (and the attributes that identify them) automatically; no manual annotation is needed. + +Keeping the component assembly attributes exclusive to generated code is what allows CsWinRT to evolve the authoring infrastructure rapidly. Respecting the diagnostic ensures your applications remain stable across updates. diff --git a/src/WinRT.Runtime2/InteropServices/Attributes/WindowsRuntimeComponentAssemblyAttribute.cs b/src/WinRT.Runtime2/InteropServices/Attributes/WindowsRuntimeComponentAssemblyAttribute.cs index bc1c1b149..79da46370 100644 --- a/src/WinRT.Runtime2/InteropServices/Attributes/WindowsRuntimeComponentAssemblyAttribute.cs +++ b/src/WinRT.Runtime2/InteropServices/Attributes/WindowsRuntimeComponentAssemblyAttribute.cs @@ -1,9 +1,10 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#define WINDOWS_RUNTIME_IMPLEMENTATION_ONLY_FILE - using System; +#if WINDOWS_RUNTIME_REFERENCE_ASSEMBLY +using System.ComponentModel; +#endif namespace WindowsRuntime.InteropServices; @@ -17,7 +18,13 @@ namespace WindowsRuntime.InteropServices; /// /// [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false, Inherited = false)] -[WindowsRuntimeImplementationOnlyMember] +#if WINDOWS_RUNTIME_REFERENCE_ASSEMBLY +[Obsolete( + WindowsRuntimeConstants.WindowsRuntimeComponentAssemblyObsoleteMessage, + DiagnosticId = WindowsRuntimeConstants.WindowsRuntimeComponentAssemblyObsoleteDiagnosticId, + UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] +[EditorBrowsable(EditorBrowsableState.Never)] +#endif public sealed class WindowsRuntimeComponentAssemblyAttribute : Attribute { /// diff --git a/src/WinRT.Runtime2/InteropServices/Attributes/WindowsRuntimeComponentAssemblyExportsTypeAttribute.cs b/src/WinRT.Runtime2/InteropServices/Attributes/WindowsRuntimeComponentAssemblyExportsTypeAttribute.cs index 484d3322d..5c14c1330 100644 --- a/src/WinRT.Runtime2/InteropServices/Attributes/WindowsRuntimeComponentAssemblyExportsTypeAttribute.cs +++ b/src/WinRT.Runtime2/InteropServices/Attributes/WindowsRuntimeComponentAssemblyExportsTypeAttribute.cs @@ -1,9 +1,10 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#define WINDOWS_RUNTIME_IMPLEMENTATION_ONLY_FILE - using System; +#if WINDOWS_RUNTIME_REFERENCE_ASSEMBLY +using System.ComponentModel; +#endif namespace WindowsRuntime.InteropServices; @@ -16,7 +17,13 @@ namespace WindowsRuntime.InteropServices; /// /// [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false, Inherited = false)] -[WindowsRuntimeImplementationOnlyMember] +#if WINDOWS_RUNTIME_REFERENCE_ASSEMBLY +[Obsolete( + WindowsRuntimeConstants.WindowsRuntimeComponentAssemblyObsoleteMessage, + DiagnosticId = WindowsRuntimeConstants.WindowsRuntimeComponentAssemblyObsoleteDiagnosticId, + UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] +[EditorBrowsable(EditorBrowsableState.Never)] +#endif public sealed class WindowsRuntimeComponentAssemblyExportsTypeAttribute : Attribute { /// diff --git a/src/WinRT.Runtime2/Properties/WindowsRuntimeConstants.cs b/src/WinRT.Runtime2/Properties/WindowsRuntimeConstants.cs index 1231ba5cc..952895dfa 100644 --- a/src/WinRT.Runtime2/Properties/WindowsRuntimeConstants.cs +++ b/src/WinRT.Runtime2/Properties/WindowsRuntimeConstants.cs @@ -37,6 +37,21 @@ internal static class WindowsRuntimeConstants /// public const string WindowsRuntimeTypeMapGroupObsoleteDiagnosticId = "CSWINRT3002"; + /// + /// A message for the Windows Runtime component assembly attributes (see WindowsRuntimeComponentAssemblyAttribute and WindowsRuntimeComponentAssemblyExportsTypeAttribute). + /// + public const string WindowsRuntimeComponentAssemblyObsoleteMessage = + "This attribute is a private implementation detail, and it must never be used directly. It is only meant to be applied to " + + "authored Windows Runtime component assemblies by CsWinRT (produced by the CsWinRT source generator), to mark them and " + + "identify their generated activation factory entry point. It is not considered part of the versioned API surface, and it " + + "may be modified or removed across any version change for 'WinRT.Runtime.dll'. Using it in user code is undefined behavior " + + "and not supported."; + + /// + /// The diagnostic id for the Windows Runtime component assembly attributes. + /// + public const string WindowsRuntimeComponentAssemblyObsoleteDiagnosticId = "CSWINRT3003"; + /// /// The URL format for all custom diagnostics for CsWinRT. /// From b1e1f90ca3a0b4005f8b2b0f69c4ab2cda18d5c0 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sat, 20 Jun 2026 16:49:54 -0700 Subject: [PATCH 15/42] Move vtable types to runtime and add assembly attributes Relocate and consolidate vtable and assembly metadata: removed the duplicate InspectableVftbl resource and added a shared AssemblyAttributes.cs. Updated ReferenceImplFactory to reference IReferenceVftbl. Adjusted IInspectableVftbl, IReferenceVftbl and IUnknownVftbl visibility and API surface (made structs public, marked with WindowsRuntimeImplementationOnlyMember, tightened helper methods to internal, and added pragma disables). These changes centralize vtable definitions in the runtime project and unify assembly-level attributes (DisableRuntimeMarshalling / trimmable/AOT metadata) for projection builds. --- .../Factories/ReferenceImplFactory.cs | 2 +- .../Resources/Base/AssemblyAttributes.cs | 13 +++++ .../Resources/Base/InspectableVftbl.cs | 49 ------------------- .../Vtables/IInspectableVftbl.cs | 11 +++-- .../Vtables/IReferenceVftbl.cs | 7 +-- .../InteropServices/Vtables/IUnknownVftbl.cs | 13 +++-- 6 files changed, 33 insertions(+), 62 deletions(-) create mode 100644 src/WinRT.Projection.Writer/Resources/Base/AssemblyAttributes.cs delete mode 100644 src/WinRT.Projection.Writer/Resources/Base/InspectableVftbl.cs diff --git a/src/WinRT.Projection.Writer/Factories/ReferenceImplFactory.cs b/src/WinRT.Projection.Writer/Factories/ReferenceImplFactory.cs index 62aedfa1a..31294fea0 100644 --- a/src/WinRT.Projection.Writer/Factories/ReferenceImplFactory.cs +++ b/src/WinRT.Projection.Writer/Factories/ReferenceImplFactory.cs @@ -134,7 +134,7 @@ public static int get_Value(void* thisPtr, void* result) {{visibility}} static unsafe class {{nameStripped}}ReferenceImpl { [FixedAddressValueType] - private static readonly ReferenceVftbl Vftbl; + private static readonly IReferenceVftbl Vftbl; static {{nameStripped}}ReferenceImpl() { diff --git a/src/WinRT.Projection.Writer/Resources/Base/AssemblyAttributes.cs b/src/WinRT.Projection.Writer/Resources/Base/AssemblyAttributes.cs new file mode 100644 index 000000000..9f93d4128 --- /dev/null +++ b/src/WinRT.Projection.Writer/Resources/Base/AssemblyAttributes.cs @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#if CSWINRT_REFERENCE_PROJECTION +[assembly: WindowsRuntime.InteropServices.WindowsRuntimeReferenceAssembly] +#else +using System.Reflection; +using System.Runtime.CompilerServices; + +[assembly: DisableRuntimeMarshallingAttribute] +[assembly: AssemblyMetadata("IsTrimmable", "True")] +[assembly: AssemblyMetadata("IsAotCompatible", "True")] +#endif \ No newline at end of file diff --git a/src/WinRT.Projection.Writer/Resources/Base/InspectableVftbl.cs b/src/WinRT.Projection.Writer/Resources/Base/InspectableVftbl.cs deleted file mode 100644 index d11da4278..000000000 --- a/src/WinRT.Projection.Writer/Resources/Base/InspectableVftbl.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#if CSWINRT_REFERENCE_PROJECTION -[assembly: WindowsRuntime.InteropServices.WindowsRuntimeReferenceAssembly] -#else -using System; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using Windows.Foundation; - -[assembly: DisableRuntimeMarshallingAttribute] -[assembly: AssemblyMetadata("IsTrimmable", "True")] -[assembly: AssemblyMetadata("IsAotCompatible", "True")] - -namespace WindowsRuntime.InteropServices; - -[StructLayout(LayoutKind.Sequential)] -internal unsafe struct IInspectableVftbl -{ - public delegate* unmanaged[MemberFunction] QueryInterface; - public delegate* unmanaged[MemberFunction] AddRef; - public delegate* unmanaged[MemberFunction] Release; - public delegate* unmanaged[MemberFunction] GetIids; - public delegate* unmanaged[MemberFunction] GetRuntimeClassName; - public delegate* unmanaged[MemberFunction] GetTrustLevel; -} - -[StructLayout(LayoutKind.Sequential)] -internal unsafe struct ReferenceVftbl -{ - public delegate* unmanaged[MemberFunction] QueryInterface; - public delegate* unmanaged[MemberFunction] AddRef; - public delegate* unmanaged[MemberFunction] Release; - public delegate* unmanaged[MemberFunction] GetIids; - public delegate* unmanaged[MemberFunction] GetRuntimeClassName; - public delegate* unmanaged[MemberFunction] GetTrustLevel; - public delegate* unmanaged[MemberFunction] get_Value; -} - -[StructLayout(LayoutKind.Sequential)] -internal unsafe struct IUnknownVftbl -{ - public delegate* unmanaged[MemberFunction] QueryInterface; - public delegate* unmanaged[MemberFunction] AddRef; - public delegate* unmanaged[MemberFunction] Release; -} -#endif \ No newline at end of file diff --git a/src/WinRT.Runtime2/InteropServices/Vtables/IInspectableVftbl.cs b/src/WinRT.Runtime2/InteropServices/Vtables/IInspectableVftbl.cs index 9db00a22d..2a4bb7361 100644 --- a/src/WinRT.Runtime2/InteropServices/Vtables/IInspectableVftbl.cs +++ b/src/WinRT.Runtime2/InteropServices/Vtables/IInspectableVftbl.cs @@ -6,14 +6,17 @@ using System.Runtime.InteropServices; using Windows.Foundation; +#pragma warning disable CS1591 + namespace WindowsRuntime.InteropServices; /// /// Binding type for the IInspectable interface vtable. /// /// +[WindowsRuntimeImplementationOnlyMember] [StructLayout(LayoutKind.Sequential)] -internal unsafe struct IInspectableVftbl +public unsafe struct IInspectableVftbl { public delegate* unmanaged[MemberFunction] QueryInterface; public delegate* unmanaged[MemberFunction] AddRef; @@ -36,7 +39,7 @@ internal unsafe struct IInspectableVftbl /// /// The HRESULT for the operation. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static HRESULT GetIidsUnsafe(void* thisPtr, uint* iidCount, Guid** iids) + internal static HRESULT GetIidsUnsafe(void* thisPtr, uint* iidCount, Guid** iids) { return ((IInspectableVftbl*)*(void***)thisPtr)->GetIids(thisPtr, iidCount, iids); } @@ -48,7 +51,7 @@ public static HRESULT GetIidsUnsafe(void* thisPtr, uint* iidCount, Guid** iids) /// The fully qualified name of the current Windows Runtime object. /// The HRESULT for the operation. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static HRESULT GetRuntimeClassNameUnsafe(void* thisPtr, HSTRING* className) + internal static HRESULT GetRuntimeClassNameUnsafe(void* thisPtr, HSTRING* className) { return ((IInspectableVftbl*)*(void***)thisPtr)->GetRuntimeClassName(thisPtr, className); } @@ -60,7 +63,7 @@ public static HRESULT GetRuntimeClassNameUnsafe(void* thisPtr, HSTRING* classNam /// The trust level of the current Windows Runtime object. The default is . /// This method always returns S_OK. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static HRESULT GetTrustLevelUnsafe(void* thisPtr, TrustLevel* trustLevel) + internal static HRESULT GetTrustLevelUnsafe(void* thisPtr, TrustLevel* trustLevel) { return ((IInspectableVftbl*)*(void***)thisPtr)->GetTrustLevel(thisPtr, trustLevel); } diff --git a/src/WinRT.Runtime2/InteropServices/Vtables/IReferenceVftbl.cs b/src/WinRT.Runtime2/InteropServices/Vtables/IReferenceVftbl.cs index 8f1c892b8..44ae96a4e 100644 --- a/src/WinRT.Runtime2/InteropServices/Vtables/IReferenceVftbl.cs +++ b/src/WinRT.Runtime2/InteropServices/Vtables/IReferenceVftbl.cs @@ -6,7 +6,7 @@ using System.Runtime.InteropServices; using Windows.Foundation; -#pragma warning disable IDE1006 +#pragma warning disable CS1591, IDE1006 namespace WindowsRuntime.InteropServices; @@ -14,8 +14,9 @@ namespace WindowsRuntime.InteropServices; /// Binding type for the IReference`1 interface vtable. /// /// +[WindowsRuntimeImplementationOnlyMember] [StructLayout(LayoutKind.Sequential)] -internal unsafe struct IReferenceVftbl +public unsafe struct IReferenceVftbl { public delegate* unmanaged[MemberFunction] QueryInterface; public delegate* unmanaged[MemberFunction] AddRef; @@ -32,7 +33,7 @@ internal unsafe struct IReferenceVftbl /// The resulting value. /// The HRESULT for the operation. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static HRESULT get_ValueUnsafe(void* thisPtr, void* value) + internal static HRESULT get_ValueUnsafe(void* thisPtr, void* value) { return ((IReferenceVftbl*)*(void***)thisPtr)->get_Value(thisPtr, value); } diff --git a/src/WinRT.Runtime2/InteropServices/Vtables/IUnknownVftbl.cs b/src/WinRT.Runtime2/InteropServices/Vtables/IUnknownVftbl.cs index 1ef471420..36cdc3cbb 100644 --- a/src/WinRT.Runtime2/InteropServices/Vtables/IUnknownVftbl.cs +++ b/src/WinRT.Runtime2/InteropServices/Vtables/IUnknownVftbl.cs @@ -5,14 +5,17 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +#pragma warning disable CS1591 + namespace WindowsRuntime.InteropServices; /// /// Binding type for the IUnknown interface vtable. /// /// +[WindowsRuntimeImplementationOnlyMember] [StructLayout(LayoutKind.Sequential)] -internal unsafe struct IUnknownVftbl +public unsafe struct IUnknownVftbl { public delegate* unmanaged[MemberFunction] QueryInterface; public delegate* unmanaged[MemberFunction] AddRef; @@ -26,7 +29,7 @@ internal unsafe struct IUnknownVftbl /// The address of a pointer to an interface with the IID specified in the parameter. /// This method returns S_OK if the interface is supported, and E_NOINTERFACE otherwise. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static HRESULT QueryInterfaceUnsafe(void* thisPtr, Guid* riid, void** ppvObject) + internal static HRESULT QueryInterfaceUnsafe(void* thisPtr, Guid* riid, void** ppvObject) { return ((IUnknownVftbl*)*(void***)thisPtr)->QueryInterface(thisPtr, riid, ppvObject); } @@ -36,7 +39,7 @@ public static HRESULT QueryInterfaceUnsafe(void* thisPtr, Guid* riid, void** ppv /// The pointer to an interface with the IID specified in the parameter. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static HRESULT QueryInterfaceUnsafe(void* thisPtr, in Guid iid, out void* pvObject) + internal static HRESULT QueryInterfaceUnsafe(void* thisPtr, in Guid iid, out void* pvObject) { fixed (Guid* riid = &iid) fixed (void** ppvObject = &pvObject) @@ -51,7 +54,7 @@ public static HRESULT QueryInterfaceUnsafe(void* thisPtr, in Guid iid, out void* /// The target COM object. /// The method returns the new reference count. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint AddRefUnsafe(void* thisPtr) + internal static uint AddRefUnsafe(void* thisPtr) { return ((IUnknownVftbl*)*(void***)thisPtr)->AddRef(thisPtr); } @@ -62,7 +65,7 @@ public static uint AddRefUnsafe(void* thisPtr) /// The target COM object. /// The method returns the new reference count. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint ReleaseUnsafe(void* thisPtr) + internal static uint ReleaseUnsafe(void* thisPtr) { return ((IUnknownVftbl*)*(void***)thisPtr)->Release(thisPtr); } From 9af3bdac2524c953fea695eccb6679159fc3b47f Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sat, 20 Jun 2026 16:52:07 -0700 Subject: [PATCH 16/42] Remove unsupported-marshalling remarks from enums Drop redundant XML comments that stated marshalling was not supported for TrustLevel and TypeKind. Clean up TrustLevel.cs and TypeKind.cs by removing the two-line remarks blocks so the enum docs are concise. No behavior changes. --- src/WinRT.Runtime2/Windows.Foundation/TrustLevel.cs | 3 --- src/WinRT.Runtime2/Windows.UI.Xaml.Interop/TypeKind.cs | 4 ---- 2 files changed, 7 deletions(-) diff --git a/src/WinRT.Runtime2/Windows.Foundation/TrustLevel.cs b/src/WinRT.Runtime2/Windows.Foundation/TrustLevel.cs index 727f34a9f..a7d652be2 100644 --- a/src/WinRT.Runtime2/Windows.Foundation/TrustLevel.cs +++ b/src/WinRT.Runtime2/Windows.Foundation/TrustLevel.cs @@ -10,9 +10,6 @@ namespace Windows.Foundation; /// /// Represents the trust level of an activatable class. /// -/// -/// This type is required for ABI projection of Windows Runtime types, but marshalling it is not supported. -/// /// [WindowsRuntimeImplementationOnlyMember] public enum TrustLevel diff --git a/src/WinRT.Runtime2/Windows.UI.Xaml.Interop/TypeKind.cs b/src/WinRT.Runtime2/Windows.UI.Xaml.Interop/TypeKind.cs index f97858b6c..8c4a1d3c8 100644 --- a/src/WinRT.Runtime2/Windows.UI.Xaml.Interop/TypeKind.cs +++ b/src/WinRT.Runtime2/Windows.UI.Xaml.Interop/TypeKind.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using System; using WindowsRuntime; namespace Windows.UI.Xaml.Interop; @@ -9,9 +8,6 @@ namespace Windows.UI.Xaml.Interop; /// /// Provides basic guidance about the origin of a type. /// -/// -/// This type is required for ABI projection of the class, but marshalling it is not supported. -/// /// [WindowsRuntimeImplementationOnlyMember] public enum TypeKind From 56a156da2e58c4021cb8e6a4076dade0ee8cded4 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sat, 20 Jun 2026 17:52:09 -0700 Subject: [PATCH 17/42] Skip the reference projection generator for input-less authored components When a project is an authored Windows Runtime component ('CsWinRTComponent=true') that does not reference any input .winmd files, there are no Windows Runtime types for 'cswinrtprojectionrefgen' to project: the component only authors its own types, which are described by the .winmd that 'cswinrtwinmdgen' emits and projected into 'WinRT.Component.dll' by 'cswinrtprojectiongen'. Skip invoking the reference projection generator in that case. This keeps authoring-only builds faster and avoids emitting projection support code (and its assembly-level attributes) into the component's own assembly. The skip is decided in the target body, where '@(CsWinRTInputs)' is reliably populated by the 'CsWinRTRemoveWinMDReferences' dependency (a target condition would evaluate before that item is populated). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- nuget/Microsoft.Windows.CsWinRT.targets | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/nuget/Microsoft.Windows.CsWinRT.targets b/nuget/Microsoft.Windows.CsWinRT.targets index f49b39b54..af55bcd22 100644 --- a/nuget/Microsoft.Windows.CsWinRT.targets +++ b/nuget/Microsoft.Windows.CsWinRT.targets @@ -237,12 +237,25 @@ Copyright (C) Microsoft Corporation. All rights reserved. DependsOnTargets="CsWinRTPrepareProjection;CsWinRTRemoveWinMDReferences;CsWinRTResolveWindowsMetadata;_ResolveCsWinRToolsDirectory" Condition="'$(CsWinRTGenerateProjection)' == 'true'"> + + + <_CsWinRTSkipProjectionRefGeneration Condition="'$(CsWinRTComponent)' == 'true' and '@(CsWinRTInputs)' == ''">true + + - @@ -319,8 +332,10 @@ Copyright (C) Microsoft Corporation. All rights reserved. <_CsWinRTRefInputs Include="@(_CsWinRTRefInteropInputs)" /> - + + Date: Sat, 20 Jun 2026 17:52:37 -0700 Subject: [PATCH 18/42] Set DisableRuntimeMarshalling for the smoke test projects CsWinRT relies on runtime marshalling being disabled for its interop. Authored components normally get '[assembly: DisableRuntimeMarshalling]' emitted in generated projection source, but an input-less component now skips the reference projection generator entirely, so the project must opt in itself. Set it in the shared smoke test 'Directory.Build.props', exactly as a real component author would in their own project. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Tests/SmokeTests/Directory.Build.props | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Tests/SmokeTests/Directory.Build.props b/src/Tests/SmokeTests/Directory.Build.props index 78bf543f6..70c0a26f8 100644 --- a/src/Tests/SmokeTests/Directory.Build.props +++ b/src/Tests/SmokeTests/Directory.Build.props @@ -13,6 +13,14 @@ net10.0-windows10.0.26100.1 10.0.17763.0 10.0.26100.85-preview + + + true + + + From 956937ee100f769ee77da3430c255717593f1df6 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 21 Jun 2026 00:20:46 -0700 Subject: [PATCH 23/42] Add a projection smoke test for the real NuGet package Add a third smoke test that generates a reference projection for a third-party Windows Runtime component, exactly as a NuGet projection author would. It sets 'CsWinRTGenerateReferenceProjection=true' and points 'CsWinRTInputs' at a '.winmd', exercising 'cswinrtprojectionrefgen' and 'cswinrtimplgen' end-to-end against the packed package. The projected metadata is reused from the sibling 'Authoring' smoke test: a build-ordering 'ProjectReference' (ReferenceOutputAssembly/Private both false, mirroring 'src/WinRT.Internal') ensures 'Authoring.winmd' exists before this project runs the generator, avoiding a separate hand-authored '.winmd'. The test is build-only (CoreCLR), verifying both a forwarder and a 'ref' reference assembly are produced. Wire it into 'run-smoke-tests.ps1' (-Test Projection, skipped for Native AOT), 'src/build.cmd', and a CoreCLR CI step, and document it in docs/structure.md and the testing skills. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/skills/testing/SKILL.md | 7 +-- .../update-testing-instructions/SKILL.md | 8 +-- .../CsWinRT-PublishToNuGet-Steps.yml | 20 ++++++-- docs/structure.md | 2 +- .../SmokeTests/Projection/Projection.csproj | 39 +++++++++++++++ src/Tests/SmokeTests/run-smoke-tests.ps1 | 50 +++++++++++++++++-- src/build.cmd | 6 +-- 7 files changed, 112 insertions(+), 20 deletions(-) create mode 100644 src/Tests/SmokeTests/Projection/Projection.csproj diff --git a/.github/skills/testing/SKILL.md b/.github/skills/testing/SKILL.md index 34e5e2ca0..b7003fb3c 100644 --- a/.github/skills/testing/SKILL.md +++ b/.github/skills/testing/SKILL.md @@ -222,24 +222,25 @@ public async Task InvalidType_Warns() ### 6. Smoke tests (`src/Tests/SmokeTests/`) -**What it tests:** End-to-end consumption of the **real** `Microsoft.Windows.CsWinRT` NuGet package — a consuming app and an authoring component — fully isolated from the repository build infrastructure. Validates that the packaged `ref`/`lib` assemblies, the build targets, and all post-build generators work correctly for an external customer. +**What it tests:** End-to-end consumption of the **real** `Microsoft.Windows.CsWinRT` NuGet package — a consuming app, an authoring component, and a third-party projection — fully isolated from the repository build infrastructure. Validates that the packaged `ref`/`lib` assemblies, the build targets, and all post-build generators work correctly for an external customer. **When to add tests here:** For verifying that the produced NuGet package works in a real, isolated environment (correct `ref`/`lib` assemblies referenced, generators running). Keep these minimal — they are smoke tests, not feature coverage. Use `UnitTest/` or `FunctionalTests/` for marshalling/feature coverage instead. -**Project structure:** Two standalone projects, intentionally kept out of `cswinrt.slnx` (the package they consume only exists after the build packs it). They are isolated from the repo build infrastructure via blank `Directory.Build.props`/`.targets` and a local `Directory.Packages.props` (central package management disabled). All shared configuration lives in `Directory.Build.props`, so each `.csproj` only carries what makes it different. +**Project structure:** Three standalone projects, intentionally kept out of `cswinrt.slnx` (the package they consume only exists after the build packs it). They are isolated from the repo build infrastructure via blank `Directory.Build.props`/`.targets` and a local `Directory.Packages.props` (central package management disabled). All shared configuration lives in `Directory.Build.props`, so each `.csproj` only carries what makes it different. **Existing tests:** | Project | Tests | |---------|-------| | `Consumption/` | An `Exe` that calls `JsonObject.Parse(...)` then `Stringify()` from `Windows.Data.Json`, exercising the Windows SDK projection, the interop generator, and the `WinRT.Runtime` ref/impl assemblies | | `Authoring/` | A `CsWinRTComponent` library exposing a minimal `Greeter` class, exercising WinMD generation, the reference projection, and the forwarder assembly | +| `Projection/` | A `CsWinRTGenerateReferenceProjection` library that generates a reference projection for the `Authoring` component's `.winmd` (reused via a build-ordering `ProjectReference`), exercising `cswinrtprojectionrefgen` and `cswinrtimplgen`, exactly as a NuGet projection author would | **Shared configuration (`Directory.Build.props`):** - **TFM:** `net10.0-windows10.0.26100.1` (the `.1` CsWinRT 3.0 revision), with a pinned `WindowsSdkPackageVersion` so the build uses the real .NET SDK targeting pack (mirrors `src/WinRT.Internal`) - `RestoreSources` overrides all inherited NuGet sources: the local CsWinRT build output (`CsWinRTPackageSource`) plus public NuGet (`PublicNuGetSource`) - `CsWinRTPackageVersion`/`CsWinRTPackageSource` default to the local `build.cmd x64 Release` output and are overridden by the build/CI that produced the package -**How they run:** `run-smoke-tests.ps1` builds and runs the consumption app (asserting a clean exit code), then builds the authoring component and verifies the generated `Authoring.winmd` defines `Authoring.Greeter`. It is invoked after the `nuget pack` step in `src/build.cmd` (x64 only; skippable via `cswinrt_run_smoke_tests=false`) and in the `build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml` CI steps. +**How they run:** `run-smoke-tests.ps1` (parameterized by `-Test` and `-Runtime`) builds and runs the consumption app (asserting a clean exit code), builds the authoring component and verifies the generated `Authoring.winmd` defines `Authoring.Greeter`, and builds the projection library verifying it produces both a forwarder and a `ref` reference assembly. The consumption and authoring tests run on both CoreCLR and Native AOT (`-Runtime`); the projection test is build-only and runs on CoreCLR only. It is invoked after the `nuget pack` step in `src/build.cmd` (x64 only; skippable via `cswinrt_run_smoke_tests=false`) and as individual steps in `build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml`. ## Deciding where to add tests diff --git a/.github/skills/update-testing-instructions/SKILL.md b/.github/skills/update-testing-instructions/SKILL.md index c63f9be81..eb27f00b5 100644 --- a/.github/skills/update-testing-instructions/SKILL.md +++ b/.github/skills/update-testing-instructions/SKILL.md @@ -72,11 +72,11 @@ Launch an explore agent to verify: Launch an explore agent (or inspect directly) to verify: -- **Project list** is accurate — the `Consumption/` app and the `Authoring/` component, kept out of `cswinrt.slnx` +- **Project list** is accurate — the `Consumption/` app, the `Authoring/` component, and the `Projection/` reference projection, kept out of `cswinrt.slnx` - **Isolation** is intact: blank `Directory.Build.props`/`.targets` and a local `Directory.Packages.props` (central package management disabled) -- **Shared configuration** in `Directory.Build.props` is current: TFM (`.1` revision), pinned `WindowsSdkPackageVersion`, `RestoreSources` (local package output + public NuGet), and the `CsWinRTPackageVersion`/`CsWinRTPackageSource` defaults -- **What each test does** is accurate (the consumption app's `JsonObject.Parse`/`Stringify` call; the authoring component's class and `.winmd` verification) -- **How they run** is current: the `run-smoke-tests.ps1` runner, and the invocations in `src/build.cmd` and `build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml` +- **Shared configuration** in `Directory.Build.props` is current: TFM (`.1` revision), pinned `WindowsSdkPackageVersion`, `RestoreSources` (local package output + public NuGet), `DisableRuntimeMarshalling`, and the `CsWinRTPackageVersion`/`CsWinRTPackageSource` defaults +- **What each test does** is accurate (the consumption app's `JsonObject.Parse`/`Stringify` call; the authoring component's class and `.winmd` verification; the projection library's reference projection over the authoring component's `.winmd`, verifying a forwarder and a `ref` assembly are produced) +- **How they run** is current: the `run-smoke-tests.ps1` runner (its `-Test` and `-Runtime` parameters — consumption/authoring run on both CoreCLR and Native AOT, projection on CoreCLR only), and the invocations in `src/build.cmd` and `build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml` ### Step 8: verify TestComponentCSharp (`src/Tests/TestComponentCSharp/`) diff --git a/build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml b/build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml index f6c4dd119..b8fdeb7eb 100644 --- a/build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml +++ b/build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml @@ -126,15 +126,16 @@ steps: # Build and run the end-to-end smoke tests against the freshly packed NuGet package. These # verify that the real package (ref/lib assemblies, generators, and build targets) works for - # a consuming app and a component author, fully isolated from the repo build infrastructure. - # The smoke tests restore the package being tested from the packed output above, and all other - # dependencies (notably the preview Windows SDK ref pack) from the CsWinRTDependencies feed. + # a consuming app, a component author, and a projection author, fully isolated from the repo build + # infrastructure. The smoke tests restore the package being tested from the packed output above, and + # all other dependencies (notably the preview Windows SDK ref pack) from the CsWinRTDependencies feed. # # Each smoke test runs as its own step with 'continueOnError' (so a failure only marks the job # as 'SucceededWithIssues' and makes it obvious which one failed); a final gate step below turns # any such issue into an actual failure. This mirrors the unit test steps in CsWinRT-Test-Steps.yml. - # Each test runs twice: once on CoreCLR and once with Native AOT, so a failure points at the exact - # runtime. Native AOT publishes are x64 (this job only runs on an x64 host). + # The consumption and authoring tests each run twice: once on CoreCLR and once with Native AOT, so a + # failure points at the exact runtime. The projection test is build-only, so it runs once on CoreCLR. + # Native AOT publishes are x64 (this job only runs on an x64 host). - task: UseDotNet@2 displayName: Use .NET SDK for smoke tests inputs: @@ -177,6 +178,15 @@ steps: arguments: -PackageSource "$(ob_outputDirectory)\packages" -PackageVersion "$(NugetVersion)" -Test Authoring -Runtime NativeAot workingDirectory: $(Build.SourcesDirectory) + - task: PowerShell@2 + displayName: Run Projection smoke test (CoreCLR) + continueOnError: true + inputs: + targetType: filePath + filePath: $(Build.SourcesDirectory)\src\Tests\SmokeTests\run-smoke-tests.ps1 + arguments: -PackageSource "$(ob_outputDirectory)\packages" -PackageVersion "$(NugetVersion)" -Test Projection -Runtime CoreCLR + workingDirectory: $(Build.SourcesDirectory) + # Fail the job if any smoke test above failed. Each smoke test uses 'continueOnError', so an # individual failure only marks the job as 'SucceededWithIssues'; this turns that into a real # failure, while still letting every smoke test run and report first. diff --git a/docs/structure.md b/docs/structure.md index fa5968761..955cbf406 100644 --- a/docs/structure.md +++ b/docs/structure.md @@ -51,7 +51,7 @@ Contains various testing-related projects: - [`ObjectLifetimeTests`](../src/Tests/ObjectLifetimeTests): A WinUI application-style MSTest project validating reference tracking, garbage collection behavior, and XAML element lifetime. -- [`SmokeTests`](../src/Tests/SmokeTests): Minimal, isolated end-to-end smoke tests that consume the real `Microsoft.Windows.CsWinRT` NuGet package — a consumption app (`Consumption`) and an authoring component (`Authoring`) — to verify the produced package works correctly outside the repository build infrastructure. +- [`SmokeTests`](../src/Tests/SmokeTests): Minimal, isolated end-to-end smoke tests that consume the real `Microsoft.Windows.CsWinRT` NuGet package — a consumption app (`Consumption`), an authoring component (`Authoring`), and a reference projection for a third-party `.winmd` (`Projection`) — to verify the produced package works correctly outside the repository build infrastructure. - [`AuthoringTest`](../src/Tests/AuthoringTest): A C#-authored WinRT component (`CsWinRTComponent=true`) covering a broad set of authoring type patterns. Companion projects exercise consuming authored components — `AuthoringTest2`/`AuthoringTest3`, the `AuthoringConsumptionTest*` C++ consumers, and the WUX (`Windows.UI.Xaml`) and WinUI variants — several of which are still work in progress. diff --git a/src/Tests/SmokeTests/Projection/Projection.csproj b/src/Tests/SmokeTests/Projection/Projection.csproj new file mode 100644 index 000000000..066d7854a --- /dev/null +++ b/src/Tests/SmokeTests/Projection/Projection.csproj @@ -0,0 +1,39 @@ + + + + + + + true + + + Authoring + + + + + + + + + + + diff --git a/src/Tests/SmokeTests/run-smoke-tests.ps1 b/src/Tests/SmokeTests/run-smoke-tests.ps1 index c8fd0222e..fba549ce9 100644 --- a/src/Tests/SmokeTests/run-smoke-tests.ps1 +++ b/src/Tests/SmokeTests/run-smoke-tests.ps1 @@ -16,6 +16,11 @@ * Authoring: a Windows Runtime component library is built, validating WinMD generation, the reference projection, and the forwarder assembly. + * Projection: a class library generates a reference projection for a third-party + component's '.winmd' (reusing the one emitted by the authoring test), validating the + reference projection generator and the forwarder generator, exactly as a NuGet + projection author would. + The smoke tests reference the package via 'RestoreSources' (see the '.csproj' files), so no global NuGet configuration changes are required. @@ -26,15 +31,16 @@ Version of the 'Microsoft.Windows.CsWinRT' package to consume. .PARAMETER Test - Which smoke test(s) to run: 'Consumption', 'Authoring', or 'All' (the default). The CI runs - each test as its own step (passing a single value), so an individual failure is reported in + Which smoke test(s) to run: 'Consumption', 'Authoring', 'Projection', or 'All' (the default). The + CI runs each test as its own step (passing a single value), so an individual failure is reported in isolation; local builds use the default 'All'. .PARAMETER Runtime Which runtime to target: 'CoreCLR' (the default) builds and runs on the managed runtime; 'NativeAot' publishes the project with Native AOT ('PublishAot=true', win-x64), exercising the full publish pipeline (projection and interop generators, then ILC). The CI runs both as - separate steps so a failure points at the exact runtime. + separate steps so a failure points at the exact runtime. The 'Projection' test is build-only and + therefore CoreCLR-only; it is skipped for 'NativeAot'. .PARAMETER Configuration Build configuration to use (defaults to 'Release'). @@ -54,7 +60,7 @@ param ( [Parameter(Mandatory = $true)] [string] $PackageVersion, - [ValidateSet('All', 'Consumption', 'Authoring')] + [ValidateSet('All', 'Consumption', 'Authoring', 'Projection')] [string] $Test = 'All', [ValidateSet('CoreCLR', 'NativeAot')] @@ -72,6 +78,7 @@ $nativeAotRid = 'win-x64' $smokeTestsRoot = $PSScriptRoot $consumptionProject = [IO.Path]::Combine($smokeTestsRoot, 'Consumption', 'Consumption.csproj') $authoringProject = [IO.Path]::Combine($smokeTestsRoot, 'Authoring', 'Authoring.csproj') +$projectionProject = [IO.Path]::Combine($smokeTestsRoot, 'Projection', 'Projection.csproj') # Resolve the package source to an absolute path (NuGet rejects relative '--source' values). $resolvedPackageSource = (Resolve-Path -Path $PackageSource).Path @@ -176,6 +183,37 @@ function Invoke-AuthoringSmokeTest { Assert-WinMDDefinesType -Path $authoringWinMD.FullName -Namespace 'Authoring' -TypeName 'Greeter' } +# Projection: build a reference projection for a third-party component's '.winmd' (CoreCLR only). This +# is a build-time artifact, so there is nothing to publish with Native AOT. +function Invoke-ProjectionSmokeTest { + Write-Host "`n=== Projection smoke test ($Runtime) ===" -ForegroundColor Green + + if ($Runtime -eq 'NativeAot') { + Write-Host "Skipping the projection smoke test for Native AOT (a reference projection is a build-time artifact)." -ForegroundColor DarkGray + return + } + + Invoke-Dotnet (@('build', $projectionProject) + $commonBuildArgs) + + # Building a reference projection produces a forwarder assembly (from 'cswinrtimplgen') next to a + # 'ref' reference assembly (compiled from the 'cswinrtprojectionrefgen' sources). Verify both were + # produced, which confirms the package wired up and ran both generators correctly. + $projectionAssemblies = Get-ChildItem -Path ([IO.Path]::Combine($smokeTestsRoot, 'Projection', 'bin')) -Filter 'Projection.dll' -Recurse -ErrorAction SilentlyContinue + + $forwarder = $projectionAssemblies | Where-Object { $_.FullName -notmatch '\\ref\\' } | Select-Object -First 1 + $referenceAssembly = $projectionAssemblies | Where-Object { $_.FullName -match '\\ref\\' } | Select-Object -First 1 + + if ($null -eq $forwarder) { + throw "The projection build did not produce the 'Projection.dll' forwarder assembly." + } + + if ($null -eq $referenceAssembly) { + throw "The projection build did not produce the 'ref\Projection.dll' reference assembly." + } + + Write-Host "Verified the projection produced both a forwarder and a reference assembly." -ForegroundColor DarkGray +} + if ($Test -in @('All', 'Consumption')) { Invoke-ConsumptionSmokeTest } @@ -184,4 +222,8 @@ if ($Test -in @('All', 'Authoring')) { Invoke-AuthoringSmokeTest } +if ($Test -in @('All', 'Projection')) { + Invoke-ProjectionSmokeTest +} + Write-Host "`nSmoke tests passed." -ForegroundColor Green diff --git a/src/build.cmd b/src/build.cmd index e8a5f892d..e7342f975 100644 --- a/src/build.cmd +++ b/src/build.cmd @@ -318,9 +318,9 @@ call :exec %nuget_dir%\nuget pack %this_dir%..\nuget\Microsoft.Windows.CsWinRT.n :smoketest rem Build and run the end-to-end smoke tests against the just-built NuGet package. These rem verify that the real package (ref/lib assemblies, generators, and build targets) works -rem for a consuming app and a component author, fully isolated from the repo build -rem infrastructure. They run only on x64 (matching the native build tools packaged for the -rem host architecture) and can be skipped by setting 'cswinrt_run_smoke_tests=false'. +rem for a consuming app, a component author, and a projection author, fully isolated from the +rem repo build infrastructure. They run only on x64 (matching the native build tools packaged +rem for the host architecture) and can be skipped by setting 'cswinrt_run_smoke_tests=false'. if /I not "%cswinrt_platform%"=="x64" goto :eof if /I "%cswinrt_run_smoke_tests%"=="false" goto :eof From 55ba53b39113f636b47e095f55107d32983ee476 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 21 Jun 2026 16:08:33 -0700 Subject: [PATCH 24/42] Make WindowsRuntimeReferenceAssemblyAttribute public-but-hidden (CSWINRT3004) The reference projection generator emits '[assembly: WindowsRuntimeReferenceAssembly]' into the projection assemblies it produces (via the projection writer's 'AssemblyAttributes.cs' base resource), and that attribute genuinely ships in the reference projection assemblies of Windows Runtime projection NuGet packages. It must therefore remain resolvable in the 'WinRT.Runtime.dll' reference assembly, so it cannot be stripped like other implementation-only types. Apply the same public-but-hidden strategy already used for the type map group types (CSWINRT3002) and the component authoring attributes (CSWINRT3003): keep the type in the reference assembly but mark it reference-assembly-only '[Obsolete(DiagnosticId = CSWINRT3004)]' + '[EditorBrowsable(Never)]' to discourage direct use. Add the obsolete message/diagnostic-id constants, a 'docs/diagnostics/cswinrt3004.md' page, and suppress the diagnostic in the generated 'AssemblyAttributes.cs'. Update the copilot instructions (the two-strategies note and the error-id table) and the maintenance skill, repurposing the previously-stale CSWINRT3004 id (it had been documented for a since-reverted 'TrustLevel' case that no longer exists). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/copilot-instructions.md | 4 +-- .../update-copilot-instructions/SKILL.md | 2 +- docs/diagnostics/cswinrt3004.md | 25 +++++++++++++++++++ .../Resources/Base/AssemblyAttributes.cs | 1 + ...indowsRuntimeReferenceAssemblyAttribute.cs | 18 ++++++++++--- .../Properties/WindowsRuntimeConstants.cs | 15 +++++++++++ 6 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 docs/diagnostics/cswinrt3004.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index a73f02acb..f44b28c3f 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -254,7 +254,7 @@ WinRT.Runtime2/ - **`[WindowsRuntimeImplementationOnlyMember]`** (`Attributes/WindowsRuntimeImplementationOnlyMemberAttribute.cs`): an `internal sealed`, `[Conditional("WINDOWS_RUNTIME_REFERENCE_ASSEMBLY")]` marker placed on implementation-only types/members (including most of the marker attributes under `Attributes/`). For the **common case** (a type/member that nothing outside the implementation assembly needs to reference), it replaces the older `[Obsolete] + [EditorBrowsable(Never)]` combination, makes the intent explicit, and is only ever emitted into the reference assembly (where it is stripped along with the members it marks). - **Two strategies for implementation-only API** — there are two ways CsWinRT keeps an implementation detail out of the supported surface, and the choice depends on whether *generated code that compiles against the reference assembly* needs to name the type: 1. **Strip it entirely** (the default, preferred): mark it `[WindowsRuntimeImplementationOnlyMember]` (or place it in a file/folder excluded from the reference build) so it is **absent** from the reference assembly. This is the cleanest option and is used for everything that is only reached at runtime or via `[IgnoresAccessChecksTo]` from `WinRT.Interop.dll` (e.g. the ABI marshallers, native object wrappers, vtable helpers). - 2. **Keep it public but hidden** (the exception): leave the type in the reference assembly, but — only there (`#if WINDOWS_RUNTIME_REFERENCE_ASSEMBLY`) — mark it `[Obsolete(..., DiagnosticId = "CSWINRT3xxx", UrlFormat = ...)]` + `[EditorBrowsable(Never)]`. This is required when **CsWinRT-generated user code** references the type by name *and that code is compiled against the reference assembly* (so stripping would cause `CS0234`/`CS0246`). Such generated code suppresses the diagnostic (e.g. `#pragma warning disable`), so normal builds are unaffected, while direct use in user code surfaces the obsolete warning. The obsolete message/diagnostic-id constants live in `Properties/WindowsRuntimeConstants.cs`, and each id has a docs page under `docs/diagnostics/`. Current cases: the three type map group types (`CSWINRT3002`; referenced by the source generator's `[assembly: TypeMapAssemblyTarget]` output), the component authoring attributes `WindowsRuntimeComponentAssemblyAttribute`/`WindowsRuntimeComponentAssemblyExportsTypeAttribute` (`CSWINRT3003`; referenced by the authoring source generator's `ManagedExports.g.cs`), and `Windows.Foundation.TrustLevel` (`CSWINRT3004`; referenced by the `IInspectable` vtable shape in generated projections). The reference-assembly-only `WindowsRuntimeObject()` constructor (`CSWINRT3001`) is the same mechanism applied to a constructor. + 2. **Keep it public but hidden** (the exception): leave the type in the reference assembly, but — only there (`#if WINDOWS_RUNTIME_REFERENCE_ASSEMBLY`) — mark it `[Obsolete(..., DiagnosticId = "CSWINRT3xxx", UrlFormat = ...)]` + `[EditorBrowsable(Never)]`. This is required when **CsWinRT-generated code** references the type by name *and that code is compiled against the reference assembly* (so stripping would cause `CS0234`/`CS0246`). Such generated code suppresses the diagnostic (e.g. `#pragma warning disable`), so normal builds are unaffected, while direct use in user code surfaces the obsolete warning. The obsolete message/diagnostic-id constants live in `Properties/WindowsRuntimeConstants.cs`, and each id has a docs page under `docs/diagnostics/`. Current cases: the three type map group types (`CSWINRT3002`; referenced by the source generator's `[assembly: TypeMapAssemblyTarget]` output), the component authoring attributes `WindowsRuntimeComponentAssemblyAttribute`/`WindowsRuntimeComponentAssemblyExportsTypeAttribute` (`CSWINRT3003`; referenced by the authoring source generator's `ManagedExports.g.cs`), and `WindowsRuntimeReferenceAssemblyAttribute` (`CSWINRT3004`; emitted as `[assembly: WindowsRuntimeReferenceAssembly]` by the projection writer's `AssemblyAttributes.cs` base resource, and — unlike the others — also genuinely shipped in the reference projection assemblies of Windows Runtime projection NuGet packages). The reference-assembly-only `WindowsRuntimeObject()` constructor (`CSWINRT3001`) is the same mechanism applied to a constructor. - **Banned API analyzer**: the reference build references `Microsoft.CodeAnalysis.BannedApiAnalyzers` and lists `WindowsRuntimeImplementationOnlyMemberAttribute` in `BannedSymbols.txt`, with `RS0030` promoted to an error, so the build fails if any implementation-only type ever leaks into the reference surface. It also suppresses warnings that only appear in the stripped build (`CS8597`, `IDE0005`, `IDE0380`). - **Reference-assembly-only `WindowsRuntimeObject()` constructor**: a parameterless `protected` constructor exists only in the reference assembly (`#if WINDOWS_RUNTIME_REFERENCE_ASSEMBLY`). It is marked `[Obsolete(..., DiagnosticId = "CSWINRT3001")]`, so user code that derives from `WindowsRuntimeObject` gets the `CSWINRT3001` warning; because the constructor is absent from the implementation assembly, doing so throws `MissingMethodException` at runtime. Only CsWinRT-generated projections may derive from `WindowsRuntimeObject`. The related messages live in `Properties/WindowsRuntimeConstants.cs`. - **Packaging**: the implementation assembly ships in `lib\net10.0\` of the `Microsoft.Windows.CsWinRT` NuGet package, and the reference assembly (with its XML documentation, trimmed to the reference surface) ships in `ref\net10.0\`. The dual build and staging are driven by `src/build.cmd` and the Azure Pipelines build steps. @@ -730,7 +730,7 @@ All five .NET build tools (`cswinrtprojectionrefgen`, `cswinrtprojectiongen`, `c | Impl Generator | `CSWINRTIMPLGENxxxx` | `0001`–`0014`, `9999` | | Interop Generator | `CSWINRTINTEROPGENxxxx` | `0001`–`0097`, `9999` | | WinMD Generator | `CSWINRTWINMDGENxxxx` | `0001`–`0010`, `9999` | -| Runtime (obsolete markers) | `CSWINRT3xxx` | `CSWINRT3001` (deriving from `WindowsRuntimeObject`), `CSWINRT3002` (type map group types), `CSWINRT3003` (component authoring attributes), `CSWINRT3004` (`Windows.Foundation.TrustLevel`) | +| Runtime (obsolete markers) | `CSWINRT3xxx` | `CSWINRT3001` (deriving from `WindowsRuntimeObject`), `CSWINRT3002` (type map group types), `CSWINRT3003` (component authoring attributes), `CSWINRT3004` (`WindowsRuntimeReferenceAssemblyAttribute`) | --- diff --git a/.github/skills/update-copilot-instructions/SKILL.md b/.github/skills/update-copilot-instructions/SKILL.md index 91d5d126b..b3ed52dd1 100644 --- a/.github/skills/update-copilot-instructions/SKILL.md +++ b/.github/skills/update-copilot-instructions/SKILL.md @@ -28,7 +28,7 @@ Launch parallel explore agents for each of the 12 CsWinRT 3.0 projects listed in - Project settings (TFM, language version, nullable, unsafe, etc.) are current - Namespace organization matches - Reference assembly build is documented: the dual implementation/reference build driven by `CsWinRTBuildReferenceAssembly`, the `WINDOWS_RUNTIME_IMPLEMENTATION_ASSEMBLY` / `WINDOWS_RUNTIME_REFERENCE_ASSEMBLY` / `WINDOWS_RUNTIME_IMPLEMENTATION_ONLY_FILE` compilation symbols, the `[WindowsRuntimeImplementationOnlyMember]` marker attribute (`Attributes/WindowsRuntimeImplementationOnlyMemberAttribute.cs`), the `BannedSymbols.txt` + `Microsoft.CodeAnalysis.BannedApiAnalyzers` guard (`RS0030` as error), the reference-assembly-only `WindowsRuntimeObject()` constructor (`CSWINRT3001` obsolete diagnostic), and packaging into `ref\net10.0\` alongside the implementation in `lib\net10.0\` (`src/build.cmd`, `nuget/Microsoft.Windows.CsWinRT.nuspec`) - - The **two strategies for keeping API out of the supported surface** are documented and current: (1) **strip entirely** (the default — `[WindowsRuntimeImplementationOnlyMember]` or an excluded file/folder, so the type is absent from the reference assembly), and (2) **public but hidden** (the exception — the type stays in the reference assembly but is marked reference-assembly-only `[Obsolete(..., DiagnosticId = "CSWINRT3xxx")]` + `[EditorBrowsable(Never)]`). Strategy 2 is required only when CsWinRT-generated code that compiles against the reference assembly names the type (stripping would then cause `CS0234`/`CS0246`); the generated code suppresses the diagnostic so normal builds are unaffected. Verify the list of current strategy-2 cases is accurate and complete by checking the `CSWINRT3xxx` constants in `Properties/WindowsRuntimeConstants.cs` and the per-diagnostic pages under `docs/diagnostics/`: `CSWINRT3001` (the `WindowsRuntimeObject()` constructor), `CSWINRT3002` (the three type map group types, named by the source generator's `[assembly: TypeMapAssemblyTarget]` output), `CSWINRT3003` (`WindowsRuntimeComponentAssemblyAttribute` / `WindowsRuntimeComponentAssemblyExportsTypeAttribute`, named by the authoring generator's `ManagedExports.g.cs`), and `CSWINRT3004` (`Windows.Foundation.TrustLevel`, named by the `IInspectable` vtable shape in generated projections). If a `CSWINRT3xxx` diagnostic is added or removed, update both the reference-assembly section and the runtime row of the "Error ID ranges" table in the instructions + - The **two strategies for keeping API out of the supported surface** are documented and current: (1) **strip entirely** (the default — `[WindowsRuntimeImplementationOnlyMember]` or an excluded file/folder, so the type is absent from the reference assembly), and (2) **public but hidden** (the exception — the type stays in the reference assembly but is marked reference-assembly-only `[Obsolete(..., DiagnosticId = "CSWINRT3xxx")]` + `[EditorBrowsable(Never)]`). Strategy 2 is required only when CsWinRT-generated code that compiles against the reference assembly names the type (stripping would then cause `CS0234`/`CS0246`); the generated code suppresses the diagnostic so normal builds are unaffected. Verify the list of current strategy-2 cases is accurate and complete by checking the `CSWINRT3xxx` constants in `Properties/WindowsRuntimeConstants.cs` and the per-diagnostic pages under `docs/diagnostics/`: `CSWINRT3001` (the `WindowsRuntimeObject()` constructor), `CSWINRT3002` (the three type map group types, named by the source generator's `[assembly: TypeMapAssemblyTarget]` output), `CSWINRT3003` (`WindowsRuntimeComponentAssemblyAttribute` / `WindowsRuntimeComponentAssemblyExportsTypeAttribute`, named by the authoring generator's `ManagedExports.g.cs`), and `CSWINRT3004` (`WindowsRuntimeReferenceAssemblyAttribute`, emitted as `[assembly: WindowsRuntimeReferenceAssembly]` by the projection writer's `AssemblyAttributes.cs` base resource and shipped in reference projection assemblies). If a `CSWINRT3xxx` diagnostic is added or removed, update both the reference-assembly section and the runtime row of the "Error ID ranges" table in the instructions 2. **WinRT.SourceGenerator2 (`src/Authoring/WinRT.SourceGenerator2/`)** - Source generators listed still exist and generate what's described diff --git a/docs/diagnostics/cswinrt3004.md b/docs/diagnostics/cswinrt3004.md new file mode 100644 index 000000000..4874c87c3 --- /dev/null +++ b/docs/diagnostics/cswinrt3004.md @@ -0,0 +1,25 @@ +# CsWinRT warning CSWINRT3004 + +The `WindowsRuntimeReferenceAssemblyAttribute` type (in the `WindowsRuntime.InteropServices` namespace) is a private implementation detail of `WinRT.Runtime.dll`. It is only meant to be applied (via `[assembly: WindowsRuntimeReferenceAssembly]`) to generated Windows Runtime projection assemblies by CsWinRT, to identify them as containing projected Windows Runtime APIs. Unlike most other CsWinRT implementation details, it is not stripped from the reference assembly for `WinRT.Runtime.dll`, because the reference projection assemblies that ship in Windows Runtime projection NuGet packages carry it and it must remain resolvable when those assemblies are consumed. It is not intended for direct use in user code. + +For instance, the following sample generates CSWINRT3004: + +```csharp +using WindowsRuntime.InteropServices; + +// CSWINRT3004: the reference assembly attribute is a private implementation detail +[assembly: WindowsRuntimeReferenceAssembly] +``` + +## Additional resources + +`CSWINRT3004` is emitted when user code references the `WindowsRuntimeReferenceAssemblyAttribute` type directly. This attribute marks an assembly as containing generated Windows Runtime APIs from a given Windows Runtime metadata file (`.winmd`): CsWinRT emits it automatically into the reference projection assemblies it produces (via `cswinrtprojectionrefgen.exe` and `cswinrtprojectiongen.exe`), and CsWinRT tooling reads it to recognize those assemblies. All of that generated code suppresses this diagnostic, so it never affects normal builds. + +The reference assembly attribute is not considered part of the versioned API surface of `WinRT.Runtime.dll`, and it may be modified or removed across any version change. Using it in user code is undefined behavior and not supported. + +## Recommended action + +- Do not reference the `WindowsRuntimeReferenceAssemblyAttribute` type in user code, and let CsWinRT emit it for you. +- If you are authoring a Windows Runtime projection to ship in a NuGet package, set `CsWinRTGenerateReferenceProjection` to `true` and let CsWinRT generate the reference projection (and the attribute that identifies it) automatically; no manual annotation is needed. + +Keeping the reference assembly attribute exclusive to generated code is what allows CsWinRT to evolve the projection infrastructure rapidly. Respecting the diagnostic ensures your applications remain stable across updates. diff --git a/src/WinRT.Projection.Writer/Resources/Base/AssemblyAttributes.cs b/src/WinRT.Projection.Writer/Resources/Base/AssemblyAttributes.cs index 9f93d4128..4df31b8f8 100644 --- a/src/WinRT.Projection.Writer/Resources/Base/AssemblyAttributes.cs +++ b/src/WinRT.Projection.Writer/Resources/Base/AssemblyAttributes.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. #if CSWINRT_REFERENCE_PROJECTION +#pragma warning disable CSWINRT3004 // "Type or member '...' is a private implementation detail" [assembly: WindowsRuntime.InteropServices.WindowsRuntimeReferenceAssembly] #else using System.Reflection; diff --git a/src/WinRT.Runtime2/InteropServices/Attributes/WindowsRuntimeReferenceAssemblyAttribute.cs b/src/WinRT.Runtime2/InteropServices/Attributes/WindowsRuntimeReferenceAssemblyAttribute.cs index a7d2d0a06..d13a59f42 100644 --- a/src/WinRT.Runtime2/InteropServices/Attributes/WindowsRuntimeReferenceAssemblyAttribute.cs +++ b/src/WinRT.Runtime2/InteropServices/Attributes/WindowsRuntimeReferenceAssemblyAttribute.cs @@ -1,9 +1,10 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -#define WINDOWS_RUNTIME_IMPLEMENTATION_ONLY_FILE - using System; +#if WINDOWS_RUNTIME_REFERENCE_ASSEMBLY +using System.ComponentModel; +#endif namespace WindowsRuntime.InteropServices; @@ -14,11 +15,20 @@ namespace WindowsRuntime.InteropServices; /// for Windows Runtime projections consumed directly from a local project reference. /// /// -/// This attribute is emitted by the CsWinRT generator, and it is not meant to be used directly. +/// This attribute is emitted by the CsWinRT generator, and it is not meant to be used directly. Unlike most other CsWinRT +/// implementation details, it is not stripped from the WinRT.Runtime.dll reference assembly: it is applied (via +/// [assembly: WindowsRuntimeReferenceAssembly]) to the reference projection assemblies that ship in Windows Runtime +/// projection NuGet packages, so it must remain resolvable when those assemblies are consumed. /// /// [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false, Inherited = false)] -[WindowsRuntimeImplementationOnlyMember] +#if WINDOWS_RUNTIME_REFERENCE_ASSEMBLY +[Obsolete( + WindowsRuntimeConstants.WindowsRuntimeReferenceAssemblyObsoleteMessage, + DiagnosticId = WindowsRuntimeConstants.WindowsRuntimeReferenceAssemblyObsoleteDiagnosticId, + UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] +[EditorBrowsable(EditorBrowsableState.Never)] +#endif public sealed class WindowsRuntimeReferenceAssemblyAttribute : Attribute { /// diff --git a/src/WinRT.Runtime2/Properties/WindowsRuntimeConstants.cs b/src/WinRT.Runtime2/Properties/WindowsRuntimeConstants.cs index 952895dfa..b6609a3f2 100644 --- a/src/WinRT.Runtime2/Properties/WindowsRuntimeConstants.cs +++ b/src/WinRT.Runtime2/Properties/WindowsRuntimeConstants.cs @@ -52,6 +52,21 @@ internal static class WindowsRuntimeConstants /// public const string WindowsRuntimeComponentAssemblyObsoleteDiagnosticId = "CSWINRT3003"; + /// + /// A message for the WindowsRuntimeReferenceAssemblyAttribute type. + /// + public const string WindowsRuntimeReferenceAssemblyObsoleteMessage = + "This attribute is a private implementation detail, and it must never be used directly. It is only meant to be applied to " + + "generated Windows Runtime projection assemblies by CsWinRT (produced by 'cswinrtprojectiongen.exe' and " + + "'cswinrtprojectionrefgen.exe'), to identify them as containing projected Windows Runtime APIs. It is not considered part " + + "of the versioned API surface, and it may be modified or removed across any version change for 'WinRT.Runtime.dll'. Using " + + "it in user code is undefined behavior and not supported."; + + /// + /// The diagnostic id for the WindowsRuntimeReferenceAssemblyAttribute type. + /// + public const string WindowsRuntimeReferenceAssemblyObsoleteDiagnosticId = "CSWINRT3004"; + /// /// The URL format for all custom diagnostics for CsWinRT. /// From 68a47fdfbc77a5b2645af566ba1328713ebc945b Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 21 Jun 2026 18:07:26 -0700 Subject: [PATCH 25/42] Stop reference projections from referencing implementation-only types A reference projection ships in a Windows Runtime projection NuGet package and is compiled (with 'ProduceOnlyReferenceAssembly') against the stripped 'WinRT.Runtime.dll' reference assembly, which contains only the public API surface. The projection writer was emitting code that referenced implementation-only types in signature positions (field types, method parameters, base types, attributes) that do not exist in that reference assembly, so building a reference projection from the package failed to compile (CS0246/CS0234). In reference-projection mode, stop emitting the implementation-only signatures: the '[WindowsRuntimeMetadata]' attribute, the private '_objRef_*' fields (typed 'WindowsRuntimeObjectReference'), the static activation-factory object references, the activation-factory plumbing (factory callback classes and args structs), and the '[UnsafeAccessor]' static extern declarations (whose parameters are typed 'WindowsRuntimeObjectReference'). Constructors keep their public signatures but emit a 'throw null' body instead of a base call referencing implementation-only activation types. Member bodies are unaffected: a reference assembly compile does not bind method bodies, so the public member signatures are all that needs to resolve. Implementation-mode output is unchanged. Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Builders/ProjectionFileBuilder.cs | 8 +-- .../Factories/ClassFactory.cs | 39 ++++++------ .../ClassMembersFactory.WriteClassMembers.cs | 6 +- ...assMembersFactory.WriteInterfaceMembers.cs | 41 ++++++++---- .../ConstructorFactory.AttributedTypes.cs | 63 ++++++++++++------- .../ConstructorFactory.Composable.cs | 19 ++++-- .../Factories/InterfaceFactory.cs | 2 +- .../Factories/MappedInterfaceStubFactory.cs | 44 +++++++++---- .../Factories/MetadataAttributeFactory.cs | 37 +++++++---- .../Factories/RefModeStubFactory.cs | 39 +++++++----- .../Helpers/ObjRefNameGenerator.cs | 11 +++- 11 files changed, 198 insertions(+), 111 deletions(-) diff --git a/src/WinRT.Projection.Writer/Builders/ProjectionFileBuilder.cs b/src/WinRT.Projection.Writer/Builders/ProjectionFileBuilder.cs index 44c4c8faa..5bc218b1a 100644 --- a/src/WinRT.Projection.Writer/Builders/ProjectionFileBuilder.cs +++ b/src/WinRT.Projection.Writer/Builders/ProjectionFileBuilder.cs @@ -94,7 +94,7 @@ private static void WriteEnum(IndentedTextWriter writer, ProjectionEmitContext c string enumUnderlyingType = isFlags ? "uint" : "int"; string typeName = type.GetRawName(); - IndentedTextWriterCallback metadataAttr = MetadataAttributeFactory.WriteWinRTMetadataAttribute(type, context.Cache); + IndentedTextWriterCallback metadataAttr = MetadataAttributeFactory.WriteWinRTMetadataAttribute(context, type); IndentedTextWriterCallback valueTypeAttr = MetadataAttributeFactory.WriteValueTypeWinRTClassNameAttribute(context, type); IndentedTextWriterCallback customAttrs = CustomAttributeFactory.WriteTypeCustomAttributes(context, type, true); IndentedTextWriterCallback comWrappersAttr = MetadataAttributeFactory.WriteComWrapperMarshallerAttribute(context, type); @@ -174,7 +174,7 @@ private static void WriteStruct(IndentedTextWriter writer, ProjectionEmitContext string projectionName = type.GetRawName(); // Header attributes + struct declaration as a single multiline template. - IndentedTextWriterCallback metadataAttr = MetadataAttributeFactory.WriteWinRTMetadataAttribute(type, context.Cache); + IndentedTextWriterCallback metadataAttr = MetadataAttributeFactory.WriteWinRTMetadataAttribute(context, type); IndentedTextWriterCallback valueTypeAttr = MetadataAttributeFactory.WriteValueTypeWinRTClassNameAttribute(context, type); IndentedTextWriterCallback customAttrs = CustomAttributeFactory.WriteTypeCustomAttributes(context, type, true); IndentedTextWriterCallback comWrappersAttr = MetadataAttributeFactory.WriteComWrapperMarshallerAttribute(context, type); @@ -321,7 +321,7 @@ private static void WriteDelegate(IndentedTextWriter writer, ProjectionEmitConte MethodSignatureInfo sig = new(invoke); - IndentedTextWriterCallback metadataAttr = MetadataAttributeFactory.WriteWinRTMetadataAttribute(type, context.Cache); + IndentedTextWriterCallback metadataAttr = MetadataAttributeFactory.WriteWinRTMetadataAttribute(context, type); IndentedTextWriterCallback customAttrs = CustomAttributeFactory.WriteTypeCustomAttributes(context, type, false); IndentedTextWriterCallback comWrappersAttr = MetadataAttributeFactory.WriteComWrapperMarshallerAttribute(context, type); string guidAttr = context.Settings.ReferenceProjection @@ -349,7 +349,7 @@ private static void WriteAttribute(IndentedTextWriter writer, ProjectionEmitCont { string typeName = type.GetRawName(); - IndentedTextWriterCallback metadataAttr = MetadataAttributeFactory.WriteWinRTMetadataAttribute(type, context.Cache); + IndentedTextWriterCallback metadataAttr = MetadataAttributeFactory.WriteWinRTMetadataAttribute(context, type); IndentedTextWriterCallback customAttrs = CustomAttributeFactory.WriteTypeCustomAttributes(context, type, true); writer.WriteLine(); diff --git a/src/WinRT.Projection.Writer/Factories/ClassFactory.cs b/src/WinRT.Projection.Writer/Factories/ClassFactory.cs index c2b5d789c..9028c1628 100644 --- a/src/WinRT.Projection.Writer/Factories/ClassFactory.cs +++ b/src/WinRT.Projection.Writer/Factories/ClassFactory.cs @@ -226,7 +226,7 @@ public static void WriteStaticClass(IndentedTextWriter writer, ProjectionEmitCon { using (context.EnterPlatformSuppressionScope(string.Empty)) { - IndentedTextWriterCallback metadataAttr = MetadataAttributeFactory.WriteWinRTMetadataAttribute(type, context.Cache); + IndentedTextWriterCallback metadataAttr = MetadataAttributeFactory.WriteWinRTMetadataAttribute(context, type); IndentedTextWriterCallback customAttrs = CustomAttributeFactory.WriteTypeCustomAttributes(context, type, true); IndentedTextWriterCallback name = TypedefNameWriter.WriteTypedefNameWithTypeParams(context, type, TypedefNameType.Projected, false); writer.WriteLine(isMultiline: true, $$""" @@ -453,31 +453,32 @@ public static event {{eventType}} {{evtName}} /// internal static void WriteStaticFactoryObjRef(IndentedTextWriter writer, ProjectionEmitContext context, TypeDefinition staticIface, string runtimeClassFullName, string objRefName) { - writer.WriteLine(); - + // The static factory '_objRef_*' field is a private implementation detail typed as the + // implementation-only 'WindowsRuntimeObjectReference', so it is omitted from reference + // projections (which compile against the stripped 'WinRT.Runtime' reference assembly). if (context.Settings.ReferenceProjection) { - writer.WriteLine($"private static WindowsRuntimeObjectReference {objRefName} => throw null;"); + return; } - else - { - IndentedTextWriterCallback iid = ObjRefNameGenerator.WriteIidExpression(context, staticIface); - writer.WriteLine(isMultiline: true, $$""" - private static WindowsRuntimeObjectReference {{objRefName}} + writer.WriteLine(); + + IndentedTextWriterCallback iid = ObjRefNameGenerator.WriteIidExpression(context, staticIface); + + writer.WriteLine(isMultiline: true, $$""" + private static WindowsRuntimeObjectReference {{objRefName}} + { + get { - get + var __{{objRefName}} = field; + if (__{{objRefName}} != null && __{{objRefName}}.IsInCurrentContext) { - var __{{objRefName}} = field; - if (__{{objRefName}} != null && __{{objRefName}}.IsInCurrentContext) - { - return __{{objRefName}}; - } - return field = WindowsRuntimeObjectReference.GetActivationFactory("{{runtimeClassFullName}}", {{iid}}); + return __{{objRefName}}; } + return field = WindowsRuntimeObjectReference.GetActivationFactory("{{runtimeClassFullName}}", {{iid}}); } - """); - } + } + """); } /// @@ -510,7 +511,7 @@ private static void WriteClassCore(IndentedTextWriter writer, ProjectionEmitCont int gcPressure = GetGcPressureAmount(type); // Header attributes + class declaration as a single multiline template. - IndentedTextWriterCallback metadataAttr = MetadataAttributeFactory.WriteWinRTMetadataAttribute(type, context.Cache); + IndentedTextWriterCallback metadataAttr = MetadataAttributeFactory.WriteWinRTMetadataAttribute(context, type); IndentedTextWriterCallback customAttrs = CustomAttributeFactory.WriteTypeCustomAttributes(context, type, true); IndentedTextWriterCallback comWrappersAttr = MetadataAttributeFactory.WriteComWrapperMarshallerAttribute(context, type); diff --git a/src/WinRT.Projection.Writer/Factories/ClassMembersFactory.WriteClassMembers.cs b/src/WinRT.Projection.Writer/Factories/ClassMembersFactory.WriteClassMembers.cs index 900167fbb..6442a5120 100644 --- a/src/WinRT.Projection.Writer/Factories/ClassMembersFactory.WriteClassMembers.cs +++ b/src/WinRT.Projection.Writer/Factories/ClassMembersFactory.WriteClassMembers.cs @@ -40,7 +40,9 @@ public static void WriteClassMembers(IndentedTextWriter writer, ProjectionEmitCo // For generic-interface properties, emit the UnsafeAccessor static externs above the // property declaration. Note: getter and setter use the same accessor name (because // C# allows method overloading on parameter list for the static externs). - if (s.HasGetter && s.GetterIsGeneric && !string.IsNullOrEmpty(s.GetterGenericInteropType)) + // These externs are impl-only plumbing for the accessor bodies; in ref mode the bodies + // are 'throw null' so the externs (which reference 'WindowsRuntimeObjectReference') are omitted. + if (!context.Settings.ReferenceProjection && s.HasGetter && s.GetterIsGeneric && !string.IsNullOrEmpty(s.GetterGenericInteropType)) { writer.WriteLine(); UnsafeAccessorFactory.EmitStaticMethod( @@ -52,7 +54,7 @@ public static void WriteClassMembers(IndentedTextWriter writer, ProjectionEmitCo parameterList: "WindowsRuntimeObjectReference thisReference"); } - if (s.HasSetter && s.SetterIsGeneric && !string.IsNullOrEmpty(s.SetterGenericInteropType)) + if (!context.Settings.ReferenceProjection && s.HasSetter && s.SetterIsGeneric && !string.IsNullOrEmpty(s.SetterGenericInteropType)) { writer.WriteLine(); UnsafeAccessorFactory.EmitStaticMethod( diff --git a/src/WinRT.Projection.Writer/Factories/ClassMembersFactory.WriteInterfaceMembers.cs b/src/WinRT.Projection.Writer/Factories/ClassMembersFactory.WriteInterfaceMembers.cs index efd44d6af..c63a21284 100644 --- a/src/WinRT.Projection.Writer/Factories/ClassMembersFactory.WriteInterfaceMembers.cs +++ b/src/WinRT.Projection.Writer/Factories/ClassMembersFactory.WriteInterfaceMembers.cs @@ -19,9 +19,16 @@ namespace WindowsRuntime.ProjectionWriter.Factories; internal static partial class ClassMembersFactory { - private static void WriteInterfaceMembersRecursive(IndentedTextWriter writer, ProjectionEmitContext context, TypeDefinition classType, TypeDefinition declaringType, + private static void WriteInterfaceMembersRecursive( + IndentedTextWriter writer, + ProjectionEmitContext context, + TypeDefinition classType, + TypeDefinition declaringType, GenericInstanceTypeSignature? currentInstance, - HashSet writtenMethods, IDictionary propertyState, HashSet writtenEvents, HashSet writtenInterfaces) + HashSet writtenMethods, + IDictionary propertyState, + HashSet writtenEvents, + HashSet writtenInterfaces) { GenericContext genericContext = new(currentInstance, null); @@ -238,10 +245,10 @@ private static void WriteInterfaceMembers(IndentedTextWriter writer, ProjectionE genericInteropType = InteropTypeNameWriter.GetInteropAssemblyQualifiedName(currentInstance, TypedefNameType.StaticAbiClass); } - // Compute the platform attribute string from the interface type's [ContractVersion] + // Compute the platform attribute string from the interface type's '[ContractVersion]' // attribute. In ref mode, this is prepended to each member emission so the projected - // class members carry [SupportedOSPlatform("WindowsX.Y.Z.0")] mirroring the interface's - // contract version. Only emitted in ref mode (WritePlatformAttribute internally returns + // class members carry '[SupportedOSPlatform("WindowsX.Y.Z.0")]' mirroring the interface's + // contract version. Only emitted in ref mode ('WritePlatformAttribute' internally returns // immediately if not ref) string platformAttribute = CustomAttributeFactory.GetPlatformAttribute(context, ifaceType); @@ -251,7 +258,7 @@ private static void WriteInterfaceMembers(IndentedTextWriter writer, ProjectionE string name = method.GetRawName(); // Track by full signature (name + each param's element-type code) to avoid trivial overload duplicates. - // This prevents collapsing distinct overloads like Format(double) and Format(ulong). + // This prevents collapsing distinct overloads like 'Format(double)' and 'Format(ulong)'. MethodSignatureInfo sig = new(method, genericContext); string key = sig.GetDedupeKey(name); @@ -309,13 +316,21 @@ private static void WriteInterfaceMembers(IndentedTextWriter writer, ProjectionE string platformTrimmed = platformAttribute.TrimEnd('\r', '\n'); writer.WriteLine(); - UnsafeAccessorFactory.EmitStaticMethod( - writer, - accessName: name, - returnType: unsafeRet.Format(), - functionName: accessorName, - interopType: genericInteropType, - parameterList: $"WindowsRuntimeObjectReference thisReference{accessorParams}"); + + // The '[UnsafeAccessor]' extern is impl-only plumbing for the dispatch body; in ref mode + // the body is 'throw null' (see 'body' above), so the extern (which references the + // implementation-only 'WindowsRuntimeObjectReference') is omitted. + if (!context.Settings.ReferenceProjection) + { + UnsafeAccessorFactory.EmitStaticMethod( + writer, + accessName: name, + returnType: unsafeRet.Format(), + functionName: accessorName, + interopType: genericInteropType, + parameterList: $"WindowsRuntimeObjectReference thisReference{accessorParams}"); + } + writer.WriteLine(isMultiline: true, $$""" {{platformTrimmed}} {{access}}{{methodSpecForThis}}{{ret}} {{name}}({{parms}}) => {{body}} diff --git a/src/WinRT.Projection.Writer/Factories/ConstructorFactory.AttributedTypes.cs b/src/WinRT.Projection.Writer/Factories/ConstructorFactory.AttributedTypes.cs index 1694c6611..45b6a2560 100644 --- a/src/WinRT.Projection.Writer/Factories/ConstructorFactory.AttributedTypes.cs +++ b/src/WinRT.Projection.Writer/Factories/ConstructorFactory.AttributedTypes.cs @@ -34,35 +34,29 @@ public static void WriteAttributedTypes(IndentedTextWriter writer, ProjectionEmi } } - if (needsClassObjRef) + // The activation factory '_objRef_*' field is a private implementation detail typed as the + // implementation-only 'WindowsRuntimeObjectReference', so it is omitted from reference projections + // (which compile against the stripped 'WinRT.Runtime' reference assembly). + if (needsClassObjRef && !context.Settings.ReferenceProjection) { string fullName = classType.FullName ?? string.Empty; string objRefName = "_objRef_" + IidExpressionGenerator.EscapeTypeNameForIdentifier(GlobalPrefix + fullName, stripGlobal: true); writer.WriteLine(); writer.Write($"private static WindowsRuntimeObjectReference {objRefName}"); - - if (context.Settings.ReferenceProjection) - { - // in ref mode the activation factory objref getter body is just 'throw null;'. - RefModeStubFactory.EmitRefModeObjRefGetterBody(writer); - } - else - { - writer.WriteLine(); - writer.WriteLine(isMultiline: true, $$""" + writer.WriteLine(); + writer.WriteLine(isMultiline: true, $$""" + { + get { - get + var __{{objRefName}} = field; + if (__{{objRefName}} != null && __{{objRefName}}.IsInCurrentContext) { - var __{{objRefName}} = field; - if (__{{objRefName}} != null && __{{objRefName}}.IsInCurrentContext) - { - return __{{objRefName}}; - } - return field = WindowsRuntimeObjectReference.GetActivationFactory("{{fullName}}"); + return __{{objRefName}}; } + return field = WindowsRuntimeObjectReference.GetActivationFactory("{{fullName}}"); } - """); - } + } + """); } foreach (KeyValuePair kv in AttributedTypes.Get(classType, context.Cache)) @@ -122,6 +116,18 @@ public static void WriteFactoryConstructors(IndentedTextWriter writer, Projectio writer.Write($"public unsafe {typeName}("); MethodFactory.WriteParameterList(writer, context, sig); + + // In ref mode the constructor keeps its public signature but gets a 'throw null' body, + // and the args struct + factory callback class below are skipped (they are private + // implementation details referencing implementation-only 'WinRT.Runtime' types). + if (context.Settings.ReferenceProjection) + { + RefModeStubFactory.EmitRefModeConstructorBody(writer); + methodIndex++; + + continue; + } + writer.Write(isMultiline: true, """ ) :base( @@ -165,9 +171,20 @@ public static void WriteFactoryConstructors(IndentedTextWriter writer, Projectio } else { - // No factory type means [Activatable(uint version)] - emit a default ctor that calls - // the WindowsRuntimeObject base constructor with the activation factory objref. - // The default interface IID is needed too. + // No factory type means '[Activatable(uint version)]', emit a parameterless default ctor + if (context.Settings.ReferenceProjection) + { + // Ref mode keeps the public signature with a 'throw null' body (the impl-mode body + // calls the base ctor with implementation-only activation types). + writer.WriteLine(); + writer.Write($"public {typeName}("); + RefModeStubFactory.EmitRefModeConstructorBody(writer); + + return; + } + + // The impl-mode default ctor calls the 'WindowsRuntimeObject' base constructor with + // the activation factory object reference. The default interface IID is needed too. string fullName = classType.FullName ?? string.Empty; string objRefName = "_objRef_" + IidExpressionGenerator.EscapeTypeNameForIdentifier(GlobalPrefix + fullName, stripGlobal: true); diff --git a/src/WinRT.Projection.Writer/Factories/ConstructorFactory.Composable.cs b/src/WinRT.Projection.Writer/Factories/ConstructorFactory.Composable.cs index 002fa51c6..20eb77b55 100644 --- a/src/WinRT.Projection.Writer/Factories/ConstructorFactory.Composable.cs +++ b/src/WinRT.Projection.Writer/Factories/ConstructorFactory.Composable.cs @@ -92,6 +92,17 @@ public static void WriteComposableConstructors(IndentedTextWriter writer, Projec writer.Write($"{(i > 0 ? ", " : "")}{p}"); } + // In ref mode the composable constructor keeps its public signature but gets a 'throw null' + // body; the base call and the args struct + factory callback class below are skipped (they + // are private implementation details referencing implementation-only 'WinRT.Runtime' types). + if (context.Settings.ReferenceProjection) + { + RefModeStubFactory.EmitRefModeConstructorBody(writer); + methodIndex++; + + continue; + } + writer.Write(isMultiline: true, """ ) :base( @@ -142,11 +153,9 @@ void WriteCtorBody(IndentedTextWriter writer) } """); - // Emit args struct + callback class for parameterized composable factories. - // skips both the args struct AND the callback class entirely in ref mode. The - // public ctor above still references these types, but reference assemblies don't - // need their bodies' references to resolve (only the public API surface matters). - if (!isParameterless && !context.Settings.ReferenceProjection) + // Emit the args struct + factory callback class for parameterized composable factories. + // (Ref mode 'continue'd above before reaching here, since it emits no factory plumbing.) + if (!isParameterless) { EmitFactoryArgsStruct(writer, context, sig, argsName, userParamCount); string factoryObjRefName = ObjRefNameGenerator.GetObjRefName(context, composableType); diff --git a/src/WinRT.Projection.Writer/Factories/InterfaceFactory.cs b/src/WinRT.Projection.Writer/Factories/InterfaceFactory.cs index 9a49411cf..7a0448b19 100644 --- a/src/WinRT.Projection.Writer/Factories/InterfaceFactory.cs +++ b/src/WinRT.Projection.Writer/Factories/InterfaceFactory.cs @@ -401,7 +401,7 @@ public static void WriteInterface(IndentedTextWriter writer, ProjectionEmitConte } writer.WriteLine(); - IndentedTextWriterCallback metadataAttr = MetadataAttributeFactory.WriteWinRTMetadataAttribute(type, context.Cache); + IndentedTextWriterCallback metadataAttr = MetadataAttributeFactory.WriteWinRTMetadataAttribute(context, type); IndentedTextWriterCallback guidAttr = WriteGuidAttribute(type); writer.WriteLine(isMultiline: true, $$""" {{metadataAttr}} diff --git a/src/WinRT.Projection.Writer/Factories/MappedInterfaceStubFactory.cs b/src/WinRT.Projection.Writer/Factories/MappedInterfaceStubFactory.cs index 44e4a4946..dc0f3b38c 100644 --- a/src/WinRT.Projection.Writer/Factories/MappedInterfaceStubFactory.cs +++ b/src/WinRT.Projection.Writer/Factories/MappedInterfaceStubFactory.cs @@ -138,7 +138,7 @@ private static void EmitGenericEnumerable(IndentedTextWriter writer, ProjectionE string prefix = "IEnumerableMethods_" + elementId + "_"; writer.WriteLine(); - EmitUnsafeAccessor(writer, "GetEnumerator", $"IEnumerator<{t}>", $"{prefix}GetEnumerator", interopType, ""); + EmitUnsafeAccessor(writer, context, "GetEnumerator", $"IEnumerator<{t}>", $"{prefix}GetEnumerator", interopType, ""); writer.WriteLine(); writer.WriteLine($"public IEnumerator<{t}> GetEnumerator() => {prefix}GetEnumerator(null, {objRefName});"); @@ -159,7 +159,7 @@ private static void EmitGenericEnumerator(IndentedTextWriter writer, ProjectionE string prefix = "IEnumeratorMethods_" + elementId + "_"; writer.WriteLine(); - EmitUnsafeAccessors(writer, interopType, [ + EmitUnsafeAccessors(writer, context, interopType, [ new("Current", t, $"{prefix}Current", ""), new("MoveNext", "bool", $"{prefix}MoveNext", "")]); @@ -207,9 +207,9 @@ private static void EmitDictionary(IndentedTextWriter writer, ProjectionEmitCont // 'Keys'/'Values' take the projected runtime class directly (passed as 'this'), rather than the // interface object reference like the other accessors. This lets the returned collection be cached // in the public property's backing 'field' so it preserves reference identity across accesses. - EmitUnsafeAccessor(writer, "Keys", $"ICollection<{k}>", $"{prefix}Keys", interopType, "", receiver: "WindowsRuntimeObject windowsRuntimeObject"); - EmitUnsafeAccessor(writer, "Values", $"ICollection<{v}>", $"{prefix}Values", interopType, "", receiver: "WindowsRuntimeObject windowsRuntimeObject"); - EmitUnsafeAccessors(writer, interopType, [ + EmitUnsafeAccessor(writer, context, "Keys", $"ICollection<{k}>", $"{prefix}Keys", interopType, "", receiver: "WindowsRuntimeObject windowsRuntimeObject"); + EmitUnsafeAccessor(writer, context, "Values", $"ICollection<{v}>", $"{prefix}Values", interopType, "", receiver: "WindowsRuntimeObject windowsRuntimeObject"); + EmitUnsafeAccessors(writer, context, interopType, [ new("Count", "int", $"{prefix}Count", ""), new("Item", v, $"{prefix}Item", $", {k} key"), new("Item", "void", $"{prefix}Item", $", {k} key, {v} value"), @@ -269,9 +269,9 @@ private static void EmitReadOnlyDictionary(IndentedTextWriter writer, Projection // 'Keys'/'Values' take the projected runtime class directly (passed as 'this'), rather than the // interface object reference like the other accessors. This lets the returned collection be cached // in the public property's backing 'field' so it preserves reference identity across accesses. - EmitUnsafeAccessor(writer, "Keys", $"IEnumerable<{k}>", $"{prefix}Keys", interopType, "", receiver: "WindowsRuntimeObject windowsRuntimeObject"); - EmitUnsafeAccessor(writer, "Values", $"IEnumerable<{v}>", $"{prefix}Values", interopType, "", receiver: "WindowsRuntimeObject windowsRuntimeObject"); - EmitUnsafeAccessors(writer, interopType, [ + EmitUnsafeAccessor(writer, context, "Keys", $"IEnumerable<{k}>", $"{prefix}Keys", interopType, "", receiver: "WindowsRuntimeObject windowsRuntimeObject"); + EmitUnsafeAccessor(writer, context, "Values", $"IEnumerable<{v}>", $"{prefix}Values", interopType, "", receiver: "WindowsRuntimeObject windowsRuntimeObject"); + EmitUnsafeAccessors(writer, context, interopType, [ new("Count", "int", $"{prefix}Count", ""), new("Item", v, $"{prefix}Item", $", {k} key"), new("ContainsKey", "bool", $"{prefix}ContainsKey", $", {k} key"), @@ -302,7 +302,7 @@ private static void EmitReadOnlyList(IndentedTextWriter writer, ProjectionEmitCo string prefix = "IReadOnlyListMethods_" + elementId + "_"; writer.WriteLine(); - EmitUnsafeAccessors(writer, interopType, [ + EmitUnsafeAccessors(writer, context, interopType, [ new("Count", "int", $"{prefix}Count", ""), new("Item", t, $"{prefix}Item", ", int index")]); @@ -349,7 +349,7 @@ private static void EmitList(IndentedTextWriter writer, ProjectionEmitContext co string prefix = "IListMethods_" + elementId + "_"; writer.WriteLine(); - EmitUnsafeAccessors(writer, interopType, [ + EmitUnsafeAccessors(writer, context, interopType, [ new("Count", "int", $"{prefix}Count", ""), new("Item", t, $"{prefix}Item", ", int index"), new("Item", "void", $"{prefix}Item", $", int index, {t} value"), @@ -393,8 +393,25 @@ private static void EmitList(IndentedTextWriter writer, ProjectionEmitContext co /// (WindowsRuntimeObjectReference objRef); a few accessors (e.g. dictionary /// Keys/Values) instead take the projected runtime class (WindowsRuntimeObject). /// - private static void EmitUnsafeAccessor(IndentedTextWriter writer, string accessName, string returnType, string functionName, string interopType, string extraParams, string receiver = "WindowsRuntimeObjectReference objRef") + private static void EmitUnsafeAccessor( + IndentedTextWriter writer, + ProjectionEmitContext context, + string accessName, + string returnType, + string functionName, + string interopType, + string extraParams, + string receiver = "WindowsRuntimeObjectReference objRef") { + // The '[UnsafeAccessor]' extern is impl-only plumbing for the stub member bodies; in a reference + // projection those bodies are not bound (the reference assembly only needs the public member + // signatures), so the extern (which typically references the implementation-only + // 'WindowsRuntimeObjectReference') is omitted. + if (context.Settings.ReferenceProjection) + { + return; + } + UnsafeAccessorFactory.EmitStaticMethod( writer, accessName: accessName, @@ -408,17 +425,18 @@ private static void EmitUnsafeAccessor(IndentedTextWriter writer, string accessN /// /// Emits a sequence of [UnsafeAccessor] static extern declarations sharing the same /// . Each row of is forwarded to - /// . + /// . /// Used by the collection-stub emitters which emit table-shaped sets of accessors. /// private static void EmitUnsafeAccessors( IndentedTextWriter writer, + ProjectionEmitContext context, string interopType, params ReadOnlySpan<(string AccessName, string ReturnType, string FunctionName, string ExtraParams)> accessors) { foreach ((string accessName, string returnType, string functionName, string extraParams) in accessors) { - EmitUnsafeAccessor(writer, accessName, returnType, functionName, interopType, extraParams); + EmitUnsafeAccessor(writer, context, accessName, returnType, functionName, interopType, extraParams); } } diff --git a/src/WinRT.Projection.Writer/Factories/MetadataAttributeFactory.cs b/src/WinRT.Projection.Writer/Factories/MetadataAttributeFactory.cs index 97b167173..cc3ba0860 100644 --- a/src/WinRT.Projection.Writer/Factories/MetadataAttributeFactory.cs +++ b/src/WinRT.Projection.Writer/Factories/MetadataAttributeFactory.cs @@ -80,30 +80,45 @@ public static string GetFileHeader() /// /// Writes a [WindowsRuntimeMetadata("<stem>")] attribute decorating with its source .winmd module name. + /// Skipped entirely in reference-projection mode. /// /// The writer to emit to. + /// The active emit context. /// The type definition. - /// The metadata cache used to resolve the source module path. - public static void WriteWinRTMetadataAttribute(IndentedTextWriter writer, TypeDefinition type, MetadataCache cache) + public static void WriteWinRTMetadataAttribute(IndentedTextWriter writer, ProjectionEmitContext context, TypeDefinition type) { - WriteWinRTMetadataAttributeBody(writer, type, cache); + if (context.Settings.ReferenceProjection) + { + return; + } + + WriteWinRTMetadataAttributeBody(writer, context, type); + writer.WriteLine(); } - /// - /// A callback emitting the attribute body (no trailing newline) so it can be interpolated into a multiline template. - public static IndentedTextWriterCallback WriteWinRTMetadataAttribute(TypeDefinition type, MetadataCache cache) + /// + /// A callback emitting the attribute body (no trailing newline) so it can be interpolated into a multiline template. Emits nothing in reference-projection mode. + public static IndentedTextWriterCallback WriteWinRTMetadataAttribute(ProjectionEmitContext context, TypeDefinition type) { - return writer => WriteWinRTMetadataAttributeBody(writer, type, cache); + return writer => WriteWinRTMetadataAttributeBody(writer, context, type); } /// - /// Writes just the attribute body (no trailing newline) for . - /// Used by the callback variant to allow the attribute to be inlined inside a multiline raw-string template line. + /// Writes just the attribute body (no trailing newline) for . + /// In reference-projection mode this emits nothing: [WindowsRuntimeMetadata] is an implementation-only + /// type, stripped from the WinRT.Runtime reference assembly that a reference projection compiles against. + /// It is only consumed (by the interop generator) from implementation projections, never from the reference + /// projections shipped in Windows Runtime projection NuGet packages. /// - internal static void WriteWinRTMetadataAttributeBody(IndentedTextWriter writer, TypeDefinition type, MetadataCache cache) + internal static void WriteWinRTMetadataAttributeBody(IndentedTextWriter writer, ProjectionEmitContext context, TypeDefinition type) { - string path = cache.GetSourcePath(type); + if (context.Settings.ReferenceProjection) + { + return; + } + + string path = context.Cache.GetSourcePath(type); string stem = string.IsNullOrEmpty(path) ? string.Empty : Path.GetFileNameWithoutExtension(path); writer.Write($"[WindowsRuntimeMetadata(\"{stem}\")]"); } diff --git a/src/WinRT.Projection.Writer/Factories/RefModeStubFactory.cs b/src/WinRT.Projection.Writer/Factories/RefModeStubFactory.cs index 19f6b68f3..f35b44059 100644 --- a/src/WinRT.Projection.Writer/Factories/RefModeStubFactory.cs +++ b/src/WinRT.Projection.Writer/Factories/RefModeStubFactory.cs @@ -13,23 +13,6 @@ namespace WindowsRuntime.ProjectionWriter.Factories; /// internal static class RefModeStubFactory { - /// - /// Emits the body of an _objRef_* property getter in reference projection mode. - /// - /// The writer to emit to. - public static void EmitRefModeObjRefGetterBody(IndentedTextWriter writer) - { - writer.WriteLine(); - writer.WriteLine(isMultiline: true, """ - { - get - { - throw null; - } - } - """); - } - /// /// Emits the synthetic private TypeName() { throw null; } ctor used in reference /// projection mode to suppress the C# compiler's implicit public default constructor when @@ -43,6 +26,28 @@ public static void EmitSyntheticPrivateCtor(IndentedTextWriter writer, string ty writer.WriteLine($"private {typeName}() {{ throw null; }}"); } + /// + /// Emits the closing ) of a constructor parameter list followed by a throw null body, + /// for constructors emitted in reference projection mode. The caller must already have written the + /// constructor signature up to (but not including) the closing ) of the parameter list. + /// + /// + /// Reference projections only need the public constructor signatures (their bodies are never run and + /// are stripped from the produced reference assembly), so the body is emitted as throw null + /// rather than the real activation logic, which would reference implementation-only 'WinRT.Runtime' + /// types (object references, activation factory callbacks, ABI IID accessors). + /// + /// The writer to emit to. + public static void EmitRefModeConstructorBody(IndentedTextWriter writer) + { + writer.WriteLine(isMultiline: true, """ + ) + { + throw null; + } + """); + } + /// /// Emits the body of a delegate factory Invoke method in reference projection mode. /// diff --git a/src/WinRT.Projection.Writer/Helpers/ObjRefNameGenerator.cs b/src/WinRT.Projection.Writer/Helpers/ObjRefNameGenerator.cs index 8e971f9dc..bc0d0bf12 100644 --- a/src/WinRT.Projection.Writer/Helpers/ObjRefNameGenerator.cs +++ b/src/WinRT.Projection.Writer/Helpers/ObjRefNameGenerator.cs @@ -245,9 +245,14 @@ public static IndentedTextWriterCallback WriteIidReferenceExpression(TypeDefinit /// public static void WriteClassObjRefDefinitions(IndentedTextWriter writer, ProjectionEmitContext context, TypeDefinition type) { - // Per-interface _objRef_* getters are emitted in BOTH impl and ref modes with full - // bodies. (Only the static factory _objRef_* getters become `throw null;` in ref mode -- - // see WriteStaticFactoryObjRef and WriteAttributedTypes.) + // The per-interface '_objRef_*' fields are private implementation details that reference + // implementation-only 'WinRT.Runtime' types ('WindowsRuntimeObjectReference', 'NativeObjectReference', + // the ABI IID accessors, etc.). A reference projection compiles against the stripped 'WinRT.Runtime' + // reference assembly and only needs the public API surface, so none of these are emitted. + if (context.Settings.ReferenceProjection) + { + return; + } // Track names emitted so we don't emit duplicates (e.g. when both IFoo and IFoo2 // produce the same _objRef_). From d7f00d4401aa33daec09c9cfe0e5c931a07846c7 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 21 Jun 2026 18:15:13 -0700 Subject: [PATCH 26/42] Broaden the authoring smoke test to cover more projection shapes The authoring smoke test produces 'Authoring.winmd', which the projection smoke test then generates a reference projection for. Add a richer set of authored Windows Runtime types alongside the existing 'Greeter' so the projection path exercises more codegen: two enums (including a [Flags] enum), a struct, a delegate, an interface, and a runtime class with two constructors (default and parameterized), instance methods, a settable property, an interface-implemented property, an event, and static members. Validated end-to-end locally: the types compile, 'cswinrtwinmdgen' emits a valid '.winmd' for them, and the resulting reference projection compiles cleanly against the stripped 'WinRT.Runtime' reference assembly (no implementation-only types referenced). Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Tests/SmokeTests/Authoring/Thermometer.cs | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 src/Tests/SmokeTests/Authoring/Thermometer.cs diff --git a/src/Tests/SmokeTests/Authoring/Thermometer.cs b/src/Tests/SmokeTests/Authoring/Thermometer.cs new file mode 100644 index 000000000..d76e84862 --- /dev/null +++ b/src/Tests/SmokeTests/Authoring/Thermometer.cs @@ -0,0 +1,91 @@ +using System; + +namespace Authoring; + +// A richer set of authored Windows Runtime types, exercised end-to-end by the projection smoke +// test: building the component produces 'Authoring.winmd', which the projection smoke test then +// generates a reference projection for. Between them, these cover the main projection shapes: +// enums, a flags enum, a struct, a delegate, an interface, and a runtime class with multiple +// constructors, instance methods, properties, an event, and static members. + +public enum Season +{ + Spring, + Summer, + Autumn, + Winter +} + +[Flags] +public enum SensorCapabilities : uint +{ + None = 0, + Temperature = 1, + Humidity = 2, + All = Temperature | Humidity +} + +public struct Measurement +{ + public int Value; + public Season Season; +} + +public delegate void TemperatureChangedHandler(int previousValue, int currentValue); + +public interface IThermometer +{ + int Temperature { get; } + + void Reset(); +} + +public sealed class Thermometer : IThermometer +{ + private int _temperature; + + public event TemperatureChangedHandler? TemperatureChanged; + + public Thermometer() + { + } + + public Thermometer(int initialTemperature) + { + _temperature = initialTemperature; + } + + public static int AbsoluteZero => -273; + + public int Temperature => _temperature; + + public string Label { get; set; } + + public Season CurrentSeason { get; set; } + + public SensorCapabilities Capabilities { get; set; } + + public static Thermometer CreateFreezing() + { + return new Thermometer(0); + } + + public void Reset() + { + SetTemperature(0); + } + + public void SetTemperature(int value) + { + int previousValue = _temperature; + + _temperature = value; + + TemperatureChanged?.Invoke(previousValue, value); + } + + public Measurement Measure() + { + return new Measurement { Value = _temperature, Season = CurrentSeason }; + } +} From 695c9c6a0c2117f85f14f508c971a8661e30821a Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 21 Jun 2026 20:12:14 -0700 Subject: [PATCH 27/42] Recognize reference projection types in interop generator discovery The interop generator identified projected Windows Runtime types via the per-type [WindowsRuntimeMetadata] attribute (IsProjectedWindowsRuntimeType). That attribute is now stripped from reference projections (it is an implementation-only type, absent from the WinRT.Runtime reference assembly that reference projections compile against), so the type-hierarchy discovery crawl over reference projection assemblies stopped recognizing any projected classes and failed with CSWINRTINTEROPGEN0036 (no type hierarchy key-value pairs discovered). Add IsReferenceProjectionWindowsRuntimeType, which recognizes a projected type by its declaring assembly's [WindowsRuntimeReferenceAssembly] marker, mirroring the existing IsComponentWindowsRuntimeType handling for authored components (which likewise expose projected types without the per-type attribute). Fold it into the five "is this a projected Windows Runtime type" gates that can observe reference projection definitions directly (type hierarchy base-type tracking, IsProjectedWindowsRuntimeClassType, IsWindowsRuntimeType, IsNotExclusiveToWindowsRuntimeType, and the projected interface branch in InteropInterfaceEntriesResolver). The type-hierarchy base-type check now inspects the resolved base type definition (instead of the unresolved reference) so the assembly-level marker can be read off it. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/skills/interop-generator/SKILL.md | 2 +- .../Discovery/InteropTypeDiscovery.cs | 8 +++--- .../Extensions/WindowsRuntimeExtensions.cs | 27 ++++++++++++++----- .../InteropInterfaceEntriesResolver.cs | 4 ++- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/.github/skills/interop-generator/SKILL.md b/.github/skills/interop-generator/SKILL.md index a32dc4587..673a9d5f9 100644 --- a/.github/skills/interop-generator/SKILL.md +++ b/.github/skills/interop-generator/SKILL.md @@ -287,7 +287,7 @@ The generator processes two categories of assemblies: - `System.Collections.Concurrent.ConditionalWeakTable<,>` — Memory semantics conflict **Type inclusion criteria:** -- Must be a projected Windows Runtime type (marked with `[WindowsRuntimeMetadata]` or similar) +- Must be a projected Windows Runtime type. A type is recognized as projected in any of three ways: it carries the per-type `[WindowsRuntimeMetadata]` attribute (implementation projections and types in `WinRT.Runtime.dll`); it is a public type from an authored component assembly (`IsComponentWindowsRuntimeType`); or it is defined in a reference projection assembly marked `[WindowsRuntimeReferenceAssembly]` (`IsReferenceProjectionWindowsRuntimeType`). The latter two do **not** carry the per-type `[WindowsRuntimeMetadata]` attribute — reference projections shipped in NuGet packages have it stripped (it is an implementation-only attribute, absent from the `WinRT.Runtime.dll` reference assembly they compile against), so the interop generator recognizes them by their assembly-level marker instead. - Generic types must be fully constructed (no open generic parameters) - Type hierarchy must be fully resolvable (no missing dependencies) - Must not be a managed-only type (types that never cross the Windows Runtime boundary) diff --git a/src/WinRT.Interop.Generator/Discovery/InteropTypeDiscovery.cs b/src/WinRT.Interop.Generator/Discovery/InteropTypeDiscovery.cs index c044ab3e1..d33fd3d69 100644 --- a/src/WinRT.Interop.Generator/Discovery/InteropTypeDiscovery.cs +++ b/src/WinRT.Interop.Generator/Discovery/InteropTypeDiscovery.cs @@ -56,15 +56,17 @@ public static void TryTrackTypeHierarchyType( } // We need to resolve the base type to be able to look up attributes on it - if (!baseType.IsFullyResolvable(interopReferences.RuntimeContext, out _)) + if (!baseType.IsFullyResolvable(interopReferences.RuntimeContext, out TypeDefinition? baseTypeDefinition)) { WellKnownInteropExceptions.WindowsRuntimeClassTypeNotResolvedWarning(baseType, typeDefinition).LogOrThrow(args.TreatWarningsAsErrors); return; } - // If the base type is also a projected Windows Runtime type, track it - if (baseType.IsProjectedWindowsRuntimeType) + // If the base type is also a projected Windows Runtime type, track it. The base type is recognized + // either by its '[WindowsRuntimeMetadata]' attribute (implementation projections) or by being defined + // in a reference projection assembly (reference projections don't carry that per-type attribute). + if (baseTypeDefinition.IsProjectedWindowsRuntimeType || baseTypeDefinition.IsReferenceProjectionWindowsRuntimeType) { discoveryState.TrackTypeHierarchyEntry(typeDefinition.FullName, baseType.FullName); } diff --git a/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs b/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs index ce70b8a1a..19fb59be7 100644 --- a/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs +++ b/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs @@ -115,6 +115,17 @@ public bool IsProjectedWindowsSdkXamlType /// public bool IsComponentWindowsRuntimeType => type.Scope?.GetAssembly() is { IsWindowsRuntimeComponentAssembly: true }; + /// + /// Gets a value indicating whether the type is from a Windows Runtime reference projection assembly. + /// + /// + /// Types in a reference projection assembly (marked with [WindowsRuntimeReferenceAssembly]) are + /// projected Windows Runtime types, but they do not carry the per-type [WindowsRuntimeMetadata] + /// attribute that implementation projections use (it is stripped from reference projections). This mirrors + /// how authored component assemblies expose projected types without that attribute (the IsComponentWindowsRuntimeType extension property). + /// + public bool IsReferenceProjectionWindowsRuntimeType => type.Scope?.GetAssembly() is { IsWindowsRuntimeReferenceAssembly: true }; + /// /// Checks whether an is some type. /// @@ -725,8 +736,10 @@ public bool IsProjectedWindowsRuntimeClassType return false; } - // The type also must be a projected type - return type.IsProjectedWindowsRuntimeType; + // The type also must be a projected type (recognized either by its '[WindowsRuntimeMetadata]' + // attribute, for implementation projections, or by being defined in a reference projection + // assembly, which doesn't carry that per-type attribute). + return type.IsProjectedWindowsRuntimeType || type.IsReferenceProjectionWindowsRuntimeType; } } @@ -1006,8 +1019,9 @@ public bool IsWindowsRuntimeType(InteropReferences interopReferences) // For all other cases, just check that the type is projected. This will also include manually // projected types that are defined in 'WinRT.Runtime.dll' (same attributes). Public types from - // authored component assemblies are also considered Windows Runtime types. - return type.IsProjectedWindowsRuntimeType || type.IsComponentWindowsRuntimeType; + // authored component assemblies, and types from reference projection assemblies, are also + // considered Windows Runtime types (they don't carry the per-type '[WindowsRuntimeMetadata]' attribute). + return type.IsProjectedWindowsRuntimeType || type.IsComponentWindowsRuntimeType || type.IsReferenceProjectionWindowsRuntimeType; } /// @@ -1073,8 +1087,9 @@ arrayType.BaseType is not SzArrayTypeSignature && TypeDefinition type = signature.Resolve(interopReferences.RuntimeContext); // For all other cases, first check that the type is projected. Public types from authored - // component assemblies are also considered projected, even without '[WindowsRuntimeMetadata]'. - if (!type.IsProjectedWindowsRuntimeType && !type.IsComponentWindowsRuntimeType) + // component assemblies, and types from reference projection assemblies, are also considered + // projected, even without '[WindowsRuntimeMetadata]'. + if (!type.IsProjectedWindowsRuntimeType && !type.IsComponentWindowsRuntimeType && !type.IsReferenceProjectionWindowsRuntimeType) { return false; } diff --git a/src/WinRT.Interop.Generator/Resolvers/InteropInterfaceEntriesResolver.cs b/src/WinRT.Interop.Generator/Resolvers/InteropInterfaceEntriesResolver.cs index 0de717e4f..abb157f50 100644 --- a/src/WinRT.Interop.Generator/Resolvers/InteropInterfaceEntriesResolver.cs +++ b/src/WinRT.Interop.Generator/Resolvers/InteropInterfaceEntriesResolver.cs @@ -113,7 +113,9 @@ public static IEnumerable EnumerateMetadataInterfaceE // Handle the common case for all normally projected, non-generic Windows Runtime interface types. For those, all the // interop code will just live in the 'WinRT.Projection.dll' assembly, with all projected types for the application domain. - if (interfaceType.IsProjectedWindowsRuntimeType) + // The interface is recognized either by its '[WindowsRuntimeMetadata]' attribute (implementation projections) or by being + // defined in a reference projection assembly (reference projections don't carry that per-type attribute). + if (interfaceType.IsProjectedWindowsRuntimeType || interfaceType.IsReferenceProjectionWindowsRuntimeType) { (IMethodDefOrRef get_IIDMethod, IMethodDefOrRef get_VtableMethod) = InteropImplTypeResolver.GetProjectedTypeImpl( type: interfaceType, From e29c0d32cabaa80fd0d5d8424a6a15a898181b2a Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 21 Jun 2026 20:28:16 -0700 Subject: [PATCH 28/42] Recover Windows Runtime metadata name from the implementation projection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The interop type-name marker for a third-party (non-well-known) projected type must be the source .winmd stem, because the projection writer encodes that same stem into the [UnsafeAccessorType] references it bakes into the implementation projection (WinRT.Projection.dll). The generator read that stem from the per-type [WindowsRuntimeMetadata] attribute. That attribute is now stripped from reference projections (it is an implementation-only attribute, absent from the WinRT.Runtime reference assembly they compile against). The discovery input set keeps the reference projection and excludes the forwarder/impl .dll, so a third-party type resolves to the reference projection where the attribute is gone. The marker would then fall back to the reference projection's own assembly name, which is not guaranteed to equal the .winmd stem (e.g. WinUI / Windows App SDK merge several .winmd files into one projection assembly), producing [UnsafeAccessor] references that don't match the generated interop type names. Add a TypeDefinition.GetWindowsRuntimeMetadataName(RuntimeContext) overload that reads the attribute directly when present, and otherwise — for a type from a reference projection — recovers the stem from the matching type in the third-party implementation projection (WinRT.Projection.dll), which retains it. The implementation projection is located through RuntimeContext.GetLoadedAssemblies(), which returns assemblies loaded via LoadModule even when they are outside the resolver's path set, so this needs no changes to the many InteropUtf8NameFactory call sites (they already flow the RuntimeContext through). When the stem cannot be found, the caller's fallback to the assembly name is preserved. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../references/name-mangling-scheme.md | 2 +- ...tomMappedTypeMapEntriesBuilder.ICommand.cs | 2 +- ...EntriesBuilder.INotifyCollectionChanged.cs | 2 +- ...apEntriesBuilder.INotifyPropertyChanged.cs | 2 +- ...ynamicCustomMappedTypeMapEntriesBuilder.cs | 37 ++++-- .../InteropTypeDefinitionBuilder.Delegate.cs | 37 +++--- ...nteropTypeDefinitionBuilder.EventSource.cs | 18 ++- ...nitionBuilder.IAsyncActionWithProgress1.cs | 17 ++- ...pTypeDefinitionBuilder.IAsyncOperation1.cs | 17 ++- ...ionBuilder.IAsyncOperationWithProgress2.cs | 17 ++- ...initionBuilder.ICollectionKeyValuePair2.cs | 9 +- ...teropTypeDefinitionBuilder.IDictionary2.cs | 34 ++++-- ...teropTypeDefinitionBuilder.IEnumerable1.cs | 25 +++- ...teropTypeDefinitionBuilder.IEnumerator1.cs | 30 ++++- .../InteropTypeDefinitionBuilder.IList1.cs | 31 +++-- ...DefinitionBuilder.IMapChangedEventArgs1.cs | 17 ++- ...opTypeDefinitionBuilder.IObservableMap2.cs | 27 ++++- ...ypeDefinitionBuilder.IObservableVector1.cs | 27 ++++- ...uilder.IReadOnlyCollectionKeyValuePair2.cs | 9 +- ...eDefinitionBuilder.IReadOnlyDictionary2.cs | 25 +++- ...ropTypeDefinitionBuilder.IReadOnlyList1.cs | 27 +++-- ...teropTypeDefinitionBuilder.KeyValuePair.cs | 24 ++-- .../InteropTypeDefinitionBuilder.SzArray.cs | 35 +++++- ...opTypeDefinitionBuilder.UserDefinedType.cs | 16 ++- .../Builders/InteropTypeDefinitionBuilder.cs | 24 ++-- .../Extensions/WindowsRuntimeExtensions.cs | 85 ++++++++++++-- ...ionFactory.IEnumeratorElementMarshaller.cs | 21 +++- ...actory.IReadOnlyCollectionKeyValuePair2.cs | 6 +- ...initionFactory.SzArrayElementMarshaller.cs | 21 +++- ...TypeDefinitionFactory.SzArrayMarshaller.cs | 40 ++++++- .../Factories/InteropUtf8NameFactory.cs | 25 ++-- .../Generation/InteropGenerator.Emit.cs | 110 +++++++++++++++++- .../Helpers/SignatureGenerator.cs | 15 +-- .../References/InteropDefinitions.cs | 5 + .../Resolvers/InteropImplTypeResolver.cs | 4 +- .../InteropInterfaceEntriesResolver.cs | 1 - 36 files changed, 663 insertions(+), 181 deletions(-) diff --git a/.github/skills/interop-generator/references/name-mangling-scheme.md b/.github/skills/interop-generator/references/name-mangling-scheme.md index 9ddfa2a95..9db179e95 100644 --- a/.github/skills/interop-generator/references/name-mangling-scheme.md +++ b/.github/skills/interop-generator/references/name-mangling-scheme.md @@ -38,7 +38,7 @@ These are the well-known assemblies and their compact identifiers: Compact identifiers are prefixed with `#` to distinguish them from user-defined assembly names. -For types not belonging to any well-known assembly, the implementation also checks for a `[WindowsRuntimeMetadata]` attribute on the resolved type definition. If the attribute is present, the Windows Runtime metadata name from the attribute is used as the assembly identifier instead of the actual assembly name. This allows types carrying WinRT metadata to be identified by their canonical Windows Runtime name rather than the .NET assembly they happen to live in. If the attribute is not present, the raw assembly name is used as-is. +For types not belonging to any well-known assembly, the implementation also derives the assembly identifier from the type's `[WindowsRuntimeMetadata]` value (the source `.winmd` module name, i.e. its "stem") instead of the actual assembly name. This allows types carrying WinRT metadata to be identified by their canonical Windows Runtime name rather than the .NET assembly they happen to live in. The stem is read directly from the attribute when present — implementation projections, the authored component projection, and manually projected types in `WinRT.Runtime.dll` all carry it. Reference projections shipped in Windows Runtime projection NuGet packages have the attribute **stripped** (it is an implementation-only attribute, absent from the `WinRT.Runtime.dll` reference assembly they compile against); for a type defined in such a reference projection (detected via `IsReferenceProjectionWindowsRuntimeType`), the stem is instead recovered from the matching type in the third-party implementation projection (`WinRT.Projection.dll`), located through `RuntimeContext.GetLoadedAssemblies()`. This recovery is essential because the projection writer encodes that very same stem into the `[UnsafeAccessorType]` references it emits into the implementation projection, and the reference projection's own assembly name can differ from the stem (e.g. when several `.winmd` files are merged into a single projection assembly, as with WinUI / Windows App SDK). If the stem cannot be found anywhere, the raw assembly name is used as-is. The recovery logic lives in `GetWindowsRuntimeMetadataName` (`src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs`). > [!NOTE] > Not all BCL types live in `System.Runtime`. For example, the `System.Numerics` types (`Matrix3x2`, `Matrix4x4`, `Plane`, `Quaternion`, `Vector2`, `Vector3`, `Vector4`) are in the `System.Numerics.Vectors` assembly, so their assembly identifier is `System-Numerics-Vectors` (not `#corlib`) after the `.` → `-` substitution. The assembly used is always the one from the type's actual metadata scope, not the namespace. diff --git a/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.ICommand.cs b/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.ICommand.cs index 90a94dbee..0b1ea36be 100644 --- a/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.ICommand.cs +++ b/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.ICommand.cs @@ -37,7 +37,7 @@ public static void InterfaceImpl( // We're declaring an 'internal interface class' type interfaceImplType = new( ns: InteropUtf8NameFactory.TypeNamespace(interfaceType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(interfaceType, interopReferences.RuntimeContext, "InterfaceImpl"), + name: InteropUtf8NameFactory.TypeName(interfaceType, interopDefinitions, "InterfaceImpl"), attributes: TypeAttributes.Interface | TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: null) { diff --git a/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.INotifyCollectionChanged.cs b/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.INotifyCollectionChanged.cs index b023b0b4d..d3274eae8 100644 --- a/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.INotifyCollectionChanged.cs +++ b/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.INotifyCollectionChanged.cs @@ -37,7 +37,7 @@ public static void InterfaceImpl( // We're declaring an 'internal interface class' type interfaceImplType = new( ns: InteropUtf8NameFactory.TypeNamespace(interfaceType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(interfaceType, interopReferences.RuntimeContext, "InterfaceImpl"), + name: InteropUtf8NameFactory.TypeName(interfaceType, interopDefinitions, "InterfaceImpl"), attributes: TypeAttributes.Interface | TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: null) { diff --git a/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.INotifyPropertyChanged.cs b/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.INotifyPropertyChanged.cs index aa5f3d632..d875da462 100644 --- a/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.INotifyPropertyChanged.cs +++ b/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.INotifyPropertyChanged.cs @@ -37,7 +37,7 @@ public static void InterfaceImpl( // We're declaring an 'internal interface class' type interfaceImplType = new( ns: InteropUtf8NameFactory.TypeNamespace(interfaceType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(interfaceType, interopReferences.RuntimeContext, "InterfaceImpl"), + name: InteropUtf8NameFactory.TypeName(interfaceType, interopDefinitions, "InterfaceImpl"), attributes: TypeAttributes.Interface | TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: null) { diff --git a/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.cs b/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.cs index f8a752bfc..e93ecaa7b 100644 --- a/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.cs +++ b/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.cs @@ -38,6 +38,7 @@ public static void AssemblyAttributes( windowsUIXamlMetadata: "Windows.Foundation.UniversalApiContract", microsoftUIXamlMetadata: "Microsoft.UI.Xaml.WinUIContract", trimTarget: interopReferences.IEnumerable.ToReferenceTypeSignature(), + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -47,6 +48,7 @@ public static void AssemblyAttributes( windowsUIXamlMetadata: "Windows.Foundation.UniversalApiContract", microsoftUIXamlMetadata: "Microsoft.UI.Xaml.WinUIContract", trimTarget: interopReferences.IEnumerator.ToReferenceTypeSignature(), + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -56,6 +58,7 @@ public static void AssemblyAttributes( windowsUIXamlMetadata: "Windows.Foundation.UniversalApiContract", microsoftUIXamlMetadata: "Microsoft.UI.Xaml.WinUIContract", trimTarget: interopReferences.IList.ToReferenceTypeSignature(), + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -83,6 +86,7 @@ public static void AssemblyAttributes( windowsUIXamlMetadata: "Windows.Foundation.UniversalApiContract", microsoftUIXamlMetadata: "Microsoft.UI.Xaml.WinUIContract", trimTarget: interopReferences.NotifyCollectionChangedEventArgs.ToReferenceTypeSignature(), + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections); @@ -91,6 +95,7 @@ public static void AssemblyAttributes( windowsUIXamlMetadata: "Windows.Foundation.UniversalApiContract", microsoftUIXamlMetadata: "Microsoft.UI.Xaml.WinUIContract", trimTarget: interopReferences.PropertyChangedEventArgs.ToReferenceTypeSignature(), + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections); @@ -99,6 +104,7 @@ public static void AssemblyAttributes( windowsUIXamlMetadata: "Windows.Foundation.UniversalApiContract", microsoftUIXamlMetadata: "Microsoft.UI.Xaml.WinUIContract", trimTarget: interopReferences.NotifyCollectionChangedEventHandler.ToReferenceTypeSignature(), + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections); @@ -107,6 +113,7 @@ public static void AssemblyAttributes( windowsUIXamlMetadata: "Windows.Foundation.UniversalApiContract", microsoftUIXamlMetadata: "Microsoft.UI.Xaml.WinUIContract", trimTarget: interopReferences.PropertyChangedEventHandler.ToReferenceTypeSignature(), + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections); @@ -115,11 +122,13 @@ public static void AssemblyAttributes( windowsUIXamlMetadata: "Windows.Foundation.UniversalApiContract", microsoftUIXamlMetadata: "Microsoft.UI.Xaml.WinUIContract", trimTarget: interopReferences.NotifyCollectionChangedAction.ToValueTypeSignature(), + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections); IBindableVectorViewType( + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections); @@ -131,6 +140,7 @@ public static void AssemblyAttributes( /// The metadata name for Windows.UI.Xaml. /// The metadata name for Microsoft.UI.Xaml. /// + /// The instance to use. /// The instance to use. /// The module that the attribute will be used from. /// Whether to use Windows.UI.Xaml projections. @@ -139,6 +149,7 @@ private static void InterfaceType( string windowsUIXamlMetadata, string microsoftUIXamlMetadata, TypeSignature trimTarget, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -157,7 +168,7 @@ private static void InterfaceType( // that is used, we can't define this proxy type in advance even if the interface type itself is not generic. InteropTypeDefinitionBuilder.Proxy( ns: InteropUtf8NameFactory.TypeNamespace(trimTarget, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(trimTarget, interopReferences.RuntimeContext), + name: InteropUtf8NameFactory.TypeName(trimTarget, interopDefinitions), mappedMetadata: metadata, runtimeClassName: null, metadataTypeName: MetadataTypeNameGenerator.GetMetadataTypeName(trimTarget, useWindowsUIXamlProjections), @@ -209,7 +220,7 @@ private static void ICommandInterfaceType( // Define the proxy type for the 'ICommand' interface type (it needs a dynamic one, same as the other interface types above) InteropTypeDefinitionBuilder.Proxy( ns: InteropUtf8NameFactory.TypeNamespace(trimTarget, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(trimTarget, interopReferences.RuntimeContext), + name: InteropUtf8NameFactory.TypeName(trimTarget, interopDefinitions), mappedMetadata: metadata, runtimeClassName: null, metadataTypeName: MetadataTypeNameGenerator.GetMetadataTypeName(trimTarget, useWindowsUIXamlProjections), @@ -266,7 +277,7 @@ private static void INotifyCollectionChangedInterfaceType( // Define the proxy type for the 'INotifyCollectionChanged' interface type InteropTypeDefinitionBuilder.Proxy( ns: InteropUtf8NameFactory.TypeNamespace(trimTarget, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(trimTarget, interopReferences.RuntimeContext), + name: InteropUtf8NameFactory.TypeName(trimTarget, interopDefinitions), mappedMetadata: metadata, runtimeClassName: null, metadataTypeName: MetadataTypeNameGenerator.GetMetadataTypeName(trimTarget, useWindowsUIXamlProjections), @@ -323,7 +334,7 @@ private static void INotifyPropertyChangedInterfaceType( // Define the proxy type for the 'INotifyPropertyChanged' interface type InteropTypeDefinitionBuilder.Proxy( ns: InteropUtf8NameFactory.TypeNamespace(trimTarget, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(trimTarget, interopReferences.RuntimeContext), + name: InteropUtf8NameFactory.TypeName(trimTarget, interopDefinitions), mappedMetadata: metadata, runtimeClassName: null, metadataTypeName: MetadataTypeNameGenerator.GetMetadataTypeName(trimTarget, useWindowsUIXamlProjections), @@ -364,6 +375,7 @@ private static void INotifyPropertyChangedInterfaceType( /// The metadata name for Windows.UI.Xaml. /// The metadata name for Microsoft.UI.Xaml. /// + /// The instance to use. /// The instance to use. /// The module that the attribute will be used from. /// Whether to use Windows.UI.Xaml projections. @@ -371,6 +383,7 @@ private static void ClassType( string windowsUIXamlMetadata, string microsoftUIXamlMetadata, TypeSignature trimTarget, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections) @@ -382,7 +395,7 @@ private static void ClassType( // able to do lookups correctly (this attribute will be used, since the input type is a normal class type). InteropTypeDefinitionBuilder.Proxy( ns: InteropUtf8NameFactory.TypeNamespace(trimTarget, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(trimTarget, interopReferences.RuntimeContext), + name: InteropUtf8NameFactory.TypeName(trimTarget, interopDefinitions), mappedMetadata: metadata, runtimeClassName: RuntimeClassNameGenerator.GetRuntimeClassName(trimTarget, interopReferences.RuntimeContext, useWindowsUIXamlProjections), metadataTypeName: null, @@ -417,6 +430,7 @@ private static void ClassType( /// The metadata name for Windows.UI.Xaml. /// The metadata name for Microsoft.UI.Xaml. /// + /// The instance to use. /// The instance to use. /// The module that the attribute will be used from. /// Whether to use Windows.UI.Xaml projections. @@ -424,6 +438,7 @@ private static void DelegateType( string windowsUIXamlMetadata, string microsoftUIXamlMetadata, TypeSignature trimTarget, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections) @@ -434,7 +449,7 @@ private static void DelegateType( // metadata type name is not fixed. This type can be instantiated and boxed, so we need both possible names. InteropTypeDefinitionBuilder.Proxy( ns: InteropUtf8NameFactory.TypeNamespace(trimTarget, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(trimTarget, interopReferences.RuntimeContext), + name: InteropUtf8NameFactory.TypeName(trimTarget, interopDefinitions), mappedMetadata: metadata, runtimeClassName: RuntimeClassNameGenerator.GetRuntimeClassName(trimTarget, interopReferences.RuntimeContext, useWindowsUIXamlProjections), metadataTypeName: MetadataTypeNameGenerator.GetMetadataTypeName(trimTarget, useWindowsUIXamlProjections), @@ -467,6 +482,7 @@ private static void DelegateType( /// The metadata name for Windows.UI.Xaml. /// The metadata name for Microsoft.UI.Xaml. /// + /// The instance to use. /// The instance to use. /// The module that the attribute will be used from. /// Whether to use Windows.UI.Xaml projections. @@ -474,6 +490,7 @@ private static void ValueType( string windowsUIXamlMetadata, string microsoftUIXamlMetadata, TypeSignature trimTarget, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections) @@ -484,7 +501,7 @@ private static void ValueType( // metadata type name, as above, but we also need to reference the boxed type instantiation for this type. InteropTypeDefinitionBuilder.Proxy( ns: InteropUtf8NameFactory.TypeNamespace(trimTarget, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(trimTarget, interopReferences.RuntimeContext), + name: InteropUtf8NameFactory.TypeName(trimTarget, interopDefinitions), mappedMetadata: metadata, runtimeClassName: RuntimeClassNameGenerator.GetRuntimeClassName(trimTarget, interopReferences.RuntimeContext, useWindowsUIXamlProjections), metadataTypeName: MetadataTypeNameGenerator.GetMetadataTypeName(trimTarget, useWindowsUIXamlProjections), @@ -514,10 +531,12 @@ private static void ValueType( /// /// Creates a new custom attribute value for for IBindableVectorView. /// + /// The instance to use. /// The instance to use. /// The module that the attribute will be used from. /// Whether to use Windows.UI.Xaml projections. private static void IBindableVectorViewType( + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections) @@ -533,7 +552,7 @@ private static void IBindableVectorViewType( // a proxy type for it, with the correct runtime class name, and an entry just in the marshalling proxy type map. InteropTypeDefinitionBuilder.Proxy( ns: InteropUtf8NameFactory.TypeNamespace(adapterType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(adapterType, interopReferences.RuntimeContext), + name: InteropUtf8NameFactory.TypeName(adapterType, interopDefinitions), mappedMetadata: null, runtimeClassName: runtimeClassName, metadataTypeName: null, @@ -646,4 +665,4 @@ private static TypeDefinition GetMethodsType(TypeSignature type, InteropReferenc return methodsType; } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs index ffc5895aa..aec8b8286 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs @@ -42,7 +42,7 @@ public static void IIDs( { // 'IDelegate' IID IID( - name: InteropUtf8NameFactory.TypeName(delegateType, interopReferences.RuntimeContext), + name: InteropUtf8NameFactory.TypeName(delegateType, interopDefinitions), interopDefinitions: interopDefinitions, interopReferences: interopReferences, iid: GuidGenerator.CreateIID(delegateType, interopDefinitions, interopReferences, useWindowsUIXamlProjections), @@ -55,7 +55,7 @@ public static void IIDs( // scenario. This is different than boxed value type, which instead are // just always projected as and using 'Nullable' to represent this. IID( - name: InteropUtf8NameFactory.TypeName(delegateType, interopReferences.RuntimeContext, "Reference"), + name: InteropUtf8NameFactory.TypeName(delegateType, interopDefinitions, "Reference"), interopDefinitions: interopDefinitions, interopReferences: interopReferences, iid: GuidGenerator.CreateIID(delegateType.MakeBoxedType(), interopDefinitions, interopReferences, useWindowsUIXamlProjections), @@ -104,7 +104,7 @@ public static void Vftbl( { vftblType = WellKnownTypeDefinitionFactory.DelegateVftbl( ns: InteropUtf8NameFactory.TypeNamespace(delegateType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(delegateType, interopReferences.RuntimeContext, "Vftbl"), + name: InteropUtf8NameFactory.TypeName(delegateType, interopDefinitions, "Vftbl"), senderType: senderType.GetAbiType(interopReferences), argsType: argsType.GetAbiType(interopReferences), interopReferences: interopReferences); @@ -120,6 +120,7 @@ static void GetOrCreateVftbl( TypeSignature argsType, TypeSignature displaySenderType, TypeSignature displayArgsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -139,7 +140,7 @@ static void GetOrCreateVftbl( // Construct a new specialized vtable type TypeDefinition newVftblType = WellKnownTypeDefinitionFactory.DelegateVftbl( ns: InteropUtf8NameFactory.TypeNamespace(sharedEventHandlerType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(sharedEventHandlerType, interopReferences.RuntimeContext, "Vftbl"), + name: InteropUtf8NameFactory.TypeName(sharedEventHandlerType, interopDefinitions, "Vftbl"), senderType: senderType, argsType: argsType, interopReferences: interopReferences); @@ -162,6 +163,7 @@ static void GetOrCreateVftbl( argsType: argsType.GetAbiType(interopReferences), displaySenderType: interopReferences.Object, displayArgsType: argsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -174,6 +176,7 @@ static void GetOrCreateVftbl( argsType: interopReferences.Void.MakePointerType(), displaySenderType: senderType, displayArgsType: interopReferences.Object, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -288,7 +291,7 @@ public static void ImplType( Impl( interfaceType: ComInterfaceType.InterfaceIsIUnknown, ns: InteropUtf8NameFactory.TypeNamespace(delegateType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(delegateType, interopReferences.RuntimeContext, "Impl"), + name: InteropUtf8NameFactory.TypeName(delegateType, interopDefinitions, "Impl"), vftblType: vftblType, interopDefinitions: interopDefinitions, interopReferences: interopReferences, @@ -396,7 +399,7 @@ public static void ReferenceImplType( Impl( interfaceType: ComInterfaceType.InterfaceIsIInspectable, ns: InteropUtf8NameFactory.TypeNamespace(delegateType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(delegateType, interopReferences.RuntimeContext, "ReferenceImpl"), + name: InteropUtf8NameFactory.TypeName(delegateType, interopDefinitions, "ReferenceImpl"), vftblType: interopDefinitions.DelegateReferenceVftbl, interopDefinitions: interopDefinitions, interopReferences: interopReferences, @@ -430,7 +433,7 @@ public static void InterfaceEntriesImpl( { InteropTypeDefinitionBuilder.InterfaceEntriesImpl( ns: InteropUtf8NameFactory.TypeNamespace(delegateType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(delegateType, interopReferences.RuntimeContext, "InterfaceEntriesImpl"), + name: InteropUtf8NameFactory.TypeName(delegateType, interopDefinitions, "InterfaceEntriesImpl"), entriesFieldType: interopDefinitions.DelegateInterfaceEntries, interopReferences: interopReferences, module: module, @@ -453,6 +456,7 @@ public static void InterfaceEntriesImpl( /// The for the type. /// The type returned by . /// The 'IID' get method for the 'IDelegate' interface. + /// The instance to use. /// The instance to use. /// The interop module being built. /// The resulting callback type. @@ -460,6 +464,7 @@ public static void ComWrappersCallbackType( TypeSignature delegateType, TypeDefinition nativeDelegateType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition callbackType) @@ -467,7 +472,7 @@ public static void ComWrappersCallbackType( // We're declaring an 'internal abstract class' type callbackType = new( ns: InteropUtf8NameFactory.TypeNamespace(delegateType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(delegateType, interopReferences.RuntimeContext, "ComWrappersCallback"), + name: InteropUtf8NameFactory.TypeName(delegateType, interopDefinitions, "ComWrappersCallback"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()) { @@ -538,7 +543,7 @@ public static void NativeDelegateType( // We're declaring an 'internal static class' type nativeDelegateType = new( ns: InteropUtf8NameFactory.TypeNamespace(delegateType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(delegateType, interopReferences.RuntimeContext, "NativeDelegate"), + name: InteropUtf8NameFactory.TypeName(delegateType, interopDefinitions, "NativeDelegate"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()); @@ -685,7 +690,7 @@ public static void ComWrappersMarshallerAttribute( // We're declaring an 'internal sealed class' type marshallerType = new( ns: InteropUtf8NameFactory.TypeNamespace(delegateType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(delegateType, interopReferences.RuntimeContext, "ComWrappersMarshallerAttribute"), + name: InteropUtf8NameFactory.TypeName(delegateType, interopDefinitions, "ComWrappersMarshallerAttribute"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit, baseType: interopReferences.WindowsRuntimeComWrappersMarshallerAttribute); @@ -785,6 +790,7 @@ public static void ComWrappersMarshallerAttribute( /// The instance returned by . /// The 'IID' get method for the 'IDelegate' interface. /// The resulting 'IID' get method for the boxed 'IDelegate' interface. + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The module that will contain the type being created. @@ -794,6 +800,7 @@ public static void Marshaller( TypeDefinition delegateComWrappersCallbackType, MethodDefinition get_IidMethod, MethodDefinition get_ReferenceIidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -802,7 +809,7 @@ public static void Marshaller( // We're declaring an 'internal static class' type marshallerType = new( ns: InteropUtf8NameFactory.TypeNamespace(delegateType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(delegateType, interopReferences.RuntimeContext, "Marshaller"), + name: InteropUtf8NameFactory.TypeName(delegateType, interopDefinitions, "Marshaller"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()); @@ -913,6 +920,7 @@ public static void Marshaller( /// /// The for the type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// Whether to use Windows.UI.Xaml projections. @@ -920,6 +928,7 @@ public static void Marshaller( public static void Proxy( TypeSignature delegateType, TypeDefinition comWrappersMarshallerAttributeType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -930,7 +939,7 @@ public static void Proxy( // '[WindowsRuntimeMetadataTypeName]', as that's different than the runtime class name (which uses 'IReference'). InteropTypeDefinitionBuilder.Proxy( ns: InteropUtf8NameFactory.TypeNamespace(delegateType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(delegateType, interopReferences.RuntimeContext), + name: InteropUtf8NameFactory.TypeName(delegateType, interopDefinitions), mappedMetadata: "Windows.Foundation.FoundationContract", runtimeClassName: RuntimeClassNameGenerator.GetRuntimeClassName(delegateType, interopReferences.RuntimeContext, useWindowsUIXamlProjections), metadataTypeName: MetadataTypeNameGenerator.GetMetadataTypeName(delegateType, useWindowsUIXamlProjections), @@ -946,7 +955,7 @@ public static void Proxy( /// Creates the type map attributes for some type. /// /// The for the type. - /// The instance returned by . + /// The instance returned by . /// The instance to use. /// The module that will contain the type being created. /// Whether to use Windows.UI.Xaml projections. @@ -975,4 +984,4 @@ public static void TypeMapAttributes( module: module); } } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.EventSource.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.EventSource.cs index 4caf22e65..dbcec17d5 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.EventSource.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.EventSource.cs @@ -24,12 +24,14 @@ public static class EventSource /// /// The for the type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// The resulting event source type. public static void EventHandler1( GenericInstanceTypeSignature delegateType, TypeDefinition marshallerType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition eventSourceType) @@ -41,6 +43,7 @@ public static void EventHandler1( baseEventSourceType: interopReferences.EventHandler1EventSource, baseEventSource_ctor: interopReferences.EventHandler1EventSource_ctor(eventArgsType), marshallerType: marshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, eventSourceType: out eventSourceType); @@ -51,12 +54,14 @@ public static void EventHandler1( /// /// The for the type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// The resulting event source type. public static void EventHandler2( GenericInstanceTypeSignature delegateType, TypeDefinition marshallerType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition eventSourceType) @@ -69,6 +74,7 @@ public static void EventHandler2( baseEventSourceType: interopReferences.EventHandler2EventSource, baseEventSource_ctor: interopReferences.EventHandler2EventSource_ctor(senderType, eventArgsType), marshallerType: marshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, eventSourceType: out eventSourceType); @@ -79,6 +85,7 @@ public static void EventHandler2( /// /// The for the delegate type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The module that will contain the type being created. @@ -86,6 +93,7 @@ public static void EventHandler2( public static void VectorChangedEventHandler1( GenericInstanceTypeSignature delegateType, TypeDefinition marshallerType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -98,6 +106,7 @@ public static void VectorChangedEventHandler1( baseEventSourceType: interopReferences.VectorChangedEventHandler1EventSource, baseEventSource_ctor: interopReferences.VectorChangedEventHandler1EventSource_ctor(elementType), marshallerType: marshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, eventSourceType: out eventSourceType); @@ -111,6 +120,7 @@ public static void VectorChangedEventHandler1( /// /// The for the delegate type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The module that will contain the type being created. @@ -118,6 +128,7 @@ public static void VectorChangedEventHandler1( public static void MapChangedEventHandler2( GenericInstanceTypeSignature delegateType, TypeDefinition marshallerType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -131,6 +142,7 @@ public static void MapChangedEventHandler2( baseEventSourceType: interopReferences.MapChangedEventHandler2EventSource, baseEventSource_ctor: interopReferences.MapChangedEventHandler2EventSource_ctor(keyType, valueType), marshallerType: marshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, eventSourceType: out eventSourceType); @@ -146,6 +158,7 @@ public static void MapChangedEventHandler2( /// The for the base event source type. /// The for the constructor of the base event source type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// The resulting event source type. @@ -154,6 +167,7 @@ private static void DerivedEventSource( TypeReference baseEventSourceType, MemberReference baseEventSource_ctor, TypeDefinition marshallerType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition eventSourceType) @@ -163,7 +177,7 @@ private static void DerivedEventSource( // We're declaring an 'internal sealed class' type eventSourceType = new( ns: "ABI.WindowsRuntime.InteropServices"u8, - name: InteropUtf8NameFactory.TypeName(baseEventSourceSignature, interopReferences.RuntimeContext), + name: InteropUtf8NameFactory.TypeName(baseEventSourceSignature, interopDefinitions), attributes: TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit, baseType: baseEventSourceSignature.ToTypeDefOrRef()); @@ -207,4 +221,4 @@ private static void DerivedEventSource( eventSourceType.Methods.Add(convertToUnmanagedMethod); } } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncActionWithProgress1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncActionWithProgress1.cs index 95b61f037..4839e06e7 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncActionWithProgress1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncActionWithProgress1.cs @@ -43,7 +43,7 @@ public static void Methods( // We're declaring an 'internal abstract class' type actionMethodsType = new TypeDefinition( ns: InteropUtf8NameFactory.TypeNamespace(actionType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(actionType, interopReferences.RuntimeContext, "Methods"), + name: InteropUtf8NameFactory.TypeName(actionType, interopDefinitions, "Methods"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()) { @@ -148,12 +148,14 @@ public static void Methods( /// /// The for the async action type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The interop module being built. /// The resulting native object type. public static void NativeObject( GenericInstanceTypeSignature actionType, TypeDefinition actionMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition nativeObjectType) @@ -166,6 +168,7 @@ public static void NativeObject( InteropTypeDefinitionBuilder.NativeObject( typeSignature: actionType, nativeObjectBaseType: windowsRuntimeAsyncActionWithProgress1Type, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out nativeObjectType); @@ -177,6 +180,7 @@ public static void NativeObject( /// The for the async action type. /// The type returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The interop module being built. /// Whether to use Windows.UI.Xaml projections. @@ -185,6 +189,7 @@ public static void ComWrappersCallbackType( TypeSignature actionType, TypeDefinition nativeObjectType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -195,6 +200,7 @@ public static void ComWrappersCallbackType( typeSignature: actionType, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out callbackType); @@ -206,6 +212,7 @@ public static void ComWrappersCallbackType( /// The for the async action type. /// The type returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// The resulting marshaller type. @@ -213,6 +220,7 @@ public static void ComWrappersMarshallerAttribute( GenericInstanceTypeSignature actionType, TypeDefinition nativeObjectType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition marshallerType) @@ -221,6 +229,7 @@ public static void ComWrappersMarshallerAttribute( typeSignature: actionType, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out marshallerType); @@ -250,7 +259,7 @@ public static void InterfaceImpl( // We're declaring an 'internal interface class' type interfaceImplType = new( ns: InteropUtf8NameFactory.TypeNamespace(actionType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(actionType, interopReferences.RuntimeContext, "InterfaceImpl"), + name: InteropUtf8NameFactory.TypeName(actionType, interopDefinitions, "InterfaceImpl"), attributes: TypeAttributes.Interface | TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: null) { @@ -473,7 +482,7 @@ public static void ImplType( Impl( interfaceType: ComInterfaceType.InterfaceIsIInspectable, ns: InteropUtf8NameFactory.TypeNamespace(actionType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(actionType, interopReferences.RuntimeContext, "Impl"), + name: InteropUtf8NameFactory.TypeName(actionType, interopDefinitions, "Impl"), vftblType: interopDefinitions.IAsyncActionWithProgressVftbl, interopDefinitions: interopDefinitions, interopReferences: interopReferences, @@ -490,4 +499,4 @@ public static void ImplType( emitState.TrackTypeDefinition(implType, actionType, "Impl"); } } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncOperation1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncOperation1.cs index 53b10c7b9..6712afce9 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncOperation1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncOperation1.cs @@ -42,7 +42,7 @@ public static void Methods( // We're declaring an 'internal abstract class' type operationMethodsType = new TypeDefinition( ns: InteropUtf8NameFactory.TypeNamespace(operationType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(operationType, interopReferences.RuntimeContext, "Methods"), + name: InteropUtf8NameFactory.TypeName(operationType, interopDefinitions, "Methods"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()) { @@ -102,12 +102,14 @@ public static void Methods( /// /// The for the async operation type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The interop module being built. /// The resulting native object type. public static void NativeObject( GenericInstanceTypeSignature operationType, TypeDefinition operationMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition nativeObjectType) @@ -120,6 +122,7 @@ public static void NativeObject( InteropTypeDefinitionBuilder.NativeObject( typeSignature: operationType, nativeObjectBaseType: windowsRuntimeAsyncOperation1Type, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out nativeObjectType); @@ -131,6 +134,7 @@ public static void NativeObject( /// The for the async operation type. /// The type returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The interop module being built. /// Whether to use Windows.UI.Xaml projections. @@ -139,6 +143,7 @@ public static void ComWrappersCallbackType( TypeSignature operationType, TypeDefinition nativeObjectType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -149,6 +154,7 @@ public static void ComWrappersCallbackType( typeSignature: operationType, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out callbackType); @@ -160,6 +166,7 @@ public static void ComWrappersCallbackType( /// The for the async operation type. /// The type returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// The resulting marshaller type. @@ -167,6 +174,7 @@ public static void ComWrappersMarshallerAttribute( GenericInstanceTypeSignature operationType, TypeDefinition nativeObjectType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition marshallerType) @@ -175,6 +183,7 @@ public static void ComWrappersMarshallerAttribute( typeSignature: operationType, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out marshallerType); @@ -204,7 +213,7 @@ public static void InterfaceImpl( // We're declaring an 'internal interface class' type interfaceImplType = new( ns: InteropUtf8NameFactory.TypeNamespace(operationType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(operationType, interopReferences.RuntimeContext, "InterfaceImpl"), + name: InteropUtf8NameFactory.TypeName(operationType, interopDefinitions, "InterfaceImpl"), attributes: TypeAttributes.Interface | TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: null) { @@ -349,7 +358,7 @@ public static void ImplType( Impl( interfaceType: ComInterfaceType.InterfaceIsIInspectable, ns: InteropUtf8NameFactory.TypeNamespace(operationType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(operationType, interopReferences.RuntimeContext, "Impl"), + name: InteropUtf8NameFactory.TypeName(operationType, interopDefinitions, "Impl"), vftblType: interopDefinitions.IAsyncOperationVftbl, interopDefinitions: interopDefinitions, interopReferences: interopReferences, @@ -364,4 +373,4 @@ public static void ImplType( emitState.TrackTypeDefinition(implType, operationType, "Impl"); } } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncOperationWithProgress2.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncOperationWithProgress2.cs index 74cb52237..d9096570a 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncOperationWithProgress2.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IAsyncOperationWithProgress2.cs @@ -43,7 +43,7 @@ public static void Methods( // We're declaring an 'internal abstract class' type operationMethodsType = new TypeDefinition( ns: InteropUtf8NameFactory.TypeNamespace(operationType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(operationType, interopReferences.RuntimeContext, "Methods"), + name: InteropUtf8NameFactory.TypeName(operationType, interopDefinitions, "Methods"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()) { @@ -141,12 +141,14 @@ public static void Methods( /// /// The for the async operation type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The interop module being built. /// The resulting native object type. public static void NativeObject( GenericInstanceTypeSignature operationType, TypeDefinition operationMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition nativeObjectType) @@ -160,6 +162,7 @@ public static void NativeObject( InteropTypeDefinitionBuilder.NativeObject( typeSignature: operationType, nativeObjectBaseType: windowsRuntimeAsyncOperationWithProgress2Type, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out nativeObjectType); @@ -171,6 +174,7 @@ public static void NativeObject( /// The for the async operation type. /// The type returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The interop module being built. /// Whether to use Windows.UI.Xaml projections. @@ -179,6 +183,7 @@ public static void ComWrappersCallbackType( TypeSignature operationType, TypeDefinition nativeObjectType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -189,6 +194,7 @@ public static void ComWrappersCallbackType( typeSignature: operationType, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out callbackType); @@ -200,6 +206,7 @@ public static void ComWrappersCallbackType( /// The for the async operation type. /// The type returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// The resulting marshaller type. @@ -207,6 +214,7 @@ public static void ComWrappersMarshallerAttribute( GenericInstanceTypeSignature operationType, TypeDefinition nativeObjectType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition marshallerType) @@ -215,6 +223,7 @@ public static void ComWrappersMarshallerAttribute( typeSignature: operationType, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out marshallerType); @@ -245,7 +254,7 @@ public static void InterfaceImpl( // We're declaring an 'internal interface class' type interfaceImplType = new( ns: InteropUtf8NameFactory.TypeNamespace(operationType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(operationType, interopReferences.RuntimeContext, "InterfaceImpl"), + name: InteropUtf8NameFactory.TypeName(operationType, interopDefinitions, "InterfaceImpl"), attributes: TypeAttributes.Interface | TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: null) { @@ -475,7 +484,7 @@ public static void ImplType( Impl( interfaceType: ComInterfaceType.InterfaceIsIInspectable, ns: InteropUtf8NameFactory.TypeNamespace(operationType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(operationType, interopReferences.RuntimeContext, "Impl"), + name: InteropUtf8NameFactory.TypeName(operationType, interopDefinitions, "Impl"), vftblType: interopDefinitions.IAsyncOperationWithProgressVftbl, interopDefinitions: interopDefinitions, interopReferences: interopReferences, @@ -492,4 +501,4 @@ public static void ImplType( emitState.TrackTypeDefinition(implType, operationType, "Impl"); } } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.ICollectionKeyValuePair2.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.ICollectionKeyValuePair2.cs index 2e6c816b4..389965812 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.ICollectionKeyValuePair2.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.ICollectionKeyValuePair2.cs @@ -23,11 +23,13 @@ public static class ICollectionKeyValuePair2 /// Creates a new type definition for the forwarder attribute for a of type. /// /// The for the generic interface type. + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// The resulting marshaller type. public static void ForwarderAttribute( GenericInstanceTypeSignature collectionType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition forwarderAttributeType) @@ -40,6 +42,7 @@ public static void ForwarderAttribute( readOnlyCollectionType: collectionType, readOnlyDictionaryType: interopReferences.IDictionary2.MakeGenericReferenceType([keyType, valueType]), readOnlyListType: interopReferences.IList1.MakeGenericReferenceType([keyValuePairType]), + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, forwarderAttributeType: out forwarderAttributeType); @@ -50,6 +53,7 @@ public static void ForwarderAttribute( /// /// The for the generic interface type. /// The type returned by . + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The module that will contain the type being created. @@ -57,6 +61,7 @@ public static void ForwarderAttribute( public static void InterfaceImpl( GenericInstanceTypeSignature collectionType, TypeDefinition forwarderAttributeType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -72,7 +77,7 @@ public static void InterfaceImpl( // We're declaring an 'internal interface class' type interfaceImplType = new( ns: InteropUtf8NameFactory.TypeNamespace(collectionType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(collectionType, interopReferences.RuntimeContext, "InterfaceImpl"), + name: InteropUtf8NameFactory.TypeName(collectionType, interopDefinitions, "InterfaceImpl"), attributes: TypeAttributes.Interface | TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: null) { @@ -278,4 +283,4 @@ public static void TypeMapAttributes( module: module); } } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs index 220ec2d23..3576808ec 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs @@ -26,6 +26,7 @@ public static class IDictionary2 /// /// The for the type. /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The interop module being built. @@ -33,6 +34,7 @@ public static class IDictionary2 public static void Interface( GenericInstanceTypeSignature dictionaryType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -41,7 +43,7 @@ public static void Interface( // We're declaring an 'internal abstract class' type interfaceType = new TypeDefinition( ns: InteropUtf8NameFactory.TypeNamespace(dictionaryType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(dictionaryType, interopReferences.RuntimeContext, "Interface"), + name: InteropUtf8NameFactory.TypeName(dictionaryType, interopDefinitions, "Interface"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()) { @@ -105,7 +107,7 @@ public static void Vftbl( { vftblType = WellKnownTypeDefinitionFactory.IDictionary2Vftbl( ns: InteropUtf8NameFactory.TypeNamespace(dictionaryType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(dictionaryType, interopReferences.RuntimeContext, "Vftbl"), + name: InteropUtf8NameFactory.TypeName(dictionaryType, interopDefinitions, "Vftbl"), keyType: keyType, valueType: valueType, interopReferences: interopReferences); @@ -121,6 +123,7 @@ static void GetOrCreateVftbl( TypeSignature valueType, TypeSignature displayKeyType, TypeSignature displayValueType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -140,7 +143,7 @@ static void GetOrCreateVftbl( // Construct a new specialized vtable type TypeDefinition newVftblType = WellKnownTypeDefinitionFactory.IDictionary2Vftbl( ns: InteropUtf8NameFactory.TypeNamespace(sharedDictionaryType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(sharedDictionaryType, interopReferences.RuntimeContext, "Vftbl"), + name: InteropUtf8NameFactory.TypeName(sharedDictionaryType, interopDefinitions, "Vftbl"), keyType: keyType, valueType: valueType, interopReferences: interopReferences); @@ -163,6 +166,7 @@ static void GetOrCreateVftbl( valueType: valueType, displayKeyType: interopReferences.Object, displayValueType: valueType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -175,6 +179,7 @@ static void GetOrCreateVftbl( valueType: interopReferences.Void.MakePointerType(), displayKeyType: keyType, displayValueType: interopReferences.Object, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -187,6 +192,7 @@ static void GetOrCreateVftbl( /// /// The for the type. /// The type returned by . + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The interop module being built. @@ -194,6 +200,7 @@ static void GetOrCreateVftbl( public static void IMapMethods( GenericInstanceTypeSignature dictionaryType, TypeDefinition vftblType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -205,7 +212,7 @@ public static void IMapMethods( // We're declaring an 'internal abstract class' type mapMethodsType = new TypeDefinition( ns: InteropUtf8NameFactory.TypeNamespace(dictionaryType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(dictionaryType, interopReferences.RuntimeContext, "IMapMethods"), + name: InteropUtf8NameFactory.TypeName(dictionaryType, interopDefinitions, "IMapMethods"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()) { @@ -271,6 +278,7 @@ public static void IMapMethods( /// /// The for the type. /// The type returned by . + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The interop module being built. @@ -278,6 +286,7 @@ public static void IMapMethods( public static void Methods( GenericInstanceTypeSignature dictionaryType, TypeDefinition mapMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -289,7 +298,7 @@ public static void Methods( // We're declaring an 'internal static class' type dictionaryMethodsType = new TypeDefinition( ns: InteropUtf8NameFactory.TypeNamespace(dictionaryType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(dictionaryType, interopReferences.RuntimeContext, "Methods"), + name: InteropUtf8NameFactory.TypeName(dictionaryType, interopDefinitions, "Methods"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()); @@ -639,6 +648,7 @@ public static void Methods( /// /// The for the type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The interop module being built. @@ -646,6 +656,7 @@ public static void Methods( public static void NativeObject( GenericInstanceTypeSignature dictionaryType, TypeDefinition mapMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -667,6 +678,7 @@ public static void NativeObject( InteropTypeDefinitionBuilder.NativeObject( typeSignature: dictionaryType, nativeObjectBaseType: windowsRuntimeDictionary5Type, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out nativeObjectType); @@ -678,6 +690,7 @@ public static void NativeObject( /// The for the type. /// The type returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The interop module being built. /// Whether to use Windows.UI.Xaml projections. @@ -686,6 +699,7 @@ public static void ComWrappersCallbackType( TypeSignature dictionaryType, TypeDefinition nativeObjectType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -696,6 +710,7 @@ public static void ComWrappersCallbackType( typeSignature: dictionaryType, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out callbackType); @@ -707,6 +722,7 @@ public static void ComWrappersCallbackType( /// The for the type. /// The type returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// The resulting marshaller type. @@ -714,6 +730,7 @@ public static void ComWrappersMarshallerAttribute( GenericInstanceTypeSignature dictionaryType, TypeDefinition nativeObjectType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition marshallerType) @@ -722,6 +739,7 @@ public static void ComWrappersMarshallerAttribute( typeSignature: dictionaryType, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out marshallerType); @@ -755,7 +773,7 @@ public static void InterfaceImpl( // We're declaring an 'internal interface class' type interfaceImplType = new( ns: InteropUtf8NameFactory.TypeNamespace(dictionaryType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(dictionaryType, interopReferences.RuntimeContext, "InterfaceImpl"), + name: InteropUtf8NameFactory.TypeName(dictionaryType, interopDefinitions, "InterfaceImpl"), attributes: TypeAttributes.Interface | TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: null) { @@ -1039,7 +1057,7 @@ public static void ImplType( Impl( interfaceType: ComInterfaceType.InterfaceIsIInspectable, ns: InteropUtf8NameFactory.TypeNamespace(dictionaryType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(dictionaryType, interopReferences.RuntimeContext, "Impl"), + name: InteropUtf8NameFactory.TypeName(dictionaryType, interopDefinitions, "Impl"), vftblType: vftblType, interopDefinitions: interopDefinitions, interopReferences: interopReferences, @@ -1058,4 +1076,4 @@ public static void ImplType( emitState.TrackTypeDefinition(implType, dictionaryType, "Impl"); } } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IEnumerable1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IEnumerable1.cs index c2b66936d..c20a92fb8 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IEnumerable1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IEnumerable1.cs @@ -28,6 +28,7 @@ public static class IEnumerable1 /// /// The for the type. /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The interop module being built. @@ -35,6 +36,7 @@ public static class IEnumerable1 public static void Interface( GenericInstanceTypeSignature enumerableType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -43,7 +45,7 @@ public static void Interface( // We're declaring an 'internal abstract class' type interfaceType = new TypeDefinition( ns: InteropUtf8NameFactory.TypeNamespace(enumerableType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(enumerableType, interopReferences.RuntimeContext, "Interface"), + name: InteropUtf8NameFactory.TypeName(enumerableType, interopDefinitions, "Interface"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()) { @@ -92,7 +94,7 @@ public static void IIterableMethods( // We're declaring an 'internal static class' type iterableMethodsType = new TypeDefinition( ns: InteropUtf8NameFactory.TypeNamespace(enumerableType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(enumerableType, interopReferences.RuntimeContext, "IIterableMethods"), + name: InteropUtf8NameFactory.TypeName(enumerableType, interopDefinitions, "IIterableMethods"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()) { @@ -211,12 +213,14 @@ public static void IIterableMethods( /// /// The for the type. /// The type returned by . + /// The instance to use. /// The instance to use. /// The interop module being built. /// The resulting methods type. public static void Methods( GenericInstanceTypeSignature enumerableType, TypeDefinition iterableMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition enumerableMethodsType) @@ -226,7 +230,7 @@ public static void Methods( // We're declaring an 'internal static class' type enumerableMethodsType = new TypeDefinition( ns: InteropUtf8NameFactory.TypeNamespace(enumerableType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(enumerableType, interopReferences.RuntimeContext, "Methods"), + name: InteropUtf8NameFactory.TypeName(enumerableType, interopDefinitions, "Methods"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()); @@ -258,12 +262,14 @@ public static void Methods( /// /// The for the type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The interop module being built. /// The resulting native object type. public static void NativeObject( GenericInstanceTypeSignature enumerableType, TypeDefinition iterableMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition nativeObjectType) @@ -276,6 +282,7 @@ public static void NativeObject( InteropTypeDefinitionBuilder.NativeObject( typeSignature: enumerableType, nativeObjectBaseType: windowsRuntimeEnumerable1Type, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out nativeObjectType); @@ -287,6 +294,7 @@ public static void NativeObject( /// The for the type. /// The type returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The interop module being built. /// Whether to use Windows.UI.Xaml projections. @@ -295,6 +303,7 @@ public static void ComWrappersCallbackType( TypeSignature enumerableType, TypeDefinition nativeObjectType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -305,6 +314,7 @@ public static void ComWrappersCallbackType( typeSignature: enumerableType, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out callbackType); @@ -316,6 +326,7 @@ public static void ComWrappersCallbackType( /// The for the type. /// The type returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// The resulting marshaller type. @@ -323,6 +334,7 @@ public static void ComWrappersMarshallerAttribute( GenericInstanceTypeSignature enumerableType, TypeDefinition nativeObjectType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition marshallerType) @@ -331,6 +343,7 @@ public static void ComWrappersMarshallerAttribute( typeSignature: enumerableType, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out marshallerType); @@ -360,7 +373,7 @@ public static void InterfaceImpl( // We're declaring an 'internal interface class' type interfaceImplType = new( ns: InteropUtf8NameFactory.TypeNamespace(enumerableType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(enumerableType, interopReferences.RuntimeContext, "InterfaceImpl"), + name: InteropUtf8NameFactory.TypeName(enumerableType, interopDefinitions, "InterfaceImpl"), attributes: TypeAttributes.Interface | TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: null) { @@ -445,7 +458,7 @@ public static void ImplType( Impl( interfaceType: ComInterfaceType.InterfaceIsIInspectable, ns: InteropUtf8NameFactory.TypeNamespace(enumerableType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(enumerableType, interopReferences.RuntimeContext, "Impl"), + name: InteropUtf8NameFactory.TypeName(enumerableType, interopDefinitions, "Impl"), vftblType: interopDefinitions.IEnumerable1Vftbl, interopDefinitions: interopDefinitions, interopReferences: interopReferences, @@ -457,4 +470,4 @@ public static void ImplType( emitState.TrackTypeDefinition(implType, enumerableType, "Impl"); } } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IEnumerator1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IEnumerator1.cs index f3447076c..e908cc287 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IEnumerator1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IEnumerator1.cs @@ -41,7 +41,7 @@ public static void IID( out MethodDefinition get_IidMethod) { InteropTypeDefinitionBuilder.IID( - name: InteropUtf8NameFactory.TypeName(enumeratorType, interopReferences.RuntimeContext), + name: InteropUtf8NameFactory.TypeName(enumeratorType, interopDefinitions), interopDefinitions: interopDefinitions, interopReferences: interopReferences, iid: GuidGenerator.CreateIID(enumeratorType, interopDefinitions, interopReferences, useWindowsUIXamlProjections), @@ -73,7 +73,7 @@ public static void IIteratorMethods( // We're declaring an 'internal abstract class' type iteratorMethodsType = new( ns: InteropUtf8NameFactory.TypeNamespace(enumeratorType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(enumeratorType, interopReferences.RuntimeContext, "IIteratorMethods"), + name: InteropUtf8NameFactory.TypeName(enumeratorType, interopDefinitions, "IIteratorMethods"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()) { @@ -210,12 +210,14 @@ public static void IIteratorMethods( /// /// The for the type. /// The type returned by . + /// The instance to use. /// The instance to use. /// The interop module being built. /// The resulting methods type. public static void Methods( GenericInstanceTypeSignature enumeratorType, TypeDefinition iteratorMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition enumeratorMethodsType) @@ -225,7 +227,7 @@ public static void Methods( // We're declaring an 'internal static class' type enumeratorMethodsType = new TypeDefinition( ns: InteropUtf8NameFactory.TypeNamespace(enumeratorType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(enumeratorType, interopReferences.RuntimeContext, "Methods"), + name: InteropUtf8NameFactory.TypeName(enumeratorType, interopDefinitions, "Methods"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()); @@ -277,12 +279,14 @@ public static void Methods( /// /// The for the type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The interop module being built. /// The resulting native object type. public static void NativeObject( GenericInstanceTypeSignature enumeratorType, TypeDefinition iteratorMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition nativeObjectType) @@ -295,6 +299,7 @@ public static void NativeObject( InteropTypeDefinitionBuilder.NativeObject( typeSignature: enumeratorType, nativeObjectBaseType: windowsRuntimeEnumerator2Type, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out nativeObjectType); @@ -306,6 +311,7 @@ public static void NativeObject( /// The for the type. /// The type returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The interop module being built. /// Whether to use Windows.UI.Xaml projections. @@ -314,6 +320,7 @@ public static void ComWrappersCallbackType( TypeSignature enumeratorType, TypeDefinition nativeObjectType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -324,6 +331,7 @@ public static void ComWrappersCallbackType( typeSignature: enumeratorType, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out callbackType); @@ -335,6 +343,7 @@ public static void ComWrappersCallbackType( /// The for the type. /// The type returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// The resulting marshaller type. @@ -342,6 +351,7 @@ public static void ComWrappersMarshallerAttribute( GenericInstanceTypeSignature enumeratorType, TypeDefinition nativeObjectType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition marshallerType) @@ -350,6 +360,7 @@ public static void ComWrappersMarshallerAttribute( typeSignature: enumeratorType, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out marshallerType); @@ -379,7 +390,7 @@ public static void InterfaceImpl( // We're declaring an 'internal interface class' type interfaceImplType = new( ns: InteropUtf8NameFactory.TypeNamespace(enumeratorType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(enumeratorType, interopReferences.RuntimeContext, "InterfaceImpl"), + name: InteropUtf8NameFactory.TypeName(enumeratorType, interopDefinitions, "InterfaceImpl"), attributes: TypeAttributes.Interface | TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: null) { @@ -529,12 +540,14 @@ public static void InterfaceImpl( /// Creates a new type definition for the element marshaller for some IIterator<T> interface. /// /// The for the type. + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The module that will contain the type being created. /// The resulting element marshaller type. public static void ElementMarshaller( GenericInstanceTypeSignature enumeratorType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -559,6 +572,7 @@ public static void ElementMarshaller( { elementMarshallerType = InteropTypeDefinitionFactory.IEnumeratorElementMarshaller.KeyValuePair( enumeratorType: enumeratorType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState); @@ -568,6 +582,7 @@ public static void ElementMarshaller( { elementMarshallerType = InteropTypeDefinitionFactory.IEnumeratorElementMarshaller.NullableValueType( enumeratorType: enumeratorType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState); @@ -577,6 +592,7 @@ public static void ElementMarshaller( { elementMarshallerType = InteropTypeDefinitionFactory.IEnumeratorElementMarshaller.ManagedValueType( enumeratorType: enumeratorType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState); @@ -586,6 +602,7 @@ public static void ElementMarshaller( { elementMarshallerType = InteropTypeDefinitionFactory.IEnumeratorElementMarshaller.UnmanagedValueType( enumeratorType: enumeratorType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState); @@ -595,6 +612,7 @@ public static void ElementMarshaller( { elementMarshallerType = InteropTypeDefinitionFactory.IEnumeratorElementMarshaller.ReferenceType( enumeratorType: enumeratorType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState); @@ -647,7 +665,7 @@ public static void ImplType( Impl( interfaceType: ComInterfaceType.InterfaceIsIInspectable, ns: InteropUtf8NameFactory.TypeNamespace(enumeratorType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(enumeratorType, interopReferences.RuntimeContext, "Impl"), + name: InteropUtf8NameFactory.TypeName(enumeratorType, interopDefinitions, "Impl"), vftblType: interopDefinitions.IEnumerator1Vftbl, interopDefinitions: interopDefinitions, interopReferences: interopReferences, @@ -663,4 +681,4 @@ public static void ImplType( emitState.TrackTypeDefinition(implType, enumeratorType, "Impl"); } } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs index 460d4c078..515977fb5 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs @@ -27,6 +27,7 @@ public static class IList1 /// /// The for the type. /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The interop module being built. @@ -34,6 +35,7 @@ public static class IList1 public static void Interface( GenericInstanceTypeSignature listType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -42,7 +44,7 @@ public static void Interface( // We're declaring an 'internal abstract class' type interfaceType = new TypeDefinition( ns: InteropUtf8NameFactory.TypeNamespace(listType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(listType, interopReferences.RuntimeContext, "Interface"), + name: InteropUtf8NameFactory.TypeName(listType, interopDefinitions, "Interface"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()) { @@ -97,7 +99,7 @@ public static void Vftbl( // Otherwise, we must construct a new specialized vtable type vftblType = WellKnownTypeDefinitionFactory.IList1Vftbl( ns: InteropUtf8NameFactory.TypeNamespace(listType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(listType, interopReferences.RuntimeContext, "Vftbl"), + name: InteropUtf8NameFactory.TypeName(listType, interopDefinitions, "Vftbl"), elementType: elementType.GetAbiType(interopReferences), interopReferences: interopReferences); @@ -109,6 +111,7 @@ public static void Vftbl( /// /// The for the type. /// The type returned by . + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The interop module being built. @@ -116,6 +119,7 @@ public static void Vftbl( public static void IVectorMethods( GenericInstanceTypeSignature listType, TypeDefinition vftblType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -126,7 +130,7 @@ public static void IVectorMethods( // We're declaring an 'internal abstract class' type vectorMethodsType = new TypeDefinition( ns: InteropUtf8NameFactory.TypeNamespace(listType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(listType, interopReferences.RuntimeContext, "IVectorMethods"), + name: InteropUtf8NameFactory.TypeName(listType, interopDefinitions, "IVectorMethods"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()) { @@ -204,6 +208,7 @@ public static void IVectorMethods( /// /// The for the type. /// The type returned by . + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The interop module being built. @@ -211,6 +216,7 @@ public static void IVectorMethods( public static void Methods( GenericInstanceTypeSignature listType, TypeDefinition vectorMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -221,7 +227,7 @@ public static void Methods( // We're declaring an 'internal static class' type listMethodsType = new TypeDefinition( ns: InteropUtf8NameFactory.TypeNamespace(listType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(listType, interopReferences.RuntimeContext, "Methods"), + name: InteropUtf8NameFactory.TypeName(listType, interopDefinitions, "Methods"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()); @@ -522,6 +528,7 @@ public static void Methods( /// /// The for the type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The interop module being built. @@ -529,6 +536,7 @@ public static void Methods( public static void NativeObject( GenericInstanceTypeSignature listType, TypeDefinition vectorMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -547,6 +555,7 @@ public static void NativeObject( InteropTypeDefinitionBuilder.NativeObject( typeSignature: listType, nativeObjectBaseType: windowsRuntimeList4Type, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out nativeObjectType); @@ -558,6 +567,7 @@ public static void NativeObject( /// The for the type. /// The type returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The interop module being built. /// Whether to use Windows.UI.Xaml projections. @@ -566,6 +576,7 @@ public static void ComWrappersCallbackType( TypeSignature listType, TypeDefinition nativeObjectType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -576,6 +587,7 @@ public static void ComWrappersCallbackType( typeSignature: listType, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out callbackType); @@ -587,6 +599,7 @@ public static void ComWrappersCallbackType( /// The for the type. /// The type returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// The resulting marshaller type. @@ -594,6 +607,7 @@ public static void ComWrappersMarshallerAttribute( GenericInstanceTypeSignature listType, TypeDefinition nativeObjectType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition marshallerType) @@ -602,6 +616,7 @@ public static void ComWrappersMarshallerAttribute( typeSignature: listType, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out marshallerType); @@ -633,7 +648,7 @@ public static void InterfaceImpl( // We're declaring an 'internal interface class' type interfaceImplType = new( ns: InteropUtf8NameFactory.TypeNamespace(listType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(listType, interopReferences.RuntimeContext, "InterfaceImpl"), + name: InteropUtf8NameFactory.TypeName(listType, interopDefinitions, "InterfaceImpl"), attributes: TypeAttributes.Interface | TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: null) { @@ -1018,7 +1033,7 @@ public static void ImplType( Impl( interfaceType: ComInterfaceType.InterfaceIsIInspectable, ns: InteropUtf8NameFactory.TypeNamespace(listType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(listType, interopReferences.RuntimeContext, "Impl"), + name: InteropUtf8NameFactory.TypeName(listType, interopDefinitions, "Impl"), vftblType: vftblType, interopDefinitions: interopDefinitions, interopReferences: interopReferences, @@ -1046,7 +1061,7 @@ public static void ImplType( /// Creates the type map attributes for some IVector<T> interface. /// /// The for the type. - /// The instance returned by . + /// The instance returned by . /// The instance returned by . /// The instance to use. /// The module that will contain the type being created. @@ -1095,4 +1110,4 @@ public static void TypeMapAttributes( } } } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IMapChangedEventArgs1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IMapChangedEventArgs1.cs index d0c4dc0e0..9c47f7da1 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IMapChangedEventArgs1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IMapChangedEventArgs1.cs @@ -43,7 +43,7 @@ public static void Methods( // We're declaring an 'internal abstract class' type argsMethodsType = new( ns: InteropUtf8NameFactory.TypeNamespace(argsType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(argsType, interopReferences.RuntimeContext, "Methods"), + name: InteropUtf8NameFactory.TypeName(argsType, interopDefinitions, "Methods"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()) { @@ -90,12 +90,14 @@ public static void Methods( /// /// The for the args type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The interop module being built. /// The resulting native object type. public static void NativeObject( GenericInstanceTypeSignature argsType, TypeDefinition argsMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition nativeObjectType) @@ -108,6 +110,7 @@ public static void NativeObject( InteropTypeDefinitionBuilder.NativeObject( typeSignature: argsType, nativeObjectBaseType: windowsRuntimeMapChangedEventArgs2Type, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out nativeObjectType); @@ -119,6 +122,7 @@ public static void NativeObject( /// The for the args type. /// The type returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The interop module being built. /// Whether to use Windows.UI.Xaml projections. @@ -127,6 +131,7 @@ public static void ComWrappersCallbackType( TypeSignature argsType, TypeDefinition nativeObjectType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -137,6 +142,7 @@ public static void ComWrappersCallbackType( typeSignature: argsType, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out callbackType); @@ -148,6 +154,7 @@ public static void ComWrappersCallbackType( /// The for the args type. /// The type returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// The resulting marshaller type. @@ -155,6 +162,7 @@ public static void ComWrappersMarshallerAttribute( GenericInstanceTypeSignature argsType, TypeDefinition nativeObjectType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition marshallerType) @@ -163,6 +171,7 @@ public static void ComWrappersMarshallerAttribute( typeSignature: argsType, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out marshallerType); @@ -192,7 +201,7 @@ public static void InterfaceImpl( // We're declaring an 'internal interface class' type interfaceImplType = new( ns: InteropUtf8NameFactory.TypeNamespace(argsType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(argsType, interopReferences.RuntimeContext, "InterfaceImpl"), + name: InteropUtf8NameFactory.TypeName(argsType, interopDefinitions, "InterfaceImpl"), attributes: TypeAttributes.Interface | TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: null) { @@ -296,7 +305,7 @@ public static void ImplType( Impl( interfaceType: ComInterfaceType.InterfaceIsIInspectable, ns: InteropUtf8NameFactory.TypeNamespace(argsType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(argsType, interopReferences.RuntimeContext, "Impl"), + name: InteropUtf8NameFactory.TypeName(argsType, interopDefinitions, "Impl"), vftblType: interopDefinitions.IMapChangedEventArgsVftbl, interopDefinitions: interopDefinitions, interopReferences: interopReferences, @@ -308,4 +317,4 @@ public static void ImplType( emitState.TrackTypeDefinition(implType, argsType, "Impl"); } } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableMap2.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableMap2.cs index ea4708ee8..4e043664c 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableMap2.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableMap2.cs @@ -25,12 +25,14 @@ public static class IObservableMap2 /// Creates a new type definition for the event source factory for an IObservableMap<K, V> interface. /// /// The for the map type. + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The interop module being built. /// The resulting factory type. public static void EventSourceFactory( GenericInstanceTypeSignature mapType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -42,7 +44,7 @@ public static void EventSourceFactory( // We're declaring an 'internal abstract class' type factoryType = new( ns: InteropUtf8NameFactory.TypeNamespace(mapType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(mapType, interopReferences.RuntimeContext, "EventSourceFactory"), + name: InteropUtf8NameFactory.TypeName(mapType, interopDefinitions, "EventSourceFactory"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()) { @@ -88,12 +90,14 @@ public static void EventSourceFactory( /// Creates the cached callback type for the property for the event args for the map. /// /// The for the map type. + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The interop module being built. /// The resulting callback type. public static void EventSourceCallback( GenericInstanceTypeSignature mapType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -105,7 +109,7 @@ public static void EventSourceCallback( // We're declaring an 'internal sealed class' type callbackType = new TypeDefinition( ns: InteropUtf8NameFactory.TypeNamespace(mapType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(mapType, interopReferences.RuntimeContext, "EventSourceCallback"), + name: InteropUtf8NameFactory.TypeName(mapType, interopDefinitions, "EventSourceCallback"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()); @@ -182,12 +186,14 @@ public static void EventSourceCallback( /// /// The for the map type. /// The type returned by . + /// The instance to use. /// The instance to use. /// The interop module being built. /// The resulting methods type. public static void Methods( GenericInstanceTypeSignature mapType, TypeDefinition eventSourceCallbackType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition methodsType) @@ -198,7 +204,7 @@ public static void Methods( // We're declaring an 'internal static class' type methodsType = new( ns: InteropUtf8NameFactory.TypeNamespace(mapType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(mapType, interopReferences.RuntimeContext, "Methods"), + name: InteropUtf8NameFactory.TypeName(mapType, interopDefinitions, "Methods"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()); @@ -262,6 +268,7 @@ public static void Methods( /// /// The for the map type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The interop module being built. @@ -269,6 +276,7 @@ public static void Methods( public static void NativeObject( GenericInstanceTypeSignature mapType, TypeDefinition factoryType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -295,6 +303,7 @@ public static void NativeObject( InteropTypeDefinitionBuilder.NativeObject( typeSignature: mapType, nativeObjectBaseType: windowsRuntimeObservableMap2Type, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out nativeObjectType); @@ -306,6 +315,7 @@ public static void NativeObject( /// The for the map type. /// The type returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The interop module being built. /// Whether to use Windows.UI.Xaml projections. @@ -314,6 +324,7 @@ public static void ComWrappersCallbackType( TypeSignature mapType, TypeDefinition nativeObjectType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -324,6 +335,7 @@ public static void ComWrappersCallbackType( typeSignature: mapType, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out callbackType); @@ -335,6 +347,7 @@ public static void ComWrappersCallbackType( /// The for the map type. /// The type returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// The resulting marshaller type. @@ -342,6 +355,7 @@ public static void ComWrappersMarshallerAttribute( GenericInstanceTypeSignature mapType, TypeDefinition nativeObjectType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition marshallerType) @@ -350,6 +364,7 @@ public static void ComWrappersMarshallerAttribute( typeSignature: mapType, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out marshallerType); @@ -386,7 +401,7 @@ public static void InterfaceImpl( // We're declaring an 'internal interface class' type interfaceImplType = new( ns: InteropUtf8NameFactory.TypeNamespace(mapType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(mapType, interopReferences.RuntimeContext, "InterfaceImpl"), + name: InteropUtf8NameFactory.TypeName(mapType, interopDefinitions, "InterfaceImpl"), attributes: TypeAttributes.Interface | TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: null) { @@ -518,7 +533,7 @@ public static void ImplType( Impl( interfaceType: ComInterfaceType.InterfaceIsIInspectable, ns: InteropUtf8NameFactory.TypeNamespace(mapType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(mapType, interopReferences.RuntimeContext, "Impl"), + name: InteropUtf8NameFactory.TypeName(mapType, interopDefinitions, "Impl"), vftblType: interopDefinitions.IObservableMapVftbl, interopDefinitions: interopDefinitions, interopReferences: interopReferences, @@ -533,4 +548,4 @@ public static void ImplType( implType.Properties.Add(mapChangedTableProperty); } } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableVector1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableVector1.cs index 90707e9a9..09e980d25 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableVector1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IObservableVector1.cs @@ -25,12 +25,14 @@ public static class IObservableVector1 /// Creates a new type definition for the event source factory for an IObservableVector<T> interface. /// /// The for the vector type. + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The interop module being built. /// The resulting factory type. public static void EventSourceFactory( GenericInstanceTypeSignature vectorType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -41,7 +43,7 @@ public static void EventSourceFactory( // We're declaring an 'internal abstract class' type factoryType = new( ns: InteropUtf8NameFactory.TypeNamespace(vectorType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(vectorType, interopReferences.RuntimeContext, "EventSourceFactory"), + name: InteropUtf8NameFactory.TypeName(vectorType, interopDefinitions, "EventSourceFactory"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()) { @@ -87,12 +89,14 @@ public static void EventSourceFactory( /// Creates the cached callback type for an IObservableVector<T> interface. /// /// The for the vector type. + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The interop module being built. /// The resulting callback type. public static void EventSourceCallback( GenericInstanceTypeSignature vectorType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -103,7 +107,7 @@ public static void EventSourceCallback( // We're declaring an 'internal sealed class' type callbackType = new TypeDefinition( ns: InteropUtf8NameFactory.TypeNamespace(vectorType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(vectorType, interopReferences.RuntimeContext, "EventSourceCallback"), + name: InteropUtf8NameFactory.TypeName(vectorType, interopDefinitions, "EventSourceCallback"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()); @@ -179,12 +183,14 @@ public static void EventSourceCallback( /// /// The for the vector type. /// The type returned by . + /// The instance to use. /// The instance to use. /// The interop module being built. /// The resulting methods type. public static void Methods( GenericInstanceTypeSignature vectorType, TypeDefinition eventSourceCallbackType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition methodsType) @@ -194,7 +200,7 @@ public static void Methods( // We're declaring an 'internal static class' type methodsType = new( ns: InteropUtf8NameFactory.TypeNamespace(vectorType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(vectorType, interopReferences.RuntimeContext, "Methods"), + name: InteropUtf8NameFactory.TypeName(vectorType, interopDefinitions, "Methods"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()); @@ -258,6 +264,7 @@ public static void Methods( /// /// The for the vector type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The interop module being built. @@ -265,6 +272,7 @@ public static void Methods( public static void NativeObject( GenericInstanceTypeSignature vectorType, TypeDefinition factoryType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -288,6 +296,7 @@ public static void NativeObject( InteropTypeDefinitionBuilder.NativeObject( typeSignature: vectorType, nativeObjectBaseType: windowsRuntimeObservableVector1Type, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out nativeObjectType); @@ -299,6 +308,7 @@ public static void NativeObject( /// The for the vector type. /// The type returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The interop module being built. /// Whether to use Windows.UI.Xaml projections. @@ -307,6 +317,7 @@ public static void ComWrappersCallbackType( TypeSignature vectorType, TypeDefinition nativeObjectType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -317,6 +328,7 @@ public static void ComWrappersCallbackType( typeSignature: vectorType, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out callbackType); @@ -328,6 +340,7 @@ public static void ComWrappersCallbackType( /// The for the vector type. /// The type returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// The resulting marshaller type. @@ -335,6 +348,7 @@ public static void ComWrappersMarshallerAttribute( GenericInstanceTypeSignature vectorType, TypeDefinition nativeObjectType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition marshallerType) @@ -343,6 +357,7 @@ public static void ComWrappersMarshallerAttribute( typeSignature: vectorType, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out marshallerType); @@ -372,7 +387,7 @@ public static void InterfaceImpl( // We're declaring an 'internal interface class' type interfaceImplType = new( ns: InteropUtf8NameFactory.TypeNamespace(vectorType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(vectorType, interopReferences.RuntimeContext, "InterfaceImpl"), + name: InteropUtf8NameFactory.TypeName(vectorType, interopDefinitions, "InterfaceImpl"), attributes: TypeAttributes.Interface | TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: null) { @@ -503,7 +518,7 @@ public static void ImplType( Impl( interfaceType: ComInterfaceType.InterfaceIsIInspectable, ns: InteropUtf8NameFactory.TypeNamespace(vectorType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(vectorType, interopReferences.RuntimeContext, "Impl"), + name: InteropUtf8NameFactory.TypeName(vectorType, interopDefinitions, "Impl"), vftblType: interopDefinitions.IObservableVectorVftbl, interopDefinitions: interopDefinitions, interopReferences: interopReferences, @@ -521,4 +536,4 @@ public static void ImplType( emitState.TrackTypeDefinition(implType, vectorType, "Impl"); } } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyCollectionKeyValuePair2.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyCollectionKeyValuePair2.cs index fb351c5ee..ed8db77ec 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyCollectionKeyValuePair2.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyCollectionKeyValuePair2.cs @@ -22,11 +22,13 @@ public static class IReadOnlyCollectionKeyValuePair2 /// Creates a new type definition for the forwarder attribute for a of type. /// /// The for the generic interface type. + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// The resulting marshaller type. public static void ForwarderAttribute( GenericInstanceTypeSignature readOnlyCollectionType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition forwarderAttributeType) @@ -39,6 +41,7 @@ public static void ForwarderAttribute( readOnlyCollectionType: readOnlyCollectionType, readOnlyDictionaryType: interopReferences.IReadOnlyDictionary2.MakeGenericReferenceType([keyType, valueType]), readOnlyListType: interopReferences.IReadOnlyList1.MakeGenericReferenceType([keyValuePairType]), + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, forwarderAttributeType: out forwarderAttributeType); @@ -49,6 +52,7 @@ public static void ForwarderAttribute( /// /// The for the generic interface type. /// The type returned by . + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The module that will contain the type being created. @@ -56,6 +60,7 @@ public static void ForwarderAttribute( public static void InterfaceImpl( GenericInstanceTypeSignature readOnlyCollectionType, TypeDefinition forwarderAttributeType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -71,7 +76,7 @@ public static void InterfaceImpl( // We're declaring an 'internal interface class' type interfaceImplType = new( ns: InteropUtf8NameFactory.TypeNamespace(readOnlyCollectionType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(readOnlyCollectionType, interopReferences.RuntimeContext, "InterfaceImpl"), + name: InteropUtf8NameFactory.TypeName(readOnlyCollectionType, interopDefinitions, "InterfaceImpl"), attributes: TypeAttributes.Interface | TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: null) { @@ -148,4 +153,4 @@ public static void TypeMapAttributes( module: module); } } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyDictionary2.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyDictionary2.cs index 031deed43..26c762b13 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyDictionary2.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyDictionary2.cs @@ -67,7 +67,7 @@ public static void Vftbl( // Otherwise, we must construct a new specialized vtable type TypeDefinition newVftblType = WellKnownTypeDefinitionFactory.IReadOnlyDictionary2Vftbl( ns: InteropUtf8NameFactory.TypeNamespace(sharedReadOnlyDictionaryType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(sharedReadOnlyDictionaryType, interopReferences.RuntimeContext, "Vftbl"), + name: InteropUtf8NameFactory.TypeName(sharedReadOnlyDictionaryType, interopDefinitions, "Vftbl"), keyType: keyType, valueType: interopReferences.Void, interopReferences: interopReferences); @@ -87,6 +87,7 @@ public static void Vftbl( /// /// The for the type. /// The type returned by . + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The interop module being built. @@ -94,6 +95,7 @@ public static void Vftbl( public static void IMapViewMethods( GenericInstanceTypeSignature readOnlyDictionaryType, TypeDefinition vftblType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -105,7 +107,7 @@ public static void IMapViewMethods( // We're declaring an 'internal abstract class' type mapViewMethodsType = new TypeDefinition( ns: InteropUtf8NameFactory.TypeNamespace(readOnlyDictionaryType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(readOnlyDictionaryType, interopReferences.RuntimeContext, "IMapViewMethods"), + name: InteropUtf8NameFactory.TypeName(readOnlyDictionaryType, interopDefinitions, "IMapViewMethods"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()) { @@ -144,6 +146,7 @@ public static void IMapViewMethods( /// /// The for the type. /// The type returned by . + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The interop module being built. @@ -151,6 +154,7 @@ public static void IMapViewMethods( public static void Methods( GenericInstanceTypeSignature readOnlyDictionaryType, TypeDefinition mapViewMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -162,7 +166,7 @@ public static void Methods( // We're declaring an 'internal static class' type readOnlyDictionaryMethodsType = new TypeDefinition( ns: InteropUtf8NameFactory.TypeNamespace(readOnlyDictionaryType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(readOnlyDictionaryType, interopReferences.RuntimeContext, "Methods"), + name: InteropUtf8NameFactory.TypeName(readOnlyDictionaryType, interopDefinitions, "Methods"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()); @@ -323,6 +327,7 @@ public static void Methods( /// /// The for the type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The interop module being built. @@ -330,6 +335,7 @@ public static void Methods( public static void NativeObject( GenericInstanceTypeSignature readOnlyDictionaryType, TypeDefinition mapViewMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -351,6 +357,7 @@ public static void NativeObject( InteropTypeDefinitionBuilder.NativeObject( typeSignature: readOnlyDictionaryType, nativeObjectBaseType: windowsRuntimeReadOnlyDictionary5Type, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out nativeObjectType); @@ -362,6 +369,7 @@ public static void NativeObject( /// The for the type. /// The type returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The interop module being built. /// Whether to use Windows.UI.Xaml projections. @@ -370,6 +378,7 @@ public static void ComWrappersCallbackType( TypeSignature readOnlyDictionaryType, TypeDefinition nativeObjectType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -380,6 +389,7 @@ public static void ComWrappersCallbackType( typeSignature: readOnlyDictionaryType, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out callbackType); @@ -391,6 +401,7 @@ public static void ComWrappersCallbackType( /// The for the type. /// The type returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// The resulting marshaller type. @@ -398,6 +409,7 @@ public static void ComWrappersMarshallerAttribute( GenericInstanceTypeSignature readOnlyDictionaryType, TypeDefinition nativeObjectType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition marshallerType) @@ -406,6 +418,7 @@ public static void ComWrappersMarshallerAttribute( typeSignature: readOnlyDictionaryType, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out marshallerType); @@ -439,7 +452,7 @@ public static void InterfaceImpl( // We're declaring an 'internal interface class' type interfaceImplType = new( ns: InteropUtf8NameFactory.TypeNamespace(readOnlyDictionaryType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(readOnlyDictionaryType, interopReferences.RuntimeContext, "InterfaceImpl"), + name: InteropUtf8NameFactory.TypeName(readOnlyDictionaryType, interopDefinitions, "InterfaceImpl"), attributes: TypeAttributes.Interface | TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: null) { @@ -641,7 +654,7 @@ public static void ImplType( Impl( interfaceType: ComInterfaceType.InterfaceIsIInspectable, ns: InteropUtf8NameFactory.TypeNamespace(readOnlyDictionaryType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(readOnlyDictionaryType, interopReferences.RuntimeContext, "Impl"), + name: InteropUtf8NameFactory.TypeName(readOnlyDictionaryType, interopDefinitions, "Impl"), vftblType: vftblType, interopDefinitions: interopDefinitions, interopReferences: interopReferences, @@ -657,4 +670,4 @@ public static void ImplType( emitState.TrackTypeDefinition(implType, readOnlyDictionaryType, "Impl"); } } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyList1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyList1.cs index 8a3afa9f1..aa7b4284d 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyList1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyList1.cs @@ -50,7 +50,7 @@ public static void Vftbl( // Otherwise, we must construct a new specialized vtable type vftblType = WellKnownTypeDefinitionFactory.IReadOnlyList1Vftbl( ns: InteropUtf8NameFactory.TypeNamespace(readOnlyListType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(readOnlyListType, interopReferences.RuntimeContext, "Vftbl"), + name: InteropUtf8NameFactory.TypeName(readOnlyListType, interopDefinitions, "Vftbl"), elementType: elementType.GetAbiType(interopReferences), interopReferences: interopReferences); @@ -62,6 +62,7 @@ public static void Vftbl( /// /// The for the type. /// The type returned by . + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The interop module being built. @@ -69,6 +70,7 @@ public static void Vftbl( public static void IVectorViewMethods( GenericInstanceTypeSignature readOnlyListType, TypeDefinition vftblType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -79,7 +81,7 @@ public static void IVectorViewMethods( // We're declaring an 'internal abstract class' type vectorViewMethodsType = new TypeDefinition( ns: InteropUtf8NameFactory.TypeNamespace(readOnlyListType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(readOnlyListType, interopReferences.RuntimeContext, "IVectorViewMethods"), + name: InteropUtf8NameFactory.TypeName(readOnlyListType, interopDefinitions, "IVectorViewMethods"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()) { @@ -106,6 +108,7 @@ public static void IVectorViewMethods( /// /// The for the type. /// The type returned by . + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The interop module being built. @@ -113,6 +116,7 @@ public static void IVectorViewMethods( public static void Methods( GenericInstanceTypeSignature readOnlyListType, TypeDefinition vectorViewMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -123,7 +127,7 @@ public static void Methods( // We're declaring an 'internal static class' type readOnlyListMethodsType = new TypeDefinition( ns: InteropUtf8NameFactory.TypeNamespace(readOnlyListType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(readOnlyListType, interopReferences.RuntimeContext, "Methods"), + name: InteropUtf8NameFactory.TypeName(readOnlyListType, interopDefinitions, "Methods"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()); @@ -187,6 +191,7 @@ public static void Methods( /// /// The for the type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The interop module being built. @@ -194,6 +199,7 @@ public static void Methods( public static void NativeObject( GenericInstanceTypeSignature readOnlyListType, TypeDefinition vectorViewMethodsType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -212,6 +218,7 @@ public static void NativeObject( InteropTypeDefinitionBuilder.NativeObject( typeSignature: readOnlyListType, nativeObjectBaseType: windowsRuntimeReadOnlyList4Type, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out nativeObjectType); @@ -223,6 +230,7 @@ public static void NativeObject( /// The for the type. /// The type returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The interop module being built. /// Whether to use Windows.UI.Xaml projections. @@ -231,6 +239,7 @@ public static void ComWrappersCallbackType( TypeSignature readOnlyListType, TypeDefinition nativeObjectType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -241,6 +250,7 @@ public static void ComWrappersCallbackType( typeSignature: readOnlyListType, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out callbackType); @@ -252,6 +262,7 @@ public static void ComWrappersCallbackType( /// The for the type. /// The type returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// The resulting marshaller type. @@ -259,6 +270,7 @@ public static void ComWrappersMarshallerAttribute( GenericInstanceTypeSignature readOnlyListType, TypeDefinition nativeObjectType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition marshallerType) @@ -267,6 +279,7 @@ public static void ComWrappersMarshallerAttribute( typeSignature: readOnlyListType, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out marshallerType); @@ -298,7 +311,7 @@ public static void InterfaceImpl( // We're declaring an 'internal interface class' type interfaceImplType = new( ns: InteropUtf8NameFactory.TypeNamespace(readOnlyListType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(readOnlyListType, interopReferences.RuntimeContext, "InterfaceImpl"), + name: InteropUtf8NameFactory.TypeName(readOnlyListType, interopDefinitions, "InterfaceImpl"), attributes: TypeAttributes.Interface | TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: null) { @@ -429,7 +442,7 @@ public static void ImplType( Impl( interfaceType: ComInterfaceType.InterfaceIsIInspectable, ns: InteropUtf8NameFactory.TypeNamespace(readOnlyListType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(readOnlyListType, interopReferences.RuntimeContext, "Impl"), + name: InteropUtf8NameFactory.TypeName(readOnlyListType, interopDefinitions, "Impl"), vftblType: vftblType, interopDefinitions: interopDefinitions, interopReferences: interopReferences, @@ -449,7 +462,7 @@ public static void ImplType( /// Creates the type map attributes for some IVectorView<T> interface. /// /// The for the type. - /// The instance returned by . + /// The instance returned by . /// The instance returned by . /// The instance to use. /// The module that will contain the type being created. @@ -499,4 +512,4 @@ public static void TypeMapAttributes( } } } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.KeyValuePair.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.KeyValuePair.cs index b0c973bec..d3814bdc2 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.KeyValuePair.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.KeyValuePair.cs @@ -28,10 +28,12 @@ public static class KeyValuePair /// Creates a new type definition for the KeyValuePairMethods type to contain shared accessor /// methods for types. /// + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// The resulting methods type. public static void Methods( + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition methodsType) @@ -39,7 +41,7 @@ public static void Methods( // We're declaring an 'internal static class' type methodsType = new TypeDefinition( ns: InteropUtf8NameFactory.TypeNamespace(interopReferences.KeyValuePair.ToReferenceTypeSignature(), interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(interopReferences.KeyValuePair.ToReferenceTypeSignature(), interopReferences.RuntimeContext, "Methods"), + name: InteropUtf8NameFactory.TypeName(interopReferences.KeyValuePair.ToReferenceTypeSignature(), interopDefinitions, "Methods"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()); @@ -69,8 +71,8 @@ public static void Accessors( TypeSignature valueType = keyValuePairType.TypeArguments[1]; // Prepare the names of the accessor methods, to define or look them up - Utf8String get_KeyMethodName = $"get_Key({InteropUtf8NameFactory.TypeName(keyType, interopReferences.RuntimeContext)})"; - Utf8String get_ValueMethodName = $"get_Value({InteropUtf8NameFactory.TypeName(valueType, interopReferences.RuntimeContext)})"; + Utf8String get_KeyMethodName = $"get_Key({InteropUtf8NameFactory.TypeName(keyType, interopDefinitions)})"; + Utf8String get_ValueMethodName = $"get_Value({InteropUtf8NameFactory.TypeName(valueType, interopDefinitions)})"; // Get or define the 'get_Key' accessor method if (!methodsType.TryGetMethod(get_KeyMethodName, out keyAccessorMethod!)) @@ -108,6 +110,7 @@ public static void Accessors( /// The 'IID' get method for . /// The accessor method for the key. /// The accessor method for the value. + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The module that will contain the type being created. @@ -117,6 +120,7 @@ public static void Marshaller( MethodDefinition get_IidMethod, MethodDefinition keyAccessorMethod, MethodDefinition valueAccessorMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -125,7 +129,7 @@ public static void Marshaller( // We're declaring an 'internal static class' type marshallerType = new( ns: InteropUtf8NameFactory.TypeNamespace(keyValuePairType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(keyValuePairType, interopReferences.RuntimeContext, "Marshaller"), + name: InteropUtf8NameFactory.TypeName(keyValuePairType, interopDefinitions, "Marshaller"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()); @@ -242,7 +246,7 @@ public static void ImplType( Impl( interfaceType: ComInterfaceType.InterfaceIsIInspectable, ns: InteropUtf8NameFactory.TypeNamespace(keyValuePairType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(keyValuePairType, interopReferences.RuntimeContext, "Impl"), + name: InteropUtf8NameFactory.TypeName(keyValuePairType, interopDefinitions, "Impl"), vftblType: interopDefinitions.IKeyValuePairVftbl, interopDefinitions: interopDefinitions, interopReferences: interopReferences, @@ -272,7 +276,7 @@ public static void InterfaceEntriesImplType( { InterfaceEntriesImpl( ns: InteropUtf8NameFactory.TypeNamespace(keyValuePairType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(keyValuePairType, interopReferences.RuntimeContext, "InterfaceEntriesImpl"), + name: InteropUtf8NameFactory.TypeName(keyValuePairType, interopDefinitions, "InterfaceEntriesImpl"), entriesFieldType: interopDefinitions.IKeyValuePairInterfaceEntries, interopReferences: interopReferences, module: module, @@ -311,7 +315,7 @@ public static void ComWrappersMarshallerAttribute( // We're declaring an 'internal sealed class' type marshallerAttributeType = new( ns: InteropUtf8NameFactory.TypeNamespace(keyValuePairType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(keyValuePairType, interopReferences.RuntimeContext, "ComWrappersMarshallerAttribute"), + name: InteropUtf8NameFactory.TypeName(keyValuePairType, interopDefinitions, "ComWrappersMarshallerAttribute"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit, baseType: interopReferences.WindowsRuntimeComWrappersMarshallerAttribute); @@ -453,6 +457,7 @@ public static void ComWrappersMarshallerAttribute( /// /// The for the type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// Whether to use Windows.UI.Xaml projections. @@ -460,6 +465,7 @@ public static void ComWrappersMarshallerAttribute( public static void Proxy( TypeSignature keyValuePairType, TypeDefinition comWrappersMarshallerAttributeType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -470,7 +476,7 @@ public static void Proxy( // reference the mapped type, so that we can retrieve the original 'Type' instance when marshalling from native. InteropTypeDefinitionBuilder.Proxy( ns: InteropUtf8NameFactory.TypeNamespace(keyValuePairType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(keyValuePairType, interopReferences.RuntimeContext), + name: InteropUtf8NameFactory.TypeName(keyValuePairType, interopDefinitions), mappedMetadata: "Windows.Foundation.FoundationContract", runtimeClassName: RuntimeClassNameGenerator.GetRuntimeClassName(keyValuePairType, interopReferences.RuntimeContext, useWindowsUIXamlProjections), metadataTypeName: null, @@ -512,4 +518,4 @@ public static void TypeMapAttributes( module: module); } } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.SzArray.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.SzArray.cs index 2eb895169..36c8df609 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.SzArray.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.SzArray.cs @@ -39,12 +39,14 @@ public static class SzArray /// Creates a new type definition for the marshaller for some SZ array type. /// /// The for the SZ array type. + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The module that will contain the type being created. /// The resulting marshaller type. public static void Marshaller( SzArrayTypeSignature arrayType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -59,6 +61,7 @@ public static void Marshaller( { marshallerType = InteropTypeDefinitionFactory.SzArrayMarshaller.BlittableValueType( arrayType: arrayType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences); module.TopLevelTypes.Add(marshallerType); @@ -67,6 +70,7 @@ public static void Marshaller( { TypeDefinition elementMarshallerType = InteropTypeDefinitionFactory.SzArrayElementMarshaller.KeyValuePair( arrayType: arrayType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState); @@ -75,6 +79,7 @@ public static void Marshaller( marshallerType = InteropTypeDefinitionFactory.SzArrayMarshaller.KeyValuePair( arrayType: arrayType, elementMarshallerType: elementMarshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences); module.TopLevelTypes.Add(marshallerType); @@ -83,6 +88,7 @@ public static void Marshaller( { TypeDefinition elementMarshallerType = InteropTypeDefinitionFactory.SzArrayElementMarshaller.NullableValueType( arrayType: arrayType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState); @@ -91,6 +97,7 @@ public static void Marshaller( marshallerType = InteropTypeDefinitionFactory.SzArrayMarshaller.NullableValueType( arrayType: arrayType, elementMarshallerType: elementMarshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences); module.TopLevelTypes.Add(marshallerType); @@ -99,6 +106,7 @@ public static void Marshaller( { TypeDefinition elementMarshallerType = InteropTypeDefinitionFactory.SzArrayElementMarshaller.ManagedValueType( arrayType: arrayType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState); @@ -107,6 +115,7 @@ public static void Marshaller( marshallerType = InteropTypeDefinitionFactory.SzArrayMarshaller.ManagedValueType( arrayType: arrayType, elementMarshallerType: elementMarshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences); module.TopLevelTypes.Add(marshallerType); @@ -115,6 +124,7 @@ public static void Marshaller( { TypeDefinition elementMarshallerType = InteropTypeDefinitionFactory.SzArrayElementMarshaller.UnmanagedValueType( arrayType: arrayType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState); @@ -123,6 +133,7 @@ public static void Marshaller( marshallerType = InteropTypeDefinitionFactory.SzArrayMarshaller.UnmanagedValueType( arrayType: arrayType, elementMarshallerType: elementMarshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences); module.TopLevelTypes.Add(marshallerType); @@ -131,6 +142,7 @@ public static void Marshaller( { marshallerType = InteropTypeDefinitionFactory.SzArrayMarshaller.Object( arrayType: arrayType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences); module.TopLevelTypes.Add(marshallerType); @@ -139,6 +151,7 @@ public static void Marshaller( { marshallerType = InteropTypeDefinitionFactory.SzArrayMarshaller.String( arrayType: arrayType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences); module.TopLevelTypes.Add(marshallerType); @@ -147,6 +160,7 @@ public static void Marshaller( { marshallerType = InteropTypeDefinitionFactory.SzArrayMarshaller.Type( arrayType: arrayType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences); module.TopLevelTypes.Add(marshallerType); @@ -155,6 +169,7 @@ public static void Marshaller( { marshallerType = InteropTypeDefinitionFactory.SzArrayMarshaller.Exception( arrayType: arrayType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences); module.TopLevelTypes.Add(marshallerType); @@ -163,6 +178,7 @@ public static void Marshaller( { TypeDefinition elementMarshallerType = InteropTypeDefinitionFactory.SzArrayElementMarshaller.ReferenceType( arrayType: arrayType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState); @@ -171,6 +187,7 @@ public static void Marshaller( marshallerType = InteropTypeDefinitionFactory.SzArrayMarshaller.ReferenceType( arrayType: arrayType, elementMarshallerType: elementMarshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences); module.TopLevelTypes.Add(marshallerType); @@ -182,12 +199,14 @@ public static void Marshaller( /// /// The for the SZ array type. /// The type returned by . + /// The instance to use. /// The instance to use. /// The interop module being built. /// The resulting callback type. public static void ComWrappersCallback( SzArrayTypeSignature arrayType, TypeDefinition marshallerType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition callbackType) @@ -195,7 +214,7 @@ public static void ComWrappersCallback( // We're declaring an 'internal abstract class' type callbackType = new( ns: InteropUtf8NameFactory.TypeNamespace(arrayType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(arrayType, interopReferences.RuntimeContext, "ComWrappersCallback"), + name: InteropUtf8NameFactory.TypeName(arrayType, interopDefinitions, "ComWrappersCallback"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()) { @@ -334,7 +353,7 @@ public static void ArrayImpl( Impl( interfaceType: ComInterfaceType.InterfaceIsIInspectable, ns: InteropUtf8NameFactory.TypeNamespace(arrayType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(arrayType, interopReferences.RuntimeContext, "Impl"), + name: InteropUtf8NameFactory.TypeName(arrayType, interopDefinitions, "Impl"), vftblType: interopDefinitions.IReferenceArrayVftbl, interopDefinitions: interopDefinitions, interopReferences: interopReferences, @@ -402,7 +421,7 @@ public static void InterfaceEntriesImpl( InteropTypeDefinitionBuilder.InterfaceEntriesImpl( ns: InteropUtf8NameFactory.TypeNamespace(arrayType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(arrayType, interopReferences.RuntimeContext, "InterfaceEntriesImpl"), + name: InteropUtf8NameFactory.TypeName(arrayType, interopDefinitions, "InterfaceEntriesImpl"), entriesFieldType: interfaceEntriesType, interopReferences: interopReferences, module: module, @@ -418,6 +437,7 @@ public static void InterfaceEntriesImpl( /// The instance returned by . /// The instance returned by . /// The 'IID' get method for the 'IReferenceArray`1<T>' interface. + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// The resulting marshaller type. @@ -427,6 +447,7 @@ public static void ComWrappersMarshallerAttribute( TypeDefinition arrayInterfaceEntriesImplType, TypeDefinition arrayComWrappersCallbackType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition marshallerType) @@ -434,7 +455,7 @@ public static void ComWrappersMarshallerAttribute( // We're declaring an 'internal sealed class' type marshallerType = new( ns: InteropUtf8NameFactory.TypeNamespace(arrayType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(arrayType, interopReferences.RuntimeContext, "ComWrappersMarshallerAttribute"), + name: InteropUtf8NameFactory.TypeName(arrayType, interopDefinitions, "ComWrappersMarshallerAttribute"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit, baseType: interopReferences.WindowsRuntimeComWrappersMarshallerAttribute); @@ -537,6 +558,7 @@ public static void ComWrappersMarshallerAttribute( /// /// The for the SZ array type. /// The instance for the marshaller attribute type. + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// Whether to use Windows.UI.Xaml projections. @@ -544,6 +566,7 @@ public static void ComWrappersMarshallerAttribute( public static void Proxy( SzArrayTypeSignature arrayType, TypeDefinition comWrappersMarshallerAttributeType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -555,7 +578,7 @@ public static void Proxy( // type map (as they're treated the same as normal user-defined types), so this allows us to distinguish them. InteropTypeDefinitionBuilder.Proxy( ns: InteropUtf8NameFactory.TypeNamespace(arrayType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(arrayType, interopReferences.RuntimeContext), + name: InteropUtf8NameFactory.TypeName(arrayType, interopDefinitions), mappedMetadata: "Windows.Foundation.FoundationContract", runtimeClassName: RuntimeClassNameGenerator.GetRuntimeClassName(arrayType, interopReferences.RuntimeContext, useWindowsUIXamlProjections), metadataTypeName: null, @@ -597,4 +620,4 @@ public static void TypeMapAttributes( module: module); } } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.UserDefinedType.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.UserDefinedType.cs index 57d95bfc7..db955fe35 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.UserDefinedType.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.UserDefinedType.cs @@ -86,7 +86,7 @@ public static void InterfaceEntriesImpl( InteropTypeDefinitionBuilder.InterfaceEntriesImpl( ns: "WindowsRuntime.Interop.UserDefinedTypes"u8, - name: InteropUtf8NameFactory.TypeName(userDefinedType, interopReferences.RuntimeContext, "InterfaceEntriesImpl"), + name: InteropUtf8NameFactory.TypeName(userDefinedType, interopDefinitions, "InterfaceEntriesImpl"), entriesFieldType: interfaceEntriesType, interopReferences: interopReferences, module: module, @@ -100,6 +100,7 @@ public static void InterfaceEntriesImpl( /// The for the user-defined type. /// The for the interface entries type returned by . /// The for the interface entries implementation type returned by . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// The resulting marshaller type. @@ -107,6 +108,7 @@ public static void ComWrappersMarshallerAttribute( TypeSignature userDefinedType, TypeDefinition interfaceEntriesType, TypeDefinition interfaceEntriesImplType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition marshallerType) @@ -114,7 +116,7 @@ public static void ComWrappersMarshallerAttribute( // We're declaring an 'internal sealed class' type marshallerType = new( ns: "WindowsRuntime.Interop.UserDefinedTypes"u8, - name: InteropUtf8NameFactory.TypeName(userDefinedType, interopReferences.RuntimeContext, "ComWrappersMarshallerAttribute"), + name: InteropUtf8NameFactory.TypeName(userDefinedType, interopDefinitions, "ComWrappersMarshallerAttribute"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit, baseType: interopReferences.WindowsRuntimeComWrappersMarshallerAttribute); @@ -180,6 +182,7 @@ public static void ComWrappersMarshallerAttribute( /// /// The for the user-defined type. /// The instance returned by . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// Whether to use Windows.UI.Xaml projections. @@ -187,6 +190,7 @@ public static void ComWrappersMarshallerAttribute( public static void Proxy( TypeSignature userDefinedType, TypeDefinition comWrappersMarshallerAttributeType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -201,7 +205,7 @@ public static void Proxy( { InteropTypeDefinitionBuilder.Proxy( ns: InteropUtf8NameFactory.TypeNamespace(userDefinedType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(userDefinedType, interopReferences.RuntimeContext), + name: InteropUtf8NameFactory.TypeName(userDefinedType, interopDefinitions), mappedMetadata: null, runtimeClassName: null, metadataTypeName: null, @@ -218,7 +222,7 @@ public static void Proxy( // For authored component types, the runtime class name is the type's own fully-qualified name. InteropTypeDefinitionBuilder.Proxy( ns: InteropUtf8NameFactory.TypeNamespace(userDefinedType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(userDefinedType, interopReferences.RuntimeContext), + name: InteropUtf8NameFactory.TypeName(userDefinedType, interopDefinitions), mappedMetadata: null, runtimeClassName: MetadataTypeNameGenerator.GetMetadataTypeName(userDefinedType, useWindowsUIXamlProjections), metadataTypeName: null, @@ -244,7 +248,7 @@ public static void Proxy( InteropTypeDefinitionBuilder.Proxy( ns: InteropUtf8NameFactory.TypeNamespace(userDefinedType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(userDefinedType, interopReferences.RuntimeContext), + name: InteropUtf8NameFactory.TypeName(userDefinedType, interopDefinitions), mappedMetadata: null, runtimeClassName: RuntimeClassNameGenerator.GetRuntimeClassName(interfaceType, interopReferences.RuntimeContext, useWindowsUIXamlProjections), metadataTypeName: null, @@ -285,4 +289,4 @@ public static void TypeMapAttributes( module: module); } } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.cs index 610317be8..c179c5295 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.cs @@ -42,7 +42,7 @@ public static void IID( out MethodDefinition get_IidMethod) { IID( - name: InteropUtf8NameFactory.TypeName(interfaceType, interopReferences.RuntimeContext), + name: InteropUtf8NameFactory.TypeName(interfaceType, interopDefinitions), interopDefinitions: interopDefinitions, interopReferences: interopReferences, iid: GuidGenerator.CreateIID(interfaceType, interopDefinitions, interopReferences, useWindowsUIXamlProjections), @@ -84,12 +84,14 @@ private static void IID( /// /// The for the generic interface type. /// The for the base native object type. + /// The instance to use. /// The instance to use. /// The interop module being built. /// The resulting native object type. private static void NativeObject( TypeSignature typeSignature, TypeSignature nativeObjectBaseType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition nativeObjectType) @@ -97,7 +99,7 @@ private static void NativeObject( // We're declaring an 'internal sealed class' type nativeObjectType = new( ns: InteropUtf8NameFactory.TypeNamespace(typeSignature, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(typeSignature, interopReferences.RuntimeContext, "NativeObject"), + name: InteropUtf8NameFactory.TypeName(typeSignature, interopDefinitions, "NativeObject"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit, baseType: nativeObjectBaseType.ToTypeDefOrRef()); @@ -119,6 +121,7 @@ private static void NativeObject( /// The for the generic interface type. /// The type returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The interop module being built. /// The resulting callback type. @@ -127,6 +130,7 @@ private static void ComWrappersCallback( TypeSignature typeSignature, TypeDefinition nativeObjectType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition callbackType) @@ -134,7 +138,7 @@ private static void ComWrappersCallback( // We're declaring an 'internal abstract class' type callbackType = new( ns: InteropUtf8NameFactory.TypeNamespace(typeSignature, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(typeSignature, interopReferences.RuntimeContext, "ComWrappersCallback"), + name: InteropUtf8NameFactory.TypeName(typeSignature, interopDefinitions, "ComWrappersCallback"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()) { @@ -251,6 +255,7 @@ private static void ComWrappersCallback( /// The for the generic interface type. /// The type returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// The resulting marshaller type. @@ -258,6 +263,7 @@ private static void ComWrappersMarshallerAttribute( TypeSignature typeSignature, TypeDefinition nativeObjectType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition marshallerType) @@ -265,7 +271,7 @@ private static void ComWrappersMarshallerAttribute( // We're declaring an 'internal sealed class' type marshallerType = new( ns: InteropUtf8NameFactory.TypeNamespace(typeSignature, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(typeSignature, interopReferences.RuntimeContext, "ComWrappersMarshallerAttribute"), + name: InteropUtf8NameFactory.TypeName(typeSignature, interopDefinitions, "ComWrappersMarshallerAttribute"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit, baseType: interopReferences.WindowsRuntimeComWrappersMarshallerAttribute); @@ -312,6 +318,7 @@ private static void ComWrappersMarshallerAttribute( /// The for the generic interface type. /// The instance returned by . /// The 'IID' get method for . + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The module that will contain the type being created. @@ -320,6 +327,7 @@ public static void Marshaller( TypeSignature typeSignature, TypeDefinition interfaceComWrappersCallbackType, MethodDefinition get_IidMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState, ModuleDefinition module, @@ -328,7 +336,7 @@ public static void Marshaller( // We're declaring an 'internal static class' type marshallerType = new( ns: InteropUtf8NameFactory.TypeNamespace(typeSignature, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(typeSignature, interopReferences.RuntimeContext, "Marshaller"), + name: InteropUtf8NameFactory.TypeName(typeSignature, interopDefinitions, "Marshaller"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()); @@ -704,6 +712,7 @@ private static void InterfaceEntriesImpl( /// /// The for the mapped type the proxy type is for. /// The instance for the marshaller attribute type. + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// Whether to use Windows.UI.Xaml projections. @@ -711,6 +720,7 @@ private static void InterfaceEntriesImpl( public static void Proxy( TypeSignature interfaceType, TypeDefinition comWrappersMarshallerAttributeType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, @@ -723,7 +733,7 @@ public static void Proxy( // when marshalling 'TypeName' instances. Nobody would need a runtime class name here. Proxy( ns: InteropUtf8NameFactory.TypeNamespace(interfaceType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(interfaceType, interopReferences.RuntimeContext), + name: InteropUtf8NameFactory.TypeName(interfaceType, interopDefinitions), mappedMetadata: null, runtimeClassName: null, metadataTypeName: MetadataTypeNameGenerator.GetMetadataTypeName(interfaceType, useWindowsUIXamlProjections), @@ -943,4 +953,4 @@ public static void TypeMapAttributes( interopReferences: interopReferences)); } } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs b/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs index 19fb59be7..9dac09122 100644 --- a/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs +++ b/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs @@ -787,6 +787,74 @@ public bool IsWindowsRuntimeManagedOnlyType(InteropReferences interopReferences) return attribute?.Signature?.FixedArguments?[0]?.Element as Utf8String; } + + /// + /// Gets the Windows Runtime metadata name for a , recovering it from the + /// implementation projection when the type comes from a reference projection. + /// + /// The instance to use. + /// The Windows Runtime metadata name (i.e. the source .winmd module name), or if not found. + /// + /// + /// The per-type [WindowsRuntimeMetadata] attribute is present on implementation projections, the + /// authored component projection, and manually projected types in WinRT.Runtime.dll, so for those the + /// value is read directly off the type. + /// + /// + /// Reference projections shipped in Windows Runtime projection NuGet packages have that attribute stripped (it + /// is an implementation-only attribute, absent from the WinRT.Runtime.dll reference assembly they compile + /// against). For a type defined in such a reference projection, the source .winmd stem is recovered from + /// the matching type in the implementation projection (located via ), + /// which retains it. That is the authoritative value the interop type-name marker must agree with: the projection + /// writer encodes the very same stem into the [UnsafeAccessorType] references it emits into that + /// implementation projection, so falling back to the reference projection's own assembly name (which can differ + /// from the stem, e.g. when several .winmd files are merged into one projection) would produce mismatched names. + /// + /// + public Utf8String? GetWindowsRuntimeMetadataName(InteropDefinitions interopDefinitions) + { + // Fast path: the attribute is present directly on the type (implementation projections, authored + // components, and 'WinRT.Runtime.dll' types all carry '[WindowsRuntimeMetadata]'). + if (type.GetWindowsRuntimeMetadataName() is { } metadataName) + { + return metadataName; + } + + // The only remaining case we can recover is a type from a reference projection, whose per-type attribute + // was stripped. For those, the metadata name lives on the matching type in the implementation projection. + if (!type.IsReferenceProjectionWindowsRuntimeType) + { + return null; + } + + // Resolve the equivalent type in the right implementation projection (via the cached top-level types + // lookup) and read the '[WindowsRuntimeMetadata]' attribute off it, which it retains. + if (type.GetImplementationProjectionModule(interopDefinitions) is { } projectionModule && + projectionModule.GetTopLevelTypesLookup().TryGetValue((type.Namespace, type.Name), out TypeDefinition? projectionType)) + { + return projectionType.GetWindowsRuntimeMetadataName(); + } + + return null; + } + + /// + /// Gets the implementation projection module that contains the marshalling code for a projected . + /// + /// The instance to use. + /// + /// The for the implementation projection the type belongs to: the Windows SDK projection + /// (WinRT.Sdk.Projection.dll), the Windows SDK XAML projection (WinRT.Sdk.Xaml.Projection.dll), or the merged + /// third-party projection (WinRT.Projection.dll); or if that projection is not available. + /// + public ModuleDefinition? GetImplementationProjectionModule(InteropDefinitions interopDefinitions) + { + return type.IsProjectedWindowsSdkType + ? interopDefinitions.WindowsRuntimeSdkProjectionModule + : type.IsProjectedWindowsSdkXamlType + ? interopDefinitions.WindowsRuntimeSdkXamlProjectionModule + : interopDefinitions.WindowsRuntimeProjectionModule; + } } extension(TypeSignature signature) @@ -1103,22 +1171,25 @@ arrayType.BaseType is not SzArrayTypeSignature && /// /// Gets the Windows Runtime metadata name for a , if available. /// - /// The context to assume when resolving types. - /// The Windows Runtime metadata name from the underlying type's WindowsRuntimeMetadataAttribute, or if not found. + /// The instance to use. + /// The Windows Runtime metadata name for the underlying type, or if not found. /// /// /// This method resolves the underlying type definition from the signature and retrieves its Windows Runtime metadata name. /// For generic instance types, it uses the generic type definition. For array types, it uses the base element type. - /// For other types, it resolves the type definition directly. + /// For other types, it resolves the type definition directly. The metadata name is recovered from the implementation + /// projection for types coming from reference projections (see the TypeDefinition overload of this method). /// /// - public Utf8String? GetWindowsRuntimeMetadataName(RuntimeContext? runtimeContext) + public Utf8String? GetWindowsRuntimeMetadataName(InteropDefinitions interopDefinitions) { + RuntimeContext? runtimeContext = interopDefinitions.RuntimeContext; + return signature switch { - GenericInstanceTypeSignature generic => generic.GenericType.Resolve(runtimeContext).GetWindowsRuntimeMetadataName(), - ArrayTypeSignature array => array.BaseType.Resolve(runtimeContext).GetWindowsRuntimeMetadataName(), - _ => signature.ToTypeDefOrRef().Resolve(runtimeContext).GetWindowsRuntimeMetadataName() + GenericInstanceTypeSignature generic => generic.GenericType.Resolve(runtimeContext).GetWindowsRuntimeMetadataName(interopDefinitions), + ArrayTypeSignature array => array.BaseType.Resolve(runtimeContext).GetWindowsRuntimeMetadataName(interopDefinitions), + _ => signature.ToTypeDefOrRef().Resolve(runtimeContext).GetWindowsRuntimeMetadataName(interopDefinitions) }; } } diff --git a/src/WinRT.Interop.Generator/Factories/InteropTypeDefinitionFactory.IEnumeratorElementMarshaller.cs b/src/WinRT.Interop.Generator/Factories/InteropTypeDefinitionFactory.IEnumeratorElementMarshaller.cs index fa5a979d9..eca50d9d0 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropTypeDefinitionFactory.IEnumeratorElementMarshaller.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropTypeDefinitionFactory.IEnumeratorElementMarshaller.cs @@ -28,11 +28,13 @@ public static class IEnumeratorElementMarshaller /// Creates a for the element marshaller for an unmanaged value type. /// /// The for the type. + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The resulting element marshaller type. public static TypeDefinition UnmanagedValueType( GenericInstanceTypeSignature enumeratorType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState) { @@ -49,6 +51,7 @@ public static TypeDefinition UnmanagedValueType( interfaceType: interfaceType, convertToUnmanagedInterfaceMethod: interopReferences.IWindowsRuntimeUnmanagedValueTypeElementMarshallerConvertToUnmanaged(elementType, elementAbiType), isValueType: true, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState); } @@ -57,11 +60,13 @@ public static TypeDefinition UnmanagedValueType( /// Creates a for the element marshaller for a managed value type. /// /// The for the type. + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The resulting element marshaller type. public static TypeDefinition ManagedValueType( GenericInstanceTypeSignature enumeratorType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState) { @@ -79,6 +84,7 @@ public static TypeDefinition ManagedValueType( interfaceType: interfaceType, convertToUnmanagedInterfaceMethod: interopReferences.IWindowsRuntimeManagedValueTypeElementMarshallerConvertToUnmanaged(elementType, elementAbiType), isValueType: true, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState); @@ -119,11 +125,13 @@ public static TypeDefinition ManagedValueType( /// Creates a for the element marshaller for a type. /// /// The for the type. + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The resulting element marshaller type. public static TypeDefinition KeyValuePair( GenericInstanceTypeSignature enumeratorType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState) { @@ -144,6 +152,7 @@ public static TypeDefinition KeyValuePair( interfaceType: interfaceType, convertToUnmanagedInterfaceMethod: interopReferences.IWindowsRuntimeKeyValuePairTypeElementMarshallerConvertToUnmanaged(keyType, valueType), isValueType: isValueType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState); } @@ -152,11 +161,13 @@ public static TypeDefinition KeyValuePair( /// Creates a for the element marshaller for a type. /// /// The for the type. + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The resulting element marshaller type. public static TypeDefinition NullableValueType( GenericInstanceTypeSignature enumeratorType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState) { @@ -173,6 +184,7 @@ public static TypeDefinition NullableValueType( interfaceType: interfaceType, convertToUnmanagedInterfaceMethod: interopReferences.IWindowsRuntimeNullableTypeElementMarshallerConvertToUnmanaged(underlyingType), isValueType: true, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState); } @@ -181,11 +193,13 @@ public static TypeDefinition NullableValueType( /// Creates a for the element marshaller for a reference type. /// /// The for the type. + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The resulting element marshaller type. public static TypeDefinition ReferenceType( GenericInstanceTypeSignature enumeratorType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState) { @@ -201,6 +215,7 @@ public static TypeDefinition ReferenceType( interfaceType: interfaceType, convertToUnmanagedInterfaceMethod: interopReferences.IWindowsRuntimeReferenceTypeElementMarshallerConvertToUnmanaged(elementType), isValueType: false, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState); } @@ -212,6 +227,7 @@ public static TypeDefinition ReferenceType( /// The interface type the element marshaller type should implement. /// The ConvertToUnmanaged interface method being implemented. /// Indicates whether the element marshaller type should be emitted as a value type. + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The resulting element marshaller type. @@ -220,6 +236,7 @@ public static TypeDefinition ElementMarshaller( TypeSignature interfaceType, MemberReference convertToUnmanagedInterfaceMethod, bool isValueType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState) { @@ -231,7 +248,7 @@ public static TypeDefinition ElementMarshaller( // We're declaring an 'internal abstract class' type TypeDefinition elementMarshallerType = new( ns: InteropUtf8NameFactory.TypeNamespace(elementType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(elementType, interopReferences.RuntimeContext, "ElementMarshaller"), + name: InteropUtf8NameFactory.TypeName(elementType, interopDefinitions, "ElementMarshaller"), attributes: attributes, baseType: baseType) { @@ -273,4 +290,4 @@ public static TypeDefinition ElementMarshaller( return elementMarshallerType; } } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Factories/InteropTypeDefinitionFactory.IReadOnlyCollectionKeyValuePair2.cs b/src/WinRT.Interop.Generator/Factories/InteropTypeDefinitionFactory.IReadOnlyCollectionKeyValuePair2.cs index 36fdab564..0f7018ead 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropTypeDefinitionFactory.IReadOnlyCollectionKeyValuePair2.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropTypeDefinitionFactory.IReadOnlyCollectionKeyValuePair2.cs @@ -26,6 +26,7 @@ public static class IReadOnlyCollectionKeyValuePair2 /// The for the generic interface type. /// The for the corresponding type. /// The for the corresponding type. + /// The instance to use. /// The instance to use. /// The module that will contain the type being created. /// The resulting marshaller type. @@ -36,6 +37,7 @@ public static void ForwarderAttribute( GenericInstanceTypeSignature readOnlyCollectionType, TypeSignature readOnlyDictionaryType, TypeSignature readOnlyListType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module, out TypeDefinition forwarderAttributeType) @@ -43,7 +45,7 @@ public static void ForwarderAttribute( // We're declaring an 'internal sealed class' type forwarderAttributeType = new( ns: InteropUtf8NameFactory.TypeNamespace(readOnlyCollectionType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(readOnlyCollectionType, interopReferences.RuntimeContext, "ForwarderAttribute"), + name: InteropUtf8NameFactory.TypeName(readOnlyCollectionType, interopDefinitions, "ForwarderAttribute"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit, baseType: interopReferences.DynamicInterfaceCastableForwarderAttribute); @@ -99,4 +101,4 @@ public static void ForwarderAttribute( forwarderAttributeType.Methods.Add(isInterfaceImplementedMethod); } } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Factories/InteropTypeDefinitionFactory.SzArrayElementMarshaller.cs b/src/WinRT.Interop.Generator/Factories/InteropTypeDefinitionFactory.SzArrayElementMarshaller.cs index e0f41b7e3..31d223e3d 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropTypeDefinitionFactory.SzArrayElementMarshaller.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropTypeDefinitionFactory.SzArrayElementMarshaller.cs @@ -25,11 +25,13 @@ public static class SzArrayElementMarshaller /// Creates a for the element marshaller for an unmanaged value type. /// /// The for the SZ array type. + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The resulting element marshaller type. public static TypeDefinition UnmanagedValueType( SzArrayTypeSignature arrayType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState) { @@ -47,6 +49,7 @@ public static TypeDefinition UnmanagedValueType( convertToUnmanagedInterfaceMethod: interopReferences.IWindowsRuntimeUnmanagedValueTypeArrayElementMarshallerConvertToUnmanaged(elementType, elementAbiType), convertToManagedInterfaceMethod: interopReferences.IWindowsRuntimeUnmanagedValueTypeArrayElementMarshallerConvertToManaged(elementType, elementAbiType), isValueType: true, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState); } @@ -55,11 +58,13 @@ public static TypeDefinition UnmanagedValueType( /// Creates a for the element marshaller for a managed value type. /// /// The for the SZ array type. + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The resulting element marshaller type. public static TypeDefinition ManagedValueType( SzArrayTypeSignature arrayType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState) { @@ -78,6 +83,7 @@ public static TypeDefinition ManagedValueType( convertToUnmanagedInterfaceMethod: interopReferences.IWindowsRuntimeManagedValueTypeArrayElementMarshallerConvertToUnmanaged(elementType, elementAbiType), convertToManagedInterfaceMethod: interopReferences.IWindowsRuntimeManagedValueTypeArrayElementMarshallerConvertToManaged(elementType, elementAbiType), isValueType: true, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState); @@ -118,11 +124,13 @@ public static TypeDefinition ManagedValueType( /// Creates a for the element marshaller for a type. /// /// The for the SZ array type. + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The resulting element marshaller type. public static TypeDefinition KeyValuePair( SzArrayTypeSignature arrayType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState) { @@ -147,6 +155,7 @@ public static TypeDefinition KeyValuePair( convertToUnmanagedInterfaceMethod: interopReferences.IWindowsRuntimeKeyValuePairTypeArrayElementMarshallerConvertToUnmanaged(keyType, valueType), convertToManagedInterfaceMethod: interopReferences.IWindowsRuntimeKeyValuePairTypeArrayElementMarshallerConvertToManaged(keyType, valueType), isValueType: isValueType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState); } @@ -155,11 +164,13 @@ public static TypeDefinition KeyValuePair( /// Creates a for the element marshaller for a type. /// /// The for the SZ array type. + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The resulting element marshaller type. public static TypeDefinition NullableValueType( SzArrayTypeSignature arrayType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState) { @@ -177,6 +188,7 @@ public static TypeDefinition NullableValueType( convertToUnmanagedInterfaceMethod: interopReferences.IWindowsRuntimeNullableTypeArrayElementMarshallerConvertToUnmanaged(underlyingType), convertToManagedInterfaceMethod: interopReferences.IWindowsRuntimeNullableTypeArrayElementMarshallerConvertToManaged(underlyingType), isValueType: true, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState); } @@ -185,11 +197,13 @@ public static TypeDefinition NullableValueType( /// Creates a for the element marshaller for a reference type. /// /// The for the SZ array type. + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The resulting element marshaller type. public static TypeDefinition ReferenceType( SzArrayTypeSignature arrayType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState) { @@ -206,6 +220,7 @@ public static TypeDefinition ReferenceType( convertToUnmanagedInterfaceMethod: interopReferences.IWindowsRuntimeReferenceTypeArrayElementMarshallerConvertToUnmanaged(elementType), convertToManagedInterfaceMethod: interopReferences.IWindowsRuntimeReferenceTypeArrayElementMarshallerConvertToManaged(elementType), isValueType: false, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState); } @@ -218,6 +233,7 @@ public static TypeDefinition ReferenceType( /// The ConvertToUnmanaged interface method being implemented. /// The ConvertToManaged interface method being implemented. /// Indicates whether the element marshaller type should be emitted as a value type. + /// The instance to use. /// The instance to use. /// The emit state for this invocation. /// The resulting element marshaller type. @@ -227,6 +243,7 @@ public static TypeDefinition ElementMarshaller( MemberReference convertToUnmanagedInterfaceMethod, MemberReference convertToManagedInterfaceMethod, bool isValueType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, InteropGeneratorEmitState emitState) { @@ -240,7 +257,7 @@ public static TypeDefinition ElementMarshaller( // We're declaring an 'internal abstract class' type TypeDefinition elementMarshallerType = new( ns: InteropUtf8NameFactory.TypeNamespace(arrayType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(arrayType, interopReferences.RuntimeContext, "ElementMarshaller"), + name: InteropUtf8NameFactory.TypeName(arrayType, interopDefinitions, "ElementMarshaller"), attributes: attributes, baseType: baseType) { @@ -312,4 +329,4 @@ public static TypeDefinition ElementMarshaller( return elementMarshallerType; } } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Factories/InteropTypeDefinitionFactory.SzArrayMarshaller.cs b/src/WinRT.Interop.Generator/Factories/InteropTypeDefinitionFactory.SzArrayMarshaller.cs index f86c4007c..0e6512c7c 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropTypeDefinitionFactory.SzArrayMarshaller.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropTypeDefinitionFactory.SzArrayMarshaller.cs @@ -23,10 +23,12 @@ public static class SzArrayMarshaller /// Creates a for the marshaller for a blittable value type. /// /// The for the SZ array type. + /// The instance to use. /// The instance to use. /// The resulting marshaller type. public static TypeDefinition BlittableValueType( SzArrayTypeSignature arrayType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences) { TypeSignature elementType = arrayType.BaseType; @@ -39,6 +41,7 @@ public static TypeDefinition BlittableValueType( copyToManagedMethod: interopReferences.WindowsRuntimeBlittableValueTypeArrayMarshallerCopyToManaged(elementType), disposeMethod: null, freeMethod: interopReferences.WindowsRuntimeBlittableValueTypeArrayMarshallerFree, + interopDefinitions: interopDefinitions, interopReferences: interopReferences); } @@ -47,11 +50,13 @@ public static TypeDefinition BlittableValueType( /// /// The for the SZ array type. /// The element marshaller type produced by . + /// The instance to use. /// The instance to use. /// The resulting marshaller type. public static TypeDefinition UnmanagedValueType( SzArrayTypeSignature arrayType, TypeDefinition elementMarshallerType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences) { TypeSignature elementType = arrayType.BaseType; @@ -66,6 +71,7 @@ public static TypeDefinition UnmanagedValueType( copyToManagedMethod: interopReferences.WindowsRuntimeUnmanagedValueTypeArrayMarshallerCopyToManaged(elementType, elementAbiType, elementMarshallerTypeSignature), disposeMethod: null, freeMethod: interopReferences.WindowsRuntimeBlittableValueTypeArrayMarshallerFree, + interopDefinitions: interopDefinitions, interopReferences: interopReferences); } @@ -74,11 +80,13 @@ public static TypeDefinition UnmanagedValueType( /// /// The for the SZ array type. /// The element marshaller type produced by . + /// The instance to use. /// The instance to use. /// The resulting marshaller type. public static TypeDefinition ManagedValueType( SzArrayTypeSignature arrayType, TypeDefinition elementMarshallerType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences) { TypeSignature elementType = arrayType.BaseType; @@ -93,6 +101,7 @@ public static TypeDefinition ManagedValueType( copyToManagedMethod: interopReferences.WindowsRuntimeManagedValueTypeArrayMarshallerCopyToManaged(elementType, elementAbiType, elementMarshallerTypeSignature), disposeMethod: interopReferences.WindowsRuntimeManagedValueTypeArrayMarshallerDispose(elementType, elementAbiType, elementMarshallerTypeSignature), freeMethod: interopReferences.WindowsRuntimeManagedValueTypeArrayMarshallerFree(elementType, elementAbiType, elementMarshallerTypeSignature), + interopDefinitions: interopDefinitions, interopReferences: interopReferences); } @@ -101,11 +110,13 @@ public static TypeDefinition ManagedValueType( /// /// The for the SZ array type. /// The element marshaller type produced by . + /// The instance to use. /// The instance to use. /// The resulting marshaller type. public static TypeDefinition KeyValuePair( SzArrayTypeSignature arrayType, TypeDefinition elementMarshallerType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences) { GenericInstanceTypeSignature elementType = (GenericInstanceTypeSignature)arrayType.BaseType; @@ -121,6 +132,7 @@ public static TypeDefinition KeyValuePair( copyToManagedMethod: interopReferences.WindowsRuntimeKeyValuePairTypeArrayMarshallerCopyToManaged(keyType, valueType, elementMarshallerTypeSignature), disposeMethod: interopReferences.WindowsRuntimeUnknownArrayMarshallerDispose, freeMethod: interopReferences.WindowsRuntimeUnknownArrayMarshallerFree, + interopDefinitions: interopDefinitions, interopReferences: interopReferences); } @@ -129,11 +141,13 @@ public static TypeDefinition KeyValuePair( /// /// The for the SZ array type. /// The element marshaller type produced by . + /// The instance to use. /// The instance to use. /// The resulting marshaller type. public static TypeDefinition NullableValueType( SzArrayTypeSignature arrayType, TypeDefinition elementMarshallerType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences) { GenericInstanceTypeSignature elementType = (GenericInstanceTypeSignature)arrayType.BaseType; @@ -148,6 +162,7 @@ public static TypeDefinition NullableValueType( copyToManagedMethod: interopReferences.WindowsRuntimeNullableTypeArrayMarshallerCopyToManaged(underlyingType, elementMarshallerTypeSignature), disposeMethod: interopReferences.WindowsRuntimeUnknownArrayMarshallerDispose, freeMethod: interopReferences.WindowsRuntimeUnknownArrayMarshallerFree, + interopDefinitions: interopDefinitions, interopReferences: interopReferences); } @@ -156,11 +171,13 @@ public static TypeDefinition NullableValueType( /// /// The for the SZ array type. /// The element marshaller type produced by . + /// The instance to use. /// The instance to use. /// The resulting marshaller type. public static TypeDefinition ReferenceType( SzArrayTypeSignature arrayType, TypeDefinition elementMarshallerType, + InteropDefinitions interopDefinitions, InteropReferences interopReferences) { TypeSignature elementType = arrayType.BaseType; @@ -174,6 +191,7 @@ public static TypeDefinition ReferenceType( copyToManagedMethod: interopReferences.WindowsRuntimeReferenceTypeArrayMarshallerCopyToManaged(elementType, elementMarshallerTypeSignature), disposeMethod: interopReferences.WindowsRuntimeUnknownArrayMarshallerDispose, freeMethod: interopReferences.WindowsRuntimeUnknownArrayMarshallerFree, + interopDefinitions: interopDefinitions, interopReferences: interopReferences); } @@ -181,9 +199,10 @@ public static TypeDefinition ReferenceType( /// Creates a for the marshaller for the type. /// /// The for the SZ array type. + /// The instance to use. /// The instance to use. /// The resulting marshaller type. - public static TypeDefinition Object(SzArrayTypeSignature arrayType, InteropReferences interopReferences) + public static TypeDefinition Object(SzArrayTypeSignature arrayType, InteropDefinitions interopDefinitions, InteropReferences interopReferences) { return Marshaller( arrayType: arrayType, @@ -193,6 +212,7 @@ public static TypeDefinition Object(SzArrayTypeSignature arrayType, InteropRefer copyToManagedMethod: interopReferences.WindowsRuntimeObjectArrayMarshallerCopyToManaged, disposeMethod: interopReferences.WindowsRuntimeUnknownArrayMarshallerDispose, freeMethod: interopReferences.WindowsRuntimeUnknownArrayMarshallerFree, + interopDefinitions: interopDefinitions, interopReferences: interopReferences); } @@ -200,9 +220,10 @@ public static TypeDefinition Object(SzArrayTypeSignature arrayType, InteropRefer /// Creates a for the marshaller for the type. /// /// The for the SZ array type. + /// The instance to use. /// The instance to use. /// The resulting marshaller type. - public static TypeDefinition String(SzArrayTypeSignature arrayType, InteropReferences interopReferences) + public static TypeDefinition String(SzArrayTypeSignature arrayType, InteropDefinitions interopDefinitions, InteropReferences interopReferences) { return Marshaller( arrayType: arrayType, @@ -212,6 +233,7 @@ public static TypeDefinition String(SzArrayTypeSignature arrayType, InteropRefer copyToManagedMethod: interopReferences.HStringArrayMarshallerCopyToManaged, disposeMethod: interopReferences.HStringArrayMarshallerDispose, freeMethod: interopReferences.HStringArrayMarshallerFree, + interopDefinitions: interopDefinitions, interopReferences: interopReferences); } @@ -219,9 +241,10 @@ public static TypeDefinition String(SzArrayTypeSignature arrayType, InteropRefer /// Creates a for the marshaller for the type. /// /// The for the SZ array type. + /// The instance to use. /// The instance to use. /// The resulting marshaller type. - public static TypeDefinition Type(SzArrayTypeSignature arrayType, InteropReferences interopReferences) + public static TypeDefinition Type(SzArrayTypeSignature arrayType, InteropDefinitions interopDefinitions, InteropReferences interopReferences) { return Marshaller( arrayType: arrayType, @@ -231,6 +254,7 @@ public static TypeDefinition Type(SzArrayTypeSignature arrayType, InteropReferen copyToManagedMethod: interopReferences.TypeArrayMarshallerCopyToManaged, disposeMethod: interopReferences.TypeArrayMarshallerDispose, freeMethod: interopReferences.TypeArrayMarshallerFree, + interopDefinitions: interopDefinitions, interopReferences: interopReferences); } @@ -238,9 +262,10 @@ public static TypeDefinition Type(SzArrayTypeSignature arrayType, InteropReferen /// Creates a for the marshaller for the type. /// /// The for the SZ array type. + /// The instance to use. /// The instance to use. /// The resulting marshaller type. - public static TypeDefinition Exception(SzArrayTypeSignature arrayType, InteropReferences interopReferences) + public static TypeDefinition Exception(SzArrayTypeSignature arrayType, InteropDefinitions interopDefinitions, InteropReferences interopReferences) { return Marshaller( arrayType: arrayType, @@ -250,6 +275,7 @@ public static TypeDefinition Exception(SzArrayTypeSignature arrayType, InteropRe copyToManagedMethod: interopReferences.ExceptionArrayMarshallerCopyToManaged, freeMethod: interopReferences.WindowsRuntimeBlittableValueTypeArrayMarshallerFree, disposeMethod: null, + interopDefinitions: interopDefinitions, interopReferences: interopReferences); } @@ -263,6 +289,7 @@ public static TypeDefinition Exception(SzArrayTypeSignature arrayType, InteropRe /// The CopyToManaged implementation method to call. /// The Dispose implementation method to call, if applicable. /// The Free implementation method to call. + /// The instance to use. /// The instance to use. /// The resulting marshaller type. private static TypeDefinition Marshaller( @@ -273,6 +300,7 @@ private static TypeDefinition Marshaller( IMethodDescriptor copyToManagedMethod, IMethodDescriptor? disposeMethod, IMethodDescriptor freeMethod, + InteropDefinitions interopDefinitions, InteropReferences interopReferences) { TypeSignature elementType = arrayType.BaseType; @@ -281,7 +309,7 @@ private static TypeDefinition Marshaller( // We're declaring an 'internal static class' type TypeDefinition marshallerType = new( ns: InteropUtf8NameFactory.TypeNamespace(arrayType, interopReferences.RuntimeContext), - name: InteropUtf8NameFactory.TypeName(arrayType, interopReferences.RuntimeContext, "Marshaller"), + name: InteropUtf8NameFactory.TypeName(arrayType, interopDefinitions, "Marshaller"), attributes: TypeAttributes.AutoLayout | TypeAttributes.Sealed | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, baseType: interopReferences.Object.ToTypeDefOrRef()); @@ -436,4 +464,4 @@ private static TypeDefinition Marshaller( return marshallerType; } } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Factories/InteropUtf8NameFactory.cs b/src/WinRT.Interop.Generator/Factories/InteropUtf8NameFactory.cs index 866d3d5b8..bf6da83b2 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropUtf8NameFactory.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropUtf8NameFactory.cs @@ -9,6 +9,7 @@ using AsmResolver.DotNet; using AsmResolver.DotNet.Signatures; using AsmResolver.PE.DotNet.Metadata.Tables; +using WindowsRuntime.InteropGenerator.References; namespace WindowsRuntime.InteropGenerator.Factories; @@ -55,10 +56,10 @@ public static Utf8String TypeNamespace(TypeSignature typeSignature, RuntimeConte /// Gets the name for a generated interop type. /// /// The source for the type to generate. - /// The context to assume when resolving types. + /// The instance to use (for resolving types and locating implementation projections). /// The optional name suffix to use. /// The name to use. - public static Utf8String TypeName(TypeSignature typeSignature, RuntimeContext? runtimeContext, string? nameSuffix = null) + public static Utf8String TypeName(TypeSignature typeSignature, InteropDefinitions interopDefinitions, string? nameSuffix = null) { DefaultInterpolatedStringHandler interpolatedStringHandler = new(literalLength: 2, formattedCount: 1); @@ -66,7 +67,7 @@ public static Utf8String TypeName(TypeSignature typeSignature, RuntimeContext? r static void AppendTypeName( ref DefaultInterpolatedStringHandler interpolatedStringHandler, TypeSignature typeSignature, - RuntimeContext? runtimeContext, + InteropDefinitions interopDefinitions, int depth) { // Special case for well known type identifiers (eg. 'string', 'int', etc.) @@ -82,7 +83,7 @@ static void AppendTypeName( { interpolatedStringHandler.AppendLiteral("<"); - AppendTypeName(ref interpolatedStringHandler, arrayTypeSignature.BaseType, runtimeContext, depth); + AppendTypeName(ref interpolatedStringHandler, arrayTypeSignature.BaseType, interopDefinitions, depth); interpolatedStringHandler.AppendLiteral(">Array"); } @@ -91,7 +92,7 @@ static void AppendTypeName( Utf8String assemblyName = AssemblyNameOrWellKnownIdentifier( assemblyName: typeSignature.Scope!.GetAssembly()!.Name!, typeSignature: typeSignature, - runtimeContext: runtimeContext); + interopDefinitions: interopDefinitions); // Each type name uses this format: 'TYPE_NAME' interpolatedStringHandler.AppendLiteral("<"); @@ -108,7 +109,7 @@ static void AppendTypeName( // type descriptor here, because we also want to detect arrays with an element type that's generic. if (typeSignature is GenericInstanceTypeSignature genericInstanceTypeSignature) { - AppendTypeArguments(ref interpolatedStringHandler, genericInstanceTypeSignature, runtimeContext, depth); + AppendTypeArguments(ref interpolatedStringHandler, genericInstanceTypeSignature, interopDefinitions, depth); } } } @@ -157,7 +158,7 @@ static void AppendRawTypeName( static void AppendTypeArguments( ref DefaultInterpolatedStringHandler interpolatedStringHandler, GenericInstanceTypeSignature type, - RuntimeContext? runtimeContext, + InteropDefinitions interopDefinitions, int depth) { interpolatedStringHandler.AppendLiteral("<"); @@ -172,14 +173,14 @@ static void AppendTypeArguments( // Append the type argument with the same format as the root type. This is // important to ensure that nested generic types will be handled correctly. - AppendTypeName(ref interpolatedStringHandler, typeArgumentSignature, runtimeContext, depth: depth + 1); + AppendTypeName(ref interpolatedStringHandler, typeArgumentSignature, interopDefinitions, depth: depth + 1); } interpolatedStringHandler.AppendLiteral(">"); } // Append the full type name first - AppendTypeName(ref interpolatedStringHandler, typeSignature, runtimeContext, depth: 0); + AppendTypeName(ref interpolatedStringHandler, typeSignature, interopDefinitions, depth: 0); // Append the suffix, if we have one interpolatedStringHandler.AppendFormatted(nameSuffix); @@ -204,13 +205,13 @@ static void AppendTypeArguments( /// /// The input assembly name to convert. /// The type signature for which to convert. - /// The context to assume when resolving the type. + /// The instance to use. /// The resulting assembly name to use. [return: NotNullIfNotNull(nameof(assemblyName))] private static Utf8String? AssemblyNameOrWellKnownIdentifier( Utf8String? assemblyName, TypeSignature typeSignature, - RuntimeContext? runtimeContext) + InteropDefinitions interopDefinitions) { // Replace some assembly names with well known constants, to make the names more compact return assemblyName switch @@ -218,7 +219,7 @@ static void AppendTypeArguments( { Value: "System.Runtime" } => "#corlib"u8, { Value: "Microsoft.Windows.SDK.NET" or "Microsoft.Windows.UI.Xaml" } => "#Windows"u8, { Value: "WinRT.Runtime" } => "#CsWinRT"u8, - _ => typeSignature.GetWindowsRuntimeMetadataName(runtimeContext) ?? assemblyName + _ => typeSignature.GetWindowsRuntimeMetadataName(interopDefinitions) ?? assemblyName }; } diff --git a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs index 012efd323..7c3752cf1 100644 --- a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs +++ b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs @@ -146,12 +146,12 @@ private static void Emit(InteropGeneratorArgs args, InteropGeneratorDiscoverySta args.Token.ThrowIfCancellationRequested(); // Emit interop types for 'IReadOnlyCollection>' types - DefineIReadOnlyCollectionKeyValuePair2Types(args, discoveryState, emitState, interopReferences, module); + DefineIReadOnlyCollectionKeyValuePair2Types(args, discoveryState, emitState, interopDefinitions, interopReferences, module); args.Token.ThrowIfCancellationRequested(); // Emit interop types for 'ICollection>' types - DefineICollectionKeyValuePair2Types(args, discoveryState, emitState, interopReferences, module); + DefineICollectionKeyValuePair2Types(args, discoveryState, emitState, interopDefinitions, interopReferences, module); args.Token.ThrowIfCancellationRequested(); @@ -329,6 +329,7 @@ private static void DefineGenericDelegateTypes( delegateType: typeSignature, nativeDelegateType: nativeDelegateType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out TypeDefinition delegateComWrappersCallbackType); @@ -338,6 +339,7 @@ private static void DefineGenericDelegateTypes( delegateComWrappersCallbackType: delegateComWrappersCallbackType, get_IidMethod: get_IidMethod, get_ReferenceIidMethod: get_ReferenceIidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -384,6 +386,7 @@ private static void DefineGenericDelegateTypes( InteropTypeDefinitionBuilder.Delegate.Proxy( delegateType: typeSignature, comWrappersMarshallerAttributeType: delegateComWrappersMarshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -402,6 +405,7 @@ private static void DefineGenericDelegateTypes( InteropTypeDefinitionBuilder.EventSource.EventHandler1( delegateType: typeSignature, marshallerType: marshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, eventSourceType: out _); @@ -411,6 +415,7 @@ private static void DefineGenericDelegateTypes( InteropTypeDefinitionBuilder.EventSource.EventHandler2( delegateType: typeSignature, marshallerType: marshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, eventSourceType: out _); @@ -420,6 +425,7 @@ private static void DefineGenericDelegateTypes( InteropTypeDefinitionBuilder.EventSource.VectorChangedEventHandler1( delegateType: typeSignature, marshallerType: marshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -430,6 +436,7 @@ private static void DefineGenericDelegateTypes( InteropTypeDefinitionBuilder.EventSource.MapChangedEventHandler2( delegateType: typeSignature, marshallerType: marshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -476,6 +483,7 @@ private static void DefineIEnumeratorTypes( InteropTypeDefinitionBuilder.IEnumerator1.ElementMarshaller( enumeratorType: typeSignature, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -500,6 +508,7 @@ private static void DefineIEnumeratorTypes( InteropTypeDefinitionBuilder.IEnumerator1.Methods( enumeratorType: typeSignature, iteratorMethodsType: iteratorMethodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, enumeratorMethodsType: out _); @@ -507,6 +516,7 @@ private static void DefineIEnumeratorTypes( InteropTypeDefinitionBuilder.IEnumerator1.NativeObject( enumeratorType: typeSignature, iteratorMethodsType: iteratorMethodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, nativeObjectType: out TypeDefinition nativeObjectType); @@ -515,6 +525,7 @@ private static void DefineIEnumeratorTypes( enumeratorType: typeSignature, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -524,6 +535,7 @@ private static void DefineIEnumeratorTypes( enumeratorType: typeSignature, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, marshallerType: out TypeDefinition enumeratorComWrappersMarshallerType); @@ -532,6 +544,7 @@ private static void DefineIEnumeratorTypes( typeSignature: typeSignature, interfaceComWrappersCallbackType: enumeratorComWrappersCallbackType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -549,6 +562,7 @@ private static void DefineIEnumeratorTypes( InteropTypeDefinitionBuilder.Proxy( interfaceType: typeSignature, comWrappersMarshallerAttributeType: enumeratorComWrappersMarshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -602,6 +616,7 @@ private static void DefineIEnumerableTypes( InteropTypeDefinitionBuilder.IEnumerable1.Interface( enumerableType: typeSignature, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -626,6 +641,7 @@ private static void DefineIEnumerableTypes( InteropTypeDefinitionBuilder.IEnumerable1.Methods( enumerableType: typeSignature, iterableMethodsType: iterableMethodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, enumerableMethodsType: out _); @@ -633,6 +649,7 @@ private static void DefineIEnumerableTypes( InteropTypeDefinitionBuilder.IEnumerable1.NativeObject( enumerableType: typeSignature, iterableMethodsType: iterableMethodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, nativeObjectType: out TypeDefinition nativeObjectType); @@ -641,6 +658,7 @@ private static void DefineIEnumerableTypes( enumerableType: typeSignature, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -650,6 +668,7 @@ private static void DefineIEnumerableTypes( enumerableType: typeSignature, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, marshallerType: out TypeDefinition enumerableComWrappersMarshallerType); @@ -658,6 +677,7 @@ private static void DefineIEnumerableTypes( typeSignature: typeSignature, interfaceComWrappersCallbackType: enumerableComWrappersCallbackType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -675,6 +695,7 @@ private static void DefineIEnumerableTypes( InteropTypeDefinitionBuilder.Proxy( interfaceType: typeSignature, comWrappersMarshallerAttributeType: enumerableComWrappersMarshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -744,6 +765,7 @@ private static void DefineIReadOnlyListTypes( InteropTypeDefinitionBuilder.IReadOnlyList1.IVectorViewMethods( readOnlyListType: typeSignature, vftblType: vftblType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -752,6 +774,7 @@ private static void DefineIReadOnlyListTypes( InteropTypeDefinitionBuilder.IReadOnlyList1.Methods( readOnlyListType: typeSignature, vectorViewMethodsType: vectorViewMethodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -760,6 +783,7 @@ private static void DefineIReadOnlyListTypes( InteropTypeDefinitionBuilder.IReadOnlyList1.NativeObject( readOnlyListType: typeSignature, vectorViewMethodsType: vectorViewMethodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -769,6 +793,7 @@ private static void DefineIReadOnlyListTypes( readOnlyListType: typeSignature, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -778,6 +803,7 @@ private static void DefineIReadOnlyListTypes( readOnlyListType: typeSignature, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out TypeDefinition readOnlyListComWrappersMarshallerType); @@ -786,6 +812,7 @@ private static void DefineIReadOnlyListTypes( typeSignature: typeSignature, interfaceComWrappersCallbackType: readOnlyListComWrappersCallbackType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -803,6 +830,7 @@ private static void DefineIReadOnlyListTypes( InteropTypeDefinitionBuilder.Proxy( interfaceType: typeSignature, comWrappersMarshallerAttributeType: readOnlyListComWrappersMarshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -856,6 +884,7 @@ private static void DefineIListTypes( InteropTypeDefinitionBuilder.IList1.Interface( listType: typeSignature, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -880,6 +909,7 @@ private static void DefineIListTypes( InteropTypeDefinitionBuilder.IList1.IVectorMethods( listType: typeSignature, vftblType: vftblType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -888,6 +918,7 @@ private static void DefineIListTypes( InteropTypeDefinitionBuilder.IList1.Methods( listType: typeSignature, vectorMethodsType: vectorMethodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -896,6 +927,7 @@ private static void DefineIListTypes( InteropTypeDefinitionBuilder.IList1.NativeObject( listType: typeSignature, vectorMethodsType: vectorMethodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -905,6 +937,7 @@ private static void DefineIListTypes( listType: typeSignature, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -914,6 +947,7 @@ private static void DefineIListTypes( listType: typeSignature, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out TypeDefinition listComWrappersMarshallerType); @@ -922,6 +956,7 @@ private static void DefineIListTypes( typeSignature: typeSignature, interfaceComWrappersCallbackType: listComWrappersCallbackType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -939,6 +974,7 @@ private static void DefineIListTypes( InteropTypeDefinitionBuilder.Proxy( interfaceType: typeSignature, comWrappersMarshallerAttributeType: listComWrappersMarshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -1009,6 +1045,7 @@ private static void DefineIReadOnlyDictionaryTypes( InteropTypeDefinitionBuilder.IReadOnlyDictionary2.IMapViewMethods( readOnlyDictionaryType: typeSignature, vftblType: vftblType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -1017,6 +1054,7 @@ private static void DefineIReadOnlyDictionaryTypes( InteropTypeDefinitionBuilder.IReadOnlyDictionary2.Methods( readOnlyDictionaryType: typeSignature, mapViewMethodsType: mapViewMethodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -1025,6 +1063,7 @@ private static void DefineIReadOnlyDictionaryTypes( InteropTypeDefinitionBuilder.IReadOnlyDictionary2.NativeObject( readOnlyDictionaryType: typeSignature, mapViewMethodsType: mapViewMethodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -1034,6 +1073,7 @@ private static void DefineIReadOnlyDictionaryTypes( readOnlyDictionaryType: typeSignature, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -1043,6 +1083,7 @@ private static void DefineIReadOnlyDictionaryTypes( readOnlyDictionaryType: typeSignature, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out TypeDefinition readOnlyDictionaryComWrappersMarshallerType); @@ -1051,6 +1092,7 @@ private static void DefineIReadOnlyDictionaryTypes( typeSignature: typeSignature, interfaceComWrappersCallbackType: readOnlyDictionaryComWrappersCallbackType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -1068,6 +1110,7 @@ private static void DefineIReadOnlyDictionaryTypes( InteropTypeDefinitionBuilder.Proxy( interfaceType: typeSignature, comWrappersMarshallerAttributeType: readOnlyDictionaryComWrappersMarshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -1121,6 +1164,7 @@ private static void DefineIDictionaryTypes( InteropTypeDefinitionBuilder.IDictionary2.Interface( dictionaryType: typeSignature, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -1146,6 +1190,7 @@ private static void DefineIDictionaryTypes( InteropTypeDefinitionBuilder.IDictionary2.IMapMethods( dictionaryType: typeSignature, vftblType: vftblType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -1154,6 +1199,7 @@ private static void DefineIDictionaryTypes( InteropTypeDefinitionBuilder.IDictionary2.Methods( dictionaryType: typeSignature, mapMethodsType: mapMethodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -1162,6 +1208,7 @@ private static void DefineIDictionaryTypes( InteropTypeDefinitionBuilder.IDictionary2.NativeObject( dictionaryType: typeSignature, mapMethodsType: mapMethodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -1171,6 +1218,7 @@ private static void DefineIDictionaryTypes( dictionaryType: typeSignature, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -1180,6 +1228,7 @@ private static void DefineIDictionaryTypes( dictionaryType: typeSignature, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out TypeDefinition dictionaryComWrappersMarshallerType); @@ -1188,6 +1237,7 @@ private static void DefineIDictionaryTypes( typeSignature: typeSignature, interfaceComWrappersCallbackType: dictionaryComWrappersCallbackType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -1205,6 +1255,7 @@ private static void DefineIDictionaryTypes( InteropTypeDefinitionBuilder.Proxy( interfaceType: typeSignature, comWrappersMarshallerAttributeType: dictionaryComWrappersMarshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -1248,6 +1299,7 @@ private static void DefineKeyValuePairTypes( try { InteropTypeDefinitionBuilder.KeyValuePair.Methods( + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, methodsType: out methodsType); @@ -1302,6 +1354,7 @@ private static void DefineKeyValuePairTypes( get_IidMethod: get_IidMethod, keyAccessorMethod: keyAccessorMethod, valueAccessorMethod: valueAccessorMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -1320,6 +1373,7 @@ private static void DefineKeyValuePairTypes( InteropTypeDefinitionBuilder.KeyValuePair.Proxy( keyValuePairType: typeSignature, comWrappersMarshallerAttributeType: marshallerAttributeType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -1388,6 +1442,7 @@ private static void DefineIMapChangedEventArgsTypes( InteropTypeDefinitionBuilder.IMapChangedEventArgs1.NativeObject( argsType: typeSignature, argsMethodsType: argsMethodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out TypeDefinition nativeObjectType); @@ -1396,6 +1451,7 @@ private static void DefineIMapChangedEventArgsTypes( argsType: typeSignature, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -1405,6 +1461,7 @@ private static void DefineIMapChangedEventArgsTypes( argsType: typeSignature, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out TypeDefinition argsComWrappersMarshallerType); @@ -1413,6 +1470,7 @@ private static void DefineIMapChangedEventArgsTypes( typeSignature: typeSignature, interfaceComWrappersCallbackType: argsComWrappersCallbackType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -1430,6 +1488,7 @@ private static void DefineIMapChangedEventArgsTypes( InteropTypeDefinitionBuilder.Proxy( interfaceType: typeSignature, comWrappersMarshallerAttributeType: argsComWrappersMarshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -1490,6 +1549,7 @@ private static void DefineIObservableVectorTypes( InteropTypeDefinitionBuilder.IObservableVector1.EventSourceFactory( vectorType: typeSignature, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -1497,6 +1557,7 @@ private static void DefineIObservableVectorTypes( InteropTypeDefinitionBuilder.IObservableVector1.EventSourceCallback( vectorType: typeSignature, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -1505,6 +1566,7 @@ private static void DefineIObservableVectorTypes( InteropTypeDefinitionBuilder.IObservableVector1.Methods( vectorType: typeSignature, eventSourceCallbackType: callbackType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, methodsType: out TypeDefinition methodsType); @@ -1512,6 +1574,7 @@ private static void DefineIObservableVectorTypes( InteropTypeDefinitionBuilder.IObservableVector1.NativeObject( vectorType: typeSignature, factoryType: factoryType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -1521,6 +1584,7 @@ private static void DefineIObservableVectorTypes( vectorType: typeSignature, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -1530,6 +1594,7 @@ private static void DefineIObservableVectorTypes( vectorType: typeSignature, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out TypeDefinition comWrappersMarshallerType); @@ -1538,6 +1603,7 @@ private static void DefineIObservableVectorTypes( typeSignature: typeSignature, interfaceComWrappersCallbackType: comWrappersCallbackType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -1555,6 +1621,7 @@ private static void DefineIObservableVectorTypes( InteropTypeDefinitionBuilder.Proxy( interfaceType: typeSignature, comWrappersMarshallerAttributeType: comWrappersMarshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -1615,6 +1682,7 @@ private static void DefineIObservableMapTypes( InteropTypeDefinitionBuilder.IObservableMap2.EventSourceFactory( mapType: typeSignature, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -1622,6 +1690,7 @@ private static void DefineIObservableMapTypes( InteropTypeDefinitionBuilder.IObservableMap2.EventSourceCallback( mapType: typeSignature, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -1630,6 +1699,7 @@ private static void DefineIObservableMapTypes( InteropTypeDefinitionBuilder.IObservableMap2.Methods( mapType: typeSignature, eventSourceCallbackType: callbackType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, methodsType: out TypeDefinition methodsType); @@ -1637,6 +1707,7 @@ private static void DefineIObservableMapTypes( InteropTypeDefinitionBuilder.IObservableMap2.NativeObject( mapType: typeSignature, factoryType: factoryType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -1646,6 +1717,7 @@ private static void DefineIObservableMapTypes( mapType: typeSignature, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -1655,6 +1727,7 @@ private static void DefineIObservableMapTypes( mapType: typeSignature, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out TypeDefinition comWrappersMarshallerType); @@ -1663,6 +1736,7 @@ private static void DefineIObservableMapTypes( typeSignature: typeSignature, interfaceComWrappersCallbackType: comWrappersCallbackType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -1680,6 +1754,7 @@ private static void DefineIObservableMapTypes( InteropTypeDefinitionBuilder.Proxy( interfaceType: typeSignature, comWrappersMarshallerAttributeType: comWrappersMarshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -1749,6 +1824,7 @@ private static void DefineIAsyncActionWithProgressTypes( InteropTypeDefinitionBuilder.IAsyncActionWithProgress1.NativeObject( actionType: typeSignature, actionMethodsType: actionMethodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out TypeDefinition nativeObjectType); @@ -1757,6 +1833,7 @@ private static void DefineIAsyncActionWithProgressTypes( actionType: typeSignature, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -1766,6 +1843,7 @@ private static void DefineIAsyncActionWithProgressTypes( actionType: typeSignature, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out TypeDefinition actionComWrappersMarshallerType); @@ -1774,6 +1852,7 @@ private static void DefineIAsyncActionWithProgressTypes( typeSignature: typeSignature, interfaceComWrappersCallbackType: actionComWrappersCallbackType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -1791,6 +1870,7 @@ private static void DefineIAsyncActionWithProgressTypes( InteropTypeDefinitionBuilder.Proxy( interfaceType: typeSignature, comWrappersMarshallerAttributeType: actionComWrappersMarshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -1860,6 +1940,7 @@ private static void DefineIAsyncOperationTypes( InteropTypeDefinitionBuilder.IAsyncOperation1.NativeObject( operationType: typeSignature, operationMethodsType: operationMethodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out TypeDefinition nativeObjectType); @@ -1868,6 +1949,7 @@ private static void DefineIAsyncOperationTypes( operationType: typeSignature, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -1877,6 +1959,7 @@ private static void DefineIAsyncOperationTypes( operationType: typeSignature, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out TypeDefinition operationComWrappersMarshallerType); @@ -1885,6 +1968,7 @@ private static void DefineIAsyncOperationTypes( typeSignature: typeSignature, interfaceComWrappersCallbackType: operationComWrappersCallbackType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -1902,6 +1986,7 @@ private static void DefineIAsyncOperationTypes( InteropTypeDefinitionBuilder.Proxy( interfaceType: typeSignature, comWrappersMarshallerAttributeType: operationComWrappersMarshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -1971,6 +2056,7 @@ private static void DefineIAsyncOperationWithProgressTypes( InteropTypeDefinitionBuilder.IAsyncOperationWithProgress2.NativeObject( operationType: typeSignature, operationMethodsType: operationMethodsType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out TypeDefinition nativeObjectType); @@ -1979,6 +2065,7 @@ private static void DefineIAsyncOperationWithProgressTypes( operationType: typeSignature, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -1988,6 +2075,7 @@ private static void DefineIAsyncOperationWithProgressTypes( operationType: typeSignature, nativeObjectType: nativeObjectType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out TypeDefinition operationComWrappersMarshallerType); @@ -1996,6 +2084,7 @@ private static void DefineIAsyncOperationWithProgressTypes( typeSignature: typeSignature, interfaceComWrappersCallbackType: operationComWrappersCallbackType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -2013,6 +2102,7 @@ private static void DefineIAsyncOperationWithProgressTypes( InteropTypeDefinitionBuilder.Proxy( interfaceType: typeSignature, comWrappersMarshallerAttributeType: operationComWrappersMarshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -2039,12 +2129,14 @@ private static void DefineIAsyncOperationWithProgressTypes( /// /// /// The emit state for this invocation. + /// The instance to use. /// The instance to use. /// The interop module being built. private static void DefineIReadOnlyCollectionKeyValuePair2Types( InteropGeneratorArgs args, InteropGeneratorDiscoveryState discoveryState, InteropGeneratorEmitState emitState, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module) { @@ -2065,6 +2157,7 @@ private static void DefineIReadOnlyCollectionKeyValuePair2Types( { InteropTypeDefinitionBuilder.IReadOnlyCollectionKeyValuePair2.ForwarderAttribute( readOnlyCollectionType: readOnlyCollectionType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, forwarderAttributeType: out TypeDefinition forwarderAttributeType); @@ -2072,6 +2165,7 @@ private static void DefineIReadOnlyCollectionKeyValuePair2Types( InteropTypeDefinitionBuilder.IReadOnlyCollectionKeyValuePair2.InterfaceImpl( readOnlyCollectionType: readOnlyCollectionType, forwarderAttributeType: forwarderAttributeType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -2096,12 +2190,14 @@ private static void DefineIReadOnlyCollectionKeyValuePair2Types( /// /// /// The emit state for this invocation. + /// The instance to use. /// The instance to use. /// The interop module being built. private static void DefineICollectionKeyValuePair2Types( InteropGeneratorArgs args, InteropGeneratorDiscoveryState discoveryState, InteropGeneratorEmitState emitState, + InteropDefinitions interopDefinitions, InteropReferences interopReferences, ModuleDefinition module) { @@ -2122,6 +2218,7 @@ private static void DefineICollectionKeyValuePair2Types( { InteropTypeDefinitionBuilder.ICollectionKeyValuePair2.ForwarderAttribute( collectionType: collectionType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, forwarderAttributeType: out TypeDefinition forwarderAttributeType); @@ -2129,6 +2226,7 @@ private static void DefineICollectionKeyValuePair2Types( InteropTypeDefinitionBuilder.ICollectionKeyValuePair2.InterfaceImpl( collectionType: collectionType, forwarderAttributeType: forwarderAttributeType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -2179,6 +2277,7 @@ private static void DefineSzArrayTypes( InteropTypeDefinitionBuilder.SzArray.Marshaller( arrayType: typeSignature, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, emitState: emitState, module: module, @@ -2187,6 +2286,7 @@ private static void DefineSzArrayTypes( InteropTypeDefinitionBuilder.SzArray.ComWrappersCallback( arrayType: typeSignature, marshallerType: marshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out TypeDefinition arrayComWrappersCallbackType); @@ -2218,6 +2318,7 @@ private static void DefineSzArrayTypes( arrayInterfaceEntriesImplType: arrayInterfaceEntriesImplType, arrayComWrappersCallbackType: arrayComWrappersCallbackType, get_IidMethod: get_IidMethod, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out TypeDefinition arrayComWrappersMarshallerType); @@ -2225,6 +2326,7 @@ private static void DefineSzArrayTypes( InteropTypeDefinitionBuilder.SzArray.Proxy( arrayType: typeSignature, comWrappersMarshallerAttributeType: arrayComWrappersMarshallerType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -2442,6 +2544,7 @@ private static void DefineUserDefinedTypes( userDefinedType: typeSignature, interfaceEntriesType: interfaceEntriesType, interfaceEntriesImplType: interfaceEntriesImplType, + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, out TypeDefinition comWrappersMarshallerType); @@ -2465,6 +2568,7 @@ private static void DefineUserDefinedTypes( InteropTypeDefinitionBuilder.UserDefinedType.Proxy( userDefinedType: typeSignature, comWrappersMarshallerAttributeType: marshallerAttributeMap[vtableTypes], + interopDefinitions: interopDefinitions, interopReferences: interopReferences, module: module, useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections, @@ -2647,4 +2751,4 @@ private static void WriteInteropModuleToDisk(InteropGeneratorArgs args, ModuleDe WellKnownInteropExceptions.EmitDllError(e).ThrowOrAttach(e); } } -} \ No newline at end of file +} diff --git a/src/WinRT.Interop.Generator/Helpers/SignatureGenerator.cs b/src/WinRT.Interop.Generator/Helpers/SignatureGenerator.cs index d790a5e6a..e01c9a9b0 100644 --- a/src/WinRT.Interop.Generator/Helpers/SignatureGenerator.cs +++ b/src/WinRT.Interop.Generator/Helpers/SignatureGenerator.cs @@ -163,15 +163,8 @@ private static bool TryGetIIDFromAttribute( // These are only needed to generate signatures, so we hide them from the reference assemblies, as they're not useful there. if (type.IsDelegate) { - // Determine the right implementation projection .dll to use for the lookup - ModuleDefinition? projectionModule = type.IsProjectedWindowsSdkType - ? interopDefinitions.WindowsRuntimeSdkProjectionModule - : type.IsProjectedWindowsSdkXamlType - ? interopDefinitions.WindowsRuntimeSdkXamlProjectionModule - : interopDefinitions.WindowsRuntimeProjectionModule; - // Try to get the implementation type via a fast lookup, if we did get a valid projection module - if (projectionModule?.GetTopLevelTypesLookup().TryGetValue((type.Namespace, type.Name), out TypeDefinition? projectedType) is true) + if (type.GetImplementationProjectionModule(interopDefinitions)?.GetTopLevelTypesLookup().TryGetValue((type.Namespace, type.Name), out TypeDefinition? projectedType) is true) { return projectedType.TryGetGuidAttribute(interopReferences, out iid); } @@ -205,11 +198,7 @@ private static bool TryGetDefaultInterfaceFromAttribute( [NotNullWhen(true)] out TypeSignature? defaultInterface) { // Determine the right implementation projection .dll (see notes above) - ModuleDefinition? projectionModule = type.IsProjectedWindowsSdkType - ? interopDefinitions.WindowsRuntimeSdkProjectionModule - : type.IsProjectedWindowsSdkXamlType - ? interopDefinitions.WindowsRuntimeSdkXamlProjectionModule - : interopDefinitions.WindowsRuntimeProjectionModule; + ModuleDefinition? projectionModule = type.GetImplementationProjectionModule(interopDefinitions); // Use the cached default interfaces lookup for O(1) lookups by (Namespace, Name) key if (projectionModule?.GetDefaultInterfacesLookup().TryGetValue((type.Namespace, type.Name), out TypeSignature? signature) is true) diff --git a/src/WinRT.Interop.Generator/References/InteropDefinitions.cs b/src/WinRT.Interop.Generator/References/InteropDefinitions.cs index 3fb8dd5c3..b105b9612 100644 --- a/src/WinRT.Interop.Generator/References/InteropDefinitions.cs +++ b/src/WinRT.Interop.Generator/References/InteropDefinitions.cs @@ -53,6 +53,11 @@ public InteropDefinitions( WindowsRuntimeComponentModule = windowsRuntimeComponentModule; } + /// + /// Gets the currently in use. + /// + public RuntimeContext RuntimeContext => _interopReferences.RuntimeContext; + /// /// Gets the for the Windows Runtime projection assembly for the Windows SDK (i.e. WinRT.Sdk.Projection.dll). /// diff --git a/src/WinRT.Interop.Generator/Resolvers/InteropImplTypeResolver.cs b/src/WinRT.Interop.Generator/Resolvers/InteropImplTypeResolver.cs index 1e6dd2966..4f74e7567 100644 --- a/src/WinRT.Interop.Generator/Resolvers/InteropImplTypeResolver.cs +++ b/src/WinRT.Interop.Generator/Resolvers/InteropImplTypeResolver.cs @@ -21,13 +21,11 @@ internal static class InteropImplTypeResolver /// /// The type to get the "Impl" method for. /// The instance to use. - /// The instance to use. /// The emit state for this invocation. /// The "Impl" methods for . public static (IMethodDefOrRef get_IID, IMethodDefOrRef get_Vtable) GetGenericInstanceTypeImpl( GenericInstanceTypeSignature type, InteropDefinitions interopDefinitions, - InteropReferences interopReferences, InteropGeneratorEmitState emitState) { // For generic types (i.e. generic interfaces), their marshalling code will be in 'WinRT.Interop.dll', @@ -36,7 +34,7 @@ public static (IMethodDefOrRef get_IID, IMethodDefOrRef get_Vtable) GetGenericIn MethodDefinition get_VtableMethod = implTypeDefinition.GetMethod("get_Vtable"u8); // The IID will be in the generated 'ABI.InterfaceIIDs' type in 'WinRT.Interop.dll' - Utf8String get_IIDMethodName = $"get_IID_{InteropUtf8NameFactory.TypeName(type, interopReferences.RuntimeContext)}"; + Utf8String get_IIDMethodName = $"get_IID_{InteropUtf8NameFactory.TypeName(type, interopDefinitions)}"; MethodDefinition get_IIDMethod = interopDefinitions.InterfaceIIDs.GetMethod(get_IIDMethodName); // Return the pair of methods from the ABI type in 'WinRT.Interop.dll' diff --git a/src/WinRT.Interop.Generator/Resolvers/InteropInterfaceEntriesResolver.cs b/src/WinRT.Interop.Generator/Resolvers/InteropInterfaceEntriesResolver.cs index abb157f50..392592106 100644 --- a/src/WinRT.Interop.Generator/Resolvers/InteropInterfaceEntriesResolver.cs +++ b/src/WinRT.Interop.Generator/Resolvers/InteropInterfaceEntriesResolver.cs @@ -60,7 +60,6 @@ public static IEnumerable EnumerateMetadataInterfaceE (IMethodDefOrRef get_IIDMethod, IMethodDefOrRef get_VtableMethod) = InteropImplTypeResolver.GetGenericInstanceTypeImpl( type: genericTypeSignature, interopDefinitions: interopDefinitions, - interopReferences: interopReferences, emitState: emitState); yield return new WindowsRuntimeInterfaceEntryInfo(get_IIDMethod, get_VtableMethod); From 3baab0331a3552bbf176ad13acf12ee2877d0f5f Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 22 Jun 2026 12:02:47 -0700 Subject: [PATCH 29/42] Emit XAML struct metadata attributes only for implementation projections The hand-authored full-replacement XAML struct additions (CornerRadius, Duration, GridLength, KeyTime, RepeatBehavior, Matrix3D, for both the Windows.UI.Xaml and Microsoft.UI.Xaml namespaces) carried their [WindowsRuntimeMetadata("...")] attribute outside the '#if !CSWINRT_REFERENCE_PROJECTION' block, so it was also emitted into reference projections. That attribute is implementation-only and is stripped from the WinRT.Runtime reference assembly, so a reference projection compiled against that reference assembly would fail to resolve it. Move the attribute inside the existing '#if !CSWINRT_REFERENCE_PROJECTION' block, alongside the other implementation-only attributes ([WindowsRuntimeClassName] and the ComWrappers marshaller), so it is only emitted for implementation projections. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Microsoft.UI.Xaml.Media.Animation.KeyTime.cs | 2 +- .../Microsoft.UI.Xaml.Media.Animation.RepeatBehavior.cs | 2 +- .../Microsoft.UI.Xaml.Media.Media3D.Matrix3D.cs | 2 +- .../Microsoft.UI.Xaml/Microsoft.UI.Xaml.CornerRadius.cs | 2 +- .../Additions/Microsoft.UI.Xaml/Microsoft.UI.Xaml.Duration.cs | 2 +- .../Additions/Microsoft.UI.Xaml/Microsoft.UI.Xaml.GridLength.cs | 2 +- .../Windows.UI.Xaml.Media.Animation.KeyTime.cs | 2 +- .../Windows.UI.Xaml.Media.Animation.RepeatBehavior.cs | 2 +- .../Windows.UI.Xaml.Media.Media3D.Matrix3D.cs | 2 +- .../Additions/Windows.UI.Xaml/Windows.UI.Xaml.CornerRadius.cs | 2 +- .../Additions/Windows.UI.Xaml/Windows.UI.Xaml.Duration.cs | 2 +- .../Additions/Windows.UI.Xaml/Windows.UI.Xaml.GridLength.cs | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml.Media.Animation/Microsoft.UI.Xaml.Media.Animation.KeyTime.cs b/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml.Media.Animation/Microsoft.UI.Xaml.Media.Animation.KeyTime.cs index 61e8f3509..3d646f27e 100644 --- a/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml.Media.Animation/Microsoft.UI.Xaml.Media.Animation.KeyTime.cs +++ b/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml.Media.Animation/Microsoft.UI.Xaml.Media.Animation.KeyTime.cs @@ -3,8 +3,8 @@ namespace Microsoft.UI.Xaml.Media.Animation { using global::Windows.Foundation; - [WindowsRuntimeMetadata("Microsoft.UI")] #if !CSWINRT_REFERENCE_PROJECTION + [WindowsRuntimeMetadata("Microsoft.UI")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] [ABI.Microsoft.UI.Xaml.Media.Animation.KeyTimeComWrappersMarshaller] #endif diff --git a/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml.Media.Animation/Microsoft.UI.Xaml.Media.Animation.RepeatBehavior.cs b/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml.Media.Animation/Microsoft.UI.Xaml.Media.Animation.RepeatBehavior.cs index 972909273..c768ea844 100644 --- a/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml.Media.Animation/Microsoft.UI.Xaml.Media.Animation.RepeatBehavior.cs +++ b/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml.Media.Animation/Microsoft.UI.Xaml.Media.Animation.RepeatBehavior.cs @@ -3,8 +3,8 @@ namespace Microsoft.UI.Xaml.Media.Animation { using global::Windows.Foundation; - [WindowsRuntimeMetadata("Microsoft.UI")] #if !CSWINRT_REFERENCE_PROJECTION + [WindowsRuntimeMetadata("Microsoft.UI")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] [ABI.Microsoft.UI.Xaml.Media.Animation.RepeatBehaviorComWrappersMarshaller] #endif diff --git a/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml.Media.Media3D/Microsoft.UI.Xaml.Media.Media3D.Matrix3D.cs b/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml.Media.Media3D/Microsoft.UI.Xaml.Media.Media3D.Matrix3D.cs index 873cc52c0..478a4a116 100644 --- a/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml.Media.Media3D/Microsoft.UI.Xaml.Media.Media3D.Matrix3D.cs +++ b/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml.Media.Media3D/Microsoft.UI.Xaml.Media.Media3D.Matrix3D.cs @@ -3,8 +3,8 @@ namespace Microsoft.UI.Xaml.Media.Media3D { using global::Windows.Foundation; - [WindowsRuntimeMetadata("Microsoft.UI")] #if !CSWINRT_REFERENCE_PROJECTION + [WindowsRuntimeMetadata("Microsoft.UI")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] [ABI.Microsoft.UI.Xaml.Media.Media3D.Matrix3DComWrappersMarshaller] #endif diff --git a/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml/Microsoft.UI.Xaml.CornerRadius.cs b/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml/Microsoft.UI.Xaml.CornerRadius.cs index 539d6ac17..0a48c3211 100644 --- a/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml/Microsoft.UI.Xaml.CornerRadius.cs +++ b/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml/Microsoft.UI.Xaml.CornerRadius.cs @@ -3,8 +3,8 @@ namespace Microsoft.UI.Xaml { using global::Windows.Foundation; - [WindowsRuntimeMetadata("Microsoft.UI")] #if !CSWINRT_REFERENCE_PROJECTION + [WindowsRuntimeMetadata("Microsoft.UI")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] [ABI.Microsoft.UI.Xaml.CornerRadiusComWrappersMarshaller] #endif diff --git a/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml/Microsoft.UI.Xaml.Duration.cs b/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml/Microsoft.UI.Xaml.Duration.cs index 524df87d2..c36ab0e3c 100644 --- a/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml/Microsoft.UI.Xaml.Duration.cs +++ b/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml/Microsoft.UI.Xaml.Duration.cs @@ -3,8 +3,8 @@ namespace Microsoft.UI.Xaml { using global::Windows.Foundation; - [WindowsRuntimeMetadata("Microsoft.UI")] #if !CSWINRT_REFERENCE_PROJECTION + [WindowsRuntimeMetadata("Microsoft.UI")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] [ABI.Microsoft.UI.Xaml.DurationComWrappersMarshaller] #endif diff --git a/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml/Microsoft.UI.Xaml.GridLength.cs b/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml/Microsoft.UI.Xaml.GridLength.cs index 78a1fabad..ae7905512 100644 --- a/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml/Microsoft.UI.Xaml.GridLength.cs +++ b/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml/Microsoft.UI.Xaml.GridLength.cs @@ -3,8 +3,8 @@ namespace Microsoft.UI.Xaml { using global::Windows.Foundation; - [WindowsRuntimeMetadata("Microsoft.UI")] #if !CSWINRT_REFERENCE_PROJECTION + [WindowsRuntimeMetadata("Microsoft.UI")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] [ABI.Microsoft.UI.Xaml.GridLengthComWrappersMarshaller] #endif diff --git a/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml.Media.Animation/Windows.UI.Xaml.Media.Animation.KeyTime.cs b/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml.Media.Animation/Windows.UI.Xaml.Media.Animation.KeyTime.cs index 0b5d196c2..f5ac26365 100644 --- a/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml.Media.Animation/Windows.UI.Xaml.Media.Animation.KeyTime.cs +++ b/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml.Media.Animation/Windows.UI.Xaml.Media.Animation.KeyTime.cs @@ -3,8 +3,8 @@ namespace Windows.UI.Xaml.Media.Animation { using global::Windows.Foundation; - [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] #if !CSWINRT_REFERENCE_PROJECTION + [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] [ABI.Windows.UI.Xaml.Media.Animation.KeyTimeComWrappersMarshaller] #endif diff --git a/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml.Media.Animation/Windows.UI.Xaml.Media.Animation.RepeatBehavior.cs b/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml.Media.Animation/Windows.UI.Xaml.Media.Animation.RepeatBehavior.cs index c19f73bc4..5cc7ef1ab 100644 --- a/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml.Media.Animation/Windows.UI.Xaml.Media.Animation.RepeatBehavior.cs +++ b/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml.Media.Animation/Windows.UI.Xaml.Media.Animation.RepeatBehavior.cs @@ -3,8 +3,8 @@ namespace Windows.UI.Xaml.Media.Animation { using global::Windows.Foundation; - [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] #if !CSWINRT_REFERENCE_PROJECTION + [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] [ABI.Windows.UI.Xaml.Media.Animation.RepeatBehaviorComWrappersMarshaller] #endif diff --git a/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml.Media.Media3D/Windows.UI.Xaml.Media.Media3D.Matrix3D.cs b/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml.Media.Media3D/Windows.UI.Xaml.Media.Media3D.Matrix3D.cs index f11fe74cb..0c283457b 100644 --- a/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml.Media.Media3D/Windows.UI.Xaml.Media.Media3D.Matrix3D.cs +++ b/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml.Media.Media3D/Windows.UI.Xaml.Media.Media3D.Matrix3D.cs @@ -3,8 +3,8 @@ namespace Windows.UI.Xaml.Media.Media3D { using global::Windows.Foundation; - [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] #if !CSWINRT_REFERENCE_PROJECTION + [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] [ABI.Windows.UI.Xaml.Media.Media3D.Matrix3DComWrappersMarshaller] #endif diff --git a/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml/Windows.UI.Xaml.CornerRadius.cs b/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml/Windows.UI.Xaml.CornerRadius.cs index 0e51a5163..45a3dc068 100644 --- a/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml/Windows.UI.Xaml.CornerRadius.cs +++ b/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml/Windows.UI.Xaml.CornerRadius.cs @@ -3,8 +3,8 @@ namespace Windows.UI.Xaml { using global::Windows.Foundation; - [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] #if !CSWINRT_REFERENCE_PROJECTION + [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] [ABI.Windows.UI.Xaml.CornerRadiusComWrappersMarshaller] #endif diff --git a/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml/Windows.UI.Xaml.Duration.cs b/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml/Windows.UI.Xaml.Duration.cs index d8dd051cb..00e6de207 100644 --- a/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml/Windows.UI.Xaml.Duration.cs +++ b/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml/Windows.UI.Xaml.Duration.cs @@ -3,8 +3,8 @@ namespace Windows.UI.Xaml { using global::Windows.Foundation; - [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] #if !CSWINRT_REFERENCE_PROJECTION + [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] [ABI.Windows.UI.Xaml.DurationComWrappersMarshaller] #endif diff --git a/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml/Windows.UI.Xaml.GridLength.cs b/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml/Windows.UI.Xaml.GridLength.cs index 15be3b17a..cd6db7203 100644 --- a/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml/Windows.UI.Xaml.GridLength.cs +++ b/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml/Windows.UI.Xaml.GridLength.cs @@ -3,8 +3,8 @@ namespace Windows.UI.Xaml { using global::Windows.Foundation; - [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] #if !CSWINRT_REFERENCE_PROJECTION + [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] [ABI.Windows.UI.Xaml.GridLengthComWrappersMarshaller] #endif From 2bf66d0916dcfb2aa0b840d366526a974821b815 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 22 Jun 2026 13:05:45 -0700 Subject: [PATCH 30/42] Emit GetDefaultInterface helper only for implementation projections The 'internal new GetDefaultInterface()' helper emitted on unsealed projected runtime classes returns 'WindowsRuntimeObjectReferenceValue', which is an implementation-only type stripped from the WinRT.Runtime reference assembly. It was emitted in both implementation and reference-projection modes, but its only consumer is the ABI marshaller (also implementation-only and not emitted in reference-projection mode). As a result, the helper was dead code in a reference projection, yet it still failed to compile against the WinRT.Runtime reference assembly that reference projections bind against. This only surfaced for unsealed classes: the helper exists so that overrides on derived classes can hide it with 'new', so sealed classes never emit it. That is why simple sealed components (e.g. the authoring smoke test) never hit it, while the Windows SDK XAML projections (full of unsealed base classes) did. Gate the helper on '!context.Settings.ReferenceProjection', matching the sibling 'IWindowsRuntimeInterface.GetInterface()' helper, so neither is emitted into reference projections. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ...assMembersFactory.WriteInterfaceMembers.cs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/WinRT.Projection.Writer/Factories/ClassMembersFactory.WriteInterfaceMembers.cs b/src/WinRT.Projection.Writer/Factories/ClassMembersFactory.WriteInterfaceMembers.cs index c63a21284..b4c7a0f84 100644 --- a/src/WinRT.Projection.Writer/Factories/ClassMembersFactory.WriteInterfaceMembers.cs +++ b/src/WinRT.Projection.Writer/Factories/ClassMembersFactory.WriteInterfaceMembers.cs @@ -91,14 +91,14 @@ private static void WriteInterfaceMembersRecursive( } // Emit GetInterface() / GetDefaultInterface() impl for this interface BEFORE its - // members. For - // overridable interfaces or non-exclusive direct interfaces, emit + // members. For overridable interfaces or non-exclusive direct interfaces, emit // IWindowsRuntimeInterface.GetInterface(). For the default interface on an // unsealed class with an exclusive default, emit "internal new GetDefaultInterface()". - // The IWindowsRuntimeInterface markers are NOT emitted in ref mode (gated by - // !context.Settings.ReferenceProjection here). The 'internal new - // GetDefaultInterface()' helper IS emitted in both modes since it's referenced by - // overrides on derived classes. + // Both helpers are implementation-only: they return 'WindowsRuntimeObjectReferenceValue' + // (which is stripped from the 'WinRT.Runtime' reference assembly), and are only ever + // called from the ABI marshallers (which are themselves implementation-only and not + // emitted in ref mode). They are therefore gated off in reference-projection mode, where + // they would otherwise be dead code that fails to compile against the reference assembly. if (IsInterfaceInInheritanceList(context.Cache, impl, includeExclusiveInterface: false) && !context.Settings.ReferenceProjection) { string giObjRefName = ObjRefNameGenerator.GetObjRefName(context, substitutedInterface); @@ -111,15 +111,15 @@ private static void WriteInterfaceMembersRecursive( } """); } - else if (impl.IsDefaultInterface() && !classType.IsSealed) + else if (impl.IsDefaultInterface() && !classType.IsSealed && !context.Settings.ReferenceProjection) { // 'internal new GetDefaultInterface()' helper whenever the interface is the // default interface and the class is unsealed -- regardless of exclusive-to - // status. In ref-projection mode this is the only branch that emits the helper - // (the prior 'IWindowsRuntimeInterface.GetInterface' branch is gated off). - // In non-ref mode this branch is only reached when the prior branch's + // status. This branch is only reached when the prior branch's // IsInterfaceInInheritanceList check fails (i.e., ExclusiveTo default interfaces), - // because non-exclusive default interfaces are routed to the prior branch. + // because non-exclusive default interfaces are routed to the prior branch. Like the + // prior branch, this helper is implementation-only (see above), so it is gated off + // in reference-projection mode. string giObjRefName = ObjRefNameGenerator.GetObjRefName(context, substitutedInterface); bool hasBaseType = false; From 3d490e51fd82adba3332d71a235442f540badbd8 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 22 Jun 2026 13:23:41 -0700 Subject: [PATCH 31/42] Clarify runtime class shapes in Thermometer test Update Thermometer smoke test comments to mention both a sealed (non-derivable) runtime class and an unsealed (derivable) runtime class. Add a commented-out Weather class (TODO) to represent an unsealed runtime class for future authoring support. The change documents intended coverage and leaves a placeholder for when unsealed class authoring is supported. --- src/Tests/SmokeTests/Authoring/Thermometer.cs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/Tests/SmokeTests/Authoring/Thermometer.cs b/src/Tests/SmokeTests/Authoring/Thermometer.cs index d76e84862..2832e9e3a 100644 --- a/src/Tests/SmokeTests/Authoring/Thermometer.cs +++ b/src/Tests/SmokeTests/Authoring/Thermometer.cs @@ -5,8 +5,9 @@ namespace Authoring; // A richer set of authored Windows Runtime types, exercised end-to-end by the projection smoke // test: building the component produces 'Authoring.winmd', which the projection smoke test then // generates a reference projection for. Between them, these cover the main projection shapes: -// enums, a flags enum, a struct, a delegate, an interface, and a runtime class with multiple -// constructors, instance methods, properties, an event, and static members. +// enums, a flags enum, a struct, a delegate, an interface, a sealed runtime class with multiple +// constructors, instance methods, properties, an event, and static members, and an unsealed +// (derivable) runtime class. public enum Season { @@ -89,3 +90,16 @@ public Measurement Measure() return new Measurement { Value = _temperature, Season = CurrentSeason }; } } + +// TODO: uncomment this when authoring unsealed classes is supported +// public class Weather +// { +// public string Location { get; set; } +// +// public Season CurrentSeason { get; set; } +// +// public int Forecast() +// { +// return CurrentSeason == Season.Winter ? -5 : 20; +// } +// } From 8927d4b5d55c6ed7f66df42c6347d97d92423a94 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 22 Jun 2026 13:47:50 -0700 Subject: [PATCH 32/42] Guard implementation-only TokenizerHelper usage in reference projections The hand-authored XAML struct/Color additions (CornerRadius, Thickness, Matrix, Matrix3D for both Windows.UI.Xaml and Microsoft.UI.Xaml, plus Windows.UI.Color) format their ToString output using 'WindowsRuntime.InteropServices.TokenizerHelper' to get the culture's numeric list separator. That helper is an implementation-only API ([WindowsRuntimeImplementationOnlyMember]) that is stripped from the WinRT.Runtime reference assembly, so a reference projection that includes any of these types fails to compile against that reference assembly (CS0234). Following the same pattern the runtime uses for its reference-assembly stubs, guard each affected method body with '#if CSWINRT_REFERENCE_PROJECTION' / 'throw null;' / '#else' / the existing implementation / '#endif'. The implementation projection keeps the real body; the reference projection gets a stub, so it no longer references the stripped helper. The bodies are never executed in a reference projection (the real implementation is generated at app build time). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Microsoft.UI.Xaml.Media.Media3D.Matrix3D.cs | 4 ++++ .../Microsoft.UI.Xaml.Media/Microsoft.UI.Xaml.Media.Matrix.cs | 4 ++++ .../Microsoft.UI.Xaml/Microsoft.UI.Xaml.CornerRadius.cs | 4 ++++ .../Microsoft.UI.Xaml/Microsoft.UI.Xaml.Thickness.cs | 4 ++++ .../Windows.UI.Xaml.Media.Media3D.Matrix3D.cs | 4 ++++ .../Windows.UI.Xaml.Media/Windows.UI.Xaml.Media.Matrix.cs | 4 ++++ .../Additions/Windows.UI.Xaml/Windows.UI.Xaml.CornerRadius.cs | 4 ++++ .../Additions/Windows.UI.Xaml/Windows.UI.Xaml.Thickness.cs | 4 ++++ .../Resources/Additions/Windows.UI/Windows.UI.Color.cs | 4 ++++ 9 files changed, 36 insertions(+) diff --git a/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml.Media.Media3D/Microsoft.UI.Xaml.Media.Media3D.Matrix3D.cs b/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml.Media.Media3D/Microsoft.UI.Xaml.Media.Media3D.Matrix3D.cs index 478a4a116..0fa0e83f5 100644 --- a/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml.Media.Media3D/Microsoft.UI.Xaml.Media.Media3D.Matrix3D.cs +++ b/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml.Media.Media3D/Microsoft.UI.Xaml.Media.Media3D.Matrix3D.cs @@ -406,6 +406,9 @@ readonly string IFormattable.ToString(string format, IFormatProvider provider) private readonly string ConvertToString(string format, IFormatProvider provider) { +#if CSWINRT_REFERENCE_PROJECTION + throw null; +#else if (IsIdentity) { return "Identity"; @@ -446,6 +449,7 @@ private readonly string ConvertToString(string format, IFormatProvider provider) handler.AppendFormatted(separator); handler.AppendFormatted(_m44, format); return handler.ToStringAndClear(); +#endif } public readonly override int GetHashCode() diff --git a/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml.Media/Microsoft.UI.Xaml.Media.Matrix.cs b/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml.Media/Microsoft.UI.Xaml.Media.Matrix.cs index 85c7a3ae7..e57974e62 100644 --- a/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml.Media/Microsoft.UI.Xaml.Media.Matrix.cs +++ b/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml.Media/Microsoft.UI.Xaml.Media.Matrix.cs @@ -44,6 +44,9 @@ readonly string IFormattable.ToString(string format, IFormatProvider provider) private readonly string ConvertToString(string format, IFormatProvider provider) { +#if CSWINRT_REFERENCE_PROJECTION + throw null; +#else if (IsIdentity) { return "Identity"; @@ -64,6 +67,7 @@ private readonly string ConvertToString(string format, IFormatProvider provider) handler.AppendFormatted(separator); handler.AppendFormatted(OffsetY, format); return handler.ToStringAndClear(); +#endif } public readonly Point Transform(Point point) diff --git a/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml/Microsoft.UI.Xaml.CornerRadius.cs b/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml/Microsoft.UI.Xaml.CornerRadius.cs index 0a48c3211..275ac52d6 100644 --- a/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml/Microsoft.UI.Xaml.CornerRadius.cs +++ b/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml/Microsoft.UI.Xaml.CornerRadius.cs @@ -53,6 +53,9 @@ public readonly override string ToString() private readonly string ToString(global::System.Globalization.CultureInfo cultureInfo) { +#if CSWINRT_REFERENCE_PROJECTION + throw null; +#else char listSeparator = global::WindowsRuntime.InteropServices.TokenizerHelper.GetNumericListSeparator(cultureInfo); // Initial capacity [64] is an estimate based on a sum of: @@ -67,6 +70,7 @@ private readonly string ToString(global::System.Globalization.CultureInfo cultur handler.AppendFormatted(listSeparator); InternalAddToHandler(_BottomLeft, ref handler); return handler.ToStringAndClear(); +#endif } private static void InternalAddToHandler(double l, ref DefaultInterpolatedStringHandler handler) diff --git a/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml/Microsoft.UI.Xaml.Thickness.cs b/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml/Microsoft.UI.Xaml.Thickness.cs index d902878b1..579ab5ca7 100644 --- a/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml/Microsoft.UI.Xaml.Thickness.cs +++ b/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Xaml/Microsoft.UI.Xaml.Thickness.cs @@ -17,6 +17,9 @@ public readonly override string ToString() private readonly string ToString(global::System.Globalization.CultureInfo cultureInfo) { +#if CSWINRT_REFERENCE_PROJECTION + throw null; +#else char listSeparator = global::WindowsRuntime.InteropServices.TokenizerHelper.GetNumericListSeparator(cultureInfo); // Initial capacity [64] is an estimate based on a sum of: @@ -31,6 +34,7 @@ private readonly string ToString(global::System.Globalization.CultureInfo cultur handler.AppendFormatted(listSeparator); InternalAddToHandler(Bottom, ref handler); return handler.ToStringAndClear(); +#endif } private static void InternalAddToHandler(double l, ref DefaultInterpolatedStringHandler handler) diff --git a/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml.Media.Media3D/Windows.UI.Xaml.Media.Media3D.Matrix3D.cs b/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml.Media.Media3D/Windows.UI.Xaml.Media.Media3D.Matrix3D.cs index 0c283457b..ed17ff3ef 100644 --- a/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml.Media.Media3D/Windows.UI.Xaml.Media.Media3D.Matrix3D.cs +++ b/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml.Media.Media3D/Windows.UI.Xaml.Media.Media3D.Matrix3D.cs @@ -406,6 +406,9 @@ readonly string IFormattable.ToString(string format, IFormatProvider provider) private readonly string ConvertToString(string format, IFormatProvider provider) { +#if CSWINRT_REFERENCE_PROJECTION + throw null; +#else if (IsIdentity) { return "Identity"; @@ -446,6 +449,7 @@ private readonly string ConvertToString(string format, IFormatProvider provider) handler.AppendFormatted(separator); handler.AppendFormatted(_m44, format); return handler.ToStringAndClear(); +#endif } public readonly override int GetHashCode() diff --git a/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml.Media/Windows.UI.Xaml.Media.Matrix.cs b/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml.Media/Windows.UI.Xaml.Media.Matrix.cs index 3ffce829f..a643aa0a0 100644 --- a/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml.Media/Windows.UI.Xaml.Media.Matrix.cs +++ b/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml.Media/Windows.UI.Xaml.Media.Matrix.cs @@ -44,6 +44,9 @@ readonly string IFormattable.ToString(string format, IFormatProvider provider) private readonly string ConvertToString(string format, IFormatProvider provider) { +#if CSWINRT_REFERENCE_PROJECTION + throw null; +#else if (IsIdentity) { return "Identity"; @@ -64,6 +67,7 @@ private readonly string ConvertToString(string format, IFormatProvider provider) handler.AppendFormatted(separator); handler.AppendFormatted(OffsetY, format); return handler.ToStringAndClear(); +#endif } public readonly Point Transform(Point point) diff --git a/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml/Windows.UI.Xaml.CornerRadius.cs b/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml/Windows.UI.Xaml.CornerRadius.cs index 45a3dc068..74c03e0be 100644 --- a/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml/Windows.UI.Xaml.CornerRadius.cs +++ b/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml/Windows.UI.Xaml.CornerRadius.cs @@ -53,6 +53,9 @@ public readonly override string ToString() private readonly string ToString(global::System.Globalization.CultureInfo cultureInfo) { +#if CSWINRT_REFERENCE_PROJECTION + throw null; +#else char listSeparator = global::WindowsRuntime.InteropServices.TokenizerHelper.GetNumericListSeparator(cultureInfo); // Initial capacity [64] is an estimate based on a sum of: @@ -67,6 +70,7 @@ private readonly string ToString(global::System.Globalization.CultureInfo cultur handler.AppendFormatted(listSeparator); InternalAddToHandler(_BottomLeft, ref handler); return handler.ToStringAndClear(); +#endif } private static void InternalAddToHandler(double l, ref DefaultInterpolatedStringHandler handler) diff --git a/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml/Windows.UI.Xaml.Thickness.cs b/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml/Windows.UI.Xaml.Thickness.cs index cc67420d3..46673ef80 100644 --- a/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml/Windows.UI.Xaml.Thickness.cs +++ b/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml/Windows.UI.Xaml.Thickness.cs @@ -17,6 +17,9 @@ public readonly override string ToString() private readonly string ToString(global::System.Globalization.CultureInfo cultureInfo) { +#if CSWINRT_REFERENCE_PROJECTION + throw null; +#else char listSeparator = global::WindowsRuntime.InteropServices.TokenizerHelper.GetNumericListSeparator(cultureInfo); // Initial capacity [64] is an estimate based on a sum of: @@ -31,6 +34,7 @@ private readonly string ToString(global::System.Globalization.CultureInfo cultur handler.AppendFormatted(listSeparator); InternalAddToHandler(Bottom, ref handler); return handler.ToStringAndClear(); +#endif } private static void InternalAddToHandler(double l, ref DefaultInterpolatedStringHandler handler) diff --git a/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI/Windows.UI.Color.cs b/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI/Windows.UI.Color.cs index f66ad04b7..aef692185 100644 --- a/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI/Windows.UI.Color.cs +++ b/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI/Windows.UI.Color.cs @@ -31,6 +31,9 @@ readonly string IFormattable.ToString(string format, IFormatProvider provider) private readonly string ConvertToString(string format, IFormatProvider provider) { +#if CSWINRT_REFERENCE_PROJECTION + throw null; +#else if (format == null) { DefaultInterpolatedStringHandler handler = new(1, 4, provider, stackalloc char[32]); @@ -60,6 +63,7 @@ private readonly string ConvertToString(string format, IFormatProvider provider) handler.AppendFormatted(B, format); return handler.ToStringAndClear(); } +#endif } } } \ No newline at end of file From 43ea99b735e5b132974bb34c011a42af46b74c32 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 22 Jun 2026 14:07:41 -0700 Subject: [PATCH 33/42] Guard implementation-only DispatcherQueueSynchronizationContext wrappers The DispatcherQueueSynchronizationContext additions (Windows.System and Microsoft.UI.Dispatching) wrap the implementation-only 'WindowsRuntime.InteropServices.DispatcherQueueSynchronizationContext' ([WindowsRuntimeImplementationOnlyMember], stripped from the WinRT.Runtime reference assembly). The impl-only type appeared in a private field, both constructors, and every method body, so a reference projection that included these types failed to compile against the reference assembly. Guard the implementation-only members (the private '_innerContext' field and the private copy constructor) with '#if !CSWINRT_REFERENCE_PROJECTION', and stub the public API bodies (the public constructor, Post, Send, CreateCopy) with '#if CSWINRT_REFERENCE_PROJECTION' / 'throw null;' / '#else'. The reference projection keeps the public API surface but no longer references the stripped type; the real implementation is generated for the implementation projection at app build time. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- ...g.DispatcherQueueSynchronizationContext.cs | 20 +++++++++++++++++++ ...m.DispatcherQueueSynchronizationContext.cs | 20 +++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Dispatching/Microsoft.UI.Dispatching.DispatcherQueueSynchronizationContext.cs b/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Dispatching/Microsoft.UI.Dispatching.DispatcherQueueSynchronizationContext.cs index d09b75156..eb925d5a7 100644 --- a/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Dispatching/Microsoft.UI.Dispatching.DispatcherQueueSynchronizationContext.cs +++ b/src/WinRT.Projection.Writer/Resources/Additions/Microsoft.UI.Dispatching/Microsoft.UI.Dispatching.DispatcherQueueSynchronizationContext.cs @@ -8,10 +8,12 @@ namespace Microsoft.UI.Dispatching /// public sealed class DispatcherQueueSynchronizationContext : global::System.Threading.SynchronizationContext { +#if !CSWINRT_REFERENCE_PROJECTION /// /// The instance to use. /// private readonly WindowsRuntime.InteropServices.DispatcherQueueSynchronizationContext _innerContext; +#endif /// /// Creates a new instance with the specified parameters. @@ -20,9 +22,14 @@ public sealed class DispatcherQueueSynchronizationContext : global::System.Threa /// Thrown if is . public DispatcherQueueSynchronizationContext(global::Microsoft.UI.Dispatching.DispatcherQueue dispatcherQueue) { +#if CSWINRT_REFERENCE_PROJECTION + throw null; +#else _innerContext = new WindowsRuntime.InteropServices.DispatcherQueueSynchronizationContext(dispatcherQueue); +#endif } +#if !CSWINRT_REFERENCE_PROJECTION /// /// Creates a new instance with the specified parameters. /// @@ -31,23 +38,36 @@ private DispatcherQueueSynchronizationContext(WindowsRuntime.InteropServices.Dis { _innerContext = innerContext; } +#endif /// public override void Post(global::System.Threading.SendOrPostCallback d, object? state) { +#if CSWINRT_REFERENCE_PROJECTION + throw null; +#else _innerContext.Post(d, state); +#endif } /// public override void Send(global::System.Threading.SendOrPostCallback d, object? state) { +#if CSWINRT_REFERENCE_PROJECTION + throw null; +#else _innerContext.Send(d, state); +#endif } /// public override global::System.Threading.SynchronizationContext CreateCopy() { +#if CSWINRT_REFERENCE_PROJECTION + throw null; +#else return new DispatcherQueueSynchronizationContext(_innerContext); +#endif } } } diff --git a/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml/Windows.System.DispatcherQueueSynchronizationContext.cs b/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml/Windows.System.DispatcherQueueSynchronizationContext.cs index 59c3dac90..a61f9424f 100644 --- a/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml/Windows.System.DispatcherQueueSynchronizationContext.cs +++ b/src/WinRT.Projection.Writer/Resources/Additions/Windows.UI.Xaml/Windows.System.DispatcherQueueSynchronizationContext.cs @@ -8,10 +8,12 @@ namespace Windows.System /// public sealed class DispatcherQueueSynchronizationContext : global::System.Threading.SynchronizationContext { +#if !CSWINRT_REFERENCE_PROJECTION /// /// The instance to use. /// private readonly WindowsRuntime.InteropServices.DispatcherQueueSynchronizationContext _innerContext; +#endif /// /// Creates a new instance with the specified parameters. @@ -20,9 +22,14 @@ public sealed class DispatcherQueueSynchronizationContext : global::System.Threa /// Thrown if is . public DispatcherQueueSynchronizationContext(global::Windows.System.DispatcherQueue dispatcherQueue) { +#if CSWINRT_REFERENCE_PROJECTION + throw null; +#else _innerContext = new WindowsRuntime.InteropServices.DispatcherQueueSynchronizationContext(dispatcherQueue); +#endif } +#if !CSWINRT_REFERENCE_PROJECTION /// /// Creates a new instance with the specified parameters. /// @@ -31,23 +38,36 @@ private DispatcherQueueSynchronizationContext(WindowsRuntime.InteropServices.Dis { _innerContext = innerContext; } +#endif /// public override void Post(global::System.Threading.SendOrPostCallback d, object? state) { +#if CSWINRT_REFERENCE_PROJECTION + throw null; +#else _innerContext.Post(d, state); +#endif } /// public override void Send(global::System.Threading.SendOrPostCallback d, object? state) { +#if CSWINRT_REFERENCE_PROJECTION + throw null; +#else _innerContext.Send(d, state); +#endif } /// public override global::System.Threading.SynchronizationContext CreateCopy() { +#if CSWINRT_REFERENCE_PROJECTION + throw null; +#else return new DispatcherQueueSynchronizationContext(_innerContext); +#endif } } } From efe226df031cb30751def51d3513806fae9ff0a7 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 22 Jun 2026 16:10:11 -0700 Subject: [PATCH 34/42] Stub mapped-interface members in reference projections MappedInterfaceStubFactory emits the C# collection-interface members (IList, IDictionary, IEnumerable, IDisposable, the bindable collections, and INotifyDataErrorInfo) on classes that implement the corresponding WinRT interfaces. It already skipped its implementation-only '[UnsafeAccessor]' externs in reference-projection mode, but it still emitted the member *bodies*, which reference those skipped externs (the '*Methods_*' helpers), the skipped '_objRef_*' fields, and the implementation-only 'ABI.*Methods' helpers. None of those exist in a reference projection, so a reference projection that included any mapped-collection class failed to compile against the stripped WinRT.Runtime reference assembly. Give each per-interface 'Emit*' method a reference-projection-first branch that emits the full member set as a single stub (every body is 'throw null'), keeping the public member signatures identical to the implementation projection. The implementation path is unchanged. The previously inline switch cases (IBindableIterable, IBindableIterator, INotifyDataErrorInfo) are extracted into their own 'Emit*' methods so they follow the same shape. Validated that the implementation-projection output is byte-for-byte identical to before across the full Windows SDK projection (no runtime impact), and that the reference projection no longer references any of the stripped plumbing. This removes ~4,900 of the reference-projection compile errors against the stripped reference assembly (the remaining errors are tracked separately in #2468). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Factories/MappedInterfaceStubFactory.cs | 262 ++++++++++++++++-- 1 file changed, 240 insertions(+), 22 deletions(-) diff --git a/src/WinRT.Projection.Writer/Factories/MappedInterfaceStubFactory.cs b/src/WinRT.Projection.Writer/Factories/MappedInterfaceStubFactory.cs index dc0f3b38c..7e7880cfc 100644 --- a/src/WinRT.Projection.Writer/Factories/MappedInterfaceStubFactory.cs +++ b/src/WinRT.Projection.Writer/Factories/MappedInterfaceStubFactory.cs @@ -69,7 +69,7 @@ public static void WriteMappedInterfaceStubs(IndentedTextWriter writer, Projecti switch (ifaceName) { case "IClosable": - EmitDisposable(writer, objRefName); + EmitDisposable(writer, context, objRefName); break; case "IIterable`1": EmitGenericEnumerable(writer, context, typeArgs, typeArgSigs, objRefName); @@ -90,40 +90,107 @@ public static void WriteMappedInterfaceStubs(IndentedTextWriter writer, Projecti EmitReadOnlyList(writer, context, typeArgs, typeArgSigs, objRefName); break; case "IBindableIterable": - writer.WriteLine(); - writer.WriteLine($"IEnumerator global::System.Collections.IEnumerable.GetEnumerator() => global::ABI.System.Collections.IEnumerableMethods.GetEnumerator({objRefName});"); + EmitNonGenericEnumerable(writer, context, objRefName); break; case "IBindableIterator": - writer.WriteLine(); - writer.WriteLine(isMultiline: true, $$""" - public bool MoveNext() => global::ABI.System.Collections.IEnumeratorMethods.MoveNext({{objRefName}}); - public void Reset() => throw new NotSupportedException(); - public object Current => global::ABI.System.Collections.IEnumeratorMethods.Current({{objRefName}}); - """); + EmitNonGenericEnumerator(writer, context, objRefName); break; case "IBindableVector": - EmitNonGenericList(writer, objRefName); + EmitNonGenericList(writer, context, objRefName); break; case "INotifyDataErrorInfo": - writer.WriteLine(); - writer.WriteLine(isMultiline: true, $$""" - public global::System.Collections.IEnumerable GetErrors(string propertyName) => global::ABI.System.ComponentModel.INotifyDataErrorInfoMethods.GetErrors({{objRefName}}, propertyName); - public bool HasErrors {get => global::ABI.System.ComponentModel.INotifyDataErrorInfoMethods.HasErrors({{objRefName}}); } - public event global::System.EventHandler ErrorsChanged - { - add => global::ABI.System.ComponentModel.INotifyDataErrorInfoMethods.ErrorsChanged(this, {{objRefName}}).Subscribe(value); - remove => global::ABI.System.ComponentModel.INotifyDataErrorInfoMethods.ErrorsChanged(this, {{objRefName}}).Unsubscribe(value); - } - """); + EmitNotifyDataErrorInfo(writer, context, objRefName); break; } } - private static void EmitDisposable(IndentedTextWriter writer, string objRefName) + + private static void EmitDisposable(IndentedTextWriter writer, ProjectionEmitContext context, string objRefName) { + // In a reference projection the member bodies dispatch to implementation-only plumbing + // (the 'ABI.*Methods' helpers, the '[UnsafeAccessor]' externs, and the '_objRef_*' fields, + // all of which are absent from the 'WinRT.Runtime' reference assembly), so the entire body is + // emitted as a stub. The public member signatures stay identical to the implementation projection. + if (context.Settings.ReferenceProjection) + { + writer.WriteLine(); + writer.WriteLine("public void Dispose() => throw null;"); + + return; + } + writer.WriteLine(); writer.WriteLine($"public void Dispose() => global::ABI.System.IDisposableMethods.Dispose({objRefName});"); } + private static void EmitNonGenericEnumerable(IndentedTextWriter writer, ProjectionEmitContext context, string objRefName) + { + // See 'EmitDisposable' for why the body is stubbed in a reference projection. + if (context.Settings.ReferenceProjection) + { + writer.WriteLine(); + writer.WriteLine("IEnumerator global::System.Collections.IEnumerable.GetEnumerator() => throw null;"); + + return; + } + + writer.WriteLine(); + writer.WriteLine($"IEnumerator global::System.Collections.IEnumerable.GetEnumerator() => global::ABI.System.Collections.IEnumerableMethods.GetEnumerator({objRefName});"); + } + + private static void EmitNonGenericEnumerator(IndentedTextWriter writer, ProjectionEmitContext context, string objRefName) + { + // See 'EmitDisposable' for why the body is stubbed in a reference projection. + if (context.Settings.ReferenceProjection) + { + writer.WriteLine(); + writer.WriteLine(isMultiline: true, """ + public bool MoveNext() => throw null; + public void Reset() => throw null; + public object Current => throw null; + """); + + return; + } + + writer.WriteLine(); + writer.WriteLine(isMultiline: true, $$""" + public bool MoveNext() => global::ABI.System.Collections.IEnumeratorMethods.MoveNext({{objRefName}}); + public void Reset() => throw new NotSupportedException(); + public object Current => global::ABI.System.Collections.IEnumeratorMethods.Current({{objRefName}}); + """); + } + + private static void EmitNotifyDataErrorInfo(IndentedTextWriter writer, ProjectionEmitContext context, string objRefName) + { + // See 'EmitDisposable' for why the body is stubbed in a reference projection. + if (context.Settings.ReferenceProjection) + { + writer.WriteLine(); + writer.WriteLine(isMultiline: true, """ + public global::System.Collections.IEnumerable GetErrors(string propertyName) => throw null; + public bool HasErrors {get => throw null; } + public event global::System.EventHandler ErrorsChanged + { + add => throw null; + remove => throw null; + } + """); + + return; + } + + writer.WriteLine(); + writer.WriteLine(isMultiline: true, $$""" + public global::System.Collections.IEnumerable GetErrors(string propertyName) => global::ABI.System.ComponentModel.INotifyDataErrorInfoMethods.GetErrors({{objRefName}}, propertyName); + public bool HasErrors {get => global::ABI.System.ComponentModel.INotifyDataErrorInfoMethods.HasErrors({{objRefName}}); } + public event global::System.EventHandler ErrorsChanged + { + add => global::ABI.System.ComponentModel.INotifyDataErrorInfoMethods.ErrorsChanged(this, {{objRefName}}).Subscribe(value); + remove => global::ABI.System.ComponentModel.INotifyDataErrorInfoMethods.ErrorsChanged(this, {{objRefName}}).Unsubscribe(value); + } + """); + } + private static void EmitGenericEnumerable(IndentedTextWriter writer, ProjectionEmitContext context, List args, List argSigs, string objRefName) { if (args.Count != 1) @@ -132,6 +199,21 @@ private static void EmitGenericEnumerable(IndentedTextWriter writer, ProjectionE } string t = WriteTypeNameToString(context, args[0], TypedefNameType.Projected, true); + + // See 'EmitDisposable' for why the body is stubbed in a reference projection. Only the + // projected type name is needed for the signatures; the implementation-only interop plumbing + // (interop type, '[UnsafeAccessor]' externs) is not computed or emitted. + if (context.Settings.ReferenceProjection) + { + writer.WriteLine(); + writer.WriteLine(isMultiline: true, $$""" + public IEnumerator<{{t}}> GetEnumerator() => throw null; + global::System.Collections.IEnumerator global::System.Collections.IEnumerable.GetEnumerator() => throw null; + """); + + return; + } + string elementId = EncodeArgIdentifier(context, args[0]); string interopTypeArgs = InteropTypeNameWriter.EncodeInteropTypeName(argSigs[0], TypedefNameType.Projected); string interopType = "ABI.System.Collections.Generic.<#corlib>IEnumerable'1<" + interopTypeArgs + ">Methods, WinRT.Interop"; @@ -153,6 +235,22 @@ private static void EmitGenericEnumerator(IndentedTextWriter writer, ProjectionE } string t = WriteTypeNameToString(context, args[0], TypedefNameType.Projected, true); + + // See 'EmitDisposable' for why the body is stubbed in a reference projection. + if (context.Settings.ReferenceProjection) + { + writer.WriteLine(); + writer.WriteLine(isMultiline: true, $$""" + public bool MoveNext() => throw null; + public void Reset() => throw null; + public void Dispose() => throw null; + public {{t}} Current => throw null; + object global::System.Collections.IEnumerator.Current => throw null; + """); + + return; + } + string elementId = EncodeArgIdentifier(context, args[0]); string interopTypeArgs = InteropTypeNameWriter.EncodeInteropTypeName(argSigs[0], TypedefNameType.Projected); string interopType = "ABI.System.Collections.Generic.<#corlib>IEnumerator'1<" + interopTypeArgs + ">Methods, WinRT.Interop"; @@ -189,6 +287,36 @@ private static void EmitDictionary(IndentedTextWriter writer, ProjectionEmitCont string kv = $"KeyValuePair<{k}, {v}>"; string kvNested = $"global::System.Collections.Generic.KeyValuePair<{k}, {v}>"; + // See 'EmitDisposable' for why the body is stubbed in a reference projection. Only the projected + // type names are needed for the signatures; the implementation-only interop plumbing (interop + // type, '[UnsafeAccessor]' externs, '_objRef_*' fields) is not computed or emitted. + if (context.Settings.ReferenceProjection) + { + writer.WriteLine(); + writer.WriteLine(isMultiline: true, $$""" + public ICollection<{{k}}> Keys => throw null; + public ICollection<{{v}}> Values => throw null; + public int Count => throw null; + public bool IsReadOnly => false; + public {{v}} this[{{k}} key] + { + get => throw null; + set => throw null; + } + public void Add({{k}} key, {{v}} value) => throw null; + public bool ContainsKey({{k}} key) => throw null; + public bool Remove({{k}} key) => throw null; + public bool TryGetValue({{k}} key, out {{v}} value) => throw null; + public void Add({{kv}} item) => throw null; + public void Clear() => throw null; + public bool Contains({{kv}} item) => throw null; + public void CopyTo({{kv}}[] array, int arrayIndex) => throw null; + bool ICollection<{{kv}}>.Remove({{kv}} item) => throw null; + """); + + return; + } + // Long form (always fully qualified) used for objref field-name computation // (matches the form WriteClassObjRefDefinitions emits transitively). string kvLong = kvNested; @@ -257,6 +385,23 @@ private static void EmitReadOnlyDictionary(IndentedTextWriter writer, Projection string k = WriteTypeNameToString(context, args[0], TypedefNameType.Projected, true); string v = WriteTypeNameToString(context, args[1], TypedefNameType.Projected, true); + + // See 'EmitDisposable' for why the body is stubbed in a reference projection. + if (context.Settings.ReferenceProjection) + { + writer.WriteLine(); + writer.WriteLine(isMultiline: true, $$""" + public {{v}} this[{{k}} key] => throw null; + public IEnumerable<{{k}}> Keys => throw null; + public IEnumerable<{{v}}> Values => throw null; + public int Count => throw null; + public bool ContainsKey({{k}} key) => throw null; + public bool TryGetValue({{k}} key, out {{v}} value) => throw null; + """); + + return; + } + string keyId = EncodeArgIdentifier(context, args[0]); string valId = EncodeArgIdentifier(context, args[1]); string keyInteropArg = InteropTypeNameWriter.EncodeInteropTypeName(argSigs[0], TypedefNameType.Projected); @@ -296,6 +441,20 @@ private static void EmitReadOnlyList(IndentedTextWriter writer, ProjectionEmitCo } string t = WriteTypeNameToString(context, args[0], TypedefNameType.Projected, true); + + // See 'EmitDisposable' for why the body is stubbed in a reference projection. + if (context.Settings.ReferenceProjection) + { + writer.WriteLine(); + writer.WriteLine(isMultiline: true, $$""" + [global::System.Runtime.CompilerServices.IndexerName("ReadOnlyListItem")] + public {{t}} this[int index] => throw null; + public int Count => throw null; + """); + + return; + } + string elementId = EncodeArgIdentifier(context, args[0]); string interopTypeArgs = InteropTypeNameWriter.EncodeInteropTypeName(argSigs[0], TypedefNameType.Projected); string interopType = "ABI.System.Collections.Generic.<#corlib>IReadOnlyList'1<" + interopTypeArgs + ">Methods, WinRT.Interop"; @@ -343,6 +502,34 @@ private static void EmitList(IndentedTextWriter writer, ProjectionEmitContext co } string t = WriteTypeNameToString(context, args[0], TypedefNameType.Projected, true); + + // See 'EmitDisposable' for why the body is stubbed in a reference projection. + if (context.Settings.ReferenceProjection) + { + writer.WriteLine(); + writer.WriteLine(isMultiline: true, $$""" + public int Count => throw null; + public bool IsReadOnly => false; + + [global::System.Runtime.CompilerServices.IndexerName("ListItem")] + public {{t}} this[int index] + { + get => throw null; + set => throw null; + } + public int IndexOf({{t}} item) => throw null; + public void Insert(int index, {{t}} item) => throw null; + public void RemoveAt(int index) => throw null; + public void Add({{t}} item) => throw null; + public void Clear() => throw null; + public bool Contains({{t}} item) => throw null; + public void CopyTo({{t}}[] array, int arrayIndex) => throw null; + public bool Remove({{t}} item) => throw null; + """); + + return; + } + string elementId = EncodeArgIdentifier(context, args[0]); string interopTypeArgs = InteropTypeNameWriter.EncodeInteropTypeName(argSigs[0], TypedefNameType.Projected); string interopType = "ABI.System.Collections.Generic.<#corlib>IList'1<" + interopTypeArgs + ">Methods, WinRT.Interop"; @@ -440,8 +627,39 @@ private static void EmitUnsafeAccessors( } } - private static void EmitNonGenericList(IndentedTextWriter writer, string objRefName) + private static void EmitNonGenericList(IndentedTextWriter writer, ProjectionEmitContext context, string objRefName) { + // See 'EmitDisposable' for why the body is stubbed in a reference projection. + if (context.Settings.ReferenceProjection) + { + writer.WriteLine(); + writer.WriteLine(isMultiline: true, """ + [global::System.Runtime.CompilerServices.IndexerName("NonGenericListItem")] + public object this[int index] + { + get => throw null; + set => throw null; + } + public int Count => throw null; + public bool IsReadOnly => false; + public bool IsFixedSize => false; + public bool IsSynchronized => false; + public object SyncRoot => this; + public int Add(object value) => throw null; + public void Clear() => throw null; + public bool Contains(object value) => throw null; + public int IndexOf(object value) => throw null; + public void Insert(int index, object value) => throw null; + public void Remove(object value) => throw null; + public void RemoveAt(int index) => throw null; + public void CopyTo(Array array, int index) => throw null; + """); + + // GetEnumerator is NOT emitted here -- it's handled separately by IBindableIterable's + // EmitNonGenericEnumerable invocation. + return; + } + writer.WriteLine(); writer.WriteLine(isMultiline: true, $$""" [global::System.Runtime.CompilerServices.IndexerName("NonGenericListItem")] From d2ebe9cf7afa2a47129c5c8e389b173404939fbd Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 22 Jun 2026 16:15:23 -0700 Subject: [PATCH 35/42] Make the synthetic ref-mode ctor accessible to derived projected classes In a reference projection, a projected class with no activatable/composable constructors gets a synthetic 'private TypeName() { throw null; }' ctor to suppress the C# compiler's implicit public default constructor. When such a class is the base of another projected class (e.g. 'UriActionEntity : ActionEntity'), the derived class's own synthetic ctor implicitly chains to the base's parameterless ctor -- which was 'private', so the derived class failed to compile against the stripped WinRT.Runtime reference assembly (CS0122). The real 'WindowsRuntimeObjectReference'-based ctor that derived classes chain to in the implementation projection is not emitted in a reference projection, so the synthetic ctor is the only one available. Emit the synthetic ctor as 'private protected' for unsealed classes (which can be base classes), so derived projected classes in the same projection can chain to it. Sealed classes keep 'private'. The ctor stays non-public, so it still suppresses the implicit public default constructor and does not widen the public API surface. The implementation projection is unaffected (its output is unchanged). This removes the CS0122 reference-projection errors (tracked in #2468). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Factories/ClassFactory.cs | 2 +- .../Factories/RefModeStubFactory.cs | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/WinRT.Projection.Writer/Factories/ClassFactory.cs b/src/WinRT.Projection.Writer/Factories/ClassFactory.cs index 9028c1628..c48843fe1 100644 --- a/src/WinRT.Projection.Writer/Factories/ClassFactory.cs +++ b/src/WinRT.Projection.Writer/Factories/ClassFactory.cs @@ -606,7 +606,7 @@ void WriteCtorBody(IndentedTextWriter writer) if (!hasRefModeCtors) { - RefModeStubFactory.EmitSyntheticPrivateCtor(writer, typeName); + RefModeStubFactory.EmitSyntheticPrivateCtor(writer, typeName, type.IsSealed); } } diff --git a/src/WinRT.Projection.Writer/Factories/RefModeStubFactory.cs b/src/WinRT.Projection.Writer/Factories/RefModeStubFactory.cs index f35b44059..16b4a2c00 100644 --- a/src/WinRT.Projection.Writer/Factories/RefModeStubFactory.cs +++ b/src/WinRT.Projection.Writer/Factories/RefModeStubFactory.cs @@ -18,12 +18,24 @@ internal static class RefModeStubFactory /// projection mode to suppress the C# compiler's implicit public default constructor when /// no explicit ctors are emitted by WriteAttributedTypes. /// + /// + /// For an unsealed class the ctor is emitted as private protected rather than private: + /// a projected class can derive from another projected class (e.g. UriActionEntity : ActionEntity), + /// and the derived class's own synthetic ctor implicitly chains to the base's parameterless ctor. The + /// real WindowsRuntimeObjectReference-based ctor that derived classes chain to in the + /// implementation projection is not emitted in a reference projection, so the synthetic ctor must be + /// accessible to derived classes in the same projection. It stays non-public, so it still suppresses the + /// implicit public default constructor. + /// /// The writer to emit to. /// The type name to emit the synthetic constructor for. - public static void EmitSyntheticPrivateCtor(IndentedTextWriter writer, string typeName) + /// Whether the type is sealed (and so can never be a base class). + public static void EmitSyntheticPrivateCtor(IndentedTextWriter writer, string typeName, bool isSealed) { + string accessibility = isSealed ? "private" : "private protected"; + writer.WriteLine(); - writer.WriteLine($"private {typeName}() {{ throw null; }}"); + writer.WriteLine($"{accessibility} {typeName}() {{ throw null; }}"); } /// From eba4de3ca2324814fb11aa21c30d80d861a87dbc Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 22 Jun 2026 16:21:52 -0700 Subject: [PATCH 36/42] Emit accessible parameterless ctor for unsealed composable classes in ref projections In reference-projection mode the real WindowsRuntimeObjectReference-based base constructor is not emitted, so a derived projected class's ref-mode constructor (whose implicit base() call has no target) fails to compile against an unsealed base that only exposes parameterized composable constructors. Emit a 'private protected TypeName() { throw null; }' for unsealed classes that don't already emit a public parameterless constructor (a default [Activatable], or a factory/composable method with no user parameters), giving derived projected classes a base-chain target. Sealed classes keep the existing behavior (a synthetic ctor only to suppress the implicit public default ctor when none are emitted). Validated byte-identical implementation-mode output for the full Windows SDK projection; reduces the reference-projection compile from 192 to 12 errors. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Factories/ClassFactory.cs | 49 +++++++++------- .../ConstructorFactory.AttributedTypes.cs | 56 +++++++++++++++++++ 2 files changed, 84 insertions(+), 21 deletions(-) diff --git a/src/WinRT.Projection.Writer/Factories/ClassFactory.cs b/src/WinRT.Projection.Writer/Factories/ClassFactory.cs index c48843fe1..1aff3fdc8 100644 --- a/src/WinRT.Projection.Writer/Factories/ClassFactory.cs +++ b/src/WinRT.Projection.Writer/Factories/ClassFactory.cs @@ -578,35 +578,42 @@ void WriteCtorBody(IndentedTextWriter writer) } else { - // In ref mode, if WriteAttributedTypes will not emit any public constructors, - // we need a 'private TypeName() { throw null; }' to suppress the C# compiler's - // implicit public default constructor (which would expose an unintended API). - // either: - // - factory.activatable is true (parameterless or parameterized — Activatable - // always emits at least one ctor), OR - // - factory.composable && factory.type && factory.type.MethodList().size() > 0 - // (composable factories with NO methods don't emit any ctors). - bool hasRefModeCtors = false; - foreach (KeyValuePair kv in AttributedTypes.Get(type, context.Cache)) + // In ref mode, a synthetic non-public parameterless ctor is emitted in two situations: + // + // 1. To suppress the C# compiler's implicit public default constructor (which would expose + // an unintended API) when 'WriteAttributedTypes' emits no constructors at all. + // 2. To give derived projected classes a base-chain target. A derived class's ref-mode ctor + // implicitly calls 'base()', but the real 'WindowsRuntimeObjectReference'-based base ctor + // is not emitted in ref mode, so an unsealed class must expose an accessible parameterless + // ctor unless it already emits a public one (a default '[Activatable]', or a factory / + // composable method with no user parameters). + // + // Sealed classes can never be a base, so they only need case 1; unsealed classes need a + // parameterless ctor whenever they don't already emit one (which also covers case 1). + if (type.IsSealed) { - AttributedType factory = kv.Value; - - if (factory.Activatable) + bool hasRefModeCtors = false; + foreach (KeyValuePair kv in AttributedTypes.Get(type, context.Cache)) { - hasRefModeCtors = true; - break; + AttributedType factory = kv.Value; + + // Activatable always emits at least one ctor; a composable factory only emits ctors + // when it has methods (a composable factory with no methods emits none). + if (factory.Activatable || (factory.Composable && factory.Type is not null && factory.Type.Methods.Count > 0)) + { + hasRefModeCtors = true; + break; + } } - if (factory.Composable && factory.Type is not null && factory.Type.Methods.Count > 0) + if (!hasRefModeCtors) { - hasRefModeCtors = true; - break; + RefModeStubFactory.EmitSyntheticPrivateCtor(writer, typeName, isSealed: true); } } - - if (!hasRefModeCtors) + else if (!ConstructorFactory.EmitsParameterlessConstructor(type, context.Cache)) { - RefModeStubFactory.EmitSyntheticPrivateCtor(writer, typeName, type.IsSealed); + RefModeStubFactory.EmitSyntheticPrivateCtor(writer, typeName, isSealed: false); } } diff --git a/src/WinRT.Projection.Writer/Factories/ConstructorFactory.AttributedTypes.cs b/src/WinRT.Projection.Writer/Factories/ConstructorFactory.AttributedTypes.cs index 45b6a2560..72d2093c8 100644 --- a/src/WinRT.Projection.Writer/Factories/ConstructorFactory.AttributedTypes.cs +++ b/src/WinRT.Projection.Writer/Factories/ConstructorFactory.AttributedTypes.cs @@ -6,6 +6,7 @@ using AsmResolver.DotNet; using WindowsRuntime.ProjectionWriter.Generation; using WindowsRuntime.ProjectionWriter.Helpers; +using WindowsRuntime.ProjectionWriter.Metadata; using WindowsRuntime.ProjectionWriter.Models; using WindowsRuntime.ProjectionWriter.Writers; using static WindowsRuntime.ProjectionWriter.References.ProjectionNames; @@ -205,4 +206,59 @@ public static void WriteFactoryConstructors(IndentedTextWriter writer, Projectio writer.WriteLine("}"); } } + + /// + /// Determines whether emits at least one parameterless public + /// constructor for the given runtime class (a default [Activatable] ctor, an activation-factory + /// method with no parameters, or a composable-factory method with no user parameters). + /// + /// + /// Used in reference-projection mode to decide whether an unsealed class already exposes a + /// parameterless constructor that derived projected classes can chain to, or whether a synthetic + /// non-public one must be emitted (see ). + /// + public static bool EmitsParameterlessConstructor(TypeDefinition classType, MetadataCache cache) + { + foreach (KeyValuePair kv in AttributedTypes.Get(classType, cache)) + { + AttributedType factory = kv.Value; + + // A default '[Activatable(uint version)]' (no factory interface) emits 'public TypeName()'. + if (factory.Activatable && factory.Type is null) + { + return true; + } + + if (factory.Type is null) + { + continue; + } + + // An activation- or composable-factory method emits a parameterless ctor when it has no user + // parameters. Composable factory methods carry two trailing ABI parameters (the base and inner + // interfaces) that are not surfaced on the projected constructor, so they are excluded. + if (factory.Activatable || factory.Composable) + { + foreach (MethodDefinition method in factory.Type.Methods) + { + if (method.IsSpecial) + { + continue; + } + + MethodSignatureInfo sig = new(method); + int userParamCount = factory.Composable && sig.Parameters.Count >= 2 + ? sig.Parameters.Count - 2 + : sig.Parameters.Count; + + if (userParamCount == 0) + { + return true; + } + } + } + } + + return false; + } } From b7862818415f696164a59ec7401d3116621a90d1 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 22 Jun 2026 16:27:38 -0700 Subject: [PATCH 37/42] Guard implementation-only storage-extension bodies in reference projections WindowsRuntimeStorageExtensions calls implementation-only APIs (WindowsRuntimeIOHelpers and the IStorage*HandleAccessMethods classes) that are absent from the WinRT.Runtime reference assembly, so the hand-authored Windows.Storage addition failed to compile in reference-projection mode. Following the same pattern the runtime uses for its reference-assembly stubs (and the earlier TokenizerHelper guard), wrap each affected method body with '#if CSWINRT_REFERENCE_PROJECTION' / 'throw null;' / '#else' / the existing implementation / '#endif'. The implementation projection keeps the real body; the reference projection gets a stub. The added directives are inert when CSWINRT_REFERENCE_PROJECTION is undefined, so implementation-mode output is unchanged. With this fix the full Windows SDK reference projection compiles with 0 errors against the stripped WinRT.Runtime reference assembly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../WindowsRuntimeStorageExtensions.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/WinRT.Projection.Writer/Resources/Additions/Windows.Storage/WindowsRuntimeStorageExtensions.cs b/src/WinRT.Projection.Writer/Resources/Additions/Windows.Storage/WindowsRuntimeStorageExtensions.cs index a48ffa4ec..6f876ac5a 100644 --- a/src/WinRT.Projection.Writer/Resources/Additions/Windows.Storage/WindowsRuntimeStorageExtensions.cs +++ b/src/WinRT.Projection.Writer/Resources/Additions/Windows.Storage/WindowsRuntimeStorageExtensions.cs @@ -29,6 +29,9 @@ public static class WindowsRuntimeStorageExtensions [SupportedOSPlatform("windows10.0.10240.0")] public static Task OpenStreamForReadAsync(this IStorageFile windowsRuntimeFile) { +#if CSWINRT_REFERENCE_PROJECTION + throw null; +#else ArgumentNullException.ThrowIfNull(windowsRuntimeFile); // Helper with the actual read logic @@ -53,6 +56,7 @@ static async Task OpenStreamForReadCoreAsync(IStorageFile windowsRuntime } return OpenStreamForReadCoreAsync(windowsRuntimeFile); +#endif } /// @@ -82,6 +86,9 @@ public static Task OpenStreamForWriteAsync(this IStorageFile windowsRunt [SupportedOSPlatform("windows10.0.10240.0")] public static Task OpenStreamForReadAsync(this IStorageFolder rootDirectory, string relativePath) { +#if CSWINRT_REFERENCE_PROJECTION + throw null; +#else ArgumentNullException.ThrowIfNull(rootDirectory); ArgumentException.ThrowIfNullOrWhiteSpace(relativePath); @@ -110,6 +117,7 @@ static async Task OpenStreamForReadCoreAsync(IStorageFolder rootDirector } return OpenStreamForReadCoreAsync(rootDirectory, relativePath); +#endif } /// @@ -128,6 +136,9 @@ public static Task OpenStreamForWriteAsync( string relativePath, CreationCollisionOption creationCollisionOption) { +#if CSWINRT_REFERENCE_PROJECTION + throw null; +#else ArgumentNullException.ThrowIfNull(rootDirectory); ArgumentException.ThrowIfNullOrWhiteSpace(relativePath); @@ -187,6 +198,7 @@ CreationCollisionOption.OpenIfExists or } return OpenStreamForWriteCoreAsync(rootDirectory, relativePath, creationCollisionOption); +#endif } /// @@ -204,6 +216,9 @@ CreationCollisionOption.OpenIfExists or FileShare share = FileShare.Read, FileOptions options = FileOptions.None) { +#if CSWINRT_REFERENCE_PROJECTION + throw null; +#else ArgumentNullException.ThrowIfNull(windowsRuntimeFile); return global::WindowsRuntime.InteropServices.IStorageItemHandleAccessMethods.Create( @@ -211,6 +226,7 @@ CreationCollisionOption.OpenIfExists or access, share, options); +#endif } /// @@ -247,6 +263,9 @@ CreationCollisionOption.OpenIfExists or FileShare share = FileShare.Read, FileOptions options = FileOptions.None) { +#if CSWINRT_REFERENCE_PROJECTION + throw null; +#else ArgumentNullException.ThrowIfNull(rootDirectory); ArgumentNullException.ThrowIfNull(relativePath); @@ -257,6 +276,7 @@ CreationCollisionOption.OpenIfExists or access, share, options); +#endif } /// @@ -264,6 +284,9 @@ CreationCollisionOption.OpenIfExists or [SupportedOSPlatform("windows10.0.10240.0")] private static async Task OpenStreamForWriteWithOffsetAsync(IStorageFile windowsRuntimeFile, long offset) { +#if CSWINRT_REFERENCE_PROJECTION + throw null; +#else Debug.Assert(windowsRuntimeFile is not null); Debug.Assert(offset >= 0); @@ -287,6 +310,7 @@ private static async Task OpenStreamForWriteWithOffsetAsync(IStorageFile return null; } +#endif } } #nullable restore From c140feb96dffd646af4288d5154449c5c94f4793 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 22 Jun 2026 16:50:30 -0700 Subject: [PATCH 38/42] Add Windows SDK and XAML reference-projection smoke tests Generating the Windows SDK reference projections (the 'Microsoft.Windows.SDK.NET.Ref' projection packages) is exactly what a downstream repository does with the CsWinRT package, and it is where reference-projection codegen regressions surface: the generated projection must compile against the stripped 'WinRT.Runtime' reference assembly, with no references to implementation-only runtime types. Add two end-to-end smoke tests that exercise this so such regressions fail here, early, instead of breaking that package. * WindowsSdkProjection generates the base Windows SDK reference projection from the 'Microsoft.Windows.SDK.Contracts' '.winmd' files. * WindowsSdkXamlProjection generates the 'Windows.UI.Xaml' reference projection, which references the base projection above (mirroring how the UWP XAML projection package depends on the base Windows SDK projection package). Both mirror the existing 'Projection' smoke test (CsWinRTGenerateReferenceProjection) and the Windows SDK metadata staging in 'WinRT.Sdk.Projection.csproj', and use the same namespace include/exclude split the projection generator applies for 'WinRT.Sdk.Projection' and 'WinRT.Sdk.Xaml.Projection' (see 'WriteWindowsSdkFilters'). The shared 'WindowsSdkContracts.targets' downloads 'Microsoft.Windows.SDK.Contracts' and feeds its '.winmd' files into '@(CsWinRTInputs)'. That package, like the preview Windows SDK ref pack, is restored from the CsWinRTDependencies feed, alongside the local package under test. The reference-projection verification in 'run-smoke-tests.ps1' (forwarder + reference assembly produced) is shared across all three reference-projection tests, and both new tests are build-only (CoreCLR), wired into the CI as their own 'continueOnError' steps. Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com> --- .../CsWinRT-PublishToNuGet-Steps.yml | 30 +++++-- docs/structure.md | 2 +- src/Tests/SmokeTests/Directory.Build.props | 4 +- .../SmokeTests/WindowsSdkContracts.targets | 56 ++++++++++++ .../WindowsSdkProjection.csproj | 46 ++++++++++ .../WindowsSdkXamlProjection.csproj | 62 ++++++++++++++ src/Tests/SmokeTests/run-smoke-tests.ps1 | 85 +++++++++++++++---- 7 files changed, 261 insertions(+), 24 deletions(-) create mode 100644 src/Tests/SmokeTests/WindowsSdkContracts.targets create mode 100644 src/Tests/SmokeTests/WindowsSdkProjection/WindowsSdkProjection.csproj create mode 100644 src/Tests/SmokeTests/WindowsSdkXamlProjection/WindowsSdkXamlProjection.csproj diff --git a/build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml b/build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml index b8fdeb7eb..0c318ce77 100644 --- a/build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml +++ b/build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml @@ -126,16 +126,18 @@ steps: # Build and run the end-to-end smoke tests against the freshly packed NuGet package. These # verify that the real package (ref/lib assemblies, generators, and build targets) works for - # a consuming app, a component author, and a projection author, fully isolated from the repo build - # infrastructure. The smoke tests restore the package being tested from the packed output above, and - # all other dependencies (notably the preview Windows SDK ref pack) from the CsWinRTDependencies feed. + # a consuming app, a component author, a projection author, and the Windows SDK projection packages, + # fully isolated from the repo build infrastructure. The smoke tests restore the package being tested + # from the packed output above, and all other dependencies (notably the preview Windows SDK ref pack + # and 'Microsoft.Windows.SDK.Contracts') from the CsWinRTDependencies feed. # # Each smoke test runs as its own step with 'continueOnError' (so a failure only marks the job # as 'SucceededWithIssues' and makes it obvious which one failed); a final gate step below turns # any such issue into an actual failure. This mirrors the unit test steps in CsWinRT-Test-Steps.yml. # The consumption and authoring tests each run twice: once on CoreCLR and once with Native AOT, so a - # failure points at the exact runtime. The projection test is build-only, so it runs once on CoreCLR. - # Native AOT publishes are x64 (this job only runs on an x64 host). + # failure points at the exact runtime. The projection, Windows SDK projection, and Windows SDK XAML + # projection tests are build-only, so they run once on CoreCLR. Native AOT publishes are x64 (this job + # only runs on an x64 host). - task: UseDotNet@2 displayName: Use .NET SDK for smoke tests inputs: @@ -187,6 +189,24 @@ steps: arguments: -PackageSource "$(ob_outputDirectory)\packages" -PackageVersion "$(NugetVersion)" -Test Projection -Runtime CoreCLR workingDirectory: $(Build.SourcesDirectory) + - task: PowerShell@2 + displayName: Run Windows SDK projection smoke test (CoreCLR) + continueOnError: true + inputs: + targetType: filePath + filePath: $(Build.SourcesDirectory)\src\Tests\SmokeTests\run-smoke-tests.ps1 + arguments: -PackageSource "$(ob_outputDirectory)\packages" -PackageVersion "$(NugetVersion)" -Test WindowsSdkProjection -Runtime CoreCLR + workingDirectory: $(Build.SourcesDirectory) + + - task: PowerShell@2 + displayName: Run Windows SDK XAML projection smoke test (CoreCLR) + continueOnError: true + inputs: + targetType: filePath + filePath: $(Build.SourcesDirectory)\src\Tests\SmokeTests\run-smoke-tests.ps1 + arguments: -PackageSource "$(ob_outputDirectory)\packages" -PackageVersion "$(NugetVersion)" -Test WindowsSdkXamlProjection -Runtime CoreCLR + workingDirectory: $(Build.SourcesDirectory) + # Fail the job if any smoke test above failed. Each smoke test uses 'continueOnError', so an # individual failure only marks the job as 'SucceededWithIssues'; this turns that into a real # failure, while still letting every smoke test run and report first. diff --git a/docs/structure.md b/docs/structure.md index 955cbf406..e6d320fba 100644 --- a/docs/structure.md +++ b/docs/structure.md @@ -51,7 +51,7 @@ Contains various testing-related projects: - [`ObjectLifetimeTests`](../src/Tests/ObjectLifetimeTests): A WinUI application-style MSTest project validating reference tracking, garbage collection behavior, and XAML element lifetime. -- [`SmokeTests`](../src/Tests/SmokeTests): Minimal, isolated end-to-end smoke tests that consume the real `Microsoft.Windows.CsWinRT` NuGet package — a consumption app (`Consumption`), an authoring component (`Authoring`), and a reference projection for a third-party `.winmd` (`Projection`) — to verify the produced package works correctly outside the repository build infrastructure. +- [`SmokeTests`](../src/Tests/SmokeTests): Minimal, isolated end-to-end smoke tests that consume the real `Microsoft.Windows.CsWinRT` NuGet package — a consumption app (`Consumption`), an authoring component (`Authoring`), a reference projection for a third-party `.winmd` (`Projection`), and reference projections for the Windows SDK (`WindowsSdkProjection`) and its `Windows.UI.Xaml` surface (`WindowsSdkXamlProjection`) — to verify the produced package works correctly outside the repository build infrastructure. - [`AuthoringTest`](../src/Tests/AuthoringTest): A C#-authored WinRT component (`CsWinRTComponent=true`) covering a broad set of authoring type patterns. Companion projects exercise consuming authored components — `AuthoringTest2`/`AuthoringTest3`, the `AuthoringConsumptionTest*` C++ consumers, and the WUX (`Windows.UI.Xaml`) and WinUI variants — several of which are still work in progress. diff --git a/src/Tests/SmokeTests/Directory.Build.props b/src/Tests/SmokeTests/Directory.Build.props index 70c0a26f8..c08d0cc32 100644 --- a/src/Tests/SmokeTests/Directory.Build.props +++ b/src/Tests/SmokeTests/Directory.Build.props @@ -36,7 +36,9 @@ https://pkgs.dev.azure.com/shine-oss/CsWinRT/_packaging/CsWinRTDependencies/nuget/v3/index.json diff --git a/src/Tests/SmokeTests/WindowsSdkContracts.targets b/src/Tests/SmokeTests/WindowsSdkContracts.targets new file mode 100644 index 000000000..fa2f0425d --- /dev/null +++ b/src/Tests/SmokeTests/WindowsSdkContracts.targets @@ -0,0 +1,56 @@ + + + + + <_SdkContractsPackageName>Microsoft.Windows.SDK.Contracts + + + <_SdkContractsPackageVersion>10.0.26100.7705 + + + + + + + + + + + + <_SdkContractsWinMDFolder>$([MSBuild]::NormalizeDirectory('$(NuGetPackageRoot)', '$(_SdkContractsPackageName)', '$(_SdkContractsPackageVersion)', 'ref', 'netstandard2.0')) + + + + + + + + + diff --git a/src/Tests/SmokeTests/WindowsSdkProjection/WindowsSdkProjection.csproj b/src/Tests/SmokeTests/WindowsSdkProjection/WindowsSdkProjection.csproj new file mode 100644 index 000000000..016f6b827 --- /dev/null +++ b/src/Tests/SmokeTests/WindowsSdkProjection/WindowsSdkProjection.csproj @@ -0,0 +1,46 @@ + + + + + + + true + + + Windows; + Windows.UI.Xaml.Interop; + Windows.UI.Xaml.Data.BindableAttribute; + Windows.UI.Xaml.Markup.ContentPropertyAttribute + + + Windows.UI.Colors; + Windows.UI.ColorHelper; + Windows.UI.IColorHelper; + Windows.UI.IColors; + Windows.UI.Text.FontWeights; + Windows.UI.Text.IFontWeights; + Windows.UI.Xaml; + Windows.ApplicationModel.Store.Preview.WebAuthenticationCoreManagerHelper; + Windows.ApplicationModel.Store.Preview.IWebAuthenticationCoreManagerHelper + + + + + + diff --git a/src/Tests/SmokeTests/WindowsSdkXamlProjection/WindowsSdkXamlProjection.csproj b/src/Tests/SmokeTests/WindowsSdkXamlProjection/WindowsSdkXamlProjection.csproj new file mode 100644 index 000000000..f758cc1a1 --- /dev/null +++ b/src/Tests/SmokeTests/WindowsSdkXamlProjection/WindowsSdkXamlProjection.csproj @@ -0,0 +1,62 @@ + + + + + + + true + + + Windows.UI.Colors; + Windows.UI.ColorHelper; + Windows.UI.IColorHelper; + Windows.UI.IColors; + Windows.UI.Text.FontWeights; + Windows.UI.Text.IFontWeights; + Windows.UI.Xaml; + Windows.ApplicationModel.Store.Preview.WebAuthenticationCoreManagerHelper; + Windows.ApplicationModel.Store.Preview.IWebAuthenticationCoreManagerHelper + + + Windows; + Windows.UI.Xaml.Interop; + Windows.UI.Xaml.Data.BindableAttribute; + Windows.UI.Xaml.Markup.ContentPropertyAttribute + + + + + + + + + + $(MSBuildThisFileDirectory)..\WindowsSdkProjection\bin\$(Configuration)\$(TargetFramework)\ref\WindowsSdkProjection.dll + false + + + + + + diff --git a/src/Tests/SmokeTests/run-smoke-tests.ps1 b/src/Tests/SmokeTests/run-smoke-tests.ps1 index fba549ce9..a58dd0ff2 100644 --- a/src/Tests/SmokeTests/run-smoke-tests.ps1 +++ b/src/Tests/SmokeTests/run-smoke-tests.ps1 @@ -21,6 +21,16 @@ reference projection generator and the forwarder generator, exactly as a NuGet projection author would. + * WindowsSdkProjection: a class library generates the base Windows SDK reference projection + from the 'Microsoft.Windows.SDK.Contracts' '.winmd' files, exactly as the + 'Microsoft.Windows.SDK.NET.Ref' projection package is produced. This validates that the full + Windows SDK surface generates and compiles against the packaged 'WinRT.Runtime' reference + assembly, catching reference-projection codegen regressions before they break that package. + + * WindowsSdkXamlProjection: as above, but for the 'Windows.UI.Xaml' surface, which references the + base Windows SDK reference projection (mirroring how the UWP XAML projection package depends on + the base Windows SDK projection package). + The smoke tests reference the package via 'RestoreSources' (see the '.csproj' files), so no global NuGet configuration changes are required. @@ -31,16 +41,17 @@ Version of the 'Microsoft.Windows.CsWinRT' package to consume. .PARAMETER Test - Which smoke test(s) to run: 'Consumption', 'Authoring', 'Projection', or 'All' (the default). The - CI runs each test as its own step (passing a single value), so an individual failure is reported in - isolation; local builds use the default 'All'. + Which smoke test(s) to run: 'Consumption', 'Authoring', 'Projection', 'WindowsSdkProjection', + 'WindowsSdkXamlProjection', or 'All' (the default). The CI runs each test as its own step (passing a + single value), so an individual failure is reported in isolation; local builds use the default 'All'. .PARAMETER Runtime Which runtime to target: 'CoreCLR' (the default) builds and runs on the managed runtime; 'NativeAot' publishes the project with Native AOT ('PublishAot=true', win-x64), exercising the full publish pipeline (projection and interop generators, then ILC). The CI runs both as - separate steps so a failure points at the exact runtime. The 'Projection' test is build-only and - therefore CoreCLR-only; it is skipped for 'NativeAot'. + separate steps so a failure points at the exact runtime. The 'Projection', 'WindowsSdkProjection', + and 'WindowsSdkXamlProjection' tests are build-only and therefore CoreCLR-only; they are skipped for + 'NativeAot'. .PARAMETER Configuration Build configuration to use (defaults to 'Release'). @@ -60,7 +71,7 @@ param ( [Parameter(Mandatory = $true)] [string] $PackageVersion, - [ValidateSet('All', 'Consumption', 'Authoring', 'Projection')] + [ValidateSet('All', 'Consumption', 'Authoring', 'Projection', 'WindowsSdkProjection', 'WindowsSdkXamlProjection')] [string] $Test = 'All', [ValidateSet('CoreCLR', 'NativeAot')] @@ -79,6 +90,8 @@ $smokeTestsRoot = $PSScriptRoot $consumptionProject = [IO.Path]::Combine($smokeTestsRoot, 'Consumption', 'Consumption.csproj') $authoringProject = [IO.Path]::Combine($smokeTestsRoot, 'Authoring', 'Authoring.csproj') $projectionProject = [IO.Path]::Combine($smokeTestsRoot, 'Projection', 'Projection.csproj') +$windowsSdkProjectionProject = [IO.Path]::Combine($smokeTestsRoot, 'WindowsSdkProjection', 'WindowsSdkProjection.csproj') +$windowsSdkXamlProjectionProject = [IO.Path]::Combine($smokeTestsRoot, 'WindowsSdkXamlProjection', 'WindowsSdkXamlProjection.csproj') # Resolve the package source to an absolute path (NuGet rejects relative '--source' values). $resolvedPackageSource = (Resolve-Path -Path $PackageSource).Path @@ -188,30 +201,60 @@ function Invoke-AuthoringSmokeTest { function Invoke-ProjectionSmokeTest { Write-Host "`n=== Projection smoke test ($Runtime) ===" -ForegroundColor Green + Invoke-ReferenceProjectionSmokeTest -Name 'Projection' -Project $projectionProject +} + +# Windows SDK projection: build the base Windows SDK reference projection, exactly as the +# 'Microsoft.Windows.SDK.NET.Ref' projection package is produced (CoreCLR only; build-time artifact). +function Invoke-WindowsSdkProjectionSmokeTest { + Write-Host "`n=== Windows SDK projection smoke test ($Runtime) ===" -ForegroundColor Green + + Invoke-ReferenceProjectionSmokeTest -Name 'WindowsSdkProjection' -Project $windowsSdkProjectionProject +} + +# Windows SDK XAML projection: build the 'Windows.UI.Xaml' reference projection (which references the +# base Windows SDK reference projection above), exactly as the UWP XAML projection package is produced +# (CoreCLR only; build-time artifact). +function Invoke-WindowsSdkXamlProjectionSmokeTest { + Write-Host "`n=== Windows SDK XAML projection smoke test ($Runtime) ===" -ForegroundColor Green + + Invoke-ReferenceProjectionSmokeTest -Name 'WindowsSdkXamlProjection' -Project $windowsSdkXamlProjectionProject +} + +# Shared implementation for the reference-projection smoke tests. Building a reference projection produces +# a forwarder assembly (from 'cswinrtimplgen') next to a 'ref' reference assembly (compiled from the +# 'cswinrtprojectionrefgen' sources). Verifying both were produced confirms the package wired up and ran +# both generators correctly, and that the generated reference projection compiled against the packaged +# 'WinRT.Runtime' reference assembly. A reference projection is a build-time artifact, so there is nothing +# to publish with Native AOT and these tests run on CoreCLR only. +function Invoke-ReferenceProjectionSmokeTest { + param ( + [Parameter(Mandatory = $true)] [string] $Name, + [Parameter(Mandatory = $true)] [string] $Project + ) + if ($Runtime -eq 'NativeAot') { - Write-Host "Skipping the projection smoke test for Native AOT (a reference projection is a build-time artifact)." -ForegroundColor DarkGray + Write-Host "Skipping the $Name smoke test for Native AOT (a reference projection is a build-time artifact)." -ForegroundColor DarkGray return } - Invoke-Dotnet (@('build', $projectionProject) + $commonBuildArgs) + Invoke-Dotnet (@('build', $Project) + $commonBuildArgs) - # Building a reference projection produces a forwarder assembly (from 'cswinrtimplgen') next to a - # 'ref' reference assembly (compiled from the 'cswinrtprojectionrefgen' sources). Verify both were - # produced, which confirms the package wired up and ran both generators correctly. - $projectionAssemblies = Get-ChildItem -Path ([IO.Path]::Combine($smokeTestsRoot, 'Projection', 'bin')) -Filter 'Projection.dll' -Recurse -ErrorAction SilentlyContinue + $projectDirectory = [IO.Path]::GetDirectoryName($Project) + $assemblies = Get-ChildItem -Path ([IO.Path]::Combine($projectDirectory, 'bin')) -Filter "$Name.dll" -Recurse -ErrorAction SilentlyContinue - $forwarder = $projectionAssemblies | Where-Object { $_.FullName -notmatch '\\ref\\' } | Select-Object -First 1 - $referenceAssembly = $projectionAssemblies | Where-Object { $_.FullName -match '\\ref\\' } | Select-Object -First 1 + $forwarder = $assemblies | Where-Object { $_.FullName -notmatch '\\ref\\' } | Select-Object -First 1 + $referenceAssembly = $assemblies | Where-Object { $_.FullName -match '\\ref\\' } | Select-Object -First 1 if ($null -eq $forwarder) { - throw "The projection build did not produce the 'Projection.dll' forwarder assembly." + throw "The $Name build did not produce the '$Name.dll' forwarder assembly." } if ($null -eq $referenceAssembly) { - throw "The projection build did not produce the 'ref\Projection.dll' reference assembly." + throw "The $Name build did not produce the 'ref\$Name.dll' reference assembly." } - Write-Host "Verified the projection produced both a forwarder and a reference assembly." -ForegroundColor DarkGray + Write-Host "Verified the $Name projection produced both a forwarder and a reference assembly." -ForegroundColor DarkGray } if ($Test -in @('All', 'Consumption')) { @@ -226,4 +269,12 @@ if ($Test -in @('All', 'Projection')) { Invoke-ProjectionSmokeTest } +if ($Test -in @('All', 'WindowsSdkProjection')) { + Invoke-WindowsSdkProjectionSmokeTest +} + +if ($Test -in @('All', 'WindowsSdkXamlProjection')) { + Invoke-WindowsSdkXamlProjectionSmokeTest +} + Write-Host "`nSmoke tests passed." -ForegroundColor Green From 3d84e8a75c1af47168f898937aafffc87da71776 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 22 Jun 2026 20:55:45 -0700 Subject: [PATCH 39/42] Build the Windows SDK projection smoke tests as plain net10.0 The two Windows SDK reference-projection smoke tests inherited the '-windows10.0.26100.1' target framework from the shared 'Directory.Build.props'. That target framework makes the .NET SDK add an implicit reference to the prebuilt Windows SDK projection ('Microsoft.Windows.SDK.NET.dll') -- the very projection these tests regenerate -- so every generated type collided with its prebuilt counterpart (tens of thousands of CS0436), and 'ApiContractAttribute' collided between 'Microsoft.Windows.SDK.NET' and 'WinRT.Runtime' (CS0433), failing the build. Override the target framework to plain 'net10.0' for both projects, exactly as the real Windows SDK projection is built ('src/WinRT.Sdk.Projection/WinRT.Sdk.Projection.csproj'): generating the Windows SDK projection means it cannot reference the Windows SDK projection. The base 'Windows.*' types the XAML projection needs come from the sibling 'WindowsSdkProjection' reference assembly instead. The '-windows'-specific properties the shared props also set ('TargetPlatformMinVersion', 'WindowsSdkPackageVersion') are inert without a target platform. The package's reference-projection flow fully supports this (CsWinRTExeTFM resolves to 'net10.0' for any net10.0+ target framework), and the generated projection still compiles against the packaged 'WinRT.Runtime' reference assembly (NuGet uses 'ref/net10.0' at compile time), which is what these tests validate. Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com> --- .../WindowsSdkProjection.csproj | 19 ++++++++++++++++--- .../WindowsSdkXamlProjection.csproj | 8 ++++++-- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/Tests/SmokeTests/WindowsSdkProjection/WindowsSdkProjection.csproj b/src/Tests/SmokeTests/WindowsSdkProjection/WindowsSdkProjection.csproj index 016f6b827..9fec3e58a 100644 --- a/src/Tests/SmokeTests/WindowsSdkProjection/WindowsSdkProjection.csproj +++ b/src/Tests/SmokeTests/WindowsSdkProjection/WindowsSdkProjection.csproj @@ -13,12 +13,25 @@ generator applies for 'WinRT.Sdk.Projection' (see 'WriteWindowsSdkFilters' in 'src/WinRT.Projection.Generator/Generation/ProjectionGenerator.Generate.cs'): everything under 'Windows' except the 'Windows.UI.Xaml' surface and the few 'Windows.UI'/'Windows.ApplicationModel' - helper types that belong to the sibling 'Windows.UI.Xaml' projection. Shared configuration (target - framework, NuGet sources, the CsWinRT package reference) comes from the parent 'Directory.Build.props', - and the Windows SDK '.winmd' inputs from the shared 'WindowsSdkContracts.targets'. + helper types that belong to the sibling 'Windows.UI.Xaml' projection. The remaining shared + configuration (NuGet sources, the CsWinRT package reference) comes from the parent + 'Directory.Build.props', and the Windows SDK '.winmd' inputs from the shared + 'WindowsSdkContracts.targets'. --> + + net10.0 + true diff --git a/src/Tests/SmokeTests/WindowsSdkXamlProjection/WindowsSdkXamlProjection.csproj b/src/Tests/SmokeTests/WindowsSdkXamlProjection/WindowsSdkXamlProjection.csproj index f758cc1a1..926598c69 100644 --- a/src/Tests/SmokeTests/WindowsSdkXamlProjection/WindowsSdkXamlProjection.csproj +++ b/src/Tests/SmokeTests/WindowsSdkXamlProjection/WindowsSdkXamlProjection.csproj @@ -13,12 +13,16 @@ The namespace include/exclude filters below mirror the 'Windows.UI.Xaml' filter set the projection generator applies for 'WinRT.Sdk.Xaml.Projection' (see 'WriteWindowsSdkFilters' in - 'src/WinRT.Projection.Generator/Generation/ProjectionGenerator.Generate.cs'). Shared configuration - comes from the parent 'Directory.Build.props', and the Windows SDK '.winmd' inputs from the shared + 'src/WinRT.Projection.Generator/Generation/ProjectionGenerator.Generate.cs'). The remaining shared + configuration (NuGet sources, the CsWinRT package reference) comes from the parent + 'Directory.Build.props', and the Windows SDK '.winmd' inputs from the shared 'WindowsSdkContracts.targets'. --> + + net10.0 + true From 25908151d11a76b38d64c68293afdd4030448cea Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 22 Jun 2026 23:48:51 -0700 Subject: [PATCH 40/42] Simplify over-escaped interpolated raw strings in MappedInterfaceStubFactory Several reference- and implementation-mode stub strings used the '$$""" + ... + """' form (with '{{x}}' interpolation holes) even though their content has no literal braces, so the doubled '$$' was unnecessary. Reduce those six to a single '$' (with '{x}' holes). The strings that do contain literal braces (indexers, event accessors, 'Dispose() { }') still need '$$' and are left unchanged. This is a purely cosmetic change: the generated text is identical. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Factories/MappedInterfaceStubFactory.cs | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/WinRT.Projection.Writer/Factories/MappedInterfaceStubFactory.cs b/src/WinRT.Projection.Writer/Factories/MappedInterfaceStubFactory.cs index 7e7880cfc..1b8c1a936 100644 --- a/src/WinRT.Projection.Writer/Factories/MappedInterfaceStubFactory.cs +++ b/src/WinRT.Projection.Writer/Factories/MappedInterfaceStubFactory.cs @@ -153,10 +153,10 @@ private static void EmitNonGenericEnumerator(IndentedTextWriter writer, Projecti } writer.WriteLine(); - writer.WriteLine(isMultiline: true, $$""" - public bool MoveNext() => global::ABI.System.Collections.IEnumeratorMethods.MoveNext({{objRefName}}); + writer.WriteLine(isMultiline: true, $""" + public bool MoveNext() => global::ABI.System.Collections.IEnumeratorMethods.MoveNext({objRefName}); public void Reset() => throw new NotSupportedException(); - public object Current => global::ABI.System.Collections.IEnumeratorMethods.Current({{objRefName}}); + public object Current => global::ABI.System.Collections.IEnumeratorMethods.Current({objRefName}); """); } @@ -206,8 +206,8 @@ private static void EmitGenericEnumerable(IndentedTextWriter writer, ProjectionE if (context.Settings.ReferenceProjection) { writer.WriteLine(); - writer.WriteLine(isMultiline: true, $$""" - public IEnumerator<{{t}}> GetEnumerator() => throw null; + writer.WriteLine(isMultiline: true, $""" + public IEnumerator<{t}> GetEnumerator() => throw null; global::System.Collections.IEnumerator global::System.Collections.IEnumerable.GetEnumerator() => throw null; """); @@ -240,11 +240,11 @@ private static void EmitGenericEnumerator(IndentedTextWriter writer, ProjectionE if (context.Settings.ReferenceProjection) { writer.WriteLine(); - writer.WriteLine(isMultiline: true, $$""" + writer.WriteLine(isMultiline: true, $""" public bool MoveNext() => throw null; public void Reset() => throw null; public void Dispose() => throw null; - public {{t}} Current => throw null; + public {t} Current => throw null; object global::System.Collections.IEnumerator.Current => throw null; """); @@ -390,13 +390,13 @@ private static void EmitReadOnlyDictionary(IndentedTextWriter writer, Projection if (context.Settings.ReferenceProjection) { writer.WriteLine(); - writer.WriteLine(isMultiline: true, $$""" - public {{v}} this[{{k}} key] => throw null; - public IEnumerable<{{k}}> Keys => throw null; - public IEnumerable<{{v}}> Values => throw null; + writer.WriteLine(isMultiline: true, $""" + public {v} this[{k} key] => throw null; + public IEnumerable<{k}> Keys => throw null; + public IEnumerable<{v}> Values => throw null; public int Count => throw null; - public bool ContainsKey({{k}} key) => throw null; - public bool TryGetValue({{k}} key, out {{v}} value) => throw null; + public bool ContainsKey({k} key) => throw null; + public bool TryGetValue({k} key, out {v} value) => throw null; """); return; @@ -446,9 +446,9 @@ private static void EmitReadOnlyList(IndentedTextWriter writer, ProjectionEmitCo if (context.Settings.ReferenceProjection) { writer.WriteLine(); - writer.WriteLine(isMultiline: true, $$""" + writer.WriteLine(isMultiline: true, $""" [global::System.Runtime.CompilerServices.IndexerName("ReadOnlyListItem")] - public {{t}} this[int index] => throw null; + public {t} this[int index] => throw null; public int Count => throw null; """); @@ -468,10 +468,10 @@ private static void EmitReadOnlyList(IndentedTextWriter writer, ProjectionEmitCo // GetEnumerator is NOT emitted here -- it's handled separately by IIterable's // EmitGenericEnumerable invocation. writer.WriteLine(); - writer.WriteLine(isMultiline: true, $$""" + writer.WriteLine(isMultiline: true, $""" [global::System.Runtime.CompilerServices.IndexerName("ReadOnlyListItem")] - public {{t}} this[int index] => {{prefix}}Item(null, {{objRefName}}, index); - public int Count => {{prefix}}Count(null, {{objRefName}}); + public {t} this[int index] => {prefix}Item(null, {objRefName}, index); + public int Count => {prefix}Count(null, {objRefName}); """); } From 038b42c5177c847cfb2d86e679a32e9d1e4bc975 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 22 Jun 2026 23:54:09 -0700 Subject: [PATCH 41/42] Update testing skill for the Windows SDK projection smoke tests The smoke tests section listed three projects; it now documents all five, adding 'WindowsSdkProjection' and 'WindowsSdkXamlProjection' (the Windows SDK reference projections built from 'Microsoft.Windows.SDK.Contracts', staged by the shared 'WindowsSdkContracts.targets'). Also correct the smoke tests' shared configuration: 'RestoreSources' uses the local package output plus the 'CsWinRTDependencies' feed (not public NuGet), the two SDK projection tests override the target framework to plain 'net10.0', and the reference-projection verification is shared across all three reference-projection tests (build-only, CoreCLR). Refresh the 'Authoring' smoke test description to reflect its broader authored type catalog ('Thermometer.cs'), and update the routing table accordingly. Update the 'update-testing-instructions' skill's smoke-test verification step to match. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/skills/testing/SKILL.md | 16 +++++++++------- .../skills/update-testing-instructions/SKILL.md | 8 ++++---- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/.github/skills/testing/SKILL.md b/.github/skills/testing/SKILL.md index b7003fb3c..7875decfe 100644 --- a/.github/skills/testing/SKILL.md +++ b/.github/skills/testing/SKILL.md @@ -222,25 +222,27 @@ public async Task InvalidType_Warns() ### 6. Smoke tests (`src/Tests/SmokeTests/`) -**What it tests:** End-to-end consumption of the **real** `Microsoft.Windows.CsWinRT` NuGet package — a consuming app, an authoring component, and a third-party projection — fully isolated from the repository build infrastructure. Validates that the packaged `ref`/`lib` assemblies, the build targets, and all post-build generators work correctly for an external customer. +**What it tests:** End-to-end consumption of the **real** `Microsoft.Windows.CsWinRT` NuGet package — a consuming app, an authoring component, a third-party projection, and the Windows SDK reference projections — fully isolated from the repository build infrastructure. Validates that the packaged `ref`/`lib` assemblies, the build targets, and all post-build generators work correctly for an external customer. **When to add tests here:** For verifying that the produced NuGet package works in a real, isolated environment (correct `ref`/`lib` assemblies referenced, generators running). Keep these minimal — they are smoke tests, not feature coverage. Use `UnitTest/` or `FunctionalTests/` for marshalling/feature coverage instead. -**Project structure:** Three standalone projects, intentionally kept out of `cswinrt.slnx` (the package they consume only exists after the build packs it). They are isolated from the repo build infrastructure via blank `Directory.Build.props`/`.targets` and a local `Directory.Packages.props` (central package management disabled). All shared configuration lives in `Directory.Build.props`, so each `.csproj` only carries what makes it different. +**Project structure:** Five standalone projects, intentionally kept out of `cswinrt.slnx` (the package they consume only exists after the build packs it). They are isolated from the repo build infrastructure via blank `Directory.Build.props`/`.targets` and a local `Directory.Packages.props` (central package management disabled). All shared configuration lives in `Directory.Build.props`, so each `.csproj` only carries what makes it different; the two Windows SDK projection tests additionally share `WindowsSdkContracts.targets` (which stages the SDK `.winmd` inputs). **Existing tests:** | Project | Tests | |---------|-------| | `Consumption/` | An `Exe` that calls `JsonObject.Parse(...)` then `Stringify()` from `Windows.Data.Json`, exercising the Windows SDK projection, the interop generator, and the `WinRT.Runtime` ref/impl assemblies | -| `Authoring/` | A `CsWinRTComponent` library exposing a minimal `Greeter` class, exercising WinMD generation, the reference projection, and the forwarder assembly | +| `Authoring/` | A `CsWinRTComponent` library exposing a `Greeter` class plus a richer catalog of authored type shapes in `Thermometer.cs` (enums, a flags enum, a struct, a delegate, an interface, and a sealed runtime class with constructors, properties, an event, and static members), exercising WinMD generation, the reference projection, and the forwarder assembly. The breadth deliberately gives the `Projection` smoke test more projection shapes to cover | | `Projection/` | A `CsWinRTGenerateReferenceProjection` library that generates a reference projection for the `Authoring` component's `.winmd` (reused via a build-ordering `ProjectReference`), exercising `cswinrtprojectionrefgen` and `cswinrtimplgen`, exactly as a NuGet projection author would | +| `WindowsSdkProjection/` | A `CsWinRTGenerateReferenceProjection` library that generates the base Windows SDK reference projection from the `Microsoft.Windows.SDK.Contracts` `.winmd` files (staged by `WindowsSdkContracts.targets`), exactly as the `Microsoft.Windows.SDK.NET.Ref` projection package is produced. Catches reference-projection codegen regressions against the full Windows SDK surface | +| `WindowsSdkXamlProjection/` | As `WindowsSdkProjection`, but for the `Windows.UI.Xaml` surface; it references the `WindowsSdkProjection` reference assembly, mirroring how the UWP XAML projection package depends on the base Windows SDK projection package | **Shared configuration (`Directory.Build.props`):** -- **TFM:** `net10.0-windows10.0.26100.1` (the `.1` CsWinRT 3.0 revision), with a pinned `WindowsSdkPackageVersion` so the build uses the real .NET SDK targeting pack (mirrors `src/WinRT.Internal`) -- `RestoreSources` overrides all inherited NuGet sources: the local CsWinRT build output (`CsWinRTPackageSource`) plus public NuGet (`PublicNuGetSource`) +- **TFM:** `net10.0-windows10.0.26100.1` (the `.1` CsWinRT 3.0 revision), with a pinned `WindowsSdkPackageVersion` so the build uses the real .NET SDK targeting pack (mirrors `src/WinRT.Internal`). The two Windows SDK projection tests override this to plain `net10.0` (a `-windows` TFM would implicitly reference the prebuilt Windows SDK projection they regenerate, colliding with every generated type), exactly as `src/WinRT.Sdk.Projection` +- `RestoreSources` overrides all inherited NuGet sources: the local CsWinRT build output (`CsWinRTPackageSource`) plus the `CsWinRTDependencies` feed (`CsWinRTDependenciesSource`), which provides the preview Windows SDK ref pack and `Microsoft.Windows.SDK.Contracts` - `CsWinRTPackageVersion`/`CsWinRTPackageSource` default to the local `build.cmd x64 Release` output and are overridden by the build/CI that produced the package -**How they run:** `run-smoke-tests.ps1` (parameterized by `-Test` and `-Runtime`) builds and runs the consumption app (asserting a clean exit code), builds the authoring component and verifies the generated `Authoring.winmd` defines `Authoring.Greeter`, and builds the projection library verifying it produces both a forwarder and a `ref` reference assembly. The consumption and authoring tests run on both CoreCLR and Native AOT (`-Runtime`); the projection test is build-only and runs on CoreCLR only. It is invoked after the `nuget pack` step in `src/build.cmd` (x64 only; skippable via `cswinrt_run_smoke_tests=false`) and as individual steps in `build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml`. +**How they run:** `run-smoke-tests.ps1` (parameterized by `-Test` and `-Runtime`) builds and runs the consumption app (asserting a clean exit code), builds the authoring component and verifies the generated `Authoring.winmd` defines `Authoring.Greeter`, and builds each reference-projection library (`Projection`, `WindowsSdkProjection`, `WindowsSdkXamlProjection`) verifying it produces both a forwarder and a `ref` reference assembly (shared verification). The consumption and authoring tests run on both CoreCLR and Native AOT (`-Runtime`); the three reference-projection tests are build-only and run on CoreCLR only. It is invoked after the `nuget pack` step in `src/build.cmd` (x64 only; skippable via `cswinrt_run_smoke_tests=false`) and as individual steps in `build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml`. ## Deciding where to add tests @@ -256,7 +258,7 @@ public async Task InvalidType_Warns() | GC/reference tracking behavior | `ObjectLifetimeTests/` | | XAML visual tree element lifetime | `ObjectLifetimeTests/` | | WinRT component authoring patterns | `AuthoringTest/` | -| The produced NuGet package works end-to-end (real `ref`/`lib` assemblies, generators) | `SmokeTests/` (`Consumption/` or `Authoring/`) | +| The produced NuGet package works end-to-end (real `ref`/`lib` assemblies, generators) | `SmokeTests/` (`Consumption/`, `Authoring/`, or a reference-projection project) | | Generated projection code patterns or cross-ABI control flow | Update `TestComponentCSharp/` and add tests in `UnitTest/` or `FunctionalTests/` | ## Test component: TestComponentCSharp (`src/Tests/TestComponentCSharp/`) diff --git a/.github/skills/update-testing-instructions/SKILL.md b/.github/skills/update-testing-instructions/SKILL.md index eb27f00b5..5f2b42d2a 100644 --- a/.github/skills/update-testing-instructions/SKILL.md +++ b/.github/skills/update-testing-instructions/SKILL.md @@ -72,11 +72,11 @@ Launch an explore agent to verify: Launch an explore agent (or inspect directly) to verify: -- **Project list** is accurate — the `Consumption/` app, the `Authoring/` component, and the `Projection/` reference projection, kept out of `cswinrt.slnx` +- **Project list** is accurate — the `Consumption/` app, the `Authoring/` component, the `Projection/` reference projection, and the `WindowsSdkProjection/`/`WindowsSdkXamlProjection/` Windows SDK reference projections, kept out of `cswinrt.slnx` - **Isolation** is intact: blank `Directory.Build.props`/`.targets` and a local `Directory.Packages.props` (central package management disabled) -- **Shared configuration** in `Directory.Build.props` is current: TFM (`.1` revision), pinned `WindowsSdkPackageVersion`, `RestoreSources` (local package output + public NuGet), `DisableRuntimeMarshalling`, and the `CsWinRTPackageVersion`/`CsWinRTPackageSource` defaults -- **What each test does** is accurate (the consumption app's `JsonObject.Parse`/`Stringify` call; the authoring component's class and `.winmd` verification; the projection library's reference projection over the authoring component's `.winmd`, verifying a forwarder and a `ref` assembly are produced) -- **How they run** is current: the `run-smoke-tests.ps1` runner (its `-Test` and `-Runtime` parameters — consumption/authoring run on both CoreCLR and Native AOT, projection on CoreCLR only), and the invocations in `src/build.cmd` and `build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml` +- **Shared configuration** in `Directory.Build.props` is current: TFM (`.1` revision; the two Windows SDK projection tests override to plain `net10.0`), pinned `WindowsSdkPackageVersion`, `RestoreSources` (local package output + the `CsWinRTDependencies` feed, which provides the preview Windows SDK ref pack and `Microsoft.Windows.SDK.Contracts`), `DisableRuntimeMarshalling`, and the `CsWinRTPackageVersion`/`CsWinRTPackageSource` defaults. Also verify `WindowsSdkContracts.targets` (the shared SDK `.winmd` staging the two SDK projection tests import) +- **What each test does** is accurate (the consumption app's `JsonObject.Parse`/`Stringify` call; the authoring component's class and `.winmd` verification; the `Projection`/`WindowsSdkProjection`/`WindowsSdkXamlProjection` libraries' reference projections, each verifying a forwarder and a `ref` assembly are produced — `Projection` over the authoring component's `.winmd`, the SDK ones over the `Microsoft.Windows.SDK.Contracts` `.winmd` files) +- **How they run** is current: the `run-smoke-tests.ps1` runner (its `-Test` and `-Runtime` parameters — consumption/authoring run on both CoreCLR and Native AOT, the three reference-projection tests on CoreCLR only via the shared forwarder + `ref` assembly verification), and the invocations in `src/build.cmd` and `build/AzurePipelineTemplates/CsWinRT-PublishToNuGet-Steps.yml` ### Step 8: verify TestComponentCSharp (`src/Tests/TestComponentCSharp/`) From e44bac4e086affb0b34209eae9995bb2e232d40f Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Tue, 23 Jun 2026 13:19:50 -0700 Subject: [PATCH 42/42] Use tag for TypeDefinition in docs Replace XML tag with a reference in the GetWindowsRuntimeMetadataName documentation to produce a proper XML doc reference and improve IntelliSense/linking. No functional changes. --- .../Extensions/WindowsRuntimeExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs b/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs index 9dac09122..31a449b61 100644 --- a/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs +++ b/src/WinRT.Interop.Generator/Extensions/WindowsRuntimeExtensions.cs @@ -1178,7 +1178,7 @@ arrayType.BaseType is not SzArrayTypeSignature && /// This method resolves the underlying type definition from the signature and retrieves its Windows Runtime metadata name. /// For generic instance types, it uses the generic type definition. For array types, it uses the base element type. /// For other types, it resolves the type definition directly. The metadata name is recovered from the implementation - /// projection for types coming from reference projections (see the TypeDefinition overload of this method). + /// projection for types coming from reference projections (see the overload of this method). /// /// public Utf8String? GetWindowsRuntimeMetadataName(InteropDefinitions interopDefinitions)