Add opt-in CCW marshalling for projected Windows Runtime types#2481
Draft
Sergio0694 wants to merge 8 commits into
Draft
Add opt-in CCW marshalling for projected Windows Runtime types#2481Sergio0694 wants to merge 8 commits into
Sergio0694 wants to merge 8 commits into
Conversation
Add a public assembly-level attribute in the WindowsRuntime.InteropServices namespace that lets developers explicitly opt a projected Windows Runtime class type into CCW marshalling code generation, which the interop generator normally skips for projected types. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
… generator Discover '[assembly: WindowsRuntimeNativeExposedType(typeof(X))]' attributes and route the referenced types through the user-defined type CCW pipeline, bypassing the check that normally skips projected Windows Runtime types. All other discovery filters still apply, so opting in a type that does not need CCW support is a safe no-op. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Add three warning diagnostics (CSWINRT2018, CSWINRT2019, CSWINRT2020) reported by a new 'WindowsRuntimeNativeExposedTypeAnalyzer'. CSWINRT2018 warns when the target type cannot be instantiated (interfaces, abstract or static classes, and generic type definitions), CSWINRT2019 warns when the target type is not a projected Windows Runtime class (for which CCW marshalling code is already generated automatically), and CSWINRT2020 warns when the same type is targeted by more than one application of the attribute in the assembly. Applications in generated code are excluded from the diagnostics, so that a duplicate spanning user code and generated code only warns on the user application. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Add unit tests covering all three diagnostics (CSWINRT2018/2019/2020) for the 'WindowsRuntimeNativeExposedTypeAnalyzer', including valid projected class usage, non-instantiable and non-projected-class targets, duplicate applications, and suppression of diagnostics for applications that appear in generated code. Extend the analyzer test helper to allow adding an additional generated source file, so the generated-code suppression behavior can be validated. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…ted types When the interop generator generates CCW marshalling code for a projected type opted in via '[WindowsRuntimeNativeExposedType]', the type's vtable set includes the manually-projected 'IStringable' interface, which every projected Windows Runtime class implements. Resolving its interface entry routes through 'WellKnownInterfaceIIDs.get_IID', which was missing a case for 'IStringable' and so threw CSWINRTINTEROPGEN0052. This path was never reached before, because managed user-defined types use the built-in 'IStringable' native entry instead of carrying the projected interface in their vtable set. Add the missing case so that CCW code can be generated for projected types. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Add a 'NativeExposedType' functional test and a 'NativeExposedTypeTests' unit test that opt a projected type into CCW marshalling code generation via '[WindowsRuntimeNativeExposedType]' and assert that the interop generator registered a proxy type map association for it, while a projected type that was not opted in has no such association. The functional test is a self-contained executable that runs in both JIT and Native AOT, and is wired into 'cswinrt.slnx' and the functional test list in 'build.cmd'. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Enhance debugging info and error handling for WindowsRuntimeComWrappers marshalling. - Include the runtime attribute type in NotSupportedException messages for GetOrCreateComInterfaceForObject and CreateObject to make failures easier to diagnose. - Change ComputeVtables to return null (with count=0) when not overridden; WindowsRuntimeMarshallingInfo now detects null vtable entries and throws a detailed NotSupportedException that includes the marshaller type and metadata provider type, and guidance for enabling marshalling or filing an issue. - Add pragma to suppress IDE0046 alongside IDE0008. This improves developer diagnostics when custom marshallers are incomplete. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Refactor WindowsRuntimeNativeExposedTypeAnalyzer: initialize validTargetTypes correctly, enumerate assembly attributes via context.Compilation, simplify Classify return logic (explicit guard + valid return), and relax CountOccurrences to accept IEnumerable<ITypeSymbol>. Also remove IDE0046 from WindowsRuntimeMarshallingInfo pragma disables. These edits improve clarity, correctness of attribute enumeration, and reduce unnecessary suppressed warnings.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Introduce a new
WindowsRuntimeNativeExposedTypeAttributethat lets a projected Windows Runtime class be explicitly opted into CCW (COM Callable Wrapper) marshalling code generation, which the interop generator normally skips for projected types. The PR adds interop generator support, three analyzer diagnostics, unit and functional (JIT and Native AOT) test coverage, and improved marshalling failure diagnostics.Motivation
The interop generator automatically generates CCW marshalling code for all managed types that implement one or more Windows Runtime interfaces. Projected Windows Runtime types are deliberately skipped, because they are backed by native objects and are marshalled by unwrapping the underlying native object directly, so they never normally require a CCW. There are, however, niche scenarios where a CCW is required for a projected type, and there was previously no way to request one.
The motivating scenario is using a projected collection type as the items source for a XAML control. Consider a
DependencyObjectCollectionassigned as the items source of anItemsControl. The control queries the assigned object (marshalled as anIInspectable) forIBindableIterableandIIterable<IInspectable>. This succeeds for most collection types, butDependencyObjectCollectionimplements neither of those interfaces: it implementsIIterable<DependencyObject>, and Windows Runtime generic interfaces are not covariant on the native side (each generic instantiation has a completely different IID). To handle this, XAML controls fall back to obtaining a CCW from the source object and querying that instead. The .NET runtime creates an RCW for the native object and usesComWrappersto obtain a CCW proxy over it; because the RCW implementsIEnumerable<DependencyObject>, which is covariant in C#, the query forIIterable<IInspectable>then succeeds through the proxy. This requires a CCW vtable to exist for the projected type, which the interop generator would not normally generate. The new attribute makes it possible to request exactly that.Changes
src/WinRT.Runtime2/InteropServices/Attributes/WindowsRuntimeNativeExposedTypeAttribute.cs: new public, assembly-level attribute (AllowMultiple) that opts a projected Windows Runtime class into CCW marshalling code generation, with detailed documentation of the motivating scenario.src/WinRT.Interop.Generator/(Discovery/InteropTypeDiscovery.cs,Generation/InteropGenerator.Discover.cs,References/InteropReferences.cs,Errors/WellKnownInteropExceptions.cs): discover[assembly: WindowsRuntimeNativeExposedType(typeof(X))]applications and route the referenced projected types through the user-defined-type CCW pipeline, bypassing the check that normally skips projected types while keeping all other discovery filters.src/WinRT.Interop.Generator/References/WellKnownInterfaceIIDs.cs: add the missingIStringablecase toget_IID. Every projected class implements the manually-projectedIStringable, so resolving its interface entry is required when CCW code is generated for a projected type; this path was previously unreachable and threwCSWINRTINTEROPGEN0052.src/Authoring/WinRT.SourceGenerator2/Diagnostics/(Analyzers/WindowsRuntimeNativeExposedTypeAnalyzer.cs,DiagnosticDescriptors.cs,AnalyzerReleases.Shipped.md): new analyzer emittingCSWINRT2018(target type cannot be instantiated),CSWINRT2019(target type is not a projected class, so CCW code is already generated automatically), andCSWINRT2020(the same type is targeted by more than one application in the assembly). Applications in generated code are excluded, so a duplicate spanning user code and generated code only warns on the user application.src/Tests/SourceGenerator2Test/Test_WindowsRuntimeNativeExposedTypeAnalyzer.cs,src/Tests/SourceGenerator2Test/Helpers/CSharpAnalyzerTest{TAnalyzer}.cs,src/Tests/UnitTest/NativeExposedTypeTests.cs,src/Tests/FunctionalTests/NativeExposedType/,src/cswinrt.slnx,src/build.cmd): analyzer unit tests (including a test-harness helper for injecting generated code to validate the generated-code exclusion), plus a self-containedNativeExposedTypefunctional test that runs in both JIT and Native AOT and a unit test. Both verify that the interop generator registers a proxy type map association for an opted-in projected type and not for a projected type that was not opted in.src/WinRT.Runtime2/InteropServices/Attributes/WindowsRuntimeComWrappersMarshallerAttribute.csandsrc/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs: improve marshalling failure diagnostics. TheNotSupportedExceptionmessages now include the concrete marshaller type, andComputeVtablesreturnsnullwhen not overridden soWindowsRuntimeMarshallingInfocan throw a detailed exception that names the marshaller and metadata provider types and points toWindowsRuntimeNativeExposedTypeAttributeas the remediation.