Skip to content

Carry over all applications of repeated Windows Runtime attributes - #2493

Merged
Sergio Pedri (Sergio0694) merged 2 commits into
staging/3.0from
user/sergiopedri/fix-repeated-winrt-attributes
Jul 31, 2026
Merged

Sergio Pedri (Sergio0694) merged 2 commits into
staging/3.0from
user/sergiopedri/fix-repeated-winrt-attributes

Conversation

@Sergio0694

Copy link
Copy Markdown
Member

Summary

Fixes #2491: when a Windows Runtime type carries the same [allowmultiple] attribute more than once, the projection only kept one of the applications. All applications are now carried over.

Motivation

CustomAttributeFactory.WriteCustomAttributes accumulated the attributes to carry over into a Dictionary<string, List<string>> keyed by the projected attribute's full name, and assigned with attributes[fullAttrName] = args. Windows Runtime attributes marked [allowmultiple] (for instance [TemplateVisualState]) can legitimately be applied several times to the same type, so every application after the first silently overwrote the previous one and was lost from the generated projection.

The issue report shows this with a control declaring eight [TemplateVisualState] attributes in its .idl: the .winmd contains all eight, but the generated C# only carries a single one.

Two adjacent problems in the same method are fixed at the same time:

  • Several [ContractVersion] attributes merged their computed platform strings into the argument list of a single [SupportedOSPlatform], which is not a valid constructor shape. Only the first resolved platform is emitted now, which matches the pre-existing member-level behavior in WritePlatformAttributeBody.

  • The Windows Runtime [AllowMultiple] metadata attribute has no .NET counterpart: it maps to the AllowMultiple named argument of [AttributeUsage] on the projected attribute type. That mapping only happened when the metadata also carried an [AttributeUsage]. When it didn't, the projected attribute type silently fell back to the .NET default of AllowMultiple = false and could not be applied more than once. An [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] is now synthesized in that case.

Changes

  • src/WinRT.Projection.Writer/Factories/CustomAttributeFactory.cs: collect the carried-over attributes into an ordered list with one entry per application instead of a dictionary keyed by attribute name, so repeated applications are all emitted; emit at most one [SupportedOSPlatform]; synthesize an [AttributeUsage] when the metadata only carries [AllowMultiple].

  • src/Tests/TestComponentCSharp/TestComponentCSharp.idl: add an [allowmultiple] attribute (MyRepeatableAttribute, attr_repeatable) and a RepeatedAttributeTest runtime class carrying several of its applications, interleaved with a non-repeatable attribute, plus one exact-duplicate application (MIDL accepts those for repeatable attributes, and reflection reports both).

  • src/Tests/UnitTest/TestComponentCSharp_Tests.cs: add TestRepeatedAttributesAreProjected, verifying every application survives the projection with the right arguments and that a non-repeatable attribute is still projected exactly once, and TestAllowMultipleIsProjectedOnAttributeUsage, verifying the [AllowMultiple] to AttributeUsage(AllowMultiple = ...) mapping in both directions.

Validation

  • Ran cswinrtprojectionrefgen over the entire Windows SDK (reference projection and merged projection modes) and over the full WinUI surface, before and after the change: the generated sources are byte-identical, so no existing projection is affected.

  • Built TestComponentCSharp.winmd with MIDL from the new .idl and projected it before and after: the only difference is the newly preserved attribute applications.

  • Verified against MIDL that duplicated applications of a non-repeatable attribute are rejected (MIDL2096) while duplicated applications of an [allowmultiple] attribute are accepted and preserved in the .winmd, so the emission is intentionally faithful rather than de-duplicating.

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

@Sergio0694 Sergio Pedri (Sergio0694) added the bug Something isn't working label Jul 28, 2026
@Sergio0694
Sergio Pedri (Sergio0694) force-pushed the user/sergiopedri/fix-repeated-winrt-attributes branch from 7cd8a0c to 0111192 Compare July 29, 2026 00:56
@Sergio0694
Sergio Pedri (Sergio0694) force-pushed the user/sergiopedri/fix-repeated-winrt-attributes branch 2 times, most recently from a0d02ff to 5ca1f3e Compare July 29, 2026 05:20
@Sergio0694
Sergio Pedri (Sergio0694) changed the base branch from staging/3.0 to user/sergiopedri/erase-winrt-attribute-generics July 29, 2026 05:27
@Sergio0694
Sergio Pedri (Sergio0694) force-pushed the user/sergiopedri/fix-repeated-winrt-attributes branch 3 times, most recently from 33afe82 to ed02190 Compare July 29, 2026 17:10
@Sergio0694
Sergio Pedri (Sergio0694) force-pushed the user/sergiopedri/fix-repeated-winrt-attributes branch from ed02190 to 642181e Compare July 29, 2026 17:47
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

@Sergio0694
Sergio Pedri (Sergio0694) force-pushed the user/sergiopedri/fix-repeated-winrt-attributes branch from 48d5a58 to 5e398cc Compare July 29, 2026 20:27
@Sergio0694
Sergio Pedri (Sergio0694) force-pushed the user/sergiopedri/fix-repeated-winrt-attributes branch from 5e398cc to 1722df3 Compare July 29, 2026 22:35
Base automatically changed from user/sergiopedri/erase-winrt-attribute-generics to staging/3.0 July 31, 2026 18:27
'CustomAttributeFactory.WriteCustomAttributes' accumulated the attributes to
carry over into a dictionary keyed by the projected attribute name, so when a
Windows Runtime type carried the same '[allowmultiple]' attribute more than
once (e.g. several '[TemplateVisualState]' applications on a control), every
application except the last was silently dropped from the projection.

The attributes are now collected into an ordered list with one entry per
application, so all of them are emitted. Also fixes a latent issue in the same
method where several '[ContractVersion]' attributes would merge their platform
strings into the argument list of a single '[SupportedOSPlatform]', which is
not a valid constructor shape: only the first resolved platform is emitted now,
matching the existing member-level behavior in 'WritePlatformAttributeBody'.

Additionally, the Windows Runtime '[AllowMultiple]' to .NET
'AttributeUsage(AllowMultiple = true)' mapping now also applies when the
metadata carries no '[AttributeUsage]', by synthesizing one. Otherwise the
projected attribute type would silently fall back to the .NET default of
'AllowMultiple = false' and could not be applied more than once.

Fixes #2491

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 37dfc23a-6ce8-4c65-a890-5ca8ff319f27
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 37dfc23a-6ce8-4c65-a890-5ca8ff319f27
@Sergio0694
Sergio Pedri (Sergio0694) force-pushed the user/sergiopedri/fix-repeated-winrt-attributes branch from 1722df3 to b6e3e79 Compare July 31, 2026 18:27
@Sergio0694
Sergio Pedri (Sergio0694) merged commit 41f7ce9 into staging/3.0 Jul 31, 2026
13 checks passed
@Sergio0694
Sergio Pedri (Sergio0694) deleted the user/sergiopedri/fix-repeated-winrt-attributes branch July 31, 2026 21:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working CsWinRT 3.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: CsWinRT only projects one instance of repeated WinRT attributes

2 participants