Skip to content

Set up dual reference assembly build for WinRT.Runtime#2444

Merged
Sergio0694 merged 7 commits into
staging/winrt-runtime-ref-assemblyfrom
user/sergiopedri/ref-assembly-setup
Jun 17, 2026
Merged

Set up dual reference assembly build for WinRT.Runtime#2444
Sergio0694 merged 7 commits into
staging/winrt-runtime-ref-assemblyfrom
user/sergiopedri/ref-assembly-setup

Conversation

@Sergio0694

Copy link
Copy Markdown
Member

Summary

Set up the dual reference/implementation assembly build for WinRT.Runtime. The normal build produces the full implementation WinRT.Runtime.dll, while an explicit, opt-in build (CsWinRTBuildReferenceAssembly=true) produces a lightweight reference assembly that exposes only the public API surface plus the WinRT metadata that reference projections need.

This is the follow-up to #2434 (which added the [WindowsRuntimeImplementationOnlyMember] marker and explicitly promised this change). A subsequent, final PR will wire this build into the packaging and build infrastructure so the reference assembly is actually produced and shipped.

Motivation

Reference projections compile against a reference assembly for WinRT.Runtime. That reference assembly must expose only the public API surface and the WinRT metadata attributes projections consume (e.g. [ContractVersion], [SupportedOSPlatform]), while completely omitting private implementation-detail types: ABI marshallers, native object wrappers, and the rest of the interop infrastructure.

The SDK-generated reference assembly is not suitable here: it would include those implementation-only types (since WINDOWS_RUNTIME_REFERENCE_ASSEMBLY is not defined in a normal build), leaking abstract members to downstream ProjectReference consumers and breaking reference projections. This PR therefore disables the default SDK reference assembly and introduces a dedicated reference assembly build that strips implementation details at the source level, keeping the public surface identical between the two flavors.

Changes

  • src/WinRT.Runtime2/WinRT.Runtime.csproj: Disable the SDK's default ProduceReferenceAssembly for normal builds and define WINDOWS_RUNTIME_IMPLEMENTATION_ASSEMBLY. When CsWinRTBuildReferenceAssembly=true, define WINDOWS_RUNTIME_REFERENCE_ASSEMBLY, suppress the warnings that are expected only in the reference build (CS8597, IDE0005, IDE0380), and add a BeforeTargets="CoreCompile" target that removes implementation-only sources from the compilation: files opting out via #define WINDOWS_RUNTIME_IMPLEMENTATION_ONLY_FILE, all ABI\** sources, and the implementation-only Exceptions\**, NativeObjects\**, and InteropServices\** subfolders.
  • Compile-time guards across src/WinRT.Runtime2/: Mark implementation-only files with #define WINDOWS_RUNTIME_IMPLEMENTATION_ONLY_FILE; split type attributes so the reference assembly carries the Windows metadata ([ContractVersion], [SupportedOSPlatform]) and the implementation assembly carries the interop/marshalling attributes ([WindowsRuntimeMetadata], [WindowsRuntimeClassName], [WindowsRuntimeReferenceType], [ABI...Marshaller]); replace method bodies with throw null; under WINDOWS_RUNTIME_REFERENCE_ASSEMBLY; and guard the using directives accordingly. This avoids sprinkling thousands of #if-s by combining file-level removal with per-member guards only where needed.
  • src/WinRT.Runtime2/WindowsRuntimeObject.cs and WindowsRuntimeObject.Impl.cs: Make WindowsRuntimeObject partial and move all implementation (caching, dynamic-cast lookup, generated COM vtable handling, QueryInterface logic, activation constructors, and the exceptions helper) into a new WindowsRuntimeObject.Impl.cs, so the implementation can be excluded from the reference assembly while the public surface remains in WindowsRuntimeObject.cs.
  • src/WinRT.Runtime2/NativeObjects/WindowsRuntimeInspectable.cs: Move WindowsRuntimeInspectable into the NativeObjects/ folder (content unchanged) so it is covered by the implementation-only folder removal.
  • src/WinRT.Runtime2/InteropServices/Platform/ComCallData.cs and HSTRING_HEADER.cs: Apply [StructLayout(LayoutKind.Sequential)] (including the _Reserved union) to guarantee the correct native layout for interop.
  • src/WinRT.Runtime2/Properties/WindowsRuntimeFeatureSwitches.cs: Suppress CS1574 (spurious XML-doc cref warning) so the build stays clean.

Validation

Verified locally that both flavors build and that the reference assembly is correctly stripped:

  • Implementation build (default) and reference build (CsWinRTBuildReferenceAssembly=true) both compile cleanly.
  • Implementation-only types (WindowsRuntimeDllModule, TaskAdapter, WindowsRuntimeInspectable, PointComWrappersMarshaller, IListAdapter, ABI marshallers) are present in the implementation .dll but absent from the reference .dll.
  • Public-surface types (WindowsRuntimeObject, IAsyncAction, Point, AsyncStatus) are present in both, confirming the public API is unchanged.
  • The reference .dll is substantially smaller than the implementation .dll (roughly 150 KB vs 800 KB).

Sergio0694 and others added 7 commits June 17, 2026 08:54
Prevent the SDK-produced reference assembly from leaking implementation-only types by customizing the ref-assembly build. When not building the explicit CsWinRT reference assembly, ProduceReferenceAssembly is disabled and WINDOWS_RUNTIME_IMPLEMENTATION_ASSEMBLY is defined to simplify #if usage. When CsWinRTBuildReferenceAssembly is true, WINDOWS_RUNTIME_REFERENCE_ASSEMBLY is defined and expected warnings (CS8597, IDE0005, IDE0380) are suppressed. A BeforeTargets CoreCompile target removes files that opt out of reference assemblies (via WINDOWS_RUNTIME_IMPLEMENTATION_ONLY_FILE), ABI sources, and several implementation-only folders so the packaged reference assembly omits private implementation details.
Wrap Windows runtime metadata and platform/contract attributes with build-time symbols to differentiate reference vs implementation assemblies. Many files now conditionally include Windows.Foundation.Metadata usings and apply [ContractVersion]/[SupportedOSPlatform] for WINDOWS_RUNTIME_REFERENCE_ASSEMBLY and [WindowsRuntimeMetadata]/[WindowsRuntimeClassName]/marshalling attributes for WINDOWS_RUNTIME_IMPLEMENTATION_ASSEMBLY. Removed unconditional SupportedOSPlatform/usings where appropriate and added #if guards across foundation, collections, streams, async adapters and task/asyncinfo helpers to allow building both reference and implementation variants.

Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com>
Suppress CS1574 (XML doc 'cref' not found) warnings in WindowsRuntimeFeatureSwitches.cs by adding `#pragma warning disable CS1574` before the namespace declaration. This prevents spurious documentation warnings during the build, likely caused by cref references to internal or conditional types.
Rename/move WindowsRuntimeInspectable.cs from src/WinRT.Runtime2/ to src/WinRT.Runtime2/NativeObjects/ to reorganize project structure. File content unchanged (100% similarity).
Move the core implementation into a new partial file (src/WinRT.Runtime2/WindowsRuntimeObject.Impl.cs) and make WindowsRuntimeObject partial. The impl file contains caching, dynamic cast lookup, generated COM vtable handling, QueryInterface logic, activation constructors and an exceptions helper; redundant usings/implementation were removed from WindowsRuntimeObject.cs to keep the public surface unchanged.
Introduce compile-time guards to separate reference and implementation builds. Many files were marked as implementation-only by adding a WINDOWS_RUNTIME_IMPLEMENTATION_ONLY_FILE define; APIs and method bodies were wrapped with WINDOWS_RUNTIME_REFERENCE_ASSEMBLY / WINDOWS_RUNTIME_IMPLEMENTATION_ASSEMBLY conditionals (throw null in reference builds, real code in implementation builds). Adjustments touch attributes, interop/activation, marshalling, async helpers, buffer/stream utilities, and WindowsRuntimeMarshal/RestrictedErrorInfo/RestrictedErrorInfoExceptionMarshaller. Also updated the project file to exclude the Marshalling folder from the reference build. This enables producing lightweight reference assemblies while keeping full implementations in the implementation assembly.
…untime

Replace the plain #else branch following #if WINDOWS_RUNTIME_REFERENCE_ASSEMBLY
with an explicit #elif WINDOWS_RUNTIME_IMPLEMENTATION_ASSEMBLY for clarity. The
two constants are mutually exclusive and exhaustive, so the behavior is
unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Sergio0694 Sergio0694 force-pushed the user/sergiopedri/ref-assembly-setup branch from 8d17cee to a27b766 Compare June 17, 2026 16:17
@Sergio0694 Sergio0694 marked this pull request as ready for review June 17, 2026 16:17
@Sergio0694 Sergio0694 merged commit 2394cbf into staging/winrt-runtime-ref-assembly Jun 17, 2026
11 checks passed
@Sergio0694 Sergio0694 deleted the user/sergiopedri/ref-assembly-setup branch June 17, 2026 18:58
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.

2 participants