Repository navigation
Add opt-in opaque RCW marshalling feature switch - #2642
Merged
Sergio Pedri (Sergio0694) merged 2 commits intoNov 5, 2026
Merged
Sergio Pedri (Sergio0694) merged 2 commits into
Sergio Pedri (Sergio0694) merged 2 commits into
Conversation
Add a new [FeatureSwitchDefinition]-based feature switch to control whether projected runtime class instances (RCWs) that are not native-exposed can be marshalled to native code as opaque CCWs, instead of reporting NotSupportedException. Defaults to false. Configurable via the CsWinRTEnableOpaqueRcwMarshalling MSBuild property. On some Windows versions, native XAML asks the reference tracker host to wrap a projected RCW (for instance a Frame or a Grid set as Window.Content) through ComWrappers. That request reaches WindowsRuntimeMarshallingInfo.GetVtableInfo(), which throws for projected classes without a native-exposed proxy, and XAML then fails fast. When the switch is enabled, GetVtableInfo() reuses the shared opaque object vtables for those classes, and GetRuntimeClassName() falls back to the full name of the projected type. Native-exposed types keep their own vtables, and the RCW forwards any other QueryInterface request to its native object. Covariant scenarios still require [WindowsRuntimeNativeExposedType]. Both fallbacks only run on paths that would otherwise throw, and are removed by ILLink and ILC when the switch is disabled, so there is no overhead by default. Add an OpaqueRcwMarshalling functional test for the enabled case, extend NativeExposedType to check the disabled default, and document the property in aot-trimming.md and interop.md. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Sergio Pedri (Sergio0694)
requested a review
from Manodasan Wignarajah (manodasanW)
November 4, 2026 19:12
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
Manodasan Wignarajah (manodasanW)
approved these changes
Nov 4, 2026
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Sergio Pedri (Sergio0694)
enabled auto-merge (squash)
November 4, 2026 22:06
Sergio Pedri (Sergio0694)
deleted the
user/sergiopedri/opaque-rcw-marshalling
branch
November 5, 2026 03:00
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
Add an opt-in (off by default) feature switch that lets projected runtime class RCWs without a native-exposed proxy be marshalled to native code as opaque CCWs, instead of throwing
NotSupportedException. It is controlled by the newCsWinRTEnableOpaqueRcwMarshallingMSBuild property, which maps to the newCSWINRT_ENABLE_OPAQUE_RCW_MARSHALLINGruntime switch.Motivation
On some Windows versions, native XAML asks the .NET reference tracker host to wrap a projected RCW (for instance a
Frameor aGridset asWindow.Content) throughComWrappers.GetOrCreateComInterfaceForObject. In CsWinRT 3.0 this reachesWindowsRuntimeMarshallingInfo.GetVtableInfo(), which throws for projected classes that don't have a native-exposed proxy, and XAML then fails fast.With the switch enabled, those requests get an opaque CCW that exposes only the standard interfaces (
IInspectable,IStringable,IWeakReferenceSource,IMarshal,IAgileObject, and so on). The RCW itself forwards any otherQueryInterfacerequest to its native object. Native-exposed types keep their own vtables, and the new behavior only applies to projected runtime classes.The feature is pay-for-play: both fallbacks sit on paths that would otherwise throw, and are removed by ILLink and ILC when the switch is disabled, so there is no overhead by default.
Changes
src/WinRT.Runtime2/Properties/WindowsRuntimeFeatureSwitches.cs: new[FeatureSwitchDefinition]propertyEnableOpaqueRcwMarshalling, backed byCSWINRT_ENABLE_OPAQUE_RCW_MARSHALLING(defaultfalse).nuget/Microsoft.Windows.CsWinRT.targets: newCsWinRTEnableOpaqueRcwMarshallingproperty (defaultfalse) and a trimmableRuntimeHostConfigurationOption.src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs: when the switch is enabled,GetVtableInfo()reuses the shared opaqueobjectvtables for projected classes, andGetRuntimeClassName()falls back to the full type name. New privateIsProjectedClasshelper.src/WinRT.Runtime2/InteropServices/Attributes/WindowsRuntimeNativeExposedTypeAttribute.cs: remarks now point to the new property as an alternative for opaque-only exposure.src/Tests/FunctionalTests/OpaqueRcwMarshalling/: new functional test for the enabled case (managed identity, standard and forwardedQueryInterface,GetIids, runtime class name, unwrapping through regular marshalling, and a native-exposedJsonArraykeeping its own vtables).src/Tests/FunctionalTests/NativeExposedType/Program.cs: new check that the default (switch disabled) still fails withNotSupportedException.src/cswinrt.slnxandbuild/AzurePipelineTemplates/CsWinRT-FunctionalTest-Steps.yml: wire up the new functional test.docs/aot-trimming.mdanddocs/interop.md: document the property and the opaque CCW semantics and limitations.Validation
OpaqueRcwMarshallingpasses (exit code 100) on x64 Native AOT and x86 trimmed JIT, and fails with the expectedNotSupportedExceptionwhen the switch is forced off.NativeExposedTypepasses (exit code 100), including the new disabled-default check.WinRT.Runtimebuilds clean in Release (warnings as errors), both the implementation and reference assembly variants.Limitations
DependencyObjectCollectionas an items source) still need[WindowsRuntimeNativeExposedType].ComWrappers-driven paths and projected runtime classes are affected.