Skip to content

Add reference assembly support for WinRT.Runtime#2396

Open
Sergio0694 wants to merge 28 commits intostaging/3.0from
user/sergiopedri/winrt-runtime-ref-assembly2
Open

Add reference assembly support for WinRT.Runtime#2396
Sergio0694 wants to merge 28 commits intostaging/3.0from
user/sergiopedri/winrt-runtime-ref-assembly2

Conversation

@Sergio0694
Copy link
Copy Markdown
Member

Summary

Add reference assembly support for WinRT.Runtime so the NuGet package ships with a stripped-down public API surface in ref\net10.0\ and the full implementation in lib\net10.0\. Implementation-detail types and members are removed from the reference assembly via a combination of the new [WindowsRuntimeImplementationOnlyMember] marker attribute, a #define WINDOWS_RUNTIME_IMPLEMENTATION_ONLY_FILE per-file opt-out, wholesale folder exclusions, and WINDOWS_RUNTIME_REFERENCE_ASSEMBLY / WINDOWS_RUNTIME_IMPLEMENTATION_ASSEMBLY define constants for the few cases that need finer-grained conditional code.

This supersedes #2377, which used a different mechanism (#if !REFERENCE_ASSEMBLY guards sprinkled across ~400 files plus [Obsolete] / [EditorBrowsable(Never)] attributes on the public-but-implementation-only APIs). The new approach is much less invasive in source files and produces a cleaner reference assembly.

Motivation

WinRT.Runtime exposes many public types and members that are "private implementation details" — they have to be public so generated projection code in other assemblies can call them, but they are not part of the versioned API surface and should not be visible to downstream consumers. Previously these were marked with [Obsolete] + [EditorBrowsable(Never)], which left them visible in IntelliSense and reflection and prevented us from cleanly evolving the implementation.

With reference assembly support:

  1. The normal build produces the implementation assembly (lib\net10.0\) with WINDOWS_RUNTIME_IMPLEMENTATION_ASSEMBLY defined.
  2. A second build with CsWinRTBuildReferenceAssembly=true produces the reference assembly (ref\net10.0\) with WINDOWS_RUNTIME_REFERENCE_ASSEMBLY defined, with all implementation-only sources removed and remaining method bodies stubbed with throw null.

The interop generator and other CsWinRT build tools continue to consume the full implementation assembly, so they retain access to all the private implementation detail APIs they need.

Changes

  • src/WinRT.Runtime2/Attributes/WindowsRuntimeImplementationOnlyMemberAttribute.cs: new internal [Conditional("WINDOWS_RUNTIME_REFERENCE_ASSEMBLY")] marker attribute applied at the top of every implementation-only top-level type
  • src/WinRT.Runtime2/WinRT.Runtime.csproj: define WINDOWS_RUNTIME_IMPLEMENTATION_ASSEMBLY for normal builds and WINDOWS_RUNTIME_REFERENCE_ASSEMBLY for reference assembly builds; add MSBuild target that scans compile items and removes any source containing [WindowsRuntimeImplementationOnlyMember] or the #define WINDOWS_RUNTIME_IMPLEMENTATION_ONLY_FILE marker; remove implementation-only folders (ABI\, NativeObjects\, most InteropServices\ subfolders) wholesale from the reference assembly compile
  • ~280 .cs files in src/WinRT.Runtime2/: add the [WindowsRuntimeImplementationOnlyMember] marker on implementation-only top-level types, or #define WINDOWS_RUNTIME_IMPLEMENTATION_ONLY_FILE at the top of files that should be removed wholesale; conditionally include using directives for Windows.Foundation.Metadata / System.Runtime.Versioning only in the implementation build; stub remaining method bodies in the reference assembly with throw null
  • src/WinRT.Runtime2/WindowsRuntimeObject.cs + WindowsRuntimeObject.Impl.cs: split WindowsRuntimeObject into a partial class so the public surface (class declaration + abstract members) lives in the reference assembly and the concrete implementation lives in WindowsRuntimeObject.Impl.cs; restore HasUnwrappableNativeObjectReference and IsOverridableInterface to abstract (reverting the temporary workaround from Hide HasUnwrappableNativeObjectReference and IsOverridableInterface from reference projections #2371)
  • build/AzurePipelineTemplates/CsWinRT-Build-Steps.yml and nuget/Microsoft.Windows.CsWinRT.nuspec: build pipeline runs the reference assembly build and packs both the reference and implementation assemblies into the NuGet
  • docs/diagnostics/cswinrt30001.md (deleted): the CSWINRT3001 diagnostic for the previous [Obsolete]-based approach is no longer applicable
  • src/WinRT.Runtime2/Properties/WindowsRuntimeConstants.cs (deleted): file only contained constants for the removed [Obsolete] messages
  • .github/copilot-instructions.md, .github/skills/interop-generator/SKILL.md, .github/skills/update-copilot-instructions/SKILL.md: document the new reference assembly mechanism (define constants, marker attribute, file-level opt-out, folder exclusions) and how the interop generator continues to use the implementation assembly
  • Several smaller fixes: add [StructLayout(LayoutKind.Sequential)] to ComCallData and HSTRING_HEADER, suppress CS1574 in WindowsRuntimeFeatureSwitches.cs, strip [SupportedOSPlatform] and [ContractVersion] from public types in the impl assembly, remove the unused UnreachableException extension method

@Sergio0694 Sergio0694 requested a review from manodasanW April 17, 2026 21:22
@Sergio0694 Sergio0694 force-pushed the user/sergiopedri/winrt-runtime-ref-assembly2 branch 2 times, most recently from ca98352 to cab1a35 Compare April 19, 2026 01:32
Sergio0694 and others added 26 commits April 27, 2026 13:47
Introduce an internal sealed attribute to mark implementation-only members for WinRT runtime. The attribute targets all members, is non-inherited, and is conditional on WINDOWS_RUNTIME_REFERENCE_ASSEMBLY so it is emitted only in reference assemblies; this makes it explicit which members are implementation-only and allows them to be stripped from the runtime DLL. Added at src/WinRT.Runtime2/Attributes/WindowsRuntimeImplementationOnlyMemberAttribute.cs.
…members

Replace the combination of [EditorBrowsable(Never)] and [Obsolete(...)] with the single [WindowsRuntimeImplementationOnlyMember] attribute on implementation-only members across WinRT.Runtime.

Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com>
Delete WindowsRuntimeConstants.cs which contained constants for WinRT private implementation detail messaging, the PrivateImplementationDetailObsoleteDiagnosticId (CSWINRT3001), and the CsWinRT diagnostics URL format. These constants have been removed from the project.
Delete the NoWarn entry and its comment for CSWINRT3001 from src/WinRT.Runtime2/WinRT.Runtime.csproj so warnings about '[Obsolete]' private implementation details are no longer suppressed. This change surfaces those warnings for visibility during builds.
Delete the NoWarn entry and accompanying comment that suppressed AD0001 analyzer warnings from WinRT.Runtime.csproj. This removes the previous workaround for the ILLink analyzer exception so AD0001 warnings will no longer be globally suppressed; signing and other project settings are unchanged.
Move the concrete implementation of WindowsRuntimeObject into a new partial file (WindowsRuntimeObject.Impl.cs) and make WindowsRuntimeObject a partial/ref-assembly-friendly type. Update WindowsRuntimeObject.cs to conditionally include implementation-only usings under WINDOWS_RUNTIME_REFERENCE_ASSEMBLY. Adjust project file to use WINDOWS_RUNTIME_REFERENCE_ASSEMBLY for reference-assembly builds (replacing REFERENCE_ASSEMBLY in comments and DefineConstants) and remove the earlier DefineConstants injection in the normal build group. Also remove the UnreachableException extension method from WindowsRuntimeExceptionExtensions.cs. These changes prepare the codebase for trimmed/reference assembly builds and separate implementation details from the reference surface.
Replace the hard-coded 'ABI\**\*.cs' removal with a dynamic scan that drops every compile item whose file contains '[WindowsRuntimeImplementationOnlyMember]'. Runs inside a target so MSBuild applies item batching to the '%(FullPath)' metadata access.

Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com>
When building reference assemblies (CsWinRTBuildReferenceAssembly == true), remove all ABI source files from compilation by adding a Compile Remove for ABI\**\*.cs. These ABI types aren't needed in reference assemblies and can contain internal-only types that would be kept otherwise and cause build errors. A clarifying comment was also added to explain the rationale.
…ENTATION_ASSEMBLY

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…public types

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the conditional compilation (#if WINDOWS_RUNTIME_REFERENCE_ASSEMBLY / #endif) around the [SupportedOSPlatform("windows10.0.10240.0")] attribute in AsyncInfo and WindowsRuntimeTaskExtensions so the attribute is always emitted. This ensures these APIs are annotated for Windows platform compatibility even when the WINDOWS_RUNTIME_REFERENCE_ASSEMBLY symbol is not defined.
Surround Windows.Foundation.Metadata and System.Runtime.Versioning using directives with #if WINDOWS_RUNTIME_REFERENCE_ASSEMBLY across many sources so metadata attributes are only included for reference-assembly builds. Add WINDOWS_RUNTIME_IMPLEMENTATION_ASSEMBLY to DefineConstants in the csproj for normal implementation builds to simplify #if logic (and update related comments to reference WINDOWS_RUNTIME_REFERENCE_ASSEMBLY). Also tidy WindowsRuntimeObject by replacing throw null! with throw null.
Define an implementation-only marker in several interop source files and update the project to produce a reference assembly build. Added #define WINDOWS_RUNTIME_IMPLEMENTATION_ONLY_FILE to selected InteropServices files, enabled CsWinRTBuildReferenceAssembly, and added MSBuild rules to exclude files that contain the marker (or the existing [WindowsRuntimeImplementationOnlyMember] attribute), ABI types, and other implementation-only folders from the reference-assembly compile. This provides a simple file-level opt-out for sources that reference internal types so the reference assembly can build cleanly.
Wrap method bodies that reference implementation-only types with #if WINDOWS_RUNTIME_REFERENCE_ASSEMBLY/#else/#endif so the reference assembly build (CsWinRTBuildReferenceAssembly=true) compiles successfully.

Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com>
Mark interop structs with [StructLayout(LayoutKind.Sequential)] to ensure correct memory layout for COM/WinRT interop: ComCallData, HSTRING_HEADER, and its nested union. Add missing System.Runtime.InteropServices using directives. Also disable CS1574 in WindowsRuntimeFeatureSwitches.cs to suppress documentation reference warnings.
Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com>
This diagnostic is no longer applicable now that the private
implementation detail [Obsolete] attributes have been removed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Update copilot-instructions.md and interop-generator SKILL.md to reflect
that private implementation detail types are now excluded from the
reference assembly via #if !REFERENCE_ASSEMBLY, rather than being marked
with [Obsolete] and [EditorBrowsable(Never)] attributes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Expand the version compatibility section to explain how the interop
generator uses WinRT.Runtime's implementation assembly (not the reference
assembly) to access private implementation detail APIs, with concrete
examples of the type categories involved.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Update copilot-instructions.md and the interop-generator and update-copilot-instructions skills to describe the actual mechanism used to build the WinRT.Runtime reference assembly: the WINDOWS_RUNTIME_REFERENCE_ASSEMBLY and WINDOWS_RUNTIME_IMPLEMENTATION_ASSEMBLY define constants, the [WindowsRuntimeImplementationOnlyMember] attribute (which triggers MSBuild file removal), the #define WINDOWS_RUNTIME_IMPLEMENTATION_ONLY_FILE opt-out, and the wholesale folder removals.

Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com>
Add a <Compile Remove> entry to src/WinRT.Runtime2/WinRT.Runtime.csproj to exclude Exceptions/**/*.cs from compilation. This matches other implementation-only folders removed from the project (e.g. ABI, InteropServices) to minimize the number of code changes and reduce the build surface.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adjust conditional compilation and attribute placement for WinRT metadata types. Add conditional import of System.Runtime.Versioning and split ApiContractAttribute between implementation (WindowsRuntimeMetadata) and reference (SupportedOSPlatform + ContractVersion) builds, moving AttributeUsage to a shared location. Do the same reordering for ContractVersionAttribute, and remove redundant remarks comments from FoundationContract and UniversalApiContract to clean up source.
@Sergio0694 Sergio0694 force-pushed the user/sergiopedri/winrt-runtime-ref-assembly2 branch from d83014f to b89f76a Compare April 27, 2026 20:54
Treat [ApiContract] like [ContractVersion] in the metadata attribute filter: only emit it for reference projections and skip it when generating implementation assemblies.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant