Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
abe3808
Add WindowsRuntimeImplementationOnlyMemberAttribute
Sergio0694 Apr 16, 2026
f29f9a7
Use [WindowsRuntimeImplementationOnlyMember] for implementation-only …
Sergio0694 Apr 16, 2026
cd74794
Remove WindowsRuntimeConstants.cs
Sergio0694 Apr 16, 2026
91328fa
Remove CSWINRT3001 NoWarn suppression
Sergio0694 Apr 16, 2026
8d28af0
Remove AD0001 NoWarn workaround
Sergio0694 Apr 16, 2026
0263523
Update WinRT.Runtime.csproj
Sergio0694 Apr 16, 2026
e868734
Split WindowsRuntimeObject into partial class
Sergio0694 Apr 16, 2026
07d8731
Remove impl-only files from ref assembly build via attribute scan
Sergio0694 Apr 16, 2026
e74cd26
Exclude ABI types from reference assemblies
Sergio0694 Apr 17, 2026
3d44e59
Guard attribute usages of impl-only types with WINDOWS_RUNTIME_IMPLEM…
Sergio0694 Apr 17, 2026
d21d0b4
Strip SupportedOSPlatform and ContractVersion from impl assembly for …
Sergio0694 Apr 17, 2026
a70b56b
Unconditionally apply SupportedOSPlatform attribute
Sergio0694 Apr 17, 2026
0fad3cd
Conditional metadata imports and define impl constant
Sergio0694 Apr 17, 2026
28f5e6b
Add implementation-only marker and exclusions
Sergio0694 Apr 17, 2026
a480741
Stub method bodies in reference assembly with throw null
Sergio0694 Apr 17, 2026
cd73893
Add StructLayout attributes and suppress CS1574
Sergio0694 Apr 17, 2026
5d14c7b
Update WinRT.Runtime for ref assemblies
Sergio0694 Mar 30, 2026
67eb3aa
Delete CSWINRT3001 diagnostic documentation
Sergio0694 Mar 30, 2026
a900468
Update instructions for reference assembly approach
Sergio0694 Mar 30, 2026
20dfdd5
Document private implementation detail APIs in interop generator skill
Sergio0694 Mar 30, 2026
3117942
Correct reference assembly mechanism in skills/instructions
Sergio0694 Apr 17, 2026
53882f0
Exclude Exceptions folder from build
Sergio0694 Apr 19, 2026
5b1a7f7
Strip WindowsRuntimeClassName attribute from reference assembly
Sergio0694 Apr 19, 2026
cd0ece8
Merge adjacent ifdef blocks where attribute order is preserved
Sergio0694 Apr 19, 2026
fe5967e
Put REFERENCE_ASSEMBLY branch first in conditional attribute blocks
Sergio0694 Apr 19, 2026
eebe557
Put [Guid] attribute first on interfaces and merge ifdef blocks
Sergio0694 Apr 19, 2026
3e1cd18
Refactor WinRT metadata attributes and conditionals
Sergio0694 Apr 27, 2026
7d6eff3
Skip emitting [ApiContract] attribute for implementation assemblies
Sergio0694 Apr 27, 2026
1f1f78d
Update CSWinMDComponent.vcxproj.filters
Sergio0694 Jun 11, 2026
f5b928c
Enforce banned-API checks for reference assembly
Sergio0694 Jun 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ The runtime library (`WinRT.Runtime.dll`) provides all common infrastructure for
- **Warnings as errors**: release only. `EnforceCodeStyleInBuild` enabled, `AnalysisLevelStyle` = `latest-all`.
- **Strong-name signed** with `key.snk`
- **AOT compatible**: `IsAotCompatible = true`
- **Reference assembly**: the project is built twice for NuGet packaging. With `CsWinRTBuildReferenceAssembly=true`, it produces a reference assembly (for `ref\net10.0\` in the NuGet) that strips all private implementation detail types and members. The normal build produces the full implementation assembly (for `lib\net10.0\`) and defines `WINDOWS_RUNTIME_IMPLEMENTATION_ASSEMBLY`; the reference assembly build defines `WINDOWS_RUNTIME_REFERENCE_ASSEMBLY` instead. Stripping is driven primarily by the `[WindowsRuntimeImplementationOnlyMember]` attribute (a `[Conditional("WINDOWS_RUNTIME_REFERENCE_ASSEMBLY")]` marker on top-level types) plus an MSBuild target that removes any source file containing that attribute, any file with a top-of-file `#define WINDOWS_RUNTIME_IMPLEMENTATION_ONLY_FILE`, and entire implementation-only folders (e.g. `ABI\`, `NativeObjects\`, most `InteropServices\` subfolders). Method bodies remaining in the reference assembly are stubbed with `throw null`. This replaces the previous approach of marking implementation details with `[Obsolete]` and `[EditorBrowsable(Never)]` attributes.

**Directory structure:**

Expand Down Expand Up @@ -554,7 +555,7 @@ The MSBuild integration is orchestrated through several `.props` and `.targets`
- **Compiler strict mode**: `<Features>strict</Features>` in all projects
- **XML documentation**: generated for all projects
- **`SkipLocalsInit`**: enabled in runtime and build tools for performance
- **Suppressed warnings**: `CS8500` (ref safety in unsafe contexts), `AD0001` (analyzer crashes), `CSWINRT3001` (obsolete internal members)
- **Suppressed warnings**: `CS8500` (ref safety in unsafe contexts), `AD0001` (analyzer crashes)
- **Strong-name signing**: all assemblies signed with `src/WinRT.Runtime2/key.snk`

### C++ project (cswinrt)
Expand Down Expand Up @@ -597,7 +598,6 @@ All four .NET build tools (`cswinrtimplgen`, `cswinrtprojectiongen`, `cswinrtint
| Projection Generator | `CSWINRTPROJECTIONGENxxxx` | `0001`–`0008`, `9999` |
| Interop Generator | `CSWINRTINTEROPGENxxxx` | Various, `9999` |
| WinMD Generator | `CSWINRTWINMDGENxxxx` | `0001`–`0007` |
| Runtime (obsolete markers) | `CSWINRT3xxx` | `CSWINRT3001` |

---

Expand Down
19 changes: 18 additions & 1 deletion .github/skills/interop-generator/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,24 @@ The `WinRT.Interop.dll` assembly is produced by `cswinrtinteropgen`, which is a
- If a project **does not** reference CsWinRT, then `cswinrtinteropgen` is loaded from the Windows SDK projections targeting pack.
- If CsWinRT **is** referenced (directly or transitively), then `cswinrtinteropgen` is loaded from that package, but only if the `WinRT.Runtime.dll` binary from that package has a higher version than the one in the Windows SDK projections package being referenced. This correctly handles cases where a dependent project might have a reference to an outdated CsWinRT package.

This version matching is critical because `cswinrtinteropgen` relies on "implementation details only" APIs in `WinRT.Runtime.dll` — APIs which are public, hidden, and marked as `[Obsolete]`, and which are exclusively meant to be consumed by generated code produced by `cswinrtinteropgen`. These APIs might change at any time without following semantic versioning for CsWinRT. For instance, they are crucial to support marshalling generic Windows Runtime collection interfaces, and the code in `WinRT.Interop.dll` makes heavy use of them in this scenario.
This version matching is critical because `cswinrtinteropgen` relies on internal implementation detail APIs in `WinRT.Runtime.dll` — APIs which are public in the implementation assembly but excluded from the reference assembly (via the `[WindowsRuntimeImplementationOnlyMember]` attribute and related MSBuild stripping, controlled by the `WINDOWS_RUNTIME_REFERENCE_ASSEMBLY` / `WINDOWS_RUNTIME_IMPLEMENTATION_ASSEMBLY` define constants), and which are exclusively meant to be consumed by generated code produced by `cswinrtinteropgen`. These APIs might change at any time without following semantic versioning for CsWinRT. For instance, they are crucial to support marshalling generic Windows Runtime collection interfaces, and the code in `WinRT.Interop.dll` makes heavy use of them in this scenario.

### Private implementation detail APIs

`WinRT.Runtime.dll` is shipped as two assemblies in the CsWinRT NuGet package: a **reference assembly** (in `ref\net10.0\`) that exposes only the versioned public API surface, and an **implementation assembly** (in `lib\net10.0\`) that contains the full set of types and members. Many types in the implementation assembly are "public" only because generated code in other assemblies (produced by `cswinrt.exe` and `cswinrtinteropgen`) needs to call them — they are not part of the stable API contract. These types are stripped from the reference assembly via the `[WindowsRuntimeImplementationOnlyMember]` attribute (a `[Conditional("WINDOWS_RUNTIME_REFERENCE_ASSEMBLY")]` marker that triggers an MSBuild target to remove the entire source file), an opt-in `#define WINDOWS_RUNTIME_IMPLEMENTATION_ONLY_FILE` directive at the top of a source file, or wholesale folder removals (e.g. `ABI\`, `NativeObjects\`, most `InteropServices\` subfolders), so consumers never see them. Method bodies that remain in the reference assembly are stubbed with `throw null`.

The interop generator receives a reference to the **implementation** `WinRT.Runtime.dll` (not the reference assembly) so that it can resolve and emit calls to these internal APIs. Examples of private implementation detail types that the interop generator uses heavily include:

- **Vtable structs** (`IVectorVftbl`, `IMapVftbl`, `IIterableVftbl`, etc.) — the interop generator emits static readonly vtable fields for each projected interface, populated with function pointers to marshalling stubs.
- **Collection adapters and methods** (`IListAdapter<T>`, `IDictionaryMethods<TKey, TValue>`, `IEnumerableMethods<T>`, etc.) — generated native object wrappers delegate collection operations to these adapter types.
- **Marshalling infrastructure** (`WindowsRuntimeObjectMarshaller`, `HStringMarshaller`, `WindowsRuntimeInterfaceMarshaller<T>`, array marshallers, etc.) — generated marshalling stubs call these to convert between managed and native representations.
- **Object reference types** (`WindowsRuntimeObjectReference`, `WindowsRuntimeObjectReferenceValue`, `CreateObjectReferenceMarshalingType`) — generated code uses these for COM pointer lifecycle management.
- **ComWrappers callbacks** (`IWindowsRuntimeObjectComWrappersCallback`, `WindowsRuntimeComWrappersMarshal`) — generated CCW vtable entries and type map registrations use these.
- **Type map groups** (`WindowsRuntimeComWrappersTypeMapGroup`, `WindowsRuntimeMetadataTypeMapGroup`, `DynamicInterfaceCastableImplementationTypeMapGroup`) — generated type map registrations target these groups.
- **Projection implementations** (`IPropertyValueImpl`, `IStringableImpl`, `IMarshalImpl`, etc.) — generated code wires up these implementations in CCW vtables.
- **ABI types** (under `ABI.*` namespaces) — per-type marshalling definitions and event source types.

All of these types are referenced extensively throughout the interop generator's builder and factory classes (in `Builders/` and `Factories/`). When modifying these types in `WinRT.Runtime`, the corresponding interop generator code must be updated in lockstep — which is why the version matching described above is essential.

## Project settings

Expand Down
1 change: 1 addition & 0 deletions .github/skills/update-copilot-instructions/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Launch parallel explore agents for each of the 8 CsWinRT 3.0 projects listed in
- Key types listed still exist and have the described purposes
- T4 templates (`.tt` files) are accurately listed
- Project settings (TFM, language version, nullable, unsafe, etc.) are current
- Reference assembly build setup (`CsWinRTBuildReferenceAssembly`, `WINDOWS_RUNTIME_REFERENCE_ASSEMBLY` / `WINDOWS_RUNTIME_IMPLEMENTATION_ASSEMBLY` defines, `[WindowsRuntimeImplementationOnlyMember]` attribute, `#define WINDOWS_RUNTIME_IMPLEMENTATION_ONLY_FILE` opt-out) is accurately described
- Namespace organization matches

2. **WinRT.SourceGenerator2 (`src/Authoring/WinRT.SourceGenerator2/`)**
Expand Down
19 changes: 19 additions & 0 deletions build/AzurePipelineTemplates/CsWinRT-Build-Steps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,25 @@ steps:
WinRT.Runtime.xml
TargetFolder: $(StagingFolder)\net10.0

# Build WinRT.Runtime reference assembly with implementation detail types stripped out
- task: VSBuild@1
displayName: Build WinRT.Runtime reference assembly
condition: and(succeeded(), eq(variables['BuildPlatform'], 'x86'), eq(variables['BuildConfiguration'], 'release'))
inputs:
solution: $(Build.SourcesDirectory)\src\WinRT.Runtime2\WinRT.Runtime.csproj
msbuildArgs: /p:VersionNumber=$(VersionNumber),VersionString=$(Build.BuildNumber),AssemblyVersionNumber=$(WinRT.Runtime.AssemblyVersion),CsWinRTBuildReferenceAssembly=true,ContinuousIntegrationBuild=true
platform: $(BuildPlatform)
configuration: $(BuildConfiguration)

# Stage WinRT.Runtime reference assembly
- task: CopyFiles@2
displayName: Stage WinRT.Runtime reference assembly
condition: and(succeeded(), eq(variables['BuildPlatform'], 'x86'), eq(variables['BuildConfiguration'], 'release'))
inputs:
SourceFolder: $(Build.SourcesDirectory)\src\WinRT.Runtime2\obj\$(BuildPlatform)\$(BuildConfiguration)\net10.0\ref
Contents: WinRT.Runtime.dll
TargetFolder: $(StagingFolder)\net10.0\ref

# Stage WinRT.Host.Shim
- task: CopyFiles@2
displayName: Stage WinRT.Host.Shim
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ steps:
command: pack
searchPatternPack: nuget/Microsoft.Windows.CsWinRT.nuspec
configurationToPack: Release
buildProperties: cswinrt_nuget_version=$(NugetVersion);cswinrt_exe=$(Build.SourcesDirectory)\release_x86\native\cswinrt.exe;interop_winmd=$(Build.SourcesDirectory)\release_x86\native\WindowsRuntime.Internal.winmd;net10_runtime=$(Build.SourcesDirectory)\release_x86\net10.0\WinRT.Runtime.dll;net10_runtime_xml=$(Build.SourcesDirectory)\release_x86\net10.0\WinRT.Runtime.xml;source_generator=$(Build.SourcesDirectory)\release_x86\net10.0\WinRT.SourceGenerator.dll;winrt_shim=$(Build.SourcesDirectory)\release_x86\net10.0\WinRT.Host.Shim.dll;winrt_host_x86=$(Build.SourcesDirectory)\release_x86\native\WinRT.Host.dll;winrt_host_x64=$(Build.SourcesDirectory)\release_x64\native\WinRT.Host.dll;winrt_host_arm64=$(Build.SourcesDirectory)\release_arm64\native\WinRT.Host.dll;winrt_host_resource_x86=$(Build.SourcesDirectory)\release_x86\native\WinRT.Host.dll.mui;winrt_host_resource_x64=$(Build.SourcesDirectory)\release_x64\native\WinRT.Host.dll.mui;winrt_host_resource_arm64=$(Build.SourcesDirectory)\release_arm64\native\WinRT.Host.dll.mui;cswinrtinteropgen_x64=$(Build.SourcesDirectory)\release_x64\net10.0\native\cswinrtinteropgen.exe;cswinrtinteropgen_arm64=$(Build.SourcesDirectory)\release_arm64\net10.0\native\cswinrtinteropgen.exe;cswinrtimplgen_x64=$(Build.SourcesDirectory)\release_x64\net10.0\native\cswinrtimplgen.exe;cswinrtimplgen_arm64=$(Build.SourcesDirectory)\release_arm64\net10.0\native\cswinrtimplgen.exe;cswinrtprojectiongen_x64=$(Build.SourcesDirectory)\release_x64\net10.0\native\cswinrtprojectiongen.exe;cswinrtprojectiongen_arm64=$(Build.SourcesDirectory)\release_arm64\net10.0\native\cswinrtprojectiongen.exe;run_cswinrt_generator_task=$(Build.SourcesDirectory)\release_x86\netstandard2.0\WinRT.Generator.Tasks.dll;branch=$(Build.SourceBranchName);commit=$(Build.SourceVersion)
buildProperties: cswinrt_nuget_version=$(NugetVersion);cswinrt_exe=$(Build.SourcesDirectory)\release_x86\native\cswinrt.exe;interop_winmd=$(Build.SourcesDirectory)\release_x86\native\WindowsRuntime.Internal.winmd;net10_runtime=$(Build.SourcesDirectory)\release_x86\net10.0\WinRT.Runtime.dll;net10_runtime_xml=$(Build.SourcesDirectory)\release_x86\net10.0\WinRT.Runtime.xml;net10_runtime_ref=$(Build.SourcesDirectory)\release_x86\net10.0\ref\WinRT.Runtime.dll;source_generator=$(Build.SourcesDirectory)\release_x86\net10.0\WinRT.SourceGenerator.dll;winrt_shim=$(Build.SourcesDirectory)\release_x86\net10.0\WinRT.Host.Shim.dll;winrt_host_x86=$(Build.SourcesDirectory)\release_x86\native\WinRT.Host.dll;winrt_host_x64=$(Build.SourcesDirectory)\release_x64\native\WinRT.Host.dll;winrt_host_arm64=$(Build.SourcesDirectory)\release_arm64\native\WinRT.Host.dll;winrt_host_resource_x86=$(Build.SourcesDirectory)\release_x86\native\WinRT.Host.dll.mui;winrt_host_resource_x64=$(Build.SourcesDirectory)\release_x64\native\WinRT.Host.dll.mui;winrt_host_resource_arm64=$(Build.SourcesDirectory)\release_arm64\native\WinRT.Host.dll.mui;cswinrtinteropgen_x64=$(Build.SourcesDirectory)\release_x64\net10.0\native\cswinrtinteropgen.exe;cswinrtinteropgen_arm64=$(Build.SourcesDirectory)\release_arm64\net10.0\native\cswinrtinteropgen.exe;cswinrtimplgen_x64=$(Build.SourcesDirectory)\release_x64\net10.0\native\cswinrtimplgen.exe;cswinrtimplgen_arm64=$(Build.SourcesDirectory)\release_arm64\net10.0\native\cswinrtimplgen.exe;cswinrtprojectiongen_x64=$(Build.SourcesDirectory)\release_x64\net10.0\native\cswinrtprojectiongen.exe;cswinrtprojectiongen_arm64=$(Build.SourcesDirectory)\release_arm64\net10.0\native\cswinrtprojectiongen.exe;run_cswinrt_generator_task=$(Build.SourcesDirectory)\release_x86\netstandard2.0\WinRT.Generator.Tasks.dll;branch=$(Build.SourceBranchName);commit=$(Build.SourceVersion)
packDestination: $(ob_outputDirectory)\packages

- task: NuGetCommand@2
Expand Down
34 changes: 0 additions & 34 deletions docs/diagnostics/cswinrt30001.md

This file was deleted.

1 change: 1 addition & 0 deletions nuget/Microsoft.Windows.CsWinRT.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
<file src="readme.txt"/>
<file src="$net10_runtime$" target="lib\net10.0\"/>
<file src="$net10_runtime_xml$" target="lib\net10.0\"/>
<file src="$net10_runtime_ref$" target="ref\net10.0\"/>
<file src="$source_generator$" target="analyzers\dotnet\cs\"/>
<file src="$winrt_host_x64$" target ="hosting\x64\native"/>
<file src="$winrt_host_x86$" target ="hosting\x86\native"/>
Expand Down
1 change: 1 addition & 0 deletions src/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<PackageVersion Include="coverlet.collector" Version="1.3.0" />
<PackageVersion Include="MarkdownLog.NS20" Version="0.10.1" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="4.14.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Common" Version="5.0.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="5.0.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Analyzer.Testing" Version="1.1.2" />
Expand Down
32 changes: 0 additions & 32 deletions src/Tests/CSWinMDComponent/CSWinMDComponent.vcxproj.filters

This file was deleted.

8 changes: 2 additions & 6 deletions src/WinRT.Runtime2/ABI/System/Boolean.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Licensed under the MIT License.

using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Windows.Foundation;
Expand Down Expand Up @@ -43,10 +42,7 @@ namespace ABI.System;
/// <summary>
/// Marshaller for <see cref="bool"/>.
/// </summary>
[Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage,
DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId,
UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)]
[EditorBrowsable(EditorBrowsableState.Never)]
[WindowsRuntimeImplementationOnlyMember]
public static unsafe class BooleanMarshaller
{
/// <inheritdoc cref="WindowsRuntimeValueTypeMarshaller.BoxToUnmanaged{T}(T?, CreateComInterfaceFlags, in Guid)"/>
Expand Down Expand Up @@ -288,4 +284,4 @@ private static HRESULT get_Type(void* thisPtr, PropertyType* value)

return WellKnownErrorCodes.S_OK;
}
}
}
Loading
Loading