From 7d5c7c3a99b801bf92d96c1b22a72b45ad366520 Mon Sep 17 00:00:00 2001 From: Will Thant Date: Mon, 24 Nov 2025 11:20:17 -0800 Subject: [PATCH 01/76] WindowsRuntimeMarshallingInfo.TryGetInfo in Type ConvertToManaged --- src/WinRT.Runtime2/ABI/System/Type.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index 98fb41a08..c2b1bb898 100644 --- a/src/WinRT.Runtime2/ABI/System/Type.cs +++ b/src/WinRT.Runtime2/ABI/System/Type.cs @@ -122,7 +122,11 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR return global::System.Type.GetType(typeName.ToString()); } - global::System.Type? type = null; // TODO + global::System.Type? type = null; + if (WindowsRuntimeMarshallingInfo.TryGetInfo(typeName, out WindowsRuntimeMarshallingInfo? marshallingInfo)) + { + type = marshallingInfo.PublicType; + } // If the target type is a projected type that has been trimmed, we can return a special type. // This is mostly used by the XAML metadata provider. The type itself should never actually be From e4d59d950b75e8cf3d0111304879a769e72aca28 Mon Sep 17 00:00:00 2001 From: Will Thant Date: Mon, 24 Nov 2025 17:39:00 -0800 Subject: [PATCH 02/76] ChkPt --- src/WinRT.Runtime2/ABI/System/Type.cs | 25 +++++++-- .../Extensions/TypeExtensions.cs | 51 +++++++++++++++++++ 2 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 src/WinRT.Runtime2/Extensions/TypeExtensions.cs diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index c2b1bb898..1dc63e763 100644 --- a/src/WinRT.Runtime2/ABI/System/Type.cs +++ b/src/WinRT.Runtime2/ABI/System/Type.cs @@ -91,11 +91,28 @@ public static Type ConvertToUnmanaged(global::System.Type value) public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeReference reference) { ArgumentNullException.ThrowIfNull(value); + reference = default; + if (value is NoMetadataTypeInfo noMetadataTypeInfo) + { + reference = new TypeReference { Name = noMetadataTypeInfo.FullName, Kind = TypeKind.Metadata }; + return; + } - string abiName = ""; // TODO - TypeKind kind = default; // TODO - - reference = new TypeReference { Name = abiName, Kind = kind }; + if (value is not null) + { + if (WindowsRuntimeMarshallingInfo.TryGetInfo(value, out WindowsRuntimeMarshallingInfo? marshallingInfo)) + { + TypeKind kind = TypeKind.Metadata; + if (value.IsPrimitive) + { + kind = TypeKind.Primitive; + } + reference = new TypeReference { Name = marshallingInfo.GetRuntimeClassName(), Kind = kind }; + return; + } + + reference = new TypeReference { Name = value.AssemblyQualifiedName, Kind = TypeKind.Custom }; + } } /// diff --git a/src/WinRT.Runtime2/Extensions/TypeExtensions.cs b/src/WinRT.Runtime2/Extensions/TypeExtensions.cs new file mode 100644 index 000000000..0e346acf7 --- /dev/null +++ b/src/WinRT.Runtime2/Extensions/TypeExtensions.cs @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using WindowsRuntime.InteropServices; + +namespace WindowsRuntime.Extensions; + +/// +/// Provides extension methods for the class. +/// +public static class TypeExtensions +{ + /// + /// Determines whether the specified type is a Windows Runtime type. + /// + /// + /// true if the type is a Windows Runtime type; otherwise, false. + /// + public static bool IsTypeWindowsRuntimeType(this global::System.Type systemType) + { + return IsTypeWindowsRuntimeTypeNoArray(systemType.GetElementType() ?? systemType); + } + + private static bool IsTypeWindowsRuntimeTypeNoArray(this global::System.Type systemType) + { + // We might not need to handle Generic Types because WindowsRuntimeMarshallingInfo should have all the possible generic types with types from CSWinRTGen + //if (systemType.IsConstructedGenericType) + //{ + // if (IsTypeWindowsRuntimeTypeNoArray(systemType.GetGenericTypeDefinition())) + // { + // foreach (System.Type arg in systemType.GetGenericArguments()) + // { + // if (!IsTypeWindowsRuntimeTypeNoArray(arg)) + // { + // return false; + // } + // } + // return true; + // } + // return false; + //} + return systemType.IsPrimitive + || systemType == typeof(string) + || systemType == typeof(object) + || systemType == typeof(Guid) + || WindowsRuntimeMarshallingInfo.TryGetInfo(systemType, out _); + // TODO: Verify Authoring Scenarios + } + +} From 774811909ee4fbaf3e12a9ff74ec1d2bcb12f407 Mon Sep 17 00:00:00 2001 From: Will Thant Date: Mon, 24 Nov 2025 17:42:25 -0800 Subject: [PATCH 03/76] ChkPt --- src/WinRT.Runtime2/Extensions/TypeExtensions.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/WinRT.Runtime2/Extensions/TypeExtensions.cs b/src/WinRT.Runtime2/Extensions/TypeExtensions.cs index 0e346acf7..f254a6d57 100644 --- a/src/WinRT.Runtime2/Extensions/TypeExtensions.cs +++ b/src/WinRT.Runtime2/Extensions/TypeExtensions.cs @@ -24,7 +24,9 @@ public static bool IsTypeWindowsRuntimeType(this global::System.Type systemType) private static bool IsTypeWindowsRuntimeTypeNoArray(this global::System.Type systemType) { - // We might not need to handle Generic Types because WindowsRuntimeMarshallingInfo should have all the possible generic types with types from CSWinRTGen + // We might not need to handle Generic Types because WindowsRuntimeMarshallingInfo should have all the possible generic types with types from CSWinRTGen + // But uncomment these lines if we need to handle them in the future + // TODO: Confirm we don't need to handle Generic Types here and remove all these comments //if (systemType.IsConstructedGenericType) //{ // if (IsTypeWindowsRuntimeTypeNoArray(systemType.GetGenericTypeDefinition())) @@ -40,6 +42,7 @@ private static bool IsTypeWindowsRuntimeTypeNoArray(this global::System.Type sys // } // return false; //} + return systemType.IsPrimitive || systemType == typeof(string) || systemType == typeof(object) From ff83e55345d92e63d0b9386ae797a34f83790cf5 Mon Sep 17 00:00:00 2001 From: Will Thant Date: Tue, 25 Nov 2025 13:49:21 -0800 Subject: [PATCH 04/76] Surgey on test cases: Will Revert --- src/Tests/UnitTest/OOPObject.cs | 119 ------------------ .../UnitTest/TestComponentCSharp_Tests.cs | 56 ++++----- src/Tests/UnitTest/UnitTest.csproj | 2 +- 3 files changed, 29 insertions(+), 148 deletions(-) delete mode 100644 src/Tests/UnitTest/OOPObject.cs diff --git a/src/Tests/UnitTest/OOPObject.cs b/src/Tests/UnitTest/OOPObject.cs deleted file mode 100644 index 6993e5ba3..000000000 --- a/src/Tests/UnitTest/OOPObject.cs +++ /dev/null @@ -1,119 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using Windows.Foundation; -using Windows.Win32; -using Windows.Win32.System.Com; -using WindowsRuntime.InteropServices; - -namespace UnitTest -{ - // https://docs.microsoft.com/windows/win32/api/unknwn/nn-unknwn-iclassfactory - [ComImport] - [ComVisible(false)] - [Guid("00000001-0000-0000-C000-000000000046")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - interface IClassFactory - { - void CreateInstance( - [MarshalAs(UnmanagedType.Interface)] object pUnkOuter, - ref Guid riid, - out IntPtr ppvObject); - - void LockServer([MarshalAs(UnmanagedType.Bool)] bool fLock); - } - - [ComVisible(true)] - internal class WinRTClassFactory : IClassFactory - { - private static readonly Guid IUnknown = new Guid("00000000-0000-0000-C000-000000000046"); - - - public static void RegisterClass(IClassFactory classFactory) - { - RegisterClassObject(typeof(T).GUID, classFactory); - } - - private static void RegisterClassObject(Guid clsid, object factory) - { - int hr = PInvoke.CoRegisterClassObject(in clsid, factory, CLSCTX.CLSCTX_LOCAL_SERVER, (int)REGCLS.REGCLS_MULTIPLEUSE, out uint _); - if (hr < 0) - { - Marshal.ThrowExceptionForHR(hr); - } - } - - private readonly Func createFunction; - private readonly Dictionary> marshalFuncByGuid; - - public WinRTClassFactory(Func createFunction, Dictionary> marshalFuncByGuid) - { - this.createFunction = createFunction ?? throw new ArgumentNullException(nameof(createFunction)); - this.marshalFuncByGuid = marshalFuncByGuid ?? throw new ArgumentNullException(nameof(marshalFuncByGuid)); - } - - public void CreateInstance( - [MarshalAs(UnmanagedType.Interface)] object pUnkOuter, - ref Guid riid, - out IntPtr ppvObject) - { - if (pUnkOuter != null) - { - throw new COMException(); - } - - object obj = this.createFunction(); - if (riid == IUnknown) - { - unsafe - { - ppvObject = (IntPtr)WindowsRuntimeMarshal.ConvertToUnmanaged(obj); - } - } - else - { - if (!this.marshalFuncByGuid.TryGetValue(riid, out Func marshalFunc)) - { - throw new InvalidCastException(); - } - - ppvObject = marshalFunc(obj); - } - } - - public void LockServer(bool fLock) - { - // No-op - } - } - - [ComVisible(true)] - [Guid("15F1005B-E23A-4154-9417-CCD083D452BB")] - [ComDefaultInterface(typeof(IAsyncAction))] - internal class OOPAsyncAction : IAsyncAction - { - public bool delegateCalled; - - public AsyncActionCompletedHandler Completed { get; set; } - - public Exception ErrorCode => throw new NotImplementedException(); - - public uint Id => throw new NotImplementedException(); - - public AsyncStatus Status => throw new NotImplementedException(); - - public void Cancel() - { - } - - public void Close() - { - Completed(this, AsyncStatus.Completed); - } - - public void GetResults() - { - delegateCalled = true; - } - } -} \ No newline at end of file diff --git a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs index 064d093ab..cd2f5cceb 100644 --- a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs +++ b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs @@ -3427,34 +3427,34 @@ public void TestEventRemovalByEventSource() Assert.True(eventCalled2); } - [Fact] - public unsafe void TestProxiedDelegate() - { - var obj = new OOPAsyncAction(); - var factory = new WinRTClassFactory( - () => obj, - new Dictionary>() - { - { typeof(IAsyncAction).GUID, obj => (IntPtr)WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged((IAsyncAction) obj, typeof(IAsyncAction).GUID).GetThisPtr() }, - }); - - WinRTClassFactory.RegisterClass(factory); - - var currentExecutingDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - var launchExePath = $"{currentExecutingDir}\\OOPExe.exe"; - var proc = Process.Start(launchExePath); - Thread.Sleep(5000); - obj.Close(); - Assert.True(obj.delegateCalled); - - try - { - proc.Kill(); - } - catch (Exception) - { - } - } + //[Fact] + //public unsafe void TestProxiedDelegate() + //{ + // var obj = new OOPAsyncAction(); + // var factory = new WinRTClassFactory( + // () => obj, + // new Dictionary>() + // { + // { typeof(IAsyncAction).GUID, obj => (IntPtr)WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged((IAsyncAction) obj, typeof(IAsyncAction).GUID).GetThisPtr() }, + // }); + + // WinRTClassFactory.RegisterClass(factory); + + // var currentExecutingDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + // var launchExePath = $"{currentExecutingDir}\\OOPExe.exe"; + // var proc = Process.Start(launchExePath); + // Thread.Sleep(5000); + // obj.Close(); + // Assert.True(obj.delegateCalled); + + // try + // { + // proc.Kill(); + // } + // catch (Exception) + // { + // } + //} [Fact] private async Task TestPnpPropertiesInLoop() diff --git a/src/Tests/UnitTest/UnitTest.csproj b/src/Tests/UnitTest/UnitTest.csproj index ffad185bf..6f3d74bef 100644 --- a/src/Tests/UnitTest/UnitTest.csproj +++ b/src/Tests/UnitTest/UnitTest.csproj @@ -15,7 +15,7 @@ - + From f66b075558a85407714ddb03be14f1e250905c10 Mon Sep 17 00:00:00 2001 From: Will Thant Date: Tue, 25 Nov 2025 16:52:42 -0800 Subject: [PATCH 05/76] Add WinRT.SourceGenerator2 to UnitTest.csproj --- src/Tests/UnitTest/UnitTest.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Tests/UnitTest/UnitTest.csproj b/src/Tests/UnitTest/UnitTest.csproj index 6f3d74bef..02e8b9b2c 100644 --- a/src/Tests/UnitTest/UnitTest.csproj +++ b/src/Tests/UnitTest/UnitTest.csproj @@ -11,6 +11,7 @@ + From 090f4209d0f15418fb6c5b8002a5a2d2af47620d Mon Sep 17 00:00:00 2001 From: Will Thant Date: Wed, 26 Nov 2025 10:56:13 -0800 Subject: [PATCH 06/76] Remove IReference --- src/WinRT.Runtime2/ABI/System/Type.cs | 28 +++++++--- .../Extensions/TypeExtensions.cs | 54 ------------------- 2 files changed, 22 insertions(+), 60 deletions(-) delete mode 100644 src/WinRT.Runtime2/Extensions/TypeExtensions.cs diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index 1dc63e763..70612ebeb 100644 --- a/src/WinRT.Runtime2/ABI/System/Type.cs +++ b/src/WinRT.Runtime2/ABI/System/Type.cs @@ -100,14 +100,14 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR if (value is not null) { + TypeKind kind = TypeKind.Metadata; + if (value.IsPrimitive) + { + kind = TypeKind.Primitive; + } if (WindowsRuntimeMarshallingInfo.TryGetInfo(value, out WindowsRuntimeMarshallingInfo? marshallingInfo)) { - TypeKind kind = TypeKind.Metadata; - if (value.IsPrimitive) - { - kind = TypeKind.Primitive; - } - reference = new TypeReference { Name = marshallingInfo.GetRuntimeClassName(), Kind = kind }; + reference = new TypeReference { Name = ExtractTypeName(marshallingInfo.GetRuntimeClassName()), Kind = kind }; return; } @@ -115,6 +115,22 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR } } + + private static string ExtractTypeName(string runtimeClassName) + { + const string prefix = "Windows.Foundation.IReference<"; + ReadOnlySpan span = runtimeClassName; + + if (span.StartsWith(prefix)) + { + // Slice directly without reassigning unnecessarily + return span.Slice(prefix.Length, span.Length - prefix.Length - 1).ToString(); + } + + return runtimeClassName; // Fallback if format doesn't match + } + + /// /// Converts an unmanaged to a managed . /// diff --git a/src/WinRT.Runtime2/Extensions/TypeExtensions.cs b/src/WinRT.Runtime2/Extensions/TypeExtensions.cs deleted file mode 100644 index f254a6d57..000000000 --- a/src/WinRT.Runtime2/Extensions/TypeExtensions.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using System; -using WindowsRuntime.InteropServices; - -namespace WindowsRuntime.Extensions; - -/// -/// Provides extension methods for the class. -/// -public static class TypeExtensions -{ - /// - /// Determines whether the specified type is a Windows Runtime type. - /// - /// - /// true if the type is a Windows Runtime type; otherwise, false. - /// - public static bool IsTypeWindowsRuntimeType(this global::System.Type systemType) - { - return IsTypeWindowsRuntimeTypeNoArray(systemType.GetElementType() ?? systemType); - } - - private static bool IsTypeWindowsRuntimeTypeNoArray(this global::System.Type systemType) - { - // We might not need to handle Generic Types because WindowsRuntimeMarshallingInfo should have all the possible generic types with types from CSWinRTGen - // But uncomment these lines if we need to handle them in the future - // TODO: Confirm we don't need to handle Generic Types here and remove all these comments - //if (systemType.IsConstructedGenericType) - //{ - // if (IsTypeWindowsRuntimeTypeNoArray(systemType.GetGenericTypeDefinition())) - // { - // foreach (System.Type arg in systemType.GetGenericArguments()) - // { - // if (!IsTypeWindowsRuntimeTypeNoArray(arg)) - // { - // return false; - // } - // } - // return true; - // } - // return false; - //} - - return systemType.IsPrimitive - || systemType == typeof(string) - || systemType == typeof(object) - || systemType == typeof(Guid) - || WindowsRuntimeMarshallingInfo.TryGetInfo(systemType, out _); - // TODO: Verify Authoring Scenarios - } - -} From fa571b0feb9336333cefdbf907a349ba5d49c09f Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Wed, 26 Nov 2025 13:18:54 -0800 Subject: [PATCH 07/76] Fix typemap not being used. --- src/Tests/UnitTest/TestModuleInitializer.cs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/Tests/UnitTest/TestModuleInitializer.cs diff --git a/src/Tests/UnitTest/TestModuleInitializer.cs b/src/Tests/UnitTest/TestModuleInitializer.cs new file mode 100644 index 000000000..859978fde --- /dev/null +++ b/src/Tests/UnitTest/TestModuleInitializer.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Reflection; + +namespace UnitTest; + +// CsWinRT makes use of the .NET typemap to register all the projected types. +// As part this, .NET makes use of TypeMapAssemblyTarget to discover the assemblies with the type map. +// But this needs to be on the launching executable for it to discover them by default. Given with +// a test runner, they aren't, this does the alternative way of setting the assembly with that attribute +// as the entry assembly which then allows .NET to discover it. +internal static class ProjectionTypesInitializer +{ + [System.Runtime.CompilerServices.ModuleInitializer] + internal static void InitializeProjectionTypes() + { + Assembly.SetEntryAssembly(typeof(ProjectionTypesInitializer).Assembly); + } +} From 9f9ea00da010baa1c67ddd5af2c79ced0b4e8719 Mon Sep 17 00:00:00 2001 From: Will Thant Date: Wed, 26 Nov 2025 16:25:45 -0800 Subject: [PATCH 08/76] Some unit tests --- .../UnitTest/TestComponentCSharp_Tests.cs | 61 +++++++++++++++++++ src/WinRT.Runtime2/ABI/System/Type.cs | 21 ++++--- 2 files changed, 73 insertions(+), 9 deletions(-) diff --git a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs index cd2f5cceb..edd5fa939 100644 --- a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs +++ b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs @@ -554,6 +554,67 @@ public void TestTypePropertyWithSystemType() Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); } + [Fact] + public void TestTypePropertyWithGuidType() + { + TestObject.TypeProperty = typeof(System.Guid); + Assert.Equal("Guid", TestObject.GetTypePropertyAbiName()); + Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); + } + + [Fact] + public void TestTypePropertyWithObjectType() + { + TestObject.TypeProperty = typeof(System.Object); + Assert.Equal("Object", TestObject.GetTypePropertyAbiName()); + Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); + } + + [Fact] + public void TestTypePropertyWithStringType() + { + TestObject.TypeProperty = typeof(System.String); + Assert.Equal("String", TestObject.GetTypePropertyAbiName()); + Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); + } + + [Fact] + public void TestTypePropertyWithPrimitiveType() + { + TestObject.TypeProperty = typeof(System.Int64); + Assert.Equal("Int64", TestObject.GetTypePropertyAbiName()); + Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); + + TestObject.TypeProperty = typeof(System.Int32); + Assert.Equal("Int32", TestObject.GetTypePropertyAbiName()); + Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); + + TestObject.TypeProperty = typeof(System.Int16); + Assert.Equal("Int16", TestObject.GetTypePropertyAbiName()); + Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); + + TestObject.TypeProperty = typeof(System.UInt64); + Assert.Equal("UInt64", TestObject.GetTypePropertyAbiName()); + Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); + + TestObject.TypeProperty = typeof(System.UInt32); + Assert.Equal("UInt32", TestObject.GetTypePropertyAbiName()); + Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); + + TestObject.TypeProperty = typeof(System.UInt16); + Assert.Equal("UInt16", TestObject.GetTypePropertyAbiName()); + Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); + + TestObject.TypeProperty = typeof(System.Byte); + Assert.Equal("Byte", TestObject.GetTypePropertyAbiName()); + Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); + + TestObject.TypeProperty = typeof(System.Byte); + Assert.Equal("Byte", TestObject.GetTypePropertyAbiName()); + Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); + } + + class CustomDictionary : Dictionary { } [Fact] diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index 70612ebeb..e60e62d33 100644 --- a/src/WinRT.Runtime2/ABI/System/Type.cs +++ b/src/WinRT.Runtime2/ABI/System/Type.cs @@ -111,23 +111,26 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR return; } - reference = new TypeReference { Name = value.AssemblyQualifiedName, Kind = TypeKind.Custom }; + reference = new TypeReference { Name = value.FullName, Kind = TypeKind.Custom }; } } + /// + /// Private method to extracts the generic type argument from a runtime class name that follows + /// the pattern Windows.Foundation.IReference<T>. + /// + /// + /// The full runtime class name, e.g., Windows.Foundation.IReference<System.Int32>. + /// + /// + /// The inner type name if the input matches the expected pattern; otherwise, the original string. + /// private static string ExtractTypeName(string runtimeClassName) { const string prefix = "Windows.Foundation.IReference<"; ReadOnlySpan span = runtimeClassName; - - if (span.StartsWith(prefix)) - { - // Slice directly without reassigning unnecessarily - return span.Slice(prefix.Length, span.Length - prefix.Length - 1).ToString(); - } - - return runtimeClassName; // Fallback if format doesn't match + return span.StartsWith(prefix) ? span.Slice(prefix.Length, span.Length - prefix.Length - 1).ToString() : runtimeClassName; } From 5e99fe02b331d82e8725e3520533950d320e70ec Mon Sep 17 00:00:00 2001 From: Will Thant Date: Wed, 26 Nov 2025 16:35:50 -0800 Subject: [PATCH 09/76] It should be AssemblyQualifiedName --- src/WinRT.Runtime2/ABI/System/Type.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index e60e62d33..7d45ec095 100644 --- a/src/WinRT.Runtime2/ABI/System/Type.cs +++ b/src/WinRT.Runtime2/ABI/System/Type.cs @@ -111,7 +111,7 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR return; } - reference = new TypeReference { Name = value.FullName, Kind = TypeKind.Custom }; + reference = new TypeReference { Name = value.AssemblyQualifiedName, Kind = TypeKind.Custom }; } } From 51b89c342f3296b38e706d713347d1198036c108 Mon Sep 17 00:00:00 2001 From: Will Thant Date: Mon, 1 Dec 2025 15:59:21 -0800 Subject: [PATCH 10/76] metadata scenario TypeMarshaling test --- .../FunctionalTests/TypeMarshaling/Program.cs | 13 +++++++++++++ .../TypeMarshaling/TypeMarshaling.csproj | 16 ++++++++++++++++ .../ManualProjectionTestClasses.cpp | 14 ++++++++++++++ .../ManualProjectionTestClasses.h | 12 ++++++++++++ .../TestComponentCSharp/TestComponentCSharp.idl | 13 +++++++++++++ src/cswinrt.slnx | 6 ++++++ 6 files changed, 74 insertions(+) create mode 100644 src/Tests/FunctionalTests/TypeMarshaling/Program.cs create mode 100644 src/Tests/FunctionalTests/TypeMarshaling/TypeMarshaling.csproj diff --git a/src/Tests/FunctionalTests/TypeMarshaling/Program.cs b/src/Tests/FunctionalTests/TypeMarshaling/Program.cs new file mode 100644 index 000000000..d1f9fc6a3 --- /dev/null +++ b/src/Tests/FunctionalTests/TypeMarshaling/Program.cs @@ -0,0 +1,13 @@ +using System; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +using TestComponent; +using TestComponentCSharp; + +// Do not reference TestComponentCSharp::TestType1 in managed because it needs to be trimmed to test the Metadata TypeKind scenario +SetTypeProperties setTypeProperties = new(); +return setTypeProperties.SetProperty().Equals("TestComponentCSharp.TestType1 Metadata") ? 100 : 101; + +//TestComponentCSharp.Class TestObject = new(); +//TestObject.TypeProperty = typeof(System.Type); +//Console.WriteLine(TestObject.GetTypePropertyAbiName()); \ No newline at end of file diff --git a/src/Tests/FunctionalTests/TypeMarshaling/TypeMarshaling.csproj b/src/Tests/FunctionalTests/TypeMarshaling/TypeMarshaling.csproj new file mode 100644 index 000000000..a54d35df2 --- /dev/null +++ b/src/Tests/FunctionalTests/TypeMarshaling/TypeMarshaling.csproj @@ -0,0 +1,16 @@ + + + Exe + $(FunctionalTestsBuildTFMs) + x86;x64 + win-x86;win-x64 + $(MSBuildProjectDirectory)\..\PublishProfiles\win-$(Platform).pubxml + + + + + + + + + diff --git a/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.cpp b/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.cpp index ae5bad157..21b83b130 100644 --- a/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.cpp +++ b/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.cpp @@ -5,9 +5,23 @@ #include "CustomBindableVectorTest.g.cpp" #include "CustomBindableObservableVectorTest.g.cpp" #include "CustomIteratorTest.g.cpp" +#include "SetTypeProperties.g.cpp" +#include namespace winrt::TestComponentCSharp::implementation { + SetTypeProperties::SetTypeProperties() + { + + } + + winrt::hstring SetTypeProperties::SetProperty() + { + TestComponentCSharp::Class TestObject; + TestObject.TypeProperty(winrt::xaml_typename()); + return TestObject.GetTypePropertyAbiName() + L" " + TestObject.GetTypePropertyKind(); + } + CustomBindableIteratorTest::CustomBindableIteratorTest() { diff --git a/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.h b/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.h index ab37f5a75..7ccd65a82 100644 --- a/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.h +++ b/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.h @@ -4,9 +4,16 @@ #include "CustomBindableVectorTest.g.h" #include "CustomBindableObservableVectorTest.g.h" #include "CustomIteratorTest.g.h" +#include "SetTypeProperties.g.h" namespace winrt::TestComponentCSharp::implementation { + struct SetTypeProperties : SetTypePropertiesT + { + SetTypeProperties(); + winrt::hstring SetProperty(); + }; + struct CustomBindableIteratorTest : CustomBindableIteratorTestT { CustomBindableIteratorTest(); @@ -72,6 +79,11 @@ namespace winrt::TestComponentCSharp::implementation namespace winrt::TestComponentCSharp::factory_implementation { + struct SetTypeProperties : SetTypePropertiesT + { + + }; + struct CustomBindableIteratorTest : CustomBindableIteratorTestT { diff --git a/src/Tests/TestComponentCSharp/TestComponentCSharp.idl b/src/Tests/TestComponentCSharp/TestComponentCSharp.idl index 7a10f8674..21dc71134 100644 --- a/src/Tests/TestComponentCSharp/TestComponentCSharp.idl +++ b/src/Tests/TestComponentCSharp/TestComponentCSharp.idl @@ -152,6 +152,19 @@ namespace TestComponentCSharp static ISingleton Instance; } + [default_interface] + runtimeclass SetTypeProperties + { + SetTypeProperties(); + String SetProperty(); + } + + // Do not reference TestComponentCSharp::TestType1 in managed because it needs to be trimmed to test the Metadata TypeKind scenario in the TypeHandling project + runtimeclass TestType1 + { + void f(); + } + [default_interface, gc_pressure(Windows.Foundation.Metadata.GCPressureAmount.High)] runtimeclass Class : Windows.Foundation.IStringable diff --git a/src/cswinrt.slnx b/src/cswinrt.slnx index 7db15b0a3..24c751453 100644 --- a/src/cswinrt.slnx +++ b/src/cswinrt.slnx @@ -323,6 +323,12 @@ + + + + + + From 3b2e3b8c91185c2e51edfae7cd0f5f2f016501f1 Mon Sep 17 00:00:00 2001 From: Will Thant Date: Mon, 1 Dec 2025 21:07:33 -0800 Subject: [PATCH 11/76] ProxyType out parameter WIP --- .../FunctionalTests/TypeMarshaling/Program.cs | 11 +++++--- .../ManualProjectionTestClasses.cpp | 9 ++++++- .../ManualProjectionTestClasses.h | 4 ++- .../TestComponentCSharp.idl | 3 ++- src/WinRT.Runtime2/ABI/System/Type.cs | 5 ++++ .../WindowsRuntimeMarshallingInfo.cs | 25 ++++++++++++++++++- 6 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/Tests/FunctionalTests/TypeMarshaling/Program.cs b/src/Tests/FunctionalTests/TypeMarshaling/Program.cs index d1f9fc6a3..ba6fd21a0 100644 --- a/src/Tests/FunctionalTests/TypeMarshaling/Program.cs +++ b/src/Tests/FunctionalTests/TypeMarshaling/Program.cs @@ -6,8 +6,11 @@ // Do not reference TestComponentCSharp::TestType1 in managed because it needs to be trimmed to test the Metadata TypeKind scenario SetTypeProperties setTypeProperties = new(); -return setTypeProperties.SetProperty().Equals("TestComponentCSharp.TestType1 Metadata") ? 100 : 101; +Console.WriteLine(setTypeProperties.GetPropertyInfo());/*.Equals("TestComponentCSharp.TestType1 Metadata");*/ -//TestComponentCSharp.Class TestObject = new(); -//TestObject.TypeProperty = typeof(System.Type); -//Console.WriteLine(TestObject.GetTypePropertyAbiName()); \ No newline at end of file +SetTypeProperties customSetTypeProperties = new(); +Console.WriteLine(customSetTypeProperties.GetPropertyInfoFromCustomType(typeof(CustomTestType))); + +sealed class CustomTestType : Composable +{ +} diff --git a/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.cpp b/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.cpp index 21b83b130..000467f38 100644 --- a/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.cpp +++ b/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.cpp @@ -15,13 +15,20 @@ namespace winrt::TestComponentCSharp::implementation } - winrt::hstring SetTypeProperties::SetProperty() + winrt::hstring SetTypeProperties::GetPropertyInfo() { TestComponentCSharp::Class TestObject; TestObject.TypeProperty(winrt::xaml_typename()); return TestObject.GetTypePropertyAbiName() + L" " + TestObject.GetTypePropertyKind(); } + winrt::hstring SetTypeProperties::GetPropertyInfoFromCustomType(winrt::Windows::UI::Xaml::Interop::TypeName typeName) + { + TestComponentCSharp::Class TestObject; + TestObject.TypeProperty(typeName); + return TestObject.GetTypePropertyAbiName() + L" " + TestObject.GetTypePropertyKind(); + } + CustomBindableIteratorTest::CustomBindableIteratorTest() { diff --git a/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.h b/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.h index 7ccd65a82..bcb28e0cb 100644 --- a/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.h +++ b/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.h @@ -5,13 +5,15 @@ #include "CustomBindableObservableVectorTest.g.h" #include "CustomIteratorTest.g.h" #include "SetTypeProperties.g.h" +#include namespace winrt::TestComponentCSharp::implementation { struct SetTypeProperties : SetTypePropertiesT { SetTypeProperties(); - winrt::hstring SetProperty(); + winrt::hstring GetPropertyInfo(); + winrt::hstring GetPropertyInfoFromCustomType(winrt::Windows::UI::Xaml::Interop::TypeName typeName); }; struct CustomBindableIteratorTest : CustomBindableIteratorTestT diff --git a/src/Tests/TestComponentCSharp/TestComponentCSharp.idl b/src/Tests/TestComponentCSharp/TestComponentCSharp.idl index 21dc71134..ec4679fff 100644 --- a/src/Tests/TestComponentCSharp/TestComponentCSharp.idl +++ b/src/Tests/TestComponentCSharp/TestComponentCSharp.idl @@ -156,7 +156,8 @@ namespace TestComponentCSharp runtimeclass SetTypeProperties { SetTypeProperties(); - String SetProperty(); + String GetPropertyInfo(); + String GetPropertyInfoFromCustomType(Windows.UI.Xaml.Interop.TypeName typeName); } // Do not reference TestComponentCSharp::TestType1 in managed because it needs to be trimmed to test the Metadata TypeKind scenario in the TypeHandling project diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index 7d45ec095..4748247c8 100644 --- a/src/WinRT.Runtime2/ABI/System/Type.cs +++ b/src/WinRT.Runtime2/ABI/System/Type.cs @@ -107,6 +107,11 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR } if (WindowsRuntimeMarshallingInfo.TryGetInfo(value, out WindowsRuntimeMarshallingInfo? marshallingInfo)) { + if (marshallingInfo.GetIsProxyType()) + { + reference = new TypeReference { Name = value.AssemblyQualifiedName, Kind = TypeKind.Custom }; + return; + } reference = new TypeReference { Name = ExtractTypeName(marshallingInfo.GetRuntimeClassName()), Kind = kind }; return; } diff --git a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs index 479a8f864..e765db7ef 100644 --- a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs +++ b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs @@ -113,6 +113,11 @@ internal sealed class WindowsRuntimeMarshallingInfo /// private string? _runtimeClassName; + /// + /// Whether the type is a proxy type and comes from ProxyTypeMapping + /// + private readonly bool _isProxyType; + /// /// Creates a new instance with the specified parameters. /// @@ -124,6 +129,19 @@ private WindowsRuntimeMarshallingInfo(Type metadataProviderType, Type? publicTyp _publicType = publicType; } + /// + /// Creates a new instance with the specified parameters. + /// + /// + /// + /// + private WindowsRuntimeMarshallingInfo(Type metadataProviderType, Type? publicType, bool isProxyType = false) + { + _metadataProviderType = metadataProviderType; + _publicType = publicType; + _isProxyType = isProxyType; + } + /// /// Gets the public type associated with the current instance (ie. the type that would be used directly by developers). /// @@ -471,6 +489,11 @@ void ThrowNotSupportedException() return _runtimeClassName ?? InitializeRuntimeClassName(); } + public bool GetIsProxyType() + { + return _isProxyType; + } + /// /// Creates a instance for a specified metadata provider type. /// @@ -506,7 +529,7 @@ private static WindowsRuntimeMarshallingInfo CreateMarshallingInfo(Type metadata // type. In this case, we don't need to query for '[WindowsRuntimeMappedType]'. if (ProxyTypeMapping.TryGetValue(managedType, out Type? proxyType)) { - return new(proxyType, publicType: managedType); + return new(proxyType, publicType: managedType, isProxyType: true); } // We don't have a metadata provider for the type (we'll just marshal it as a generic 'IInspectable') From bc5a718ef2a99d52e0fb662a18ce9c2c1b2ae948 Mon Sep 17 00:00:00 2001 From: Will Thant Date: Tue, 2 Dec 2025 10:48:38 -0800 Subject: [PATCH 12/76] CustomTypeReference GOTO --- .../FunctionalTests/TypeMarshaling/Program.cs | 19 +++++++++++++++++-- src/WinRT.Runtime2/ABI/System/Type.cs | 6 +++--- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/Tests/FunctionalTests/TypeMarshaling/Program.cs b/src/Tests/FunctionalTests/TypeMarshaling/Program.cs index ba6fd21a0..96a2163da 100644 --- a/src/Tests/FunctionalTests/TypeMarshaling/Program.cs +++ b/src/Tests/FunctionalTests/TypeMarshaling/Program.cs @@ -4,13 +4,28 @@ using TestComponent; using TestComponentCSharp; +bool success = true; + +// Metadata TypeKind test case // Do not reference TestComponentCSharp::TestType1 in managed because it needs to be trimmed to test the Metadata TypeKind scenario +String expectedPropertyInfo = "TestComponentCSharp.TestType1 Metadata"; SetTypeProperties setTypeProperties = new(); -Console.WriteLine(setTypeProperties.GetPropertyInfo());/*.Equals("TestComponentCSharp.TestType1 Metadata");*/ +if (setTypeProperties.GetPropertyInfo() != expectedPropertyInfo) +{ + success = false; +} +// Custom TypeKind test case +String expectedCustomTypePropertyInfo = "CustomTestType, TypeMarshaling, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null Custom"; SetTypeProperties customSetTypeProperties = new(); -Console.WriteLine(customSetTypeProperties.GetPropertyInfoFromCustomType(typeof(CustomTestType))); +if (customSetTypeProperties.GetPropertyInfoFromCustomType(typeof(CustomTestType)) != expectedCustomTypePropertyInfo) +{ + success = false; +} + +return success ? 100 : 101; sealed class CustomTestType : Composable { } + diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index 4748247c8..d9a133fc8 100644 --- a/src/WinRT.Runtime2/ABI/System/Type.cs +++ b/src/WinRT.Runtime2/ABI/System/Type.cs @@ -98,9 +98,9 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR return; } + TypeKind kind = TypeKind.Metadata; if (value is not null) { - TypeKind kind = TypeKind.Metadata; if (value.IsPrimitive) { kind = TypeKind.Primitive; @@ -109,13 +109,13 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR { if (marshallingInfo.GetIsProxyType()) { - reference = new TypeReference { Name = value.AssemblyQualifiedName, Kind = TypeKind.Custom }; - return; + goto CustomTypeReference; } reference = new TypeReference { Name = ExtractTypeName(marshallingInfo.GetRuntimeClassName()), Kind = kind }; return; } + CustomTypeReference: reference = new TypeReference { Name = value.AssemblyQualifiedName, Kind = TypeKind.Custom }; } } From b6fa2a4e3e954a939ad121896fcc2f54c84661d8 Mon Sep 17 00:00:00 2001 From: Will Thant Date: Tue, 2 Dec 2025 11:55:51 -0800 Subject: [PATCH 13/76] Fix up conditions on Custom vs Metadata types --- .../FunctionalTests/TypeMarshaling/Program.cs | 25 ++++++++++++++++--- .../UnitTest/TestComponentCSharp_Tests.cs | 6 +---- src/WinRT.Runtime2/ABI/System/Type.cs | 7 +++++- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/Tests/FunctionalTests/TypeMarshaling/Program.cs b/src/Tests/FunctionalTests/TypeMarshaling/Program.cs index 96a2163da..8b53dc9d0 100644 --- a/src/Tests/FunctionalTests/TypeMarshaling/Program.cs +++ b/src/Tests/FunctionalTests/TypeMarshaling/Program.cs @@ -6,11 +6,12 @@ bool success = true; +SetTypeProperties setTypeProperties = new(); + // Metadata TypeKind test case // Do not reference TestComponentCSharp::TestType1 in managed because it needs to be trimmed to test the Metadata TypeKind scenario -String expectedPropertyInfo = "TestComponentCSharp.TestType1 Metadata"; -SetTypeProperties setTypeProperties = new(); -if (setTypeProperties.GetPropertyInfo() != expectedPropertyInfo) +String expectedMetadataPropertyInfo = "TestComponentCSharp.TestType1 Metadata"; +if (setTypeProperties.GetPropertyInfo() != expectedMetadataPropertyInfo) { success = false; } @@ -18,7 +19,23 @@ // Custom TypeKind test case String expectedCustomTypePropertyInfo = "CustomTestType, TypeMarshaling, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null Custom"; SetTypeProperties customSetTypeProperties = new(); -if (customSetTypeProperties.GetPropertyInfoFromCustomType(typeof(CustomTestType)) != expectedCustomTypePropertyInfo) +if (setTypeProperties.GetPropertyInfoFromCustomType(typeof(CustomTestType)) != expectedCustomTypePropertyInfo) +{ + success = false; +} + +// Primitive TypeKind test case +String expectedPrimitiveTypePropertyInfo = "Int32 Primitive"; +SetTypeProperties primitiveSetTypeProperties = new(); +if (setTypeProperties.GetPropertyInfoFromCustomType(typeof(int)) != expectedPrimitiveTypePropertyInfo) +{ + success = false; +} + +// Primitive TypeKind test case 2 +String expectedPrimitiveTypePropertyInfo2 = "Int64 Primitive"; +SetTypeProperties primitiveSetTypeProperties2 = new(); +if (setTypeProperties.GetPropertyInfoFromCustomType(typeof(System.Int64)) != expectedPrimitiveTypePropertyInfo2) { success = false; } diff --git a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs index edd5fa939..08afbd450 100644 --- a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs +++ b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs @@ -606,11 +606,7 @@ public void TestTypePropertyWithPrimitiveType() Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); TestObject.TypeProperty = typeof(System.Byte); - Assert.Equal("Byte", TestObject.GetTypePropertyAbiName()); - Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); - - TestObject.TypeProperty = typeof(System.Byte); - Assert.Equal("Byte", TestObject.GetTypePropertyAbiName()); + Assert.Equal("UInt8", TestObject.GetTypePropertyAbiName()); Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); } diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index d9a133fc8..5b13c158c 100644 --- a/src/WinRT.Runtime2/ABI/System/Type.cs +++ b/src/WinRT.Runtime2/ABI/System/Type.cs @@ -107,7 +107,12 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR } if (WindowsRuntimeMarshallingInfo.TryGetInfo(value, out WindowsRuntimeMarshallingInfo? marshallingInfo)) { - if (marshallingInfo.GetIsProxyType()) + if (marshallingInfo.GetIsProxyType() + && !value.IsPrimitive + && value != typeof(object) + && value != typeof(string) + && value != typeof(Guid) + && value != typeof(global::System.Type)) { goto CustomTypeReference; } From 62cf4dcd105ed1f7ebc0c41b9c895f0403526ec7 Mon Sep 17 00:00:00 2001 From: Will Thant Date: Tue, 2 Dec 2025 13:41:30 -0800 Subject: [PATCH 14/76] ExtractTypeName should take in ReadOnlySpan --- src/WinRT.Runtime2/ABI/System/Type.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index 5b13c158c..4e807de5d 100644 --- a/src/WinRT.Runtime2/ABI/System/Type.cs +++ b/src/WinRT.Runtime2/ABI/System/Type.cs @@ -116,7 +116,7 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR { goto CustomTypeReference; } - reference = new TypeReference { Name = ExtractTypeName(marshallingInfo.GetRuntimeClassName()), Kind = kind }; + reference = new TypeReference { Name = ExtractTypeName(marshallingInfo.GetRuntimeClassName().AsSpan()).ToString(), Kind = kind }; return; } @@ -136,11 +136,10 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR /// /// The inner type name if the input matches the expected pattern; otherwise, the original string. /// - private static string ExtractTypeName(string runtimeClassName) + private static ReadOnlySpan ExtractTypeName(ReadOnlySpan runtimeClassName) { const string prefix = "Windows.Foundation.IReference<"; - ReadOnlySpan span = runtimeClassName; - return span.StartsWith(prefix) ? span.Slice(prefix.Length, span.Length - prefix.Length - 1).ToString() : runtimeClassName; + return runtimeClassName.StartsWith(prefix, StringComparison.Ordinal) ? runtimeClassName.Slice(prefix.Length, runtimeClassName.Length - prefix.Length - 1) : runtimeClassName; } From 3879ccfe7414c0affae0cd5c9bcfd1099bc29687 Mon Sep 17 00:00:00 2001 From: Will Thant Date: Tue, 2 Dec 2025 13:43:11 -0800 Subject: [PATCH 15/76] Revert "Surgey on test cases: Will Revert" This reverts commit ff83e55345d92e63d0b9386ae797a34f83790cf5. --- src/Tests/UnitTest/OOPObject.cs | 119 ++++++++++++++++++ .../UnitTest/TestComponentCSharp_Tests.cs | 56 ++++----- src/Tests/UnitTest/UnitTest.csproj | 2 +- 3 files changed, 148 insertions(+), 29 deletions(-) create mode 100644 src/Tests/UnitTest/OOPObject.cs diff --git a/src/Tests/UnitTest/OOPObject.cs b/src/Tests/UnitTest/OOPObject.cs new file mode 100644 index 000000000..6993e5ba3 --- /dev/null +++ b/src/Tests/UnitTest/OOPObject.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Windows.Foundation; +using Windows.Win32; +using Windows.Win32.System.Com; +using WindowsRuntime.InteropServices; + +namespace UnitTest +{ + // https://docs.microsoft.com/windows/win32/api/unknwn/nn-unknwn-iclassfactory + [ComImport] + [ComVisible(false)] + [Guid("00000001-0000-0000-C000-000000000046")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + interface IClassFactory + { + void CreateInstance( + [MarshalAs(UnmanagedType.Interface)] object pUnkOuter, + ref Guid riid, + out IntPtr ppvObject); + + void LockServer([MarshalAs(UnmanagedType.Bool)] bool fLock); + } + + [ComVisible(true)] + internal class WinRTClassFactory : IClassFactory + { + private static readonly Guid IUnknown = new Guid("00000000-0000-0000-C000-000000000046"); + + + public static void RegisterClass(IClassFactory classFactory) + { + RegisterClassObject(typeof(T).GUID, classFactory); + } + + private static void RegisterClassObject(Guid clsid, object factory) + { + int hr = PInvoke.CoRegisterClassObject(in clsid, factory, CLSCTX.CLSCTX_LOCAL_SERVER, (int)REGCLS.REGCLS_MULTIPLEUSE, out uint _); + if (hr < 0) + { + Marshal.ThrowExceptionForHR(hr); + } + } + + private readonly Func createFunction; + private readonly Dictionary> marshalFuncByGuid; + + public WinRTClassFactory(Func createFunction, Dictionary> marshalFuncByGuid) + { + this.createFunction = createFunction ?? throw new ArgumentNullException(nameof(createFunction)); + this.marshalFuncByGuid = marshalFuncByGuid ?? throw new ArgumentNullException(nameof(marshalFuncByGuid)); + } + + public void CreateInstance( + [MarshalAs(UnmanagedType.Interface)] object pUnkOuter, + ref Guid riid, + out IntPtr ppvObject) + { + if (pUnkOuter != null) + { + throw new COMException(); + } + + object obj = this.createFunction(); + if (riid == IUnknown) + { + unsafe + { + ppvObject = (IntPtr)WindowsRuntimeMarshal.ConvertToUnmanaged(obj); + } + } + else + { + if (!this.marshalFuncByGuid.TryGetValue(riid, out Func marshalFunc)) + { + throw new InvalidCastException(); + } + + ppvObject = marshalFunc(obj); + } + } + + public void LockServer(bool fLock) + { + // No-op + } + } + + [ComVisible(true)] + [Guid("15F1005B-E23A-4154-9417-CCD083D452BB")] + [ComDefaultInterface(typeof(IAsyncAction))] + internal class OOPAsyncAction : IAsyncAction + { + public bool delegateCalled; + + public AsyncActionCompletedHandler Completed { get; set; } + + public Exception ErrorCode => throw new NotImplementedException(); + + public uint Id => throw new NotImplementedException(); + + public AsyncStatus Status => throw new NotImplementedException(); + + public void Cancel() + { + } + + public void Close() + { + Completed(this, AsyncStatus.Completed); + } + + public void GetResults() + { + delegateCalled = true; + } + } +} \ No newline at end of file diff --git a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs index 08afbd450..a8fa29e4a 100644 --- a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs +++ b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs @@ -3484,34 +3484,34 @@ public void TestEventRemovalByEventSource() Assert.True(eventCalled2); } - //[Fact] - //public unsafe void TestProxiedDelegate() - //{ - // var obj = new OOPAsyncAction(); - // var factory = new WinRTClassFactory( - // () => obj, - // new Dictionary>() - // { - // { typeof(IAsyncAction).GUID, obj => (IntPtr)WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged((IAsyncAction) obj, typeof(IAsyncAction).GUID).GetThisPtr() }, - // }); - - // WinRTClassFactory.RegisterClass(factory); - - // var currentExecutingDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - // var launchExePath = $"{currentExecutingDir}\\OOPExe.exe"; - // var proc = Process.Start(launchExePath); - // Thread.Sleep(5000); - // obj.Close(); - // Assert.True(obj.delegateCalled); - - // try - // { - // proc.Kill(); - // } - // catch (Exception) - // { - // } - //} + [Fact] + public unsafe void TestProxiedDelegate() + { + var obj = new OOPAsyncAction(); + var factory = new WinRTClassFactory( + () => obj, + new Dictionary>() + { + { typeof(IAsyncAction).GUID, obj => (IntPtr)WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged((IAsyncAction) obj, typeof(IAsyncAction).GUID).GetThisPtr() }, + }); + + WinRTClassFactory.RegisterClass(factory); + + var currentExecutingDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + var launchExePath = $"{currentExecutingDir}\\OOPExe.exe"; + var proc = Process.Start(launchExePath); + Thread.Sleep(5000); + obj.Close(); + Assert.True(obj.delegateCalled); + + try + { + proc.Kill(); + } + catch (Exception) + { + } + } [Fact] private async Task TestPnpPropertiesInLoop() diff --git a/src/Tests/UnitTest/UnitTest.csproj b/src/Tests/UnitTest/UnitTest.csproj index 02e8b9b2c..42ef79938 100644 --- a/src/Tests/UnitTest/UnitTest.csproj +++ b/src/Tests/UnitTest/UnitTest.csproj @@ -16,7 +16,7 @@ - + From b5746d20899ce40840450087bbee65296c3e5471 Mon Sep 17 00:00:00 2001 From: Will Thant Date: Tue, 2 Dec 2025 14:32:56 -0800 Subject: [PATCH 16/76] Add more primitive type cases --- .../UnitTest/TestComponentCSharp_Tests.cs | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs index a8fa29e4a..67127c1f0 100644 --- a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs +++ b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs @@ -581,33 +581,49 @@ public void TestTypePropertyWithStringType() [Fact] public void TestTypePropertyWithPrimitiveType() { - TestObject.TypeProperty = typeof(System.Int64); + TestObject.TypeProperty = typeof(long); Assert.Equal("Int64", TestObject.GetTypePropertyAbiName()); Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); - TestObject.TypeProperty = typeof(System.Int32); + TestObject.TypeProperty = typeof(int); Assert.Equal("Int32", TestObject.GetTypePropertyAbiName()); Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); - TestObject.TypeProperty = typeof(System.Int16); + TestObject.TypeProperty = typeof(short); Assert.Equal("Int16", TestObject.GetTypePropertyAbiName()); Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); - TestObject.TypeProperty = typeof(System.UInt64); + TestObject.TypeProperty = typeof(ulong); Assert.Equal("UInt64", TestObject.GetTypePropertyAbiName()); Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); - TestObject.TypeProperty = typeof(System.UInt32); + TestObject.TypeProperty = typeof(uint); Assert.Equal("UInt32", TestObject.GetTypePropertyAbiName()); Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); - TestObject.TypeProperty = typeof(System.UInt16); + TestObject.TypeProperty = typeof(ushort); Assert.Equal("UInt16", TestObject.GetTypePropertyAbiName()); Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); - TestObject.TypeProperty = typeof(System.Byte); + TestObject.TypeProperty = typeof(byte); Assert.Equal("UInt8", TestObject.GetTypePropertyAbiName()); Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); + + TestObject.TypeProperty = typeof(char); + Assert.Equal("Char16", TestObject.GetTypePropertyAbiName()); + Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); + + TestObject.TypeProperty = typeof(float); + Assert.Equal("Single", TestObject.GetTypePropertyAbiName()); + Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); + + TestObject.TypeProperty = typeof(double); + Assert.Equal("Double", TestObject.GetTypePropertyAbiName()); + Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); + + TestObject.TypeProperty = typeof(bool); + Assert.Equal("Boolean", TestObject.GetTypePropertyAbiName()); + Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); } From 5161eae08bf0532bc0eaa5e199db72062055d2b3 Mon Sep 17 00:00:00 2001 From: Will Thant Date: Tue, 2 Dec 2025 16:02:34 -0800 Subject: [PATCH 17/76] Refactor/Fix trimmed metadata test --- .../FunctionalTests/TypeMarshaling/Program.cs | 6 ++++-- .../Properties/launchSettings.json | 8 ++++++++ .../ManualProjectionTestClasses.cpp | 17 +++++++++++++---- .../ManualProjectionTestClasses.h | 2 +- .../TestComponentCSharp/TestComponentCSharp.idl | 7 ++++++- 5 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 src/Tests/FunctionalTests/TypeMarshaling/Properties/launchSettings.json diff --git a/src/Tests/FunctionalTests/TypeMarshaling/Program.cs b/src/Tests/FunctionalTests/TypeMarshaling/Program.cs index 8b53dc9d0..54a4bf7a6 100644 --- a/src/Tests/FunctionalTests/TypeMarshaling/Program.cs +++ b/src/Tests/FunctionalTests/TypeMarshaling/Program.cs @@ -11,7 +11,8 @@ // Metadata TypeKind test case // Do not reference TestComponentCSharp::TestType1 in managed because it needs to be trimmed to test the Metadata TypeKind scenario String expectedMetadataPropertyInfo = "TestComponentCSharp.TestType1 Metadata"; -if (setTypeProperties.GetPropertyInfo() != expectedMetadataPropertyInfo) +CustomTestType customTestType = new(); +if (setTypeProperties.GetPropertyInfoWithIType(customTestType) != expectedMetadataPropertyInfo) { success = false; } @@ -42,7 +43,8 @@ return success ? 100 : 101; -sealed class CustomTestType : Composable +sealed class CustomTestType : IType { + public System.Type TypeProperty { get; set; } } diff --git a/src/Tests/FunctionalTests/TypeMarshaling/Properties/launchSettings.json b/src/Tests/FunctionalTests/TypeMarshaling/Properties/launchSettings.json new file mode 100644 index 000000000..1bc4d802e --- /dev/null +++ b/src/Tests/FunctionalTests/TypeMarshaling/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "TypeMarshaling": { + "commandName": "Project", + "nativeDebugging": true + } + } +} \ No newline at end of file diff --git a/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.cpp b/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.cpp index 000467f38..c0bd56d43 100644 --- a/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.cpp +++ b/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.cpp @@ -15,11 +15,20 @@ namespace winrt::TestComponentCSharp::implementation } - winrt::hstring SetTypeProperties::GetPropertyInfo() + winrt::hstring SetTypeProperties::GetPropertyInfoWithIType(IType testObject) { - TestComponentCSharp::Class TestObject; - TestObject.TypeProperty(winrt::xaml_typename()); - return TestObject.GetTypePropertyAbiName() + L" " + TestObject.GetTypePropertyKind(); + testObject.TypeProperty(winrt::xaml_typename()); + winrt::hstring kind; + switch (testObject.TypeProperty().Kind) + { + case Windows::UI::Xaml::Interop::TypeKind::Custom: + kind = winrt::hstring(L"Custom"); + case Windows::UI::Xaml::Interop::TypeKind::Metadata: + kind = winrt::hstring(L"Metadata"); + default: + kind = winrt::hstring(L"Primitive"); + } + return testObject.TypeProperty().Name + L" " + kind; } winrt::hstring SetTypeProperties::GetPropertyInfoFromCustomType(winrt::Windows::UI::Xaml::Interop::TypeName typeName) diff --git a/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.h b/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.h index bcb28e0cb..48aefeace 100644 --- a/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.h +++ b/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.h @@ -12,7 +12,7 @@ namespace winrt::TestComponentCSharp::implementation struct SetTypeProperties : SetTypePropertiesT { SetTypeProperties(); - winrt::hstring GetPropertyInfo(); + winrt::hstring GetPropertyInfoWithIType(IType testObject); winrt::hstring GetPropertyInfoFromCustomType(winrt::Windows::UI::Xaml::Interop::TypeName typeName); }; diff --git a/src/Tests/TestComponentCSharp/TestComponentCSharp.idl b/src/Tests/TestComponentCSharp/TestComponentCSharp.idl index ec4679fff..77b008141 100644 --- a/src/Tests/TestComponentCSharp/TestComponentCSharp.idl +++ b/src/Tests/TestComponentCSharp/TestComponentCSharp.idl @@ -106,6 +106,11 @@ namespace TestComponentCSharp Int32 DrawTo(); } + interface IType + { + Windows.UI.Xaml.Interop.TypeName TypeProperty{ get; set; }; + }; + interface IProperties1 { Int32 ReadWriteProperty{ get; }; @@ -156,7 +161,7 @@ namespace TestComponentCSharp runtimeclass SetTypeProperties { SetTypeProperties(); - String GetPropertyInfo(); + String GetPropertyInfoWithIType(IType testObject); String GetPropertyInfoFromCustomType(Windows.UI.Xaml.Interop.TypeName typeName); } From 62f26be58adc529541fbbe2b3335dc4cd185bfcb Mon Sep 17 00:00:00 2001 From: Will Thant Date: Tue, 2 Dec 2025 16:05:04 -0800 Subject: [PATCH 18/76] TODO comment --- .../FunctionalTests/TypeMarshaling/Program.cs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/Tests/FunctionalTests/TypeMarshaling/Program.cs b/src/Tests/FunctionalTests/TypeMarshaling/Program.cs index 54a4bf7a6..266b849b0 100644 --- a/src/Tests/FunctionalTests/TypeMarshaling/Program.cs +++ b/src/Tests/FunctionalTests/TypeMarshaling/Program.cs @@ -8,14 +8,17 @@ SetTypeProperties setTypeProperties = new(); -// Metadata TypeKind test case -// Do not reference TestComponentCSharp::TestType1 in managed because it needs to be trimmed to test the Metadata TypeKind scenario -String expectedMetadataPropertyInfo = "TestComponentCSharp.TestType1 Metadata"; -CustomTestType customTestType = new(); -if (setTypeProperties.GetPropertyInfoWithIType(customTestType) != expectedMetadataPropertyInfo) -{ - success = false; -} +// TODO: This test case fails because of a System.InvalidCastException when passing in CustomTestType to GetPropertyInfoWithIType. +// Reenable this once the issue is resolved. +// +//// Trimmed Metadata test case +//// Do not reference TestComponentCSharp::TestType1 in managed because it needs to be trimmed to test the Metadata TypeKind scenario +//String expectedMetadataPropertyInfo = "TestComponentCSharp.TestType1 Metadata"; +//CustomTestType customTestType = new(); +//if (setTypeProperties.GetPropertyInfoWithIType(customTestType) != expectedMetadataPropertyInfo) +//{ +// success = false; +//} // Custom TypeKind test case String expectedCustomTypePropertyInfo = "CustomTestType, TypeMarshaling, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null Custom"; From a39b1ded7682721d7f6d38b9c9aebf45ad6effe0 Mon Sep 17 00:00:00 2001 From: Will Thant Date: Tue, 2 Dec 2025 16:09:19 -0800 Subject: [PATCH 19/76] comments --- src/WinRT.Runtime2/ABI/System/Type.cs | 4 ++++ .../TypeMapInfo/WindowsRuntimeMarshallingInfo.cs | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index 4e807de5d..42e46ec29 100644 --- a/src/WinRT.Runtime2/ABI/System/Type.cs +++ b/src/WinRT.Runtime2/ABI/System/Type.cs @@ -92,12 +92,14 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR { ArgumentNullException.ThrowIfNull(value); reference = default; + if (value is NoMetadataTypeInfo noMetadataTypeInfo) { reference = new TypeReference { Name = noMetadataTypeInfo.FullName, Kind = TypeKind.Metadata }; return; } + TypeKind kind = TypeKind.Metadata; if (value is not null) { @@ -105,6 +107,7 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR { kind = TypeKind.Primitive; } + if (WindowsRuntimeMarshallingInfo.TryGetInfo(value, out WindowsRuntimeMarshallingInfo? marshallingInfo)) { if (marshallingInfo.GetIsProxyType() @@ -116,6 +119,7 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR { goto CustomTypeReference; } + reference = new TypeReference { Name = ExtractTypeName(marshallingInfo.GetRuntimeClassName().AsSpan()).ToString(), Kind = kind }; return; } diff --git a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs index e765db7ef..08f355bad 100644 --- a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs +++ b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs @@ -116,6 +116,9 @@ internal sealed class WindowsRuntimeMarshallingInfo /// /// Whether the type is a proxy type and comes from ProxyTypeMapping /// + /// + /// This is in Type.cs to determine the correct way to marshal the type + /// private readonly bool _isProxyType; /// @@ -489,6 +492,10 @@ void ThrowNotSupportedException() return _runtimeClassName ?? InitializeRuntimeClassName(); } + /// + /// Gets whether the type is a proxy type from ProxyTypeMapping + /// + /// if the type is a proxy type; otherwise, . public bool GetIsProxyType() { return _isProxyType; From 066bbee74a4c7f9c504f12894f5546e5fff6e779 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Wed, 3 Dec 2025 12:58:25 -0800 Subject: [PATCH 20/76] Refactor TypeMarshaller.ConvertToUnmanagedUnsafe logic Simplifies and clarifies the handling of TypeReference creation, including improved comments and restructuring for primitive and proxy types. Ensures more consistent reporting of TypeKind and streamlines marshalling info usage. --- src/WinRT.Runtime2/ABI/System/Type.cs | 44 +++++++++++++-------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index 42e46ec29..670ee6227 100644 --- a/src/WinRT.Runtime2/ABI/System/Type.cs +++ b/src/WinRT.Runtime2/ABI/System/Type.cs @@ -91,42 +91,42 @@ public static Type ConvertToUnmanaged(global::System.Type value) public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeReference reference) { ArgumentNullException.ThrowIfNull(value); - reference = default; + // Special case for 'NoMetadataTypeInfo' instances, which can only be obtained + // from previous calls to 'ConvertToManaged' for types that had been trimmed. if (value is NoMetadataTypeInfo noMetadataTypeInfo) { reference = new TypeReference { Name = noMetadataTypeInfo.FullName, Kind = TypeKind.Metadata }; + return; } + // For primitive types, we always report 'TypeKind.Primitive'. This means that some + // types that are C# primitives (e.g. 'sbyte') will be reported as such, even though + // they're not Windows Runtime types. This is expected, and matches C++/WinRT as well. + TypeKind kind = value.IsPrimitive + ? TypeKind.Primitive + : TypeKind.Metadata; - TypeKind kind = TypeKind.Metadata; - if (value is not null) + if (WindowsRuntimeMarshallingInfo.TryGetInfo(value, out WindowsRuntimeMarshallingInfo? marshallingInfo)) { - if (value.IsPrimitive) + if (marshallingInfo.GetIsProxyType() + && !value.IsPrimitive + && value != typeof(object) + && value != typeof(string) + && value != typeof(Guid) + && value != typeof(global::System.Type)) { - kind = TypeKind.Primitive; + goto CustomTypeReference; } - if (WindowsRuntimeMarshallingInfo.TryGetInfo(value, out WindowsRuntimeMarshallingInfo? marshallingInfo)) - { - if (marshallingInfo.GetIsProxyType() - && !value.IsPrimitive - && value != typeof(object) - && value != typeof(string) - && value != typeof(Guid) - && value != typeof(global::System.Type)) - { - goto CustomTypeReference; - } - - reference = new TypeReference { Name = ExtractTypeName(marshallingInfo.GetRuntimeClassName().AsSpan()).ToString(), Kind = kind }; - return; - } + reference = new TypeReference { Name = ExtractTypeName(marshallingInfo.GetRuntimeClassName()), Kind = kind }; - CustomTypeReference: - reference = new TypeReference { Name = value.AssemblyQualifiedName, Kind = TypeKind.Custom }; + return; } + + CustomTypeReference: + reference = new TypeReference { Name = value.AssemblyQualifiedName, Kind = TypeKind.Custom }; } From 815627d31392568a9526774b52822df2caa24023 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Wed, 3 Dec 2025 13:03:22 -0800 Subject: [PATCH 21/76] Optimize type name slicing with JIT unrolling --- src/WinRT.Runtime2/ABI/System/Type.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index 670ee6227..623a41c40 100644 --- a/src/WinRT.Runtime2/ABI/System/Type.cs +++ b/src/WinRT.Runtime2/ABI/System/Type.cs @@ -142,10 +142,12 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR /// private static ReadOnlySpan ExtractTypeName(ReadOnlySpan runtimeClassName) { - const string prefix = "Windows.Foundation.IReference<"; - return runtimeClassName.StartsWith(prefix, StringComparison.Ordinal) ? runtimeClassName.Slice(prefix.Length, runtimeClassName.Length - prefix.Length - 1) : runtimeClassName; - } + const string IReferencePrefix = "Windows.Foundation.IReference<"; + return runtimeClassName.StartsWith(IReferencePrefix, StringComparison.Ordinal) + ? runtimeClassName[IReferencePrefix.Length..^1] + : runtimeClassName; + } /// /// Converts an unmanaged to a managed . From 7bc9c560778bd040b780fb52feef604f9f10beec Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Wed, 3 Dec 2025 13:03:46 -0800 Subject: [PATCH 22/76] Refactor TypeReference to use ReadOnlySpan for Name Changed the TypeReference.Name field from string? to ReadOnlySpan for improved memory safety and performance. Updated marshalling logic and related references to accommodate the new type. --- .../Marshalling/TypeReference.cs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/WinRT.Runtime2/InteropServices/Marshalling/TypeReference.cs b/src/WinRT.Runtime2/InteropServices/Marshalling/TypeReference.cs index 7f50ef269..9e05ceb96 100644 --- a/src/WinRT.Runtime2/InteropServices/Marshalling/TypeReference.cs +++ b/src/WinRT.Runtime2/InteropServices/Marshalling/TypeReference.cs @@ -3,7 +3,9 @@ using System; using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using Windows.UI.Xaml.Interop; namespace WindowsRuntime.InteropServices.Marshalling; @@ -18,7 +20,7 @@ namespace WindowsRuntime.InteropServices.Marshalling; public unsafe ref struct TypeReference { /// - internal string? Name; + internal ReadOnlySpan Name; /// internal TypeKind Kind; @@ -26,7 +28,7 @@ public unsafe ref struct TypeReference /// /// The to use for marshalling. /// - private HStringReference NameRef; + private HStringReference NameReference; /// /// Converts the current value into a value for marshalling. @@ -51,11 +53,11 @@ public ABI.System.Type ConvertToUnmanaged() public ABI.System.Type ConvertToUnmanagedUnsafe() { HStringMarshaller.ConvertToUnmanagedUnsafe( - (char*)Unsafe.AsPointer(in Name!.GetPinnableReference()), - Name?.Length, - out NameRef); + value: (char*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(Name)), + length: Name.Length, + reference: out NameReference); - return new() { Name = NameRef.HString, Kind = Kind }; + return new() { Name = NameReference.HString, Kind = Kind }; } /// @@ -63,8 +65,9 @@ public ABI.System.Type ConvertToUnmanagedUnsafe() /// /// A pinnable reference for the current value. [MethodImpl(MethodImplOptions.AggressiveInlining)] + [UnscopedRef] public readonly ref byte GetPinnableReference() { - return ref Unsafe.As(ref Unsafe.AsRef(in Name!.GetPinnableReference())); + return ref Unsafe.As(ref MemoryMarshal.GetReference(Name)); } } \ No newline at end of file From 2ea14e9954e9f97a5975c37bd207e40245732850 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Wed, 3 Dec 2025 10:33:48 -0800 Subject: [PATCH 23/76] Add WindowsRuntimeMetadata attributes to ABI types Added [WindowsRuntimeMetadata] attributes to ABI type classes in WinRT.Runtime2 to specify their associated Windows contracts. This improves metadata clarity and contract mapping for types such as Boolean, Byte, Char, DateTimeOffset, Double, EventHandler, Exception, Guid, Int16, Int32, Int64, Numerics types, Object, Single, String, TimeSpan, Type, UInt16, UInt32, UInt64, and Uri. --- src/WinRT.Runtime2/ABI/System/Boolean.cs | 1 + src/WinRT.Runtime2/ABI/System/Byte.cs | 1 + src/WinRT.Runtime2/ABI/System/Char.cs | 1 + src/WinRT.Runtime2/ABI/System/DateTimeOffset.cs | 1 + src/WinRT.Runtime2/ABI/System/Double.cs | 1 + src/WinRT.Runtime2/ABI/System/EventHandler.cs | 1 + src/WinRT.Runtime2/ABI/System/Exception.cs | 1 + src/WinRT.Runtime2/ABI/System/Guid.cs | 1 + src/WinRT.Runtime2/ABI/System/Int16.cs | 1 + src/WinRT.Runtime2/ABI/System/Int32.cs | 1 + src/WinRT.Runtime2/ABI/System/Int64.cs | 1 + src/WinRT.Runtime2/ABI/System/Numerics/Matrix3x2.cs | 1 + src/WinRT.Runtime2/ABI/System/Numerics/Matrix4x4.cs | 1 + src/WinRT.Runtime2/ABI/System/Numerics/Plane.cs | 1 + src/WinRT.Runtime2/ABI/System/Numerics/Quaternion.cs | 1 + src/WinRT.Runtime2/ABI/System/Numerics/Vector2.cs | 1 + src/WinRT.Runtime2/ABI/System/Numerics/Vector3.cs | 1 + src/WinRT.Runtime2/ABI/System/Numerics/Vector4.cs | 1 + src/WinRT.Runtime2/ABI/System/Object.cs | 1 + src/WinRT.Runtime2/ABI/System/Single.cs | 1 + src/WinRT.Runtime2/ABI/System/String.cs | 1 + src/WinRT.Runtime2/ABI/System/TimeSpan.cs | 1 + src/WinRT.Runtime2/ABI/System/Type.cs | 1 + src/WinRT.Runtime2/ABI/System/UInt16.cs | 1 + src/WinRT.Runtime2/ABI/System/UInt32.cs | 1 + src/WinRT.Runtime2/ABI/System/UInt64.cs | 1 + src/WinRT.Runtime2/ABI/System/Uri.cs | 2 +- 27 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/WinRT.Runtime2/ABI/System/Boolean.cs b/src/WinRT.Runtime2/ABI/System/Boolean.cs index 0d95e5aae..3acc81388 100644 --- a/src/WinRT.Runtime2/ABI/System/Boolean.cs +++ b/src/WinRT.Runtime2/ABI/System/Boolean.cs @@ -27,6 +27,7 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [BooleanComWrappersMarshaller] file static class Boolean; diff --git a/src/WinRT.Runtime2/ABI/System/Byte.cs b/src/WinRT.Runtime2/ABI/System/Byte.cs index 93b4266de..4ab29ddc0 100644 --- a/src/WinRT.Runtime2/ABI/System/Byte.cs +++ b/src/WinRT.Runtime2/ABI/System/Byte.cs @@ -27,6 +27,7 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [ByteComWrappersMarshaller] file static class Byte; diff --git a/src/WinRT.Runtime2/ABI/System/Char.cs b/src/WinRT.Runtime2/ABI/System/Char.cs index bb5e3d069..06b1994f1 100644 --- a/src/WinRT.Runtime2/ABI/System/Char.cs +++ b/src/WinRT.Runtime2/ABI/System/Char.cs @@ -27,6 +27,7 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [CharComWrappersMarshaller] file static class Char; diff --git a/src/WinRT.Runtime2/ABI/System/DateTimeOffset.cs b/src/WinRT.Runtime2/ABI/System/DateTimeOffset.cs index 072cab0e5..6ac3b5276 100644 --- a/src/WinRT.Runtime2/ABI/System/DateTimeOffset.cs +++ b/src/WinRT.Runtime2/ABI/System/DateTimeOffset.cs @@ -28,6 +28,7 @@ namespace ABI.System; /// ABI type for . /// /// +[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [DateTimeOffsetComWrappersMarshaller] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, diff --git a/src/WinRT.Runtime2/ABI/System/Double.cs b/src/WinRT.Runtime2/ABI/System/Double.cs index e51cd15b4..28831fae7 100644 --- a/src/WinRT.Runtime2/ABI/System/Double.cs +++ b/src/WinRT.Runtime2/ABI/System/Double.cs @@ -27,6 +27,7 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [DoubleComWrappersMarshaller] file static class Double; diff --git a/src/WinRT.Runtime2/ABI/System/EventHandler.cs b/src/WinRT.Runtime2/ABI/System/EventHandler.cs index 0e8336d1f..dac41d584 100644 --- a/src/WinRT.Runtime2/ABI/System/EventHandler.cs +++ b/src/WinRT.Runtime2/ABI/System/EventHandler.cs @@ -38,6 +38,7 @@ namespace ABI.System; /// ABI type for . /// /// +[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference>")] [EventHandlerComWrappersMarshaller] file static class EventHandler; diff --git a/src/WinRT.Runtime2/ABI/System/Exception.cs b/src/WinRT.Runtime2/ABI/System/Exception.cs index e15674e1a..41e4bcb8e 100644 --- a/src/WinRT.Runtime2/ABI/System/Exception.cs +++ b/src/WinRT.Runtime2/ABI/System/Exception.cs @@ -28,6 +28,7 @@ namespace ABI.System; /// ABI type for . /// /// +[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [ExceptionComWrappersMarshaller] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, diff --git a/src/WinRT.Runtime2/ABI/System/Guid.cs b/src/WinRT.Runtime2/ABI/System/Guid.cs index c6876e054..b9c550aa3 100644 --- a/src/WinRT.Runtime2/ABI/System/Guid.cs +++ b/src/WinRT.Runtime2/ABI/System/Guid.cs @@ -27,6 +27,7 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [GuidComWrappersMarshaller] file static class Guid; diff --git a/src/WinRT.Runtime2/ABI/System/Int16.cs b/src/WinRT.Runtime2/ABI/System/Int16.cs index 629fe5096..40e364738 100644 --- a/src/WinRT.Runtime2/ABI/System/Int16.cs +++ b/src/WinRT.Runtime2/ABI/System/Int16.cs @@ -27,6 +27,7 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [Int16ComWrappersMarshaller] file static class Int16; diff --git a/src/WinRT.Runtime2/ABI/System/Int32.cs b/src/WinRT.Runtime2/ABI/System/Int32.cs index 4bf5f5660..281d11aa7 100644 --- a/src/WinRT.Runtime2/ABI/System/Int32.cs +++ b/src/WinRT.Runtime2/ABI/System/Int32.cs @@ -27,6 +27,7 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [Int32ComWrappersMarshaller] file static class Int32; diff --git a/src/WinRT.Runtime2/ABI/System/Int64.cs b/src/WinRT.Runtime2/ABI/System/Int64.cs index e283e2245..7e333fd15 100644 --- a/src/WinRT.Runtime2/ABI/System/Int64.cs +++ b/src/WinRT.Runtime2/ABI/System/Int64.cs @@ -27,6 +27,7 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [Int64ComWrappersMarshaller] file static class Int64; diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Matrix3x2.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Matrix3x2.cs index 49ca34d37..3c220a9e8 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Matrix3x2.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Matrix3x2.cs @@ -29,6 +29,7 @@ namespace ABI.System.Numerics; /// ABI type for . /// /// +[WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [Matrix3x2ComWrappersMarshaller] file static class Matrix3x2; diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Matrix4x4.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Matrix4x4.cs index b33b52e9c..40974ad70 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Matrix4x4.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Matrix4x4.cs @@ -29,6 +29,7 @@ namespace ABI.System.Numerics; /// ABI type for . /// /// +[WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [Matrix4x4ComWrappersMarshaller] file static class Matrix4x4; diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Plane.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Plane.cs index be76efb0e..f70e92a91 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Plane.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Plane.cs @@ -29,6 +29,7 @@ namespace ABI.System.Numerics; /// ABI type for . /// /// +[WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [PlaneComWrappersMarshaller] file static class Plane; diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Quaternion.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Quaternion.cs index 0e41448a9..6e1d04247 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Quaternion.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Quaternion.cs @@ -29,6 +29,7 @@ namespace ABI.System.Numerics; /// ABI type for . /// /// +[WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [QuaternionComWrappersMarshaller] file static class Quaternion; diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Vector2.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Vector2.cs index 40ce67b61..da6c7e55d 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Vector2.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Vector2.cs @@ -29,6 +29,7 @@ namespace ABI.System.Numerics; /// ABI type for . /// /// +[WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [Vector2ComWrappersMarshaller] file static class Vector2; diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Vector3.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Vector3.cs index 34aefc8fd..e33abb272 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Vector3.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Vector3.cs @@ -29,6 +29,7 @@ namespace ABI.System.Numerics; /// ABI type for . /// /// +[WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [Vector3ComWrappersMarshaller] file static class Vector3; diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Vector4.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Vector4.cs index d37b57fec..5e9870438 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Vector4.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Vector4.cs @@ -29,6 +29,7 @@ namespace ABI.System.Numerics; /// ABI type for . /// /// +[WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [Vector4ComWrappersMarshaller] file static class Vector4; diff --git a/src/WinRT.Runtime2/ABI/System/Object.cs b/src/WinRT.Runtime2/ABI/System/Object.cs index a665fa802..630b6d758 100644 --- a/src/WinRT.Runtime2/ABI/System/Object.cs +++ b/src/WinRT.Runtime2/ABI/System/Object.cs @@ -14,6 +14,7 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Object")] [ObjectComWrappersMarshaller] file static class Object; diff --git a/src/WinRT.Runtime2/ABI/System/Single.cs b/src/WinRT.Runtime2/ABI/System/Single.cs index 7565aed65..5b4d2d333 100644 --- a/src/WinRT.Runtime2/ABI/System/Single.cs +++ b/src/WinRT.Runtime2/ABI/System/Single.cs @@ -27,6 +27,7 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [SingleComWrappersMarshaller] file static class Single; diff --git a/src/WinRT.Runtime2/ABI/System/String.cs b/src/WinRT.Runtime2/ABI/System/String.cs index 201a747f1..87139a2fd 100644 --- a/src/WinRT.Runtime2/ABI/System/String.cs +++ b/src/WinRT.Runtime2/ABI/System/String.cs @@ -28,6 +28,7 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [StringComWrappersMarshaller] file static class String; diff --git a/src/WinRT.Runtime2/ABI/System/TimeSpan.cs b/src/WinRT.Runtime2/ABI/System/TimeSpan.cs index 2b6bdf828..b561101c9 100644 --- a/src/WinRT.Runtime2/ABI/System/TimeSpan.cs +++ b/src/WinRT.Runtime2/ABI/System/TimeSpan.cs @@ -28,6 +28,7 @@ namespace ABI.System; /// ABI type for . /// /// +[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [TimeSpanComWrappersMarshaller] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index 623a41c40..1cce925c1 100644 --- a/src/WinRT.Runtime2/ABI/System/Type.cs +++ b/src/WinRT.Runtime2/ABI/System/Type.cs @@ -34,6 +34,7 @@ namespace ABI.System; /// ABI type for . /// /// +[WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [TypeComWrappersMarshaller] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, diff --git a/src/WinRT.Runtime2/ABI/System/UInt16.cs b/src/WinRT.Runtime2/ABI/System/UInt16.cs index 4612b0a17..22ce63502 100644 --- a/src/WinRT.Runtime2/ABI/System/UInt16.cs +++ b/src/WinRT.Runtime2/ABI/System/UInt16.cs @@ -27,6 +27,7 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [UInt16ComWrappersMarshaller] file static class UInt16; diff --git a/src/WinRT.Runtime2/ABI/System/UInt32.cs b/src/WinRT.Runtime2/ABI/System/UInt32.cs index f1ed50043..7629997c1 100644 --- a/src/WinRT.Runtime2/ABI/System/UInt32.cs +++ b/src/WinRT.Runtime2/ABI/System/UInt32.cs @@ -27,6 +27,7 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [UInt32ComWrappersMarshaller] file static class UInt32; diff --git a/src/WinRT.Runtime2/ABI/System/UInt64.cs b/src/WinRT.Runtime2/ABI/System/UInt64.cs index dc33f6b0c..30396f418 100644 --- a/src/WinRT.Runtime2/ABI/System/UInt64.cs +++ b/src/WinRT.Runtime2/ABI/System/UInt64.cs @@ -27,6 +27,7 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [UInt64ComWrappersMarshaller] file static class UInt64; diff --git a/src/WinRT.Runtime2/ABI/System/Uri.cs b/src/WinRT.Runtime2/ABI/System/Uri.cs index 08691d722..1769656f5 100644 --- a/src/WinRT.Runtime2/ABI/System/Uri.cs +++ b/src/WinRT.Runtime2/ABI/System/Uri.cs @@ -26,7 +26,7 @@ namespace ABI.System; /// ABI type for . /// /// -[WindowsRuntimeClassName("Windows.Foundation.Uri")] +[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [UriComWrappersMarshaller] file static class Uri; From 0d3e4f94900ee452c2f76a4bace979cf13860786 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Wed, 3 Dec 2025 13:14:39 -0800 Subject: [PATCH 24/76] Add TypeMapAssociation and WinRT metadata to ABI interfaces Introduces TypeMapAssociation attributes for DynamicInterfaceCastableImplementationTypeMapGroup to INotifyDataErrorInfo, IDisposable, and IServiceProvider ABI interfaces. Also adds WindowsRuntimeMetadata and WindowsRuntimeClassName attributes to their respective interface implementations for improved WinRT interop. --- .../ABI/System/ComponentModel/INotifyDataErrorInfo.cs | 6 ++++++ src/WinRT.Runtime2/ABI/System/IDisposable.cs | 6 ++++++ src/WinRT.Runtime2/ABI/System/IServiceProvider.cs | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/src/WinRT.Runtime2/ABI/System/ComponentModel/INotifyDataErrorInfo.cs b/src/WinRT.Runtime2/ABI/System/ComponentModel/INotifyDataErrorInfo.cs index 6d1699463..265706302 100644 --- a/src/WinRT.Runtime2/ABI/System/ComponentModel/INotifyDataErrorInfo.cs +++ b/src/WinRT.Runtime2/ABI/System/ComponentModel/INotifyDataErrorInfo.cs @@ -16,6 +16,10 @@ #pragma warning disable IDE0008, IDE1006 +[assembly: TypeMapAssociation( + source: typeof(INotifyDataErrorInfo), + proxy: typeof(ABI.System.ComponentModel.INotifyDataErrorInfoInterfaceImpl))] + namespace ABI.System.ComponentModel; /// @@ -306,6 +310,8 @@ static extern WindowsRuntimeObjectReferenceValue ConvertToUnmanaged( /// /// The implementation for . /// +[WindowsRuntimeMetadata("Microsoft.UI.Xaml.WinUIContract")] +[WindowsRuntimeClassName("Microsoft.UI.Xaml.Data.INotifyDataErrorInfo")] [DynamicInterfaceCastableImplementation] file interface INotifyDataErrorInfoInterfaceImpl : INotifyDataErrorInfo { diff --git a/src/WinRT.Runtime2/ABI/System/IDisposable.cs b/src/WinRT.Runtime2/ABI/System/IDisposable.cs index c57f72f9e..13c1cbfdd 100644 --- a/src/WinRT.Runtime2/ABI/System/IDisposable.cs +++ b/src/WinRT.Runtime2/ABI/System/IDisposable.cs @@ -13,6 +13,10 @@ #pragma warning disable IDE0008 +[assembly: TypeMapAssociation( + source: typeof(IDisposable), + proxy: typeof(ABI.System.IDisposableInterfaceImpl))] + namespace ABI.System; /// @@ -127,6 +131,8 @@ private static HRESULT Close(void* thisPtr) /// /// The implementation for . /// +[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeClassName("Windows.Foundation.IClosable")] [DynamicInterfaceCastableImplementation] file interface IDisposableInterfaceImpl : IDisposable { diff --git a/src/WinRT.Runtime2/ABI/System/IServiceProvider.cs b/src/WinRT.Runtime2/ABI/System/IServiceProvider.cs index d38df50ab..b9aa22adb 100644 --- a/src/WinRT.Runtime2/ABI/System/IServiceProvider.cs +++ b/src/WinRT.Runtime2/ABI/System/IServiceProvider.cs @@ -13,6 +13,10 @@ #pragma warning disable IDE0008 +[assembly: TypeMapAssociation( + source: typeof(IServiceProvider), + proxy: typeof(ABI.System.IServiceProviderInterfaceImpl))] + namespace ABI.System; /// @@ -159,6 +163,8 @@ private static HRESULT GetService(void* thisPtr, Type serviceType, void** result /// /// The implementation for . /// +[WindowsRuntimeMetadata("Microsoft.UI.Xaml.WinUIContract")] +[WindowsRuntimeClassName("Microsoft.UI.Xaml.IXamlServiceProvider")] [DynamicInterfaceCastableImplementation] file interface IServiceProviderInterfaceImpl : IServiceProvider { From 89e68a916429867bf70a38ac1c58513f4188b1ab Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Wed, 3 Dec 2025 13:25:49 -0800 Subject: [PATCH 25/76] Improve TypeMarshaller to handle C# primitive types Added logic to TypeMarshaller to support round-tripping C# primitive types (e.g., System.SByte) that are not Windows Runtime types. This ensures such types can be resolved even if not found in the WindowsRuntimeMarshallingInfo lookup. --- src/WinRT.Runtime2/ABI/System/Type.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index 1cce925c1..9447b99b2 100644 --- a/src/WinRT.Runtime2/ABI/System/Type.cs +++ b/src/WinRT.Runtime2/ABI/System/Type.cs @@ -175,11 +175,22 @@ private static ReadOnlySpan ExtractTypeName(ReadOnlySpan runtimeClas } global::System.Type? type = null; + + // Try to retrieve the marshalling info for the input type name. + // This will work for both 'Primitive' and 'Metadata' types. if (WindowsRuntimeMarshallingInfo.TryGetInfo(typeName, out WindowsRuntimeMarshallingInfo? marshallingInfo)) { type = marshallingInfo.PublicType; } + // Handle the case of C# primitive types that are not Windows Runtime types. + // For instance, 'System.SByte' could be passed, which would not be found + // in the previous lookup. We still want to be able to round-trip such values. + if (type is null && value.Kind is TypeKind.Primitive && typeName.StartsWith("System.", StringComparison.Ordinal)) + { + return global::System.Type.GetType(typeName.ToString()); + } + // If the target type is a projected type that has been trimmed, we can return a special type. // This is mostly used by the XAML metadata provider. The type itself should never actually be // used, as there's no C# references causing it to be rooted. If anyone tried to use it, the From 05fc31ee45b38d913d6d907010021c27338a87b2 Mon Sep 17 00:00:00 2001 From: Will Thant Date: Wed, 3 Dec 2025 12:50:06 -0800 Subject: [PATCH 26/76] TestTypePropertyWithIServiceProvider() --- src/Tests/UnitTest/TestComponentCSharp_Tests.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs index 67127c1f0..7da4d98d2 100644 --- a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs +++ b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs @@ -626,6 +626,14 @@ public void TestTypePropertyWithPrimitiveType() Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); } + [Fact] + public void TestTypePropertyWithIServiceProvider() + { + TestObject.TypeProperty = typeof(IServiceProvider); + Assert.Equal("Microsoft.UI.Xaml.IXamlServiceProvider", TestObject.GetTypePropertyAbiName()); + Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); + } + class CustomDictionary : Dictionary { } From 7c43b447a6aa813b0de1ff29f7aefe6b8ac70cad Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Wed, 3 Dec 2025 16:12:23 -0800 Subject: [PATCH 27/76] Refactor metadata type detection in marshalling info Replaces the _isProxyType flag with a volatile int _isMetadataType to track whether a type is defined in metadata. Adds deferred attribute lookup for custom-mapped types and exposes IsMetadataType property. Updates constructors and related logic to use the new flag, improving clarity and correctness in type marshalling scenarios. --- .../WindowsRuntimeMarshallingInfo.cs | 74 +++++++++++++------ 1 file changed, 53 insertions(+), 21 deletions(-) diff --git a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs index 08f355bad..f36b60f7e 100644 --- a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs +++ b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs @@ -111,15 +111,15 @@ internal sealed class WindowsRuntimeMarshallingInfo /// This is only used for managed types that are marshalled to native. For RCWs (ie. for Windows /// Runtime projected types), the runtime class name would just be provided by the native object. /// - private string? _runtimeClassName; + private volatile string? _runtimeClassName; /// - /// Whether the type is a proxy type and comes from ProxyTypeMapping + /// A flag indicating whether the current type is a type defined in metadata (either projected or custom-mapped). /// /// - /// This is in Type.cs to determine the correct way to marshal the type + /// A value of -1 indicates a value that has not been computed yet. /// - private readonly bool _isProxyType; + private volatile int _isMetadataType; /// /// Creates a new instance with the specified parameters. @@ -130,6 +130,7 @@ private WindowsRuntimeMarshallingInfo(Type metadataProviderType, Type? publicTyp { _metadataProviderType = metadataProviderType; _publicType = publicType; + _isMetadataType = -1; } /// @@ -137,12 +138,12 @@ private WindowsRuntimeMarshallingInfo(Type metadataProviderType, Type? publicTyp /// /// /// - /// - private WindowsRuntimeMarshallingInfo(Type metadataProviderType, Type? publicType, bool isProxyType = false) + /// + private WindowsRuntimeMarshallingInfo(Type metadataProviderType, Type? publicType, bool isMetadataType) { _metadataProviderType = metadataProviderType; _publicType = publicType; - _isProxyType = isProxyType; + _isMetadataType = isMetadataType ? 1 : 0; } /// @@ -174,6 +175,38 @@ Type InitializePublicType() } } + /// + /// Gets whether or not the managed type for the current instance is a Windows Runtime type (either projected or custom-mapped). + /// + public bool IsMetadataType + { + get + { + // This fallback will only ever be triggered for custom-mapped types (e.g. 'System.Guid'). + // We structure the code this way so this lookup on the proxy is only ever paid in those + // cases, and only if someone is actually trying to check the value of this property. + // In practice, this is only needed for 'TypeName' marshalling, which is exclusively a + // XAML scenario. So this code path should never be hit for any non-UI applications. + [MethodImpl(MethodImplOptions.NoInlining)] + bool InitializeIsMetadataType() + { + bool isMetadataType = _metadataProviderType.IsDefined(typeof(WindowsRuntimeMetadataAttribute), inherit: false); + + _isMetadataType = isMetadataType ? 1 : 0; + + return isMetadataType; + } + + // Convert the flag back to a boolean, or compute the deferred attribute lookup + return _isMetadataType switch + { + 0 => false, + 1 => true, + _ => InitializeIsMetadataType() + }; + } + } + /// /// Tries to get a instance for a given runtime class name. /// @@ -492,15 +525,6 @@ void ThrowNotSupportedException() return _runtimeClassName ?? InitializeRuntimeClassName(); } - /// - /// Gets whether the type is a proxy type from ProxyTypeMapping - /// - /// if the type is a proxy type; otherwise, . - public bool GetIsProxyType() - { - return _isProxyType; - } - /// /// Creates a instance for a specified metadata provider type. /// @@ -513,8 +537,8 @@ private static WindowsRuntimeMarshallingInfo CreateMarshallingInfo(Type metadata // since we don't need that information right away, we can delay this to later to reduce the // overhead at startup. That value is only needed eg. when associating native memory for vtables. return metadataProviderType.IsDefined(typeof(WindowsRuntimeMetadataAttribute), inherit: false) - ? new(metadataProviderType, metadataProviderType) - : new(metadataProviderType, publicType: null); + ? new(metadataProviderType, metadataProviderType, isMetadataType: true) + : new(metadataProviderType, publicType: null, isMetadataType: false); } /// @@ -524,11 +548,13 @@ private static WindowsRuntimeMarshallingInfo CreateMarshallingInfo(Type metadata /// The resulting instance, if created successfully. private static WindowsRuntimeMarshallingInfo? GetMetadataProviderType(Type managedType) { + bool isMetadataType = managedType.IsDefined(typeof(WindowsRuntimeMetadataAttribute), inherit: false); + // Same as above: if the type is a projected type, then it is also used as the metadata source. // We need to special-case generic types, as the marshalling code for them is also on proxies. - if (managedType.IsDefined(typeof(WindowsRuntimeMetadataAttribute), inherit: false) && !managedType.IsGenericType) + if (isMetadataType && !managedType.IsGenericType) { - return new(managedType, publicType: managedType); + return new(managedType, publicType: managedType, isMetadataType: true); } // Check if we have a mapped proxy type for this managed type. If we do, that type @@ -536,7 +562,13 @@ private static WindowsRuntimeMarshallingInfo CreateMarshallingInfo(Type metadata // type. In this case, we don't need to query for '[WindowsRuntimeMappedType]'. if (ProxyTypeMapping.TryGetValue(managedType, out Type? proxyType)) { - return new(proxyType, publicType: managedType, isProxyType: true); + // If the managed type is a metadata type, we have all the information we need. + // However, if the attribute wasn't present, we cannot be certain that the type + // is not in fact a metadata type, as it could also be a custom-mapped type. In + // that case, we defer this check to later, with a lookup on the proxy type. + return isMetadataType + ? new(proxyType, publicType: managedType, isMetadataType) + : new(proxyType, publicType: managedType); } // We don't have a metadata provider for the type (we'll just marshal it as a generic 'IInspectable') From 278fa32950309f3e8934ec71cf86387a6a371e3d Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Wed, 3 Dec 2025 16:21:51 -0800 Subject: [PATCH 28/76] Refactor TypeMarshaller to improve type kind detection Updated TypeMarshaller to use WindowsRuntimeMarshallingInfo for detecting projected or custom-mapped Windows Runtime types before handling primitives. This change ensures correct TypeKind assignment and aligns behavior with C++/WinRT, while simplifying the logic for custom and primitive type handling. --- src/WinRT.Runtime2/ABI/System/Type.cs | 38 +++++++++++++++------------ 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index 9447b99b2..7752e321e 100644 --- a/src/WinRT.Runtime2/ABI/System/Type.cs +++ b/src/WinRT.Runtime2/ABI/System/Type.cs @@ -102,31 +102,35 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR return; } + // Use the marshalling info lookup to detect projected or custom-mapped Windows Runtime types + if (WindowsRuntimeMarshallingInfo.TryGetInfo(value, out WindowsRuntimeMarshallingInfo? marshallingInfo) && marshallingInfo.IsMetadataType) + { + // For primitive types, we always report 'TypeKind.Primitive'. This means that some + // types that are C# primitives (e.g. 'sbyte') will be reported as such, even though + // they're not Windows Runtime types. This is expected, and matches C++/WinRT as well. + TypeKind kind = value.IsPrimitive + ? TypeKind.Primitive + : TypeKind.Metadata; + + reference = new TypeReference { Name = ExtractTypeName(marshallingInfo.GetRuntimeClassName()), Kind = kind }; + + return; + } + // For primitive types, we always report 'TypeKind.Primitive'. This means that some // types that are C# primitives (e.g. 'sbyte') will be reported as such, even though // they're not Windows Runtime types. This is expected, and matches C++/WinRT as well. - TypeKind kind = value.IsPrimitive - ? TypeKind.Primitive - : TypeKind.Metadata; - - if (WindowsRuntimeMarshallingInfo.TryGetInfo(value, out WindowsRuntimeMarshallingInfo? marshallingInfo)) + // Note that all primitive types that are Windows Runtime types should have been handled + // by the case above already. This path just ensures the other ones are not treated as + // custom types, which they would be otherwise, since they don't have marshalling info. + if (value.IsPrimitive) { - if (marshallingInfo.GetIsProxyType() - && !value.IsPrimitive - && value != typeof(object) - && value != typeof(string) - && value != typeof(Guid) - && value != typeof(global::System.Type)) - { - goto CustomTypeReference; - } - - reference = new TypeReference { Name = ExtractTypeName(marshallingInfo.GetRuntimeClassName()), Kind = kind }; + reference = new TypeReference { Name = value.FullName, Kind = TypeKind.Primitive }; return; } - CustomTypeReference: + // All other cases are treated as custom types (e.g. user-defined types) reference = new TypeReference { Name = value.AssemblyQualifiedName, Kind = TypeKind.Custom }; } From e87da3f6a89a6bfc0cfa9ba91fa7d9016f7a260b Mon Sep 17 00:00:00 2001 From: Will Thant Date: Wed, 3 Dec 2025 17:28:10 -0800 Subject: [PATCH 29/76] Tests for Timespan and CLosable --- src/Tests/UnitTest/TestComponentCSharp_Tests.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs index 7da4d98d2..4ea85c806 100644 --- a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs +++ b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs @@ -634,6 +634,22 @@ public void TestTypePropertyWithIServiceProvider() Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); } + [Fact] + public void TestTypePropertyWithIDisposable() + { + TestObject.TypeProperty = typeof(IDisposable); + Assert.Equal("Windows.Foundation.IClosable", TestObject.GetTypePropertyAbiName()); + Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); + } + + [Fact] + public void TestTypePropertyWithTimespan() + { + TestObject.TypeProperty = typeof(TimeSpan); + Assert.Equal("TimeSpan", TestObject.GetTypePropertyAbiName()); + Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); + } + class CustomDictionary : Dictionary { } From f14aa7ecee06ea8560adc28544e4253ced70aed4 Mon Sep 17 00:00:00 2001 From: Will Thant Date: Thu, 4 Dec 2025 11:59:36 -0800 Subject: [PATCH 30/76] Reapply "Surgey on test cases: Will Revert" This reverts commit 3879ccfe7414c0affae0cd5c9bcfd1099bc29687. --- src/Tests/UnitTest/OOPObject.cs | 119 ------------------ .../UnitTest/TestComponentCSharp_Tests.cs | 56 ++++----- src/Tests/UnitTest/UnitTest.csproj | 2 +- 3 files changed, 29 insertions(+), 148 deletions(-) delete mode 100644 src/Tests/UnitTest/OOPObject.cs diff --git a/src/Tests/UnitTest/OOPObject.cs b/src/Tests/UnitTest/OOPObject.cs deleted file mode 100644 index 6993e5ba3..000000000 --- a/src/Tests/UnitTest/OOPObject.cs +++ /dev/null @@ -1,119 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using Windows.Foundation; -using Windows.Win32; -using Windows.Win32.System.Com; -using WindowsRuntime.InteropServices; - -namespace UnitTest -{ - // https://docs.microsoft.com/windows/win32/api/unknwn/nn-unknwn-iclassfactory - [ComImport] - [ComVisible(false)] - [Guid("00000001-0000-0000-C000-000000000046")] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - interface IClassFactory - { - void CreateInstance( - [MarshalAs(UnmanagedType.Interface)] object pUnkOuter, - ref Guid riid, - out IntPtr ppvObject); - - void LockServer([MarshalAs(UnmanagedType.Bool)] bool fLock); - } - - [ComVisible(true)] - internal class WinRTClassFactory : IClassFactory - { - private static readonly Guid IUnknown = new Guid("00000000-0000-0000-C000-000000000046"); - - - public static void RegisterClass(IClassFactory classFactory) - { - RegisterClassObject(typeof(T).GUID, classFactory); - } - - private static void RegisterClassObject(Guid clsid, object factory) - { - int hr = PInvoke.CoRegisterClassObject(in clsid, factory, CLSCTX.CLSCTX_LOCAL_SERVER, (int)REGCLS.REGCLS_MULTIPLEUSE, out uint _); - if (hr < 0) - { - Marshal.ThrowExceptionForHR(hr); - } - } - - private readonly Func createFunction; - private readonly Dictionary> marshalFuncByGuid; - - public WinRTClassFactory(Func createFunction, Dictionary> marshalFuncByGuid) - { - this.createFunction = createFunction ?? throw new ArgumentNullException(nameof(createFunction)); - this.marshalFuncByGuid = marshalFuncByGuid ?? throw new ArgumentNullException(nameof(marshalFuncByGuid)); - } - - public void CreateInstance( - [MarshalAs(UnmanagedType.Interface)] object pUnkOuter, - ref Guid riid, - out IntPtr ppvObject) - { - if (pUnkOuter != null) - { - throw new COMException(); - } - - object obj = this.createFunction(); - if (riid == IUnknown) - { - unsafe - { - ppvObject = (IntPtr)WindowsRuntimeMarshal.ConvertToUnmanaged(obj); - } - } - else - { - if (!this.marshalFuncByGuid.TryGetValue(riid, out Func marshalFunc)) - { - throw new InvalidCastException(); - } - - ppvObject = marshalFunc(obj); - } - } - - public void LockServer(bool fLock) - { - // No-op - } - } - - [ComVisible(true)] - [Guid("15F1005B-E23A-4154-9417-CCD083D452BB")] - [ComDefaultInterface(typeof(IAsyncAction))] - internal class OOPAsyncAction : IAsyncAction - { - public bool delegateCalled; - - public AsyncActionCompletedHandler Completed { get; set; } - - public Exception ErrorCode => throw new NotImplementedException(); - - public uint Id => throw new NotImplementedException(); - - public AsyncStatus Status => throw new NotImplementedException(); - - public void Cancel() - { - } - - public void Close() - { - Completed(this, AsyncStatus.Completed); - } - - public void GetResults() - { - delegateCalled = true; - } - } -} \ No newline at end of file diff --git a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs index 4ea85c806..604031a69 100644 --- a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs +++ b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs @@ -3524,34 +3524,34 @@ public void TestEventRemovalByEventSource() Assert.True(eventCalled2); } - [Fact] - public unsafe void TestProxiedDelegate() - { - var obj = new OOPAsyncAction(); - var factory = new WinRTClassFactory( - () => obj, - new Dictionary>() - { - { typeof(IAsyncAction).GUID, obj => (IntPtr)WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged((IAsyncAction) obj, typeof(IAsyncAction).GUID).GetThisPtr() }, - }); - - WinRTClassFactory.RegisterClass(factory); - - var currentExecutingDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - var launchExePath = $"{currentExecutingDir}\\OOPExe.exe"; - var proc = Process.Start(launchExePath); - Thread.Sleep(5000); - obj.Close(); - Assert.True(obj.delegateCalled); - - try - { - proc.Kill(); - } - catch (Exception) - { - } - } + //[Fact] + //public unsafe void TestProxiedDelegate() + //{ + // var obj = new OOPAsyncAction(); + // var factory = new WinRTClassFactory( + // () => obj, + // new Dictionary>() + // { + // { typeof(IAsyncAction).GUID, obj => (IntPtr)WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged((IAsyncAction) obj, typeof(IAsyncAction).GUID).GetThisPtr() }, + // }); + + // WinRTClassFactory.RegisterClass(factory); + + // var currentExecutingDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + // var launchExePath = $"{currentExecutingDir}\\OOPExe.exe"; + // var proc = Process.Start(launchExePath); + // Thread.Sleep(5000); + // obj.Close(); + // Assert.True(obj.delegateCalled); + + // try + // { + // proc.Kill(); + // } + // catch (Exception) + // { + // } + //} [Fact] private async Task TestPnpPropertiesInLoop() diff --git a/src/Tests/UnitTest/UnitTest.csproj b/src/Tests/UnitTest/UnitTest.csproj index 42ef79938..02e8b9b2c 100644 --- a/src/Tests/UnitTest/UnitTest.csproj +++ b/src/Tests/UnitTest/UnitTest.csproj @@ -16,7 +16,7 @@ - + From ca8dd4877673d4fecc27229c847e584351def895 Mon Sep 17 00:00:00 2001 From: Will Thant Date: Thu, 4 Dec 2025 12:08:58 -0800 Subject: [PATCH 31/76] Add back ToString() --- src/WinRT.Runtime2/ABI/System/Type.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index 623a41c40..d16698b9d 100644 --- a/src/WinRT.Runtime2/ABI/System/Type.cs +++ b/src/WinRT.Runtime2/ABI/System/Type.cs @@ -120,7 +120,7 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR goto CustomTypeReference; } - reference = new TypeReference { Name = ExtractTypeName(marshallingInfo.GetRuntimeClassName()), Kind = kind }; + reference = new TypeReference { Name = ExtractTypeName(marshallingInfo.GetRuntimeClassName()).ToString(), Kind = kind }; return; } From 58f71da1d0d8efc4ebc77167f71c40cc3e7f18d1 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 4 Dec 2025 15:34:00 -0800 Subject: [PATCH 32/76] Add 'WindowsRuntimeMetadataTypeNameAttribute' --- ...WindowsRuntimeMetadataTypeNameAttribute.cs | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/WinRT.Runtime2/Attributes/WindowsRuntimeMetadataTypeNameAttribute.cs diff --git a/src/WinRT.Runtime2/Attributes/WindowsRuntimeMetadataTypeNameAttribute.cs b/src/WinRT.Runtime2/Attributes/WindowsRuntimeMetadataTypeNameAttribute.cs new file mode 100644 index 000000000..352cae8da --- /dev/null +++ b/src/WinRT.Runtime2/Attributes/WindowsRuntimeMetadataTypeNameAttribute.cs @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.ComponentModel; + +namespace WindowsRuntime; + +/// +/// Indicates the metadata type class name to use for types exposed to the Windows Runtime. +/// +/// +/// +/// This attribute is only needed for the marshalling infrastructure for custom-mapped types. +/// +/// +/// It differs from in that it represents the metadata name of +/// the type itself, not the runtime class name for when an instance is marshalled to native as an object. +/// For instance, when applied to value types it would contain their type name, not the IReference<T> name. +/// +/// +[AttributeUsage( + AttributeTargets.Class | + AttributeTargets.Struct | + AttributeTargets.Enum | + AttributeTargets.Interface | + AttributeTargets.Delegate, + AllowMultiple = false, + Inherited = false)] +[Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, + DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, + UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] +[EditorBrowsable(EditorBrowsableState.Never)] +public sealed class WindowsRuntimeMetadataTypeNameAttribute : Attribute +{ + /// + /// Creates a new instance with the specified parameters. + /// + /// The metadata type name to use. + public WindowsRuntimeMetadataTypeNameAttribute(string metadataTypeName) + { + MetadataTypeName = metadataTypeName; + } + + /// + /// Gets the metadata type name for the current instance. + /// + public string MetadataTypeName { get; } +} \ No newline at end of file From a719f847dc94644741c303a10497a4bc741e6905 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 4 Dec 2025 15:36:14 -0800 Subject: [PATCH 33/76] Add 'WindowsRuntimeMetadataTypeMapGroup' --- .../WindowsRuntimeMetadataTypeMapGroup.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/WinRT.Runtime2/InteropServices/TypeMapGroups/WindowsRuntimeMetadataTypeMapGroup.cs diff --git a/src/WinRT.Runtime2/InteropServices/TypeMapGroups/WindowsRuntimeMetadataTypeMapGroup.cs b/src/WinRT.Runtime2/InteropServices/TypeMapGroups/WindowsRuntimeMetadataTypeMapGroup.cs new file mode 100644 index 000000000..59b512bf8 --- /dev/null +++ b/src/WinRT.Runtime2/InteropServices/TypeMapGroups/WindowsRuntimeMetadataTypeMapGroup.cs @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.ComponentModel; + +namespace WindowsRuntime.InteropServices; + +/// +/// The type map group placeholder for all Windows Runtime types that need to support marshalling. +/// +/// +/// This type is only meant to be used as type map group for APIs. +/// +[Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, + DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, + UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] +[EditorBrowsable(EditorBrowsableState.Never)] +public abstract class WindowsRuntimeMetadataTypeMapGroup +{ + /// + /// This type should never be instantiated (it just can't be static because it needs to be used as a type argument). + /// + private WindowsRuntimeMetadataTypeMapGroup() + { + } +} \ No newline at end of file From 30d76572dfd6b8e18e8b2d25c3952cfdfc370953 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 4 Dec 2025 16:38:07 -0800 Subject: [PATCH 34/76] Add WindowsRuntimeMetadataInfo for type metadata caching Introduces WindowsRuntimeMetadataInfo, an internal class providing cached metadata information and mapping for Windows Runtime types. This enables efficient lookup and handling of type metadata, supporting marshalling and attribute resolution for projected and proxy types. --- .../TypeMapInfo/WindowsRuntimeMetadataInfo.cs | 191 ++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMetadataInfo.cs diff --git a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMetadataInfo.cs b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMetadataInfo.cs new file mode 100644 index 000000000..18b629818 --- /dev/null +++ b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMetadataInfo.cs @@ -0,0 +1,191 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +#pragma warning disable IDE0008 + +namespace WindowsRuntime.InteropServices; + +/// +/// A type providing cached metadata information on Windows Runtime types. +/// +internal sealed class WindowsRuntimeMetadataInfo +{ + /// + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "We expect external types to only be preserved if used in runtime casts.")] + private static readonly IReadOnlyDictionary ExternalTypeMapping = TypeMapping.GetOrCreateExternalTypeMapping(); + + /// + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "We expect only proxy types for constructed types to be preserved.")] + private static readonly IReadOnlyDictionary ProxyTypeMapping = TypeMapping.GetOrCreateProxyTypeMapping(); + + /// + private static readonly ConcurrentDictionary TypeNameToMappedTypeDictionary = []; + + /// + /// The table of metadata info for all types that require special handling. + /// + /// + /// This will only have non values for types needing special metadata handling. + /// + private static readonly ConditionalWeakTable TypeToMarshallingInfoTable = []; + + /// + /// Cached creation factory for . + /// + private static readonly Func CreateMetadataInfoCallback = new(CreateMetadataInfo); + + /// + /// Cached creation factory for . + /// + private static readonly Func GetMetadataProviderTypeCallback = new(GetMetadataProviderType); + + /// + /// The metadata provider type associated with the current instance (ie. the mapped type to use to resolve attributes). + /// + /// + /// Here's some examples of how this type would relate to the associated metadata type in different scenarios: + /// + /// For a Windows Runtime projected type, this would be the same as the metadata type. + /// For custom-mapped types, this would be some proxy type with the right attributes on it. + /// + /// + private readonly Type _metadataProviderType; + + /// + /// The cached runtime class name for the type. + /// + /// + /// This is only used for managed types that are marshalled to native. For RCWs (ie. for Windows + /// Runtime projected types), the runtime class name would just be provided by the native object. + /// + private volatile string? _metadataTypeName; + + /// + /// Creates a new instance with the specified parameters. + /// + /// + private WindowsRuntimeMetadataInfo(Type metadataProviderType) + { + _metadataProviderType = metadataProviderType; + } + + /// + /// Tries to get a instance for a given metadata type name. + /// + /// The input metadata type name to use for lookups. + /// The resulting instance, if found. + /// Whether was retrieved successfully. + public static bool TryGetInfo(ReadOnlySpan metadataTypeName, [NotNullWhen(true)] out WindowsRuntimeMetadataInfo? info) + { + // Tries to get the external type for the input metadata type name + static Type? TryGetExternalType(ReadOnlySpan runtimeClassName) + { + var alternate = TypeNameToMappedTypeDictionary.GetAlternateLookup>(); + + // Check if we already have a cached result (it might be 'null') + if (alternate.TryGetValue(runtimeClassName, out Type? externalType)) + { + return externalType; + } + + // Try to get the external type (which might not be present, if the entry has been removed) + _ = ExternalTypeMapping.TryGetValue(runtimeClassName.ToString(), out externalType); + + // Try to add the cached value to the table + _ = alternate.TryAdd(runtimeClassName, externalType); + + // Always return the external type (see notes in 'WindowsRuntimeMarshallingInfo') + return externalType; + } + + Type? externalType = TryGetExternalType(metadataTypeName); + + // We found a mapped external type, return its associated marshalling info + if (externalType is not null) + { + info = TypeToMarshallingInfoTable.GetOrAdd(externalType, CreateMetadataInfoCallback)!; + + return true; + } + + info = null; + + return false; + } + + /// + /// Tries to get a instance for a given managed type. + /// + /// The input managed type to use for lookups. + /// The resulting instance, if found. + /// Whether was retrieved successfully. + public static bool TryGetInfo(Type managedType, [NotNullWhen(true)] out WindowsRuntimeMetadataInfo? info) + { + WindowsRuntimeMetadataInfo? result = TypeToMarshallingInfoTable.GetOrAdd(managedType, GetMetadataProviderTypeCallback); + + info = result; + + return result is not null; + } + + /// + /// Gets the metadata type name for the public type associated with the current metadata provider type. + /// + /// The resulting metadata type name. + public string GetMetadataTypeName() + { + [MethodImpl(MethodImplOptions.NoInlining)] + string InitializeMetadataTypeName() + { + WindowsRuntimeMetadataTypeNameAttribute? metadataTypeNameAttribute = + _metadataProviderType.GetCustomAttribute(inherit: false); + + string metadataTypeName = metadataTypeNameAttribute?.MetadataTypeName ?? _metadataProviderType.FullName!; + + return _metadataTypeName ??= metadataTypeName; + } + + return _metadataTypeName ?? InitializeMetadataTypeName(); + } + + /// + /// Creates a instance for a specified metadata provider type. + /// + /// The metadata provider type to wrap. + /// The resulting instance. + private static WindowsRuntimeMetadataInfo CreateMetadataInfo(Type metadataProviderType) + { + return new(metadataProviderType); + } + + /// + /// Creates a instance associated with a given managed type, if possible. + /// + /// The managed type to create an instance for, if possible. + /// The resulting instance, if created successfully. + private static WindowsRuntimeMetadataInfo? GetMetadataProviderType(Type managedType) + { + // Same as above: if the type is a projected type, then it is also used as the metadata source + if (managedType.IsDefined(typeof(WindowsRuntimeMetadataAttribute), inherit: false) && !managedType.IsGenericType) + { + return new(managedType); + } + + // If we have a proxy type, then that will be the metadata provider + if (ProxyTypeMapping.TryGetValue(managedType, out Type? proxyType)) + { + return new(proxyType); + } + + // We don't have a metadata provider for the type (we'll just marshal it as a generic 'IInspectable') + return null; + } +} \ No newline at end of file From 89977a2ecb6b6732ac845698c3f36477df597986 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 4 Dec 2025 16:38:17 -0800 Subject: [PATCH 35/76] Clarify XML documentation in WindowsRuntimeMarshallingInfo Added clarification to XML comments regarding custom-mapped types and fixed a minor typo in the parameter documentation for GetMetadataProviderType. --- .../TypeMapInfo/WindowsRuntimeMarshallingInfo.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs index f36b60f7e..80318276c 100644 --- a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs +++ b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs @@ -84,6 +84,7 @@ internal sealed class WindowsRuntimeMarshallingInfo /// For other generated associations (eg. generic type instantiations), this would also /// be the generated proxy type. This is because there would be no other way to link the /// additional metadata required for marshalling to the original types otherwise. + /// The same applies to custom-mapped types (e.g. fundamental types). /// /// /// @@ -544,7 +545,7 @@ private static WindowsRuntimeMarshallingInfo CreateMarshallingInfo(Type metadata /// /// Creates a instance associated with a given managed type, if possible. /// - /// The managed type to create an instance for, if possible.. + /// The managed type to create an instance for, if possible. /// The resulting instance, if created successfully. private static WindowsRuntimeMarshallingInfo? GetMetadataProviderType(Type managedType) { From 415500db4ce5700ad30f0cc753c155396c7e2299 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 4 Dec 2025 16:50:35 -0800 Subject: [PATCH 36/76] Add PublicType property to WindowsRuntimeMetadataInfo Introduces a PublicType property that lazily initializes and caches the public type using the WindowsRuntimeMappedTypeAttribute. This change improves type mapping and aligns with the implementation in WindowsRuntimeMarshallingInfo. --- .../TypeMapInfo/WindowsRuntimeMetadataInfo.cs | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMetadataInfo.cs b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMetadataInfo.cs index 18b629818..e13093ed5 100644 --- a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMetadataInfo.cs +++ b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMetadataInfo.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.CompilerServices; @@ -59,13 +60,12 @@ internal sealed class WindowsRuntimeMetadataInfo /// private readonly Type _metadataProviderType; + /// + private volatile Type? _publicType; + /// - /// The cached runtime class name for the type. + /// The cached metadata type name for the type. /// - /// - /// This is only used for managed types that are marshalled to native. For RCWs (ie. for Windows - /// Runtime projected types), the runtime class name would just be provided by the native object. - /// private volatile string? _metadataTypeName; /// @@ -77,6 +77,26 @@ private WindowsRuntimeMetadataInfo(Type metadataProviderType) _metadataProviderType = metadataProviderType; } + /// + public Type PublicType + { + get + { + // Same implementation as in 'WindowsRuntimeMarshallingInfo.PublicType', see notes there + [MethodImpl(MethodImplOptions.NoInlining)] + Type InitializePublicType() + { + WindowsRuntimeMappedTypeAttribute mappedTypeAttribute = _metadataProviderType.GetCustomAttribute(inherit: false)!; + + Debug.Assert(mappedTypeAttribute is not null); + + return _publicType ??= mappedTypeAttribute.PublicType; + } + + return _publicType ?? InitializePublicType(); + } + } + /// /// Tries to get a instance for a given metadata type name. /// From d025fe1711b20f3f81810ee13d26f9184c523dfa Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Thu, 4 Dec 2025 16:58:05 -0800 Subject: [PATCH 37/76] Improve handling of nullable types in type marshalling Refactored TypeMarshaller to correctly handle 'Nullable' types by using the underlying type for lookups and skipping metadata table lookup for nullable types. Updated TypeReference to use string for Name and improved marshalling logic. Enhanced WindowsRuntimeMetadataInfo to track and expose the public type for metadata mapping. --- src/WinRT.Runtime2/ABI/System/Type.cs | 66 +++++++++++-------- .../Marshalling/TypeReference.cs | 17 ++--- .../TypeMapInfo/WindowsRuntimeMetadataInfo.cs | 12 ++-- 3 files changed, 54 insertions(+), 41 deletions(-) diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index 7752e321e..c0388789d 100644 --- a/src/WinRT.Runtime2/ABI/System/Type.cs +++ b/src/WinRT.Runtime2/ABI/System/Type.cs @@ -102,8 +102,16 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR return; } - // Use the marshalling info lookup to detect projected or custom-mapped Windows Runtime types - if (WindowsRuntimeMarshallingInfo.TryGetInfo(value, out WindowsRuntimeMarshallingInfo? marshallingInfo) && marshallingInfo.IsMetadataType) + // We need special handling for 'Nullable' values. If we have one, we want to use the underlying type + // for the lookup, because the nullable version would not have any entries in the type map. Additionally, + // we want to skip the metadata table lookup, as that would give us the actual metadata type name for the + // underlying type. Instead, for 'Nullable' values we need the runtime class name, which in this case + // would be the 'IReference' type name for boxed instances of this type. + global::System.Type? nullableUnderlyingType = Nullable.GetUnderlyingType(value); + + // Use the metadata info lookup first to handle projected and custom-mapped Windows Runtime types. + // As mentioned above, we skip this lookup entirely if the input type is a nullable type. + if (nullableUnderlyingType is null && WindowsRuntimeMetadataInfo.TryGetInfo(value, out WindowsRuntimeMetadataInfo? metadataInfo)) { // For primitive types, we always report 'TypeKind.Primitive'. This means that some // types that are C# primitives (e.g. 'sbyte') will be reported as such, even though @@ -112,7 +120,21 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR ? TypeKind.Primitive : TypeKind.Metadata; - reference = new TypeReference { Name = ExtractTypeName(marshallingInfo.GetRuntimeClassName()), Kind = kind }; + reference = new TypeReference { Name = metadataInfo.GetMetadataTypeName(), Kind = kind }; + + return; + } + + global::System.Type typeOrUnderlyingType = nullableUnderlyingType ?? value; + + // Use the marshalling info lookup to detect projected or custom-mapped Windows Runtime types. + // If we have an underlying nullable type, we use that for the lookup instead of the input type. + if (WindowsRuntimeMarshallingInfo.TryGetInfo(typeOrUnderlyingType, out WindowsRuntimeMarshallingInfo? marshallingInfo) && marshallingInfo.IsMetadataType) + { + // Same check as above to differentiate primitive types from metadata types + TypeKind kind = typeOrUnderlyingType.IsPrimitive ? TypeKind.Primitive : TypeKind.Metadata; + + reference = new TypeReference { Name = marshallingInfo.GetRuntimeClassName(), Kind = kind }; return; } @@ -134,26 +156,6 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR reference = new TypeReference { Name = value.AssemblyQualifiedName, Kind = TypeKind.Custom }; } - - /// - /// Private method to extracts the generic type argument from a runtime class name that follows - /// the pattern Windows.Foundation.IReference<T>. - /// - /// - /// The full runtime class name, e.g., Windows.Foundation.IReference<System.Int32>. - /// - /// - /// The inner type name if the input matches the expected pattern; otherwise, the original string. - /// - private static ReadOnlySpan ExtractTypeName(ReadOnlySpan runtimeClassName) - { - const string IReferencePrefix = "Windows.Foundation.IReference<"; - - return runtimeClassName.StartsWith(IReferencePrefix, StringComparison.Ordinal) - ? runtimeClassName[IReferencePrefix.Length..^1] - : runtimeClassName; - } - /// /// Converts an unmanaged to a managed . /// @@ -180,11 +182,21 @@ private static ReadOnlySpan ExtractTypeName(ReadOnlySpan runtimeClas global::System.Type? type = null; - // Try to retrieve the marshalling info for the input type name. - // This will work for both 'Primitive' and 'Metadata' types. - if (WindowsRuntimeMarshallingInfo.TryGetInfo(typeName, out WindowsRuntimeMarshallingInfo? marshallingInfo)) + // If the type was handled by the metadata lookup, get the public type from there + if (WindowsRuntimeMetadataInfo.TryGetInfo(typeName, out WindowsRuntimeMetadataInfo? metadataInfo)) + { + type = metadataInfo.PublicType; + } + else if (WindowsRuntimeMarshallingInfo.TryGetInfo(typeName, out WindowsRuntimeMarshallingInfo? marshallingInfo)) { - type = marshallingInfo.PublicType; + // Otherwise, try to retrieve the marshalling info for the input type name. + // This will work for both 'Primitive' and 'Metadata' types, same as above. + global::System.Type publicType = marshallingInfo.PublicType; + + // TODO + type = publicType.IsValueType + ? typeof(Nullable<>).MakeGenericType(publicType) + : publicType; } // Handle the case of C# primitive types that are not Windows Runtime types. diff --git a/src/WinRT.Runtime2/InteropServices/Marshalling/TypeReference.cs b/src/WinRT.Runtime2/InteropServices/Marshalling/TypeReference.cs index 9e05ceb96..7f50ef269 100644 --- a/src/WinRT.Runtime2/InteropServices/Marshalling/TypeReference.cs +++ b/src/WinRT.Runtime2/InteropServices/Marshalling/TypeReference.cs @@ -3,9 +3,7 @@ using System; using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using Windows.UI.Xaml.Interop; namespace WindowsRuntime.InteropServices.Marshalling; @@ -20,7 +18,7 @@ namespace WindowsRuntime.InteropServices.Marshalling; public unsafe ref struct TypeReference { /// - internal ReadOnlySpan Name; + internal string? Name; /// internal TypeKind Kind; @@ -28,7 +26,7 @@ public unsafe ref struct TypeReference /// /// The to use for marshalling. /// - private HStringReference NameReference; + private HStringReference NameRef; /// /// Converts the current value into a value for marshalling. @@ -53,11 +51,11 @@ public ABI.System.Type ConvertToUnmanaged() public ABI.System.Type ConvertToUnmanagedUnsafe() { HStringMarshaller.ConvertToUnmanagedUnsafe( - value: (char*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(Name)), - length: Name.Length, - reference: out NameReference); + (char*)Unsafe.AsPointer(in Name!.GetPinnableReference()), + Name?.Length, + out NameRef); - return new() { Name = NameReference.HString, Kind = Kind }; + return new() { Name = NameRef.HString, Kind = Kind }; } /// @@ -65,9 +63,8 @@ public ABI.System.Type ConvertToUnmanagedUnsafe() /// /// A pinnable reference for the current value. [MethodImpl(MethodImplOptions.AggressiveInlining)] - [UnscopedRef] public readonly ref byte GetPinnableReference() { - return ref Unsafe.As(ref MemoryMarshal.GetReference(Name)); + return ref Unsafe.As(ref Unsafe.AsRef(in Name!.GetPinnableReference())); } } \ No newline at end of file diff --git a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMetadataInfo.cs b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMetadataInfo.cs index e13093ed5..b825a54ae 100644 --- a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMetadataInfo.cs +++ b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMetadataInfo.cs @@ -72,9 +72,11 @@ internal sealed class WindowsRuntimeMetadataInfo /// Creates a new instance with the specified parameters. /// /// - private WindowsRuntimeMetadataInfo(Type metadataProviderType) + /// + private WindowsRuntimeMetadataInfo(Type metadataProviderType, Type? publicType) { _metadataProviderType = metadataProviderType; + _publicType = publicType; } /// @@ -183,7 +185,9 @@ string InitializeMetadataTypeName() /// The resulting instance. private static WindowsRuntimeMetadataInfo CreateMetadataInfo(Type metadataProviderType) { - return new(metadataProviderType); + return metadataProviderType.IsDefined(typeof(WindowsRuntimeMetadataAttribute), inherit: false) + ? new(metadataProviderType, metadataProviderType) + : new(metadataProviderType, publicType: null); } /// @@ -196,13 +200,13 @@ private static WindowsRuntimeMetadataInfo CreateMetadataInfo(Type metadataProvid // Same as above: if the type is a projected type, then it is also used as the metadata source if (managedType.IsDefined(typeof(WindowsRuntimeMetadataAttribute), inherit: false) && !managedType.IsGenericType) { - return new(managedType); + return new(managedType, managedType); } // If we have a proxy type, then that will be the metadata provider if (ProxyTypeMapping.TryGetValue(managedType, out Type? proxyType)) { - return new(proxyType); + return new(proxyType, managedType); } // We don't have a metadata provider for the type (we'll just marshal it as a generic 'IInspectable') From 50ef998363bc46405963d147df3d557e18bd9bda Mon Sep 17 00:00:00 2001 From: Will Thant Date: Fri, 5 Dec 2025 01:51:23 -0800 Subject: [PATCH 38/76] supress IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling --- src/WinRT.Runtime2/ABI/System/Type.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index c33e2b5ba..9ea9b9ffa 100644 --- a/src/WinRT.Runtime2/ABI/System/Type.cs +++ b/src/WinRT.Runtime2/ABI/System/Type.cs @@ -161,6 +161,7 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR /// The unmanaged value. /// The managed value [UnconditionalSuppressMessage("Trimming", "IL2057", Justification = "Any types which are trimmed are not used by managed user code and there is fallback logic to handle that.")] + [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "")] public static global::System.Type? ConvertToManaged(Type value) { ReadOnlySpan typeName = HStringMarshaller.ConvertToManagedUnsafe(value.Name); From ba5e619944189ebdd6c01edb7625a4cc2f930b4b Mon Sep 17 00:00:00 2001 From: Will Thant Date: Thu, 4 Dec 2025 17:48:41 -0800 Subject: [PATCH 39/76] WindowsRuntimeMetadataTypeMapGroup: --- src/cswinrt/code_writers.h | 18 ++++++++++++++++++ src/cswinrt/main.cpp | 4 ++++ 2 files changed, 22 insertions(+) diff --git a/src/cswinrt/code_writers.h b/src/cswinrt/code_writers.h index 9b67a7d2b..03a9dcbd2 100644 --- a/src/cswinrt/code_writers.h +++ b/src/cswinrt/code_writers.h @@ -4641,6 +4641,24 @@ R"(file static class %InterfaceEntriesImpl )", name, name, bind(type), name, bind(type), name); } + + void write_winrt_windowsmetadata_typemapgroup_assembly_attribute(writer& w, TypeDef const& type) + { + auto projection_name = w.write_temp("%", bind(type, typedef_name_type::NonProjected, true)); + w.write( + R"(#pragma warning disable IL2026 +[assembly: TypeMap( + value: "%", + target: typeof(%), + trimTarget: typeof(%))] +#pragma warning restore IL2026 + +)", + projection_name, + projection_name, + projection_name); + } + void write_winrt_comwrappers_typemapgroup_assembly_attribute(writer& w, TypeDef const& type, bool is_value_type) { auto projection_name = w.write_temp("%", bind(type, typedef_name_type::NonProjected, true)); diff --git a/src/cswinrt/main.cpp b/src/cswinrt/main.cpp index ceb34c7d9..3be87897f 100644 --- a/src/cswinrt/main.cpp +++ b/src/cswinrt/main.cpp @@ -278,18 +278,22 @@ Where is one or more of: break; case category::delegate_type: write_winrt_comwrappers_typemapgroup_assembly_attribute(w, type, true); + write_winrt_windowsmetadata_typemapgroup_assembly_attribute(w, type); break; case category::enum_type: write_winrt_comwrappers_typemapgroup_assembly_attribute(w, type, true); + write_winrt_windowsmetadata_typemapgroup_assembly_attribute(w, type); break; case category::interface_type: write_winrt_idic_typemapgroup_assembly_attribute(w, type); + write_winrt_windowsmetadata_typemapgroup_assembly_attribute(w, type); break; case category::struct_type: // Similarly for API contracts, we don't expect them to be passed across the ABI. if (!is_api_contract_type(type)) { write_winrt_comwrappers_typemapgroup_assembly_attribute(w, type, true); + write_winrt_windowsmetadata_typemapgroup_assembly_attribute(w, type); } break; } From b2c9cb8301641459daf2a52e374dd13d0c9c2351 Mon Sep 17 00:00:00 2001 From: Will Thant Date: Fri, 5 Dec 2025 02:16:22 -0800 Subject: [PATCH 40/76] Test cases with TestComponent and TestComponentCsharp --- .../UnitTest/TestComponentCSharp_Tests.cs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs index 604031a69..d87618268 100644 --- a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs +++ b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs @@ -546,6 +546,38 @@ public void TestBufferTryGetArraySubset() Assert.Equal(2, array.Count); } + [Fact] + public void TestTypePropertyWithTestComponentNested() + { + TestObject.TypeProperty = typeof(TestComponent.Nested); + Assert.Equal("TestComponent.Nested", TestObject.GetTypePropertyAbiName()); + Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); + } + + [Fact] + public void TestTypePropertyWithTestComponentParam10Handler() + { + TestObject.TypeProperty = typeof(TestComponent.Param10Handler); + Assert.Equal("TestComponent.Param10Handler", TestObject.GetTypePropertyAbiName()); + Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); + } + + [Fact] + public void TestTypePropertyWithTestComponentCSharpEnumValue() + { + TestObject.TypeProperty = typeof(TestComponentCSharp.EnumValue); + Assert.Equal("TestComponentCSharp.EnumValue", TestObject.GetTypePropertyAbiName()); + Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); + } + + [Fact] + public void TestTypePropertyWithTestComponentIComposable() + { + TestObject.TypeProperty = typeof(TestComponent.IComposable); + Assert.Equal("TestComponent.IComposable", TestObject.GetTypePropertyAbiName()); + Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); + } + [Fact] public void TestTypePropertyWithSystemType() { From a3cd4992ffb3285724f693635467fe890b0d53e8 Mon Sep 17 00:00:00 2001 From: Will Thant Date: Fri, 5 Dec 2025 02:19:45 -0800 Subject: [PATCH 41/76] TestComponentCsharp Class Test --- .../UnitTest/TestComponentCSharp_Tests.cs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs index d87618268..db9d83d3f 100644 --- a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs +++ b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs @@ -555,10 +555,14 @@ public void TestTypePropertyWithTestComponentNested() } [Fact] - public void TestTypePropertyWithTestComponentParam10Handler() + public void TestTypePropertyWithTestComponentParamHandlers() { - TestObject.TypeProperty = typeof(TestComponent.Param10Handler); - Assert.Equal("TestComponent.Param10Handler", TestObject.GetTypePropertyAbiName()); + TestObject.TypeProperty = typeof(TestComponent.Param6Handler); + Assert.Equal("TestComponent.Param6Handler", TestObject.GetTypePropertyAbiName()); + Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); + + TestObject.TypeProperty = typeof(TestComponent.Param7Handler); + Assert.Equal("TestComponent.Param7Handler", TestObject.GetTypePropertyAbiName()); Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); } @@ -578,6 +582,14 @@ public void TestTypePropertyWithTestComponentIComposable() Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); } + [Fact] + public void TestTypePropertyWithTestComponentCSharpClass() + { + TestObject.TypeProperty = typeof(TestComponentCSharp.Class); + Assert.Equal("TestComponentCSharp.Class", TestObject.GetTypePropertyAbiName()); + Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); + } + [Fact] public void TestTypePropertyWithSystemType() { From 47b6af222ac9f0be909acc2880413484e2f7a084 Mon Sep 17 00:00:00 2001 From: Will Thant Date: Fri, 5 Dec 2025 11:01:50 -0800 Subject: [PATCH 42/76] refactor code gen on disable and restore on IL2026 --- src/cswinrt/code_writers.h | 24 ++++++++++++++++++------ src/cswinrt/main.cpp | 3 +++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/cswinrt/code_writers.h b/src/cswinrt/code_writers.h index 03a9dcbd2..ed1589aff 100644 --- a/src/cswinrt/code_writers.h +++ b/src/cswinrt/code_writers.h @@ -4642,17 +4642,31 @@ R"(file static class %InterfaceEntriesImpl } + void write_pragma_restore_IL2026(writer& w) + { + w.write( +R"( +#pragma warning restore IL2026 +)"); + } + + void write_pragma_disable_IL2026(writer& w) + { + w.write( +R"( +#pragma warning disable IL2026 +)"); + } + void write_winrt_windowsmetadata_typemapgroup_assembly_attribute(writer& w, TypeDef const& type) { auto projection_name = w.write_temp("%", bind(type, typedef_name_type::NonProjected, true)); w.write( - R"(#pragma warning disable IL2026 +R"( [assembly: TypeMap( value: "%", target: typeof(%), trimTarget: typeof(%))] -#pragma warning restore IL2026 - )", projection_name, projection_name, @@ -4663,13 +4677,11 @@ R"(file static class %InterfaceEntriesImpl { auto projection_name = w.write_temp("%", bind(type, typedef_name_type::NonProjected, true)); w.write( -R"(#pragma warning disable IL2026 +R"( [assembly: TypeMap( value: "%", target: typeof(%), trimTarget: typeof(%))] -#pragma warning restore IL2026 - )", bind([&](writer& w) { if (is_value_type) diff --git a/src/cswinrt/main.cpp b/src/cswinrt/main.cpp index 3be87897f..9450adf2c 100644 --- a/src/cswinrt/main.cpp +++ b/src/cswinrt/main.cpp @@ -263,9 +263,11 @@ Where is one or more of: continue; } } + auto guard{ w.push_generic_params(type.GenericParam()) }; auto guard1{ helperWriter.push_generic_params(type.GenericParam()) }; + write_pragma_disable_IL2026(w); switch (get_category(type)) { case category::class_type: @@ -297,6 +299,7 @@ Where is one or more of: } break; } + write_pragma_restore_IL2026(w); } // Attributes need to be written at the start, so handling this addition separately. From 858bd0a91f4033d62cb491e274cc005f00baba5f Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 5 Dec 2025 13:20:29 -0800 Subject: [PATCH 43/76] Add WindowsRuntimeReferenceTypeAttribute class Introduces the WindowsRuntimeReferenceTypeAttribute for annotating Windows Runtime value types with their associated reference types. This attribute is intended for use with the type marshalling infrastructure and is marked obsolete for internal implementation details. --- .../WindowsRuntimeReferenceTypeAttribute.cs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/WinRT.Runtime2/Attributes/WindowsRuntimeReferenceTypeAttribute.cs diff --git a/src/WinRT.Runtime2/Attributes/WindowsRuntimeReferenceTypeAttribute.cs b/src/WinRT.Runtime2/Attributes/WindowsRuntimeReferenceTypeAttribute.cs new file mode 100644 index 000000000..68f1a6e26 --- /dev/null +++ b/src/WinRT.Runtime2/Attributes/WindowsRuntimeReferenceTypeAttribute.cs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.ComponentModel; + +namespace WindowsRuntime; + +/// +/// Indicates the reference type associated to a given Windows Runtime value type. +/// +/// This attribute is only needed for the marshalling infrastructure. +[AttributeUsage( + AttributeTargets.Class | + AttributeTargets.Struct | + AttributeTargets.Enum, + AllowMultiple = false, + Inherited = false)] +[Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, + DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, + UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] +[EditorBrowsable(EditorBrowsableState.Never)] +public sealed class WindowsRuntimeReferenceTypeAttribute : Attribute +{ + /// + /// Creates a new instance with the specified parameters. + /// + /// The reference type (a constructed type) for the annotated type. + public WindowsRuntimeReferenceTypeAttribute(Type referenceType) + { + ReferenceType = referenceType; + } + + /// + /// Gets the reference type (a constructed type) for the annotated type. + /// + public Type ReferenceType { get; } +} \ No newline at end of file From 06791914bf872cdc4e21b4a25f7c2c9f38b70797 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 5 Dec 2025 13:42:31 -0800 Subject: [PATCH 44/76] Add ReferenceType property to WindowsRuntimeMarshallingInfo Introduces a ReferenceType property to WindowsRuntimeMarshallingInfo to provide the constructed Nullable type for value types. Updates TypeMarshaller to use this property for value types instead of constructing Nullable directly, improving type resolution and attribute validation. --- src/WinRT.Runtime2/ABI/System/Type.cs | 7 ++- .../WindowsRuntimeMarshallingInfo.cs | 44 +++++++++++++++++++ 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index 9ea9b9ffa..e1aaff947 100644 --- a/src/WinRT.Runtime2/ABI/System/Type.cs +++ b/src/WinRT.Runtime2/ABI/System/Type.cs @@ -193,10 +193,9 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR // This will work for both 'Primitive' and 'Metadata' types, same as above. global::System.Type publicType = marshallingInfo.PublicType; - // TODO - type = publicType.IsValueType - ? typeof(Nullable<>).MakeGenericType(publicType) - : publicType; + // For value types, we get the reference type (i.e. the constructed 'Nullable' type) + // from the marshalling info. This will perform a lookup for '[WindowsRuntimeReferenceType]'. + type = publicType.IsValueType ? marshallingInfo.ReferenceType : publicType; } // Handle the case of C# primitive types that are not Windows Runtime types. diff --git a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs index 80318276c..12d63e4f0 100644 --- a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs +++ b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs @@ -95,6 +95,11 @@ internal sealed class WindowsRuntimeMarshallingInfo /// private volatile Type? _publicType; + /// + /// The reference type (a constructed type) for the current instance. + /// + private volatile Type? _referenceType; + /// /// The cached instance (possibly a placeholder). /// @@ -176,6 +181,45 @@ Type InitializePublicType() } } + /// + /// Gets the reference type (a constructed type) for the current instance. + /// + public Type ReferenceType + { + get + { + [MethodImpl(MethodImplOptions.NoInlining)] + Type InitializeReferenceType() + { + // Try to get the attribute, which should always be present for value types + WindowsRuntimeReferenceTypeAttribute? referenceTypeAttribute = _metadataProviderType.GetCustomAttribute(inherit: false); + + // Analogous validation as for when retrieving the marshaller attribute + [DoesNotReturn] + [StackTraceHidden] + void ThrowNotSupportedException() + { + throw new NotSupportedException( + $"The metadata provider type '{_metadataProviderType}' does not have an associated reference type. " + + $"This code path should have never been reached. Please file an issue at https://github.com/microsoft/CsWinRT."); + } + + // We expect this to always be present for value types. If the attribute is 'null', it means that + // either a value type was missing it, or that 'ReferenceType' was accessed for an invalid public + // type (e.g. some Windows Runtime class type). In both cases, this is a bug, and we should throw. + if (referenceTypeAttribute is null) + { + ThrowNotSupportedException(); + } + + // Cache the reference type for later (no interlocked operations are needed, same as above) + return _referenceType ??= referenceTypeAttribute.ReferenceType; + } + + return _referenceType ?? InitializeReferenceType(); + } + } + /// /// Gets whether or not the managed type for the current instance is a Windows Runtime type (either projected or custom-mapped). /// From 6bb2e678166c1cbbea8733eb3b03dbd121c46bb8 Mon Sep 17 00:00:00 2001 From: Will Thant Date: Fri, 5 Dec 2025 14:02:14 -0800 Subject: [PATCH 45/76] Adding WindowsRuntimeReferenceType attribute on CodeWriters.h --- src/cswinrt/code_writers.h | 11 +++++++++-- src/cswinrt/main.cpp | 12 ++++++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/cswinrt/code_writers.h b/src/cswinrt/code_writers.h index ed1589aff..68ad72680 100644 --- a/src/cswinrt/code_writers.h +++ b/src/cswinrt/code_writers.h @@ -4721,6 +4721,11 @@ R"( bind(type, typedef_name_type::ABI, true)); } + void write_winrt_reference_type_attribute(writer& w, TypeDef const& type) + { + w.write("[WindowsRuntimeReferenceType(typeof(%?))]\n", type.TypeName()); + } + void write_winrt_metadata_attribute(writer& w, TypeDef const& type) { std::filesystem::path db_path(type.get_database().path()); @@ -9182,13 +9187,14 @@ internal unsafe struct %Vftbl w.write( R"( -%%%%% enum % : % +%%%%%% enum % : % { )", is_flags_enum(type) ? "[FlagsAttribute]\n" : "", bind(type), bind(type, true), bind(type), + bind(type), (settings.internal) ? "internal" : "public", bind(type, typedef_name_type::Projected, false), enum_underlying_type); { @@ -9247,10 +9253,11 @@ R"( } // struct - w.write("%%%public% struct %: IEquatable<%>\n{\n", + w.write("%%%%public% struct %: IEquatable<%>\n{\n", bind(type), bind(type), bind(type), + bind(type), has_addition_to_type(type) ? " partial" : "", type.TypeName(), type.TypeName()); diff --git a/src/cswinrt/main.cpp b/src/cswinrt/main.cpp index 9450adf2c..3638304ae 100644 --- a/src/cswinrt/main.cpp +++ b/src/cswinrt/main.cpp @@ -267,7 +267,6 @@ Where is one or more of: auto guard{ w.push_generic_params(type.GenericParam()) }; auto guard1{ helperWriter.push_generic_params(type.GenericParam()) }; - write_pragma_disable_IL2026(w); switch (get_category(type)) { case category::class_type: @@ -275,31 +274,40 @@ Where is one or more of: if (!is_static(type) && !is_attribute_type(type)) { + write_pragma_disable_IL2026(w); write_winrt_comwrappers_typemapgroup_assembly_attribute(w, type, false); + write_pragma_restore_IL2026(w); } break; case category::delegate_type: + write_pragma_disable_IL2026(w); write_winrt_comwrappers_typemapgroup_assembly_attribute(w, type, true); write_winrt_windowsmetadata_typemapgroup_assembly_attribute(w, type); + write_pragma_restore_IL2026(w); break; case category::enum_type: + write_pragma_disable_IL2026(w); write_winrt_comwrappers_typemapgroup_assembly_attribute(w, type, true); write_winrt_windowsmetadata_typemapgroup_assembly_attribute(w, type); + write_pragma_restore_IL2026(w); break; case category::interface_type: + write_pragma_disable_IL2026(w); write_winrt_idic_typemapgroup_assembly_attribute(w, type); write_winrt_windowsmetadata_typemapgroup_assembly_attribute(w, type); + write_pragma_restore_IL2026(w); break; case category::struct_type: // Similarly for API contracts, we don't expect them to be passed across the ABI. if (!is_api_contract_type(type)) { + write_pragma_disable_IL2026(w); write_winrt_comwrappers_typemapgroup_assembly_attribute(w, type, true); write_winrt_windowsmetadata_typemapgroup_assembly_attribute(w, type); + write_pragma_restore_IL2026(w); } break; } - write_pragma_restore_IL2026(w); } // Attributes need to be written at the start, so handling this addition separately. From f4a2151c49c7512e6156948f8ddec60f9b929408 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 5 Dec 2025 14:15:53 -0800 Subject: [PATCH 46/76] Refactor reference type handling in marshalling info Replaces the ReferenceType property with GetReferenceType and TryGetReferenceType methods for improved error handling and caching. Introduces a placeholder WindowsRuntimeReferenceTypeAttribute for cases where the reference type is missing. Also updates placeholder attribute instance declarations to be readonly. --- .../WindowsRuntimeMarshallingInfo.cs | 119 +++++++++++------- 1 file changed, 77 insertions(+), 42 deletions(-) diff --git a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs index 12d63e4f0..fc8fe4b1c 100644 --- a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs +++ b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs @@ -96,9 +96,9 @@ internal sealed class WindowsRuntimeMarshallingInfo private volatile Type? _publicType; /// - /// The reference type (a constructed type) for the current instance. + /// The cached instance (possibly a placeholder). /// - private volatile Type? _referenceType; + private volatile WindowsRuntimeReferenceTypeAttribute? _referenceType; /// /// The cached instance (possibly a placeholder). @@ -181,45 +181,6 @@ Type InitializePublicType() } } - /// - /// Gets the reference type (a constructed type) for the current instance. - /// - public Type ReferenceType - { - get - { - [MethodImpl(MethodImplOptions.NoInlining)] - Type InitializeReferenceType() - { - // Try to get the attribute, which should always be present for value types - WindowsRuntimeReferenceTypeAttribute? referenceTypeAttribute = _metadataProviderType.GetCustomAttribute(inherit: false); - - // Analogous validation as for when retrieving the marshaller attribute - [DoesNotReturn] - [StackTraceHidden] - void ThrowNotSupportedException() - { - throw new NotSupportedException( - $"The metadata provider type '{_metadataProviderType}' does not have an associated reference type. " + - $"This code path should have never been reached. Please file an issue at https://github.com/microsoft/CsWinRT."); - } - - // We expect this to always be present for value types. If the attribute is 'null', it means that - // either a value type was missing it, or that 'ReferenceType' was accessed for an invalid public - // type (e.g. some Windows Runtime class type). In both cases, this is a bug, and we should throw. - if (referenceTypeAttribute is null) - { - ThrowNotSupportedException(); - } - - // Cache the reference type for later (no interlocked operations are needed, same as above) - return _referenceType ??= referenceTypeAttribute.ReferenceType; - } - - return _referenceType ?? InitializeReferenceType(); - } - } - /// /// Gets whether or not the managed type for the current instance is a Windows Runtime type (either projected or custom-mapped). /// @@ -570,6 +531,69 @@ void ThrowNotSupportedException() return _runtimeClassName ?? InitializeRuntimeClassName(); } + /// + /// Gets the reference type (a constructed type) for the current instance. + /// + /// Thrown if no reference type (a constructed type) could be resolved. + public Type GetReferenceType() + { + if (!TryGetReferenceType(out Type? referenceType)) + { + // Analogous validation as for when retrieving the marshaller attribute + [DoesNotReturn] + [StackTraceHidden] + void ThrowNotSupportedException() + { + throw new NotSupportedException( + $"The metadata provider type '{_metadataProviderType}' does not have an associated reference type. " + + $"This code path should have never been reached. Please file an issue at https://github.com/microsoft/CsWinRT."); + } + + ThrowNotSupportedException(); + } + + return referenceType; + } + + /// + /// Tries to get the reference type (a constructed type) for the current instance. + /// + /// The resulting reference type (a constructed type) for the current instance, if available. + /// Whether was retrieved successfully. + public bool TryGetReferenceType([NotNullWhen(true)] out Type? referenceType) + { + // Initializes the reference type instance, if present + [MethodImpl(MethodImplOptions.NoInlining)] + bool Load([NotNullWhen(true)] out Type? referenceType) + { + // Try to get the attribute, which should always be present for value types + WindowsRuntimeReferenceTypeAttribute? referenceTypeAttribute = _metadataProviderType.GetCustomAttribute(inherit: false); + + referenceTypeAttribute ??= PlaceholderWindowsRuntimeReferenceTypeAttribute.Instance; + + _referenceType = referenceTypeAttribute; + + referenceType = referenceTypeAttribute.ReferenceType; + + return referenceType is not null; + } + + WindowsRuntimeReferenceTypeAttribute? referenceTypeAttribute = _referenceType; + + // We have a cached reference type, so return it immediately. + // The instance we have here could be the placeholder one that + // returns 'null', but it's still faster to do just do the check + // here than comparing the instance by accessing that static field. + if (referenceTypeAttribute is not null) + { + referenceType = referenceTypeAttribute.ReferenceType; + + return referenceType is not null; + } + + return Load(out referenceType); + } + /// /// Creates a instance for a specified metadata provider type. /// @@ -629,7 +653,7 @@ private static WindowsRuntimeMarshallingInfo CreateMarshallingInfo(Type metadata /// /// The shared placeholder instance. /// - public static PlaceholderWindowsRuntimeComWrappersMarshallerAttribute Instance = new(); + public static readonly PlaceholderWindowsRuntimeComWrappersMarshallerAttribute Instance = new(); /// public override void* GetOrCreateComInterfaceForObject(object value) @@ -652,4 +676,15 @@ public override object CreateObject(void* value, out CreatedWrapperFlags wrapper return null!; } +} + +/// +/// A placeholder type. +/// +file sealed class PlaceholderWindowsRuntimeReferenceTypeAttribute +{ + /// + /// The shared instance (it will return for its reference type). + /// + public static readonly WindowsRuntimeReferenceTypeAttribute Instance = new(null!); } \ No newline at end of file From 11c2c81afa619896bdbd69af761182cfd7ccac68 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 5 Dec 2025 14:28:32 -0800 Subject: [PATCH 47/76] Add support for metadata type name caching and retrieval Introduces a volatile field to cache the metadata type name and implements GetMetadataTypeName and TryGetMetadataTypeName methods for retrieving it. This enables efficient access to metadata type names for marshalling scenarios, with error handling for unsupported types. --- .../WindowsRuntimeMarshallingInfo.cs | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs index fc8fe4b1c..58a7fbd96 100644 --- a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs +++ b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs @@ -119,6 +119,14 @@ internal sealed class WindowsRuntimeMarshallingInfo /// private volatile string? _runtimeClassName; + /// + /// The cached metadata type name for the type. + /// + /// + /// This is only used for marshalling, and it will only be available for some types (e.g. value types). + /// + private volatile string? _metadataTypeName; + /// /// A flag indicating whether the current type is a type defined in metadata (either projected or custom-mapped). /// @@ -531,6 +539,80 @@ void ThrowNotSupportedException() return _runtimeClassName ?? InitializeRuntimeClassName(); } + /// + /// Gets the metadata type name for the public type associated with the current metadata provider type. + /// + /// The resulting metadata type name. + /// Thrown if no metadata type name could be resolved. + public string GetMetadataTypeName() + { + if (!TryGetMetadataTypeName(out string? metadataTypeName)) + { + // Analogous validation as for when retrieving the marshaller attribute + [DoesNotReturn] + [StackTraceHidden] + void ThrowNotSupportedException() + { + throw new NotSupportedException( + $"The metadata provider type '{_metadataProviderType}' does not have any metadata type name info. " + + $"This path should never be reached. Please file an issue at https://github.com/microsoft/CsWinRT."); + } + + ThrowNotSupportedException(); + } + + return metadataTypeName; + } + + /// + /// Tries to get the metadata type name for the public type associated with the current metadata provider type. + /// + /// The resulting metadata type name, if available. + /// Whether was retrieved successfully. + public bool TryGetMetadataTypeName([NotNullWhen(true)] out string? metadataTypeName) + { + // Initializes the reference type instance, if present + [MethodImpl(MethodImplOptions.NoInlining)] + bool Load([NotNullWhen(true)] out string? metadataTypeName) + { + WindowsRuntimeMetadataTypeNameAttribute? metadataTypeNameAttribute = _metadataProviderType.GetCustomAttribute(inherit: false); + + if (metadataTypeNameAttribute is null) + { + _metadataTypeName ??= ""; + + metadataTypeName = null; + + return false; + } + + _metadataTypeName = metadataTypeNameAttribute.MetadataTypeName; + + metadataTypeName = metadataTypeNameAttribute.MetadataTypeName; + + return true; + } + + string? value = _metadataTypeName; + + // We have a cached metadata type name, so return it immediately + if (value is not null) + { + if (value is "") + { + metadataTypeName = null; + + return false; + } + + metadataTypeName = value; + + return true; + } + + return Load(out metadataTypeName); + } + /// /// Gets the reference type (a constructed type) for the current instance. /// From 20ab9f23f6677b22c5606958e0e20c722f73500b Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 5 Dec 2025 14:29:52 -0800 Subject: [PATCH 48/76] Refactor reference type handling in marshalling info Replaces the cached WindowsRuntimeReferenceTypeAttribute with a cached Type for reference type. Removes GetReferenceType and TryGetReferenceType methods, introducing a ReferenceType property for direct access and caching. This simplifies reference type retrieval and improves code clarity. --- .../WindowsRuntimeMarshallingInfo.cs | 106 +++++++----------- 1 file changed, 41 insertions(+), 65 deletions(-) diff --git a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs index 58a7fbd96..809dff808 100644 --- a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs +++ b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs @@ -96,9 +96,9 @@ internal sealed class WindowsRuntimeMarshallingInfo private volatile Type? _publicType; /// - /// The cached instance (possibly a placeholder). + /// The reference type (a constructed type) for the current instance. /// - private volatile WindowsRuntimeReferenceTypeAttribute? _referenceType; + private volatile Type? _referenceType; /// /// The cached instance (possibly a placeholder). @@ -189,6 +189,45 @@ Type InitializePublicType() } } + /// + /// Gets the reference type (a constructed type) for the current instance. + /// + public Type ReferenceType + { + get + { + [MethodImpl(MethodImplOptions.NoInlining)] + Type InitializeReferenceType() + { + // Try to get the attribute, which should always be present for value types + WindowsRuntimeReferenceTypeAttribute? referenceTypeAttribute = _metadataProviderType.GetCustomAttribute(inherit: false); + + // Analogous validation as for when retrieving the marshaller attribute + [DoesNotReturn] + [StackTraceHidden] + void ThrowNotSupportedException() + { + throw new NotSupportedException( + $"The metadata provider type '{_metadataProviderType}' does not have an associated reference type. " + + $"This code path should have never been reached. Please file an issue at https://github.com/microsoft/CsWinRT."); + } + + // We expect this to always be present for value types. If the attribute is 'null', it means that + // either a value type was missing it, or that 'ReferenceType' was accessed for an invalid public + // type (e.g. some Windows Runtime class type). In both cases, this is a bug, and we should throw. + if (referenceTypeAttribute is null) + { + ThrowNotSupportedException(); + } + + // Cache the reference type for later (no interlocked operations are needed, same as above) + return _referenceType ??= referenceTypeAttribute.ReferenceType; + } + + return _referenceType ?? InitializeReferenceType(); + } + } + /// /// Gets whether or not the managed type for the current instance is a Windows Runtime type (either projected or custom-mapped). /// @@ -613,69 +652,6 @@ bool Load([NotNullWhen(true)] out string? metadataTypeName) return Load(out metadataTypeName); } - /// - /// Gets the reference type (a constructed type) for the current instance. - /// - /// Thrown if no reference type (a constructed type) could be resolved. - public Type GetReferenceType() - { - if (!TryGetReferenceType(out Type? referenceType)) - { - // Analogous validation as for when retrieving the marshaller attribute - [DoesNotReturn] - [StackTraceHidden] - void ThrowNotSupportedException() - { - throw new NotSupportedException( - $"The metadata provider type '{_metadataProviderType}' does not have an associated reference type. " + - $"This code path should have never been reached. Please file an issue at https://github.com/microsoft/CsWinRT."); - } - - ThrowNotSupportedException(); - } - - return referenceType; - } - - /// - /// Tries to get the reference type (a constructed type) for the current instance. - /// - /// The resulting reference type (a constructed type) for the current instance, if available. - /// Whether was retrieved successfully. - public bool TryGetReferenceType([NotNullWhen(true)] out Type? referenceType) - { - // Initializes the reference type instance, if present - [MethodImpl(MethodImplOptions.NoInlining)] - bool Load([NotNullWhen(true)] out Type? referenceType) - { - // Try to get the attribute, which should always be present for value types - WindowsRuntimeReferenceTypeAttribute? referenceTypeAttribute = _metadataProviderType.GetCustomAttribute(inherit: false); - - referenceTypeAttribute ??= PlaceholderWindowsRuntimeReferenceTypeAttribute.Instance; - - _referenceType = referenceTypeAttribute; - - referenceType = referenceTypeAttribute.ReferenceType; - - return referenceType is not null; - } - - WindowsRuntimeReferenceTypeAttribute? referenceTypeAttribute = _referenceType; - - // We have a cached reference type, so return it immediately. - // The instance we have here could be the placeholder one that - // returns 'null', but it's still faster to do just do the check - // here than comparing the instance by accessing that static field. - if (referenceTypeAttribute is not null) - { - referenceType = referenceTypeAttribute.ReferenceType; - - return referenceType is not null; - } - - return Load(out referenceType); - } - /// /// Creates a instance for a specified metadata provider type. /// From 2318cf4b1d518a57123ba9e4ca8ca378dc5f6f3f Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 5 Dec 2025 14:38:45 -0800 Subject: [PATCH 49/76] Enhance Type marshalling for Windows Runtime types Refactors Type marshalling logic to use WindowsRuntimeMarshallingInfo for improved detection of projected and custom-mapped Windows Runtime types. Adds new assembly and class attributes for TypeName metadata, updates handling of nullable types, and clarifies logic for primitive and metadata type name resolution. Also adds TODOs for further handling of specific IReference and delegate types. --- src/WinRT.Runtime2/ABI/System/Type.cs | 40 +++++++++++++++++---------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index e1aaff947..2f8d5bd52 100644 --- a/src/WinRT.Runtime2/ABI/System/Type.cs +++ b/src/WinRT.Runtime2/ABI/System/Type.cs @@ -20,6 +20,11 @@ #pragma warning disable IDE1006, CA1416 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Windows.UI.Xaml.Interop.TypeName", + target: typeof(ABI.System.Type), + trimTarget: typeof(Type))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(ABI.System.Type), @@ -36,6 +41,7 @@ namespace ABI.System; /// [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("Windows.UI.Xaml.Interop.TypeName")] [TypeComWrappersMarshaller] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -108,10 +114,11 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR // underlying type. Instead, for 'Nullable' values we need the runtime class name, which in this case // would be the 'IReference' type name for boxed instances of this type. global::System.Type? nullableUnderlyingType = Nullable.GetUnderlyingType(value); + global::System.Type typeOrUnderlyingType = nullableUnderlyingType ?? value; - // Use the metadata info lookup first to handle projected and custom-mapped Windows Runtime types. - // As mentioned above, we skip this lookup entirely if the input type is a nullable type. - if (nullableUnderlyingType is null && WindowsRuntimeMetadataInfo.TryGetInfo(value, out WindowsRuntimeMetadataInfo? metadataInfo)) + // Use the marshalling info lookup to detect projected or custom-mapped Windows Runtime types. + // If we have an underlying nullable type, we use that for the lookup instead of the input type. + if (WindowsRuntimeMarshallingInfo.TryGetInfo(typeOrUnderlyingType, out WindowsRuntimeMarshallingInfo? marshallingInfo) && marshallingInfo.IsMetadataType) { // For primitive types, we always report 'TypeKind.Primitive'. This means that some // types that are C# primitives (e.g. 'sbyte') will be reported as such, even though @@ -120,21 +127,22 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR ? TypeKind.Primitive : TypeKind.Metadata; - reference = new TypeReference { Name = metadataInfo.GetMetadataTypeName(), Kind = kind }; - return; - } - - global::System.Type typeOrUnderlyingType = nullableUnderlyingType ?? value; + // Special case primitive types that are of types that can be boxed. That is, if the input type is not + // some 'Nullable' type, check if we have an explicit metadata type name, and use that if so. This + // will ensure that e.g. 'typeof(int)' will report 'Int32', rather than 'Windows.Foundation.IReference'. + if (nullableUnderlyingType is null && marshallingInfo.TryGetMetadataTypeName(out string? metadataTypeName)) + { + reference = new TypeReference { Name = metadataTypeName, Kind = kind }; - // Use the marshalling info lookup to detect projected or custom-mapped Windows Runtime types. - // If we have an underlying nullable type, we use that for the lookup instead of the input type. - if (WindowsRuntimeMarshallingInfo.TryGetInfo(typeOrUnderlyingType, out WindowsRuntimeMarshallingInfo? marshallingInfo) && marshallingInfo.IsMetadataType) - { - // Same check as above to differentiate primitive types from metadata types - TypeKind kind = typeOrUnderlyingType.IsPrimitive ? TypeKind.Primitive : TypeKind.Metadata; + return; + } + // In all other cases, just use the runtime class name, which will always be present. This will also + // account for all constructed 'Nullable' instantiations, which will report their boxed type name. reference = new TypeReference { Name = marshallingInfo.GetRuntimeClassName(), Kind = kind }; + // TODO: handle 'Nullable>' here + return; } @@ -161,7 +169,6 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR /// The unmanaged value. /// The managed value [UnconditionalSuppressMessage("Trimming", "IL2057", Justification = "Any types which are trimmed are not used by managed user code and there is fallback logic to handle that.")] - [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "")] public static global::System.Type? ConvertToManaged(Type value) { ReadOnlySpan typeName = HStringMarshaller.ConvertToManagedUnsafe(value.Name); @@ -182,6 +189,9 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR global::System.Type? type = null; + // TODO: handle 'IReference', 'IReference' and 'IReference'. + // Those should all be reported as 'NoMetadataTypeInfo', not as the custom-mapped C# type. + // If the type was handled by the metadata lookup, get the public type from there if (WindowsRuntimeMetadataInfo.TryGetInfo(typeName, out WindowsRuntimeMetadataInfo? metadataInfo)) { From 91340b6d318e08590ca3af3946767c134fd9552f Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 5 Dec 2025 15:31:58 -0800 Subject: [PATCH 50/76] Add WindowsRuntime type mapping attributes Introduces [TypeMap] and related attributes for WindowsRuntime type mapping in ABI classes, including metadata type names and reference types. Updates marshaller and interface implementations to use fully qualified type names for clarity and consistency with WindowsRuntime interop. --- src/WinRT.Runtime2/ABI/System/Boolean.cs | 7 ++ src/WinRT.Runtime2/ABI/System/Byte.cs | 7 ++ src/WinRT.Runtime2/ABI/System/Char.cs | 7 ++ .../ABI/System/DateTimeOffset.cs | 7 ++ src/WinRT.Runtime2/ABI/System/Double.cs | 7 ++ src/WinRT.Runtime2/ABI/System/Exception.cs | 6 ++ src/WinRT.Runtime2/ABI/System/Guid.cs | 7 ++ src/WinRT.Runtime2/ABI/System/IDisposable.cs | 46 +++++++---- .../ABI/System/IServiceProvider.cs | 48 +++++++---- src/WinRT.Runtime2/ABI/System/Int16.cs | 7 ++ src/WinRT.Runtime2/ABI/System/Int32.cs | 7 ++ src/WinRT.Runtime2/ABI/System/Int64.cs | 7 ++ .../ABI/System/Numerics/Matrix3x2.cs | 7 ++ .../ABI/System/Numerics/Matrix4x4.cs | 7 ++ .../ABI/System/Numerics/Plane.cs | 7 ++ .../ABI/System/Numerics/Quaternion.cs | 7 ++ .../ABI/System/Numerics/Vector2.cs | 7 ++ .../ABI/System/Numerics/Vector3.cs | 7 ++ .../ABI/System/Numerics/Vector4.cs | 7 ++ src/WinRT.Runtime2/ABI/System/Object.cs | 7 ++ src/WinRT.Runtime2/ABI/System/Single.cs | 7 ++ src/WinRT.Runtime2/ABI/System/String.cs | 6 ++ src/WinRT.Runtime2/ABI/System/TimeSpan.cs | 7 ++ src/WinRT.Runtime2/ABI/System/UInt16.cs | 7 ++ src/WinRT.Runtime2/ABI/System/UInt32.cs | 7 ++ src/WinRT.Runtime2/ABI/System/UInt64.cs | 7 ++ src/WinRT.Runtime2/ABI/System/Uri.cs | 1 + .../Collections/CollectionChange.cs | 5 ++ .../Collections/IVectorChangedEventArgs.cs | 64 +++++++++------ .../ABI/Windows.Foundation/IAsyncAction.cs | 64 +++++++++------ .../ABI/Windows.Foundation/IAsyncInfo.cs | 82 +++++++++++-------- .../ABI/Windows.Foundation/Point.cs | 5 ++ .../ABI/Windows.Foundation/Rect.cs | 5 ++ .../ABI/Windows.Foundation/Size.cs | 5 ++ .../Collections/CollectionChange.cs | 2 + .../Windows.Foundation/Point.cs | 2 + src/WinRT.Runtime2/Windows.Foundation/Rect.cs | 2 + src/WinRT.Runtime2/Windows.Foundation/Size.cs | 2 + 38 files changed, 385 insertions(+), 114 deletions(-) diff --git a/src/WinRT.Runtime2/ABI/System/Boolean.cs b/src/WinRT.Runtime2/ABI/System/Boolean.cs index 3acc81388..421f3f67e 100644 --- a/src/WinRT.Runtime2/ABI/System/Boolean.cs +++ b/src/WinRT.Runtime2/ABI/System/Boolean.cs @@ -14,6 +14,11 @@ #pragma warning disable IDE1006, CA1416 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Boolean", + target: typeof(ABI.System.Boolean), + trimTarget: typeof(bool))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(ABI.System.Boolean), @@ -29,6 +34,8 @@ namespace ABI.System; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("Boolean")] +[WindowsRuntimeReferenceType(typeof(bool?))] [BooleanComWrappersMarshaller] file static class Boolean; diff --git a/src/WinRT.Runtime2/ABI/System/Byte.cs b/src/WinRT.Runtime2/ABI/System/Byte.cs index 4ab29ddc0..57dde057c 100644 --- a/src/WinRT.Runtime2/ABI/System/Byte.cs +++ b/src/WinRT.Runtime2/ABI/System/Byte.cs @@ -14,6 +14,11 @@ #pragma warning disable IDE1006, CA1416 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "UInt8", + target: typeof(ABI.System.Byte), + trimTarget: typeof(byte))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(ABI.System.Byte), @@ -29,6 +34,8 @@ namespace ABI.System; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("UInt8")] +[WindowsRuntimeReferenceType(typeof(byte?))] [ByteComWrappersMarshaller] file static class Byte; diff --git a/src/WinRT.Runtime2/ABI/System/Char.cs b/src/WinRT.Runtime2/ABI/System/Char.cs index 06b1994f1..3dede0117 100644 --- a/src/WinRT.Runtime2/ABI/System/Char.cs +++ b/src/WinRT.Runtime2/ABI/System/Char.cs @@ -14,6 +14,11 @@ #pragma warning disable IDE1006, CA1416 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Char16", + target: typeof(ABI.System.Char), + trimTarget: typeof(char))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(ABI.System.Char), @@ -29,6 +34,8 @@ namespace ABI.System; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("Char16")] +[WindowsRuntimeReferenceType(typeof(char?))] [CharComWrappersMarshaller] file static class Char; diff --git a/src/WinRT.Runtime2/ABI/System/DateTimeOffset.cs b/src/WinRT.Runtime2/ABI/System/DateTimeOffset.cs index 6ac3b5276..92280835f 100644 --- a/src/WinRT.Runtime2/ABI/System/DateTimeOffset.cs +++ b/src/WinRT.Runtime2/ABI/System/DateTimeOffset.cs @@ -14,6 +14,11 @@ #pragma warning disable IDE1006, CA1416 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Windows.Foundation.DateTime", + target: typeof(ABI.System.DateTimeOffset), + trimTarget: typeof(DateTimeOffset))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(ABI.System.DateTimeOffset), @@ -30,6 +35,8 @@ namespace ABI.System; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("Windows.Foundation.DateTime")] +[WindowsRuntimeReferenceType(typeof(global::System.DateTimeOffset?))] [DateTimeOffsetComWrappersMarshaller] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, diff --git a/src/WinRT.Runtime2/ABI/System/Double.cs b/src/WinRT.Runtime2/ABI/System/Double.cs index 28831fae7..0dcf53d17 100644 --- a/src/WinRT.Runtime2/ABI/System/Double.cs +++ b/src/WinRT.Runtime2/ABI/System/Double.cs @@ -14,6 +14,11 @@ #pragma warning disable IDE1006, CA1416 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Double", + target: typeof(ABI.System.Double), + trimTarget: typeof(double))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(ABI.System.Double), @@ -29,6 +34,8 @@ namespace ABI.System; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("Double")] +[WindowsRuntimeReferenceType(typeof(double?))] [DoubleComWrappersMarshaller] file static class Double; diff --git a/src/WinRT.Runtime2/ABI/System/Exception.cs b/src/WinRT.Runtime2/ABI/System/Exception.cs index 41e4bcb8e..458afacbe 100644 --- a/src/WinRT.Runtime2/ABI/System/Exception.cs +++ b/src/WinRT.Runtime2/ABI/System/Exception.cs @@ -14,6 +14,11 @@ #pragma warning disable IDE1006 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Windows.Foundation.HResult", + target: typeof(ABI.System.Exception), + trimTarget: typeof(Exception))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(ABI.System.Exception), @@ -30,6 +35,7 @@ namespace ABI.System; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("Windows.Foundation.HResult")] [ExceptionComWrappersMarshaller] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, diff --git a/src/WinRT.Runtime2/ABI/System/Guid.cs b/src/WinRT.Runtime2/ABI/System/Guid.cs index b9c550aa3..ec27c04bd 100644 --- a/src/WinRT.Runtime2/ABI/System/Guid.cs +++ b/src/WinRT.Runtime2/ABI/System/Guid.cs @@ -14,6 +14,11 @@ #pragma warning disable IDE0008, IDE1006, CA1416 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Guid", + target: typeof(ABI.System.Guid), + trimTarget: typeof(Guid))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(ABI.System.Guid), @@ -29,6 +34,8 @@ namespace ABI.System; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("Guid")] +[WindowsRuntimeReferenceType(typeof(global::System.Guid?))] [GuidComWrappersMarshaller] file static class Guid; diff --git a/src/WinRT.Runtime2/ABI/System/IDisposable.cs b/src/WinRT.Runtime2/ABI/System/IDisposable.cs index 13c1cbfdd..06aa10d89 100644 --- a/src/WinRT.Runtime2/ABI/System/IDisposable.cs +++ b/src/WinRT.Runtime2/ABI/System/IDisposable.cs @@ -13,6 +13,13 @@ #pragma warning disable IDE0008 +#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Windows.Foundation.IClosable", + target: typeof(ABI.System.IDisposable), + trimTarget: typeof(IDisposable))] +#pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code + [assembly: TypeMapAssociation( source: typeof(IDisposable), proxy: typeof(ABI.System.IDisposableInterfaceImpl))] @@ -20,7 +27,14 @@ namespace ABI.System; /// -/// Marshaller for . +/// ABI type for . +/// +[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeMetadataTypeName("Windows.Foundation.IClosable")] +file static class IDisposable; + +/// +/// Marshaller for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -29,20 +43,20 @@ namespace ABI.System; public static unsafe class IDisposableMarshaller { /// - public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(IDisposable? value) + public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(global::System.IDisposable? value) { - return WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged(value, in WellKnownWindowsInterfaceIIDs.IID_IClosable); + return WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged(value, in WellKnownWindowsInterfaceIIDs.IID_IClosable); } /// - public static IDisposable? ConvertToManaged(void* value) + public static global::System.IDisposable? ConvertToManaged(void* value) { - return (IDisposable?)WindowsRuntimeObjectMarshaller.ConvertToManaged(value); + return (global::System.IDisposable?)WindowsRuntimeObjectMarshaller.ConvertToManaged(value); } } /// -/// Interop methods for . +/// Interop methods for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -50,7 +64,7 @@ public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(IDisposable? [EditorBrowsable(EditorBrowsableState.Never)] public static unsafe class IDisposableMethods { - /// + /// [MethodImpl(MethodImplOptions.NoInlining)] public static void Dispose(WindowsRuntimeObjectReference thisReference) { @@ -63,7 +77,7 @@ public static void Dispose(WindowsRuntimeObjectReference thisReference) } /// -/// Binding type for . +/// Binding type for . /// [StructLayout(LayoutKind.Sequential)] internal unsafe struct IDisposableVftbl @@ -78,7 +92,7 @@ internal unsafe struct IDisposableVftbl } /// -/// The implementation. +/// The implementation. /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -87,7 +101,7 @@ internal unsafe struct IDisposableVftbl public static unsafe class IDisposableImpl { /// - /// The value for the managed implementation. + /// The value for the managed implementation. /// [FixedAddressValueType] private static readonly IDisposableVftbl Vftbl; @@ -103,7 +117,7 @@ static IDisposableImpl() } /// - /// Gets a pointer to the managed implementation. + /// Gets a pointer to the managed implementation. /// public static nint Vtable { @@ -117,7 +131,7 @@ private static HRESULT Close(void* thisPtr) { try { - ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr).Dispose(); + ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr).Dispose(); return WellKnownErrorCodes.S_OK; } @@ -129,17 +143,17 @@ private static HRESULT Close(void* thisPtr) } /// -/// The implementation for . +/// The implementation for . /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IClosable")] [DynamicInterfaceCastableImplementation] -file interface IDisposableInterfaceImpl : IDisposable +file interface IDisposableInterfaceImpl : global::System.IDisposable { /// - void IDisposable.Dispose() + void global::System.IDisposable.Dispose() { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IDisposable).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::System.IDisposable).TypeHandle); IDisposableMethods.Dispose(thisReference); } diff --git a/src/WinRT.Runtime2/ABI/System/IServiceProvider.cs b/src/WinRT.Runtime2/ABI/System/IServiceProvider.cs index b9aa22adb..34214f0b5 100644 --- a/src/WinRT.Runtime2/ABI/System/IServiceProvider.cs +++ b/src/WinRT.Runtime2/ABI/System/IServiceProvider.cs @@ -13,6 +13,13 @@ #pragma warning disable IDE0008 +#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Microsoft.UI.Xaml.IXamlServiceProvider", + target: typeof(ABI.System.IServiceProvider), + trimTarget: typeof(IServiceProvider))] +#pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code + [assembly: TypeMapAssociation( source: typeof(IServiceProvider), proxy: typeof(ABI.System.IServiceProviderInterfaceImpl))] @@ -20,7 +27,14 @@ namespace ABI.System; /// -/// Marshaller for . +/// ABI type for . +/// +[WindowsRuntimeMetadata("Microsoft.UI.Xaml.WinUIContract")] +[WindowsRuntimeMetadataTypeName("Microsoft.UI.Xaml.IXamlServiceProvider")] +file static class IServiceProvider; + +/// +/// Marshaller for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -29,20 +43,20 @@ namespace ABI.System; public static unsafe class IServiceProviderMarshaller { /// - public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(IServiceProvider? value) + public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(global::System.IServiceProvider? value) { - return WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged(value, in WellKnownWindowsInterfaceIIDs.IID_IXamlServiceProvider); + return WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged(value, in WellKnownWindowsInterfaceIIDs.IID_IXamlServiceProvider); } /// - public static IServiceProvider? ConvertToManaged(void* value) + public static global::System.IServiceProvider? ConvertToManaged(void* value) { - return (IServiceProvider?)WindowsRuntimeObjectMarshaller.ConvertToManaged(value); + return (global::System.IServiceProvider?)WindowsRuntimeObjectMarshaller.ConvertToManaged(value); } } /// -/// Interop methods for . +/// Interop methods for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -50,7 +64,7 @@ public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(IServiceProv [EditorBrowsable(EditorBrowsableState.Never)] public static unsafe class IServiceProviderMethods { - /// + /// [MethodImpl(MethodImplOptions.NoInlining)] public static object? GetService(WindowsRuntimeObjectReference thisReference, global::System.Type serviceType) { @@ -78,7 +92,7 @@ public static unsafe class IServiceProviderMethods } /// -/// Binding type for . +/// Binding type for . /// [StructLayout(LayoutKind.Sequential)] internal unsafe struct IServiceProviderVftbl @@ -93,7 +107,7 @@ internal unsafe struct IServiceProviderVftbl } /// -/// The implementation. +/// The implementation. /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -102,7 +116,7 @@ internal unsafe struct IServiceProviderVftbl public static unsafe class IServiceProviderImpl { /// - /// The value for the managed implementation. + /// The value for the managed implementation. /// [FixedAddressValueType] private static readonly IServiceProviderVftbl Vftbl; @@ -118,7 +132,7 @@ static IServiceProviderImpl() } /// - /// Gets a pointer to the managed implementation. + /// Gets a pointer to the managed implementation. /// public static nint Vtable { @@ -137,7 +151,7 @@ private static HRESULT GetService(void* thisPtr, Type serviceType, void** result try { - var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); global::System.Type? managedType = TypeMarshaller.ConvertToManaged(serviceType); @@ -161,17 +175,15 @@ private static HRESULT GetService(void* thisPtr, Type serviceType, void** result } /// -/// The implementation for . +/// The implementation for . /// -[WindowsRuntimeMetadata("Microsoft.UI.Xaml.WinUIContract")] -[WindowsRuntimeClassName("Microsoft.UI.Xaml.IXamlServiceProvider")] [DynamicInterfaceCastableImplementation] -file interface IServiceProviderInterfaceImpl : IServiceProvider +file interface IServiceProviderInterfaceImpl : global::System.IServiceProvider { /// - object? IServiceProvider.GetService(global::System.Type serviceType) + object? global::System.IServiceProvider.GetService(global::System.Type serviceType) { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IServiceProvider).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::System.IServiceProvider).TypeHandle); return IServiceProviderMethods.GetService(thisReference, serviceType); } diff --git a/src/WinRT.Runtime2/ABI/System/Int16.cs b/src/WinRT.Runtime2/ABI/System/Int16.cs index 40e364738..4b786846e 100644 --- a/src/WinRT.Runtime2/ABI/System/Int16.cs +++ b/src/WinRT.Runtime2/ABI/System/Int16.cs @@ -14,6 +14,11 @@ #pragma warning disable IDE1006, CA1416 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Int16", + target: typeof(ABI.System.Int16), + trimTarget: typeof(short))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(ABI.System.Int16), @@ -29,6 +34,8 @@ namespace ABI.System; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("Int16")] +[WindowsRuntimeReferenceType(typeof(short?))] [Int16ComWrappersMarshaller] file static class Int16; diff --git a/src/WinRT.Runtime2/ABI/System/Int32.cs b/src/WinRT.Runtime2/ABI/System/Int32.cs index 281d11aa7..2bcc88436 100644 --- a/src/WinRT.Runtime2/ABI/System/Int32.cs +++ b/src/WinRT.Runtime2/ABI/System/Int32.cs @@ -14,6 +14,11 @@ #pragma warning disable IDE1006, CA1416 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Int32", + target: typeof(ABI.System.Int32), + trimTarget: typeof(int))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(ABI.System.Int32), @@ -29,6 +34,8 @@ namespace ABI.System; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("Int32")] +[WindowsRuntimeReferenceType(typeof(int?))] [Int32ComWrappersMarshaller] file static class Int32; diff --git a/src/WinRT.Runtime2/ABI/System/Int64.cs b/src/WinRT.Runtime2/ABI/System/Int64.cs index 7e333fd15..7387896aa 100644 --- a/src/WinRT.Runtime2/ABI/System/Int64.cs +++ b/src/WinRT.Runtime2/ABI/System/Int64.cs @@ -14,6 +14,11 @@ #pragma warning disable IDE1006, CA1416 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Int64", + target: typeof(ABI.System.Int64), + trimTarget: typeof(long))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(ABI.System.Int64), @@ -29,6 +34,8 @@ namespace ABI.System; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("Int64")] +[WindowsRuntimeReferenceType(typeof(long?))] [Int64ComWrappersMarshaller] file static class Int64; diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Matrix3x2.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Matrix3x2.cs index 3c220a9e8..6cafd1181 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Matrix3x2.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Matrix3x2.cs @@ -15,6 +15,11 @@ #pragma warning disable IDE1006 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Windows.Foundation.Numerics.Matrix3x2", + target: typeof(ABI.System.Numerics.Matrix3x2), + trimTarget: typeof(Matrix3x2))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(ABI.System.Numerics.Matrix3x2), @@ -31,6 +36,8 @@ namespace ABI.System.Numerics; /// [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("Windows.Foundation.Numerics.Matrix3x2")] +[WindowsRuntimeReferenceType(typeof(global::System.Numerics.Matrix3x2?))] [Matrix3x2ComWrappersMarshaller] file static class Matrix3x2; diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Matrix4x4.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Matrix4x4.cs index 40974ad70..cc60d6e18 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Matrix4x4.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Matrix4x4.cs @@ -15,6 +15,11 @@ #pragma warning disable IDE1006 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Windows.Foundation.Numerics.Matrix4x4", + target: typeof(ABI.System.Numerics.Matrix4x4), + trimTarget: typeof(Matrix4x4))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(ABI.System.Numerics.Matrix4x4), @@ -31,6 +36,8 @@ namespace ABI.System.Numerics; /// [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("Windows.Foundation.Numerics.Matrix4x4")] +[WindowsRuntimeReferenceType(typeof(global::System.Numerics.Matrix4x4?))] [Matrix4x4ComWrappersMarshaller] file static class Matrix4x4; diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Plane.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Plane.cs index f70e92a91..baf0c702a 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Plane.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Plane.cs @@ -15,6 +15,11 @@ #pragma warning disable IDE1006 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Windows.Foundation.Numerics.Plane", + target: typeof(ABI.System.Numerics.Plane), + trimTarget: typeof(Plane))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(ABI.System.Numerics.Plane), @@ -31,6 +36,8 @@ namespace ABI.System.Numerics; /// [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("Windows.Foundation.Numerics.Plane")] +[WindowsRuntimeReferenceType(typeof(global::System.Numerics.Plane?))] [PlaneComWrappersMarshaller] file static class Plane; diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Quaternion.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Quaternion.cs index 6e1d04247..9e56747ad 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Quaternion.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Quaternion.cs @@ -15,6 +15,11 @@ #pragma warning disable IDE1006 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Windows.Foundation.Numerics.Quaternion", + target: typeof(ABI.System.Numerics.Quaternion), + trimTarget: typeof(Quaternion))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(ABI.System.Numerics.Quaternion), @@ -31,6 +36,8 @@ namespace ABI.System.Numerics; /// [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("Windows.Foundation.Numerics.Quaternion")] +[WindowsRuntimeReferenceType(typeof(global::System.Numerics.Quaternion?))] [QuaternionComWrappersMarshaller] file static class Quaternion; diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Vector2.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Vector2.cs index da6c7e55d..9f8e74ae0 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Vector2.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Vector2.cs @@ -15,6 +15,11 @@ #pragma warning disable IDE1006 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Windows.Foundation.Numerics.Vector2", + target: typeof(ABI.System.Numerics.Vector2), + trimTarget: typeof(Vector2))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(ABI.System.Numerics.Vector2), @@ -31,6 +36,8 @@ namespace ABI.System.Numerics; /// [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("Windows.Foundation.Numerics.Vector2")] +[WindowsRuntimeReferenceType(typeof(global::System.Numerics.Vector2?))] [Vector2ComWrappersMarshaller] file static class Vector2; diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Vector3.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Vector3.cs index e33abb272..706e43293 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Vector3.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Vector3.cs @@ -15,6 +15,11 @@ #pragma warning disable IDE1006 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Windows.Foundation.Numerics.Vector3", + target: typeof(ABI.System.Numerics.Vector3), + trimTarget: typeof(Vector3))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(ABI.System.Numerics.Vector3), @@ -31,6 +36,8 @@ namespace ABI.System.Numerics; /// [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("Windows.Foundation.Numerics.Vector3")] +[WindowsRuntimeReferenceType(typeof(global::System.Numerics.Vector3?))] [Vector3ComWrappersMarshaller] file static class Vector3; diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Vector4.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Vector4.cs index 5e9870438..1c80cd97d 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Vector4.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Vector4.cs @@ -15,6 +15,11 @@ #pragma warning disable IDE1006 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Windows.Foundation.Numerics.Vector4", + target: typeof(ABI.System.Numerics.Vector4), + trimTarget: typeof(Vector4))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(ABI.System.Numerics.Vector4), @@ -31,6 +36,8 @@ namespace ABI.System.Numerics; /// [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("Windows.Foundation.Numerics.Vector4")] +[WindowsRuntimeReferenceType(typeof(global::System.Numerics.Vector4?))] [Vector4ComWrappersMarshaller] file static class Vector4; diff --git a/src/WinRT.Runtime2/ABI/System/Object.cs b/src/WinRT.Runtime2/ABI/System/Object.cs index 630b6d758..d73d86d9c 100644 --- a/src/WinRT.Runtime2/ABI/System/Object.cs +++ b/src/WinRT.Runtime2/ABI/System/Object.cs @@ -7,6 +7,13 @@ using WindowsRuntime.InteropServices; using static System.Runtime.InteropServices.ComWrappers; +#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Object", + target: typeof(ABI.System.Object), + trimTarget: typeof(object))] +#pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code + [assembly: TypeMapAssociation(typeof(object), typeof(ABI.System.Object))] namespace ABI.System; diff --git a/src/WinRT.Runtime2/ABI/System/Single.cs b/src/WinRT.Runtime2/ABI/System/Single.cs index 5b4d2d333..5f97c84ad 100644 --- a/src/WinRT.Runtime2/ABI/System/Single.cs +++ b/src/WinRT.Runtime2/ABI/System/Single.cs @@ -14,6 +14,11 @@ #pragma warning disable IDE1006, CA1416 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Single", + target: typeof(ABI.System.Single), + trimTarget: typeof(float))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(ABI.System.Single), @@ -29,6 +34,8 @@ namespace ABI.System; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("Single")] +[WindowsRuntimeReferenceType(typeof(float?))] [SingleComWrappersMarshaller] file static class Single; diff --git a/src/WinRT.Runtime2/ABI/System/String.cs b/src/WinRT.Runtime2/ABI/System/String.cs index 87139a2fd..4e7e9f7f9 100644 --- a/src/WinRT.Runtime2/ABI/System/String.cs +++ b/src/WinRT.Runtime2/ABI/System/String.cs @@ -15,6 +15,11 @@ #pragma warning disable IDE0008, IDE1006, CA1416 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "String", + target: typeof(ABI.System.String), + trimTarget: typeof(string))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(ABI.System.String), @@ -30,6 +35,7 @@ namespace ABI.System; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("String")] [StringComWrappersMarshaller] file static class String; diff --git a/src/WinRT.Runtime2/ABI/System/TimeSpan.cs b/src/WinRT.Runtime2/ABI/System/TimeSpan.cs index b561101c9..59d00a8d9 100644 --- a/src/WinRT.Runtime2/ABI/System/TimeSpan.cs +++ b/src/WinRT.Runtime2/ABI/System/TimeSpan.cs @@ -14,6 +14,11 @@ #pragma warning disable IDE1006, CA1416 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Windows.Foundation.TimeSpan", + target: typeof(ABI.System.TimeSpan), + trimTarget: typeof(TimeSpan))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(ABI.System.TimeSpan), @@ -30,6 +35,8 @@ namespace ABI.System; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("Windows.Foundation.TimeSpan")] +[WindowsRuntimeReferenceType(typeof(global::System.TimeSpan?))] [TimeSpanComWrappersMarshaller] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, diff --git a/src/WinRT.Runtime2/ABI/System/UInt16.cs b/src/WinRT.Runtime2/ABI/System/UInt16.cs index 22ce63502..864395cd2 100644 --- a/src/WinRT.Runtime2/ABI/System/UInt16.cs +++ b/src/WinRT.Runtime2/ABI/System/UInt16.cs @@ -14,6 +14,11 @@ #pragma warning disable IDE1006, CA1416 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "UInt16", + target: typeof(ABI.System.UInt16), + trimTarget: typeof(ushort))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(ABI.System.UInt16), @@ -29,6 +34,8 @@ namespace ABI.System; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("UInt16")] +[WindowsRuntimeReferenceType(typeof(ushort?))] [UInt16ComWrappersMarshaller] file static class UInt16; diff --git a/src/WinRT.Runtime2/ABI/System/UInt32.cs b/src/WinRT.Runtime2/ABI/System/UInt32.cs index 7629997c1..79d23d76d 100644 --- a/src/WinRT.Runtime2/ABI/System/UInt32.cs +++ b/src/WinRT.Runtime2/ABI/System/UInt32.cs @@ -14,6 +14,11 @@ #pragma warning disable IDE1006, CA1416 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "UInt32", + target: typeof(ABI.System.UInt32), + trimTarget: typeof(uint))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(ABI.System.UInt32), @@ -29,6 +34,8 @@ namespace ABI.System; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("UInt32")] +[WindowsRuntimeReferenceType(typeof(uint?))] [UInt32ComWrappersMarshaller] file static class UInt32; diff --git a/src/WinRT.Runtime2/ABI/System/UInt64.cs b/src/WinRT.Runtime2/ABI/System/UInt64.cs index 30396f418..e9965b845 100644 --- a/src/WinRT.Runtime2/ABI/System/UInt64.cs +++ b/src/WinRT.Runtime2/ABI/System/UInt64.cs @@ -14,6 +14,11 @@ #pragma warning disable IDE1006, CA1416 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "UInt64", + target: typeof(ABI.System.UInt64), + trimTarget: typeof(ulong))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(ABI.System.UInt64), @@ -29,6 +34,8 @@ namespace ABI.System; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("UInt64")] +[WindowsRuntimeReferenceType(typeof(ulong?))] [UInt64ComWrappersMarshaller] file static class UInt64; diff --git a/src/WinRT.Runtime2/ABI/System/Uri.cs b/src/WinRT.Runtime2/ABI/System/Uri.cs index 1769656f5..6074aff0a 100644 --- a/src/WinRT.Runtime2/ABI/System/Uri.cs +++ b/src/WinRT.Runtime2/ABI/System/Uri.cs @@ -27,6 +27,7 @@ namespace ABI.System; /// /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeClassName("Windows.Foundation.Uri")] [UriComWrappersMarshaller] file static class Uri; diff --git a/src/WinRT.Runtime2/ABI/Windows.Foundation/Collections/CollectionChange.cs b/src/WinRT.Runtime2/ABI/Windows.Foundation/Collections/CollectionChange.cs index 09ab034da..68b065fbc 100644 --- a/src/WinRT.Runtime2/ABI/Windows.Foundation/Collections/CollectionChange.cs +++ b/src/WinRT.Runtime2/ABI/Windows.Foundation/Collections/CollectionChange.cs @@ -14,6 +14,11 @@ #pragma warning disable IDE1006, CA1416 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Windows.Foundation.Collections.CollectionChange", + target: typeof(CollectionChange), + trimTarget: typeof(CollectionChange))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(CollectionChange), diff --git a/src/WinRT.Runtime2/ABI/Windows.Foundation/Collections/IVectorChangedEventArgs.cs b/src/WinRT.Runtime2/ABI/Windows.Foundation/Collections/IVectorChangedEventArgs.cs index 39546c8b1..158fffdcf 100644 --- a/src/WinRT.Runtime2/ABI/Windows.Foundation/Collections/IVectorChangedEventArgs.cs +++ b/src/WinRT.Runtime2/ABI/Windows.Foundation/Collections/IVectorChangedEventArgs.cs @@ -14,10 +14,28 @@ #pragma warning disable IDE0008, IDE1006 -namespace ABI.System.ComponentModel; +#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Windows.Foundation.Collections.IVectorChangedEventArgs", + target: typeof(ABI.Windows.Foundation.Collections.IVectorChangedEventArgs), + trimTarget: typeof(IVectorChangedEventArgs))] +#pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code + +[assembly: TypeMapAssociation( + source: typeof(IVectorChangedEventArgs), + proxy: typeof(ABI.Windows.Foundation.Collections.IVectorChangedEventArgs))] + +namespace ABI.Windows.Foundation.Collections; + +/// +/// ABI type for . +/// +[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeMetadataTypeName("Windows.Foundation.Collections.IVectorChangedEventArgs")] +file static class IVectorChangedEventArgs; /// -/// Marshaller for . +/// Marshaller for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -26,22 +44,22 @@ namespace ABI.System.ComponentModel; public static unsafe class IVectorChangedEventArgsMarshaller { /// - public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(IVectorChangedEventArgs? value) + public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(global::Windows.Foundation.Collections.IVectorChangedEventArgs? value) { - return WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged( + return WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged( value: value, iid: in WellKnownWindowsInterfaceIIDs.IID_IVectorChangedEventArgs); } /// - public static IVectorChangedEventArgs? ConvertToManaged(void* value) + public static global::Windows.Foundation.Collections.IVectorChangedEventArgs? ConvertToManaged(void* value) { - return (IVectorChangedEventArgs?)WindowsRuntimeObjectMarshaller.ConvertToManaged(value); + return (global::Windows.Foundation.Collections.IVectorChangedEventArgs?)WindowsRuntimeObjectMarshaller.ConvertToManaged(value); } } /// -/// Interop methods for . +/// Interop methods for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -49,7 +67,7 @@ public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(IVectorChang [EditorBrowsable(EditorBrowsableState.Never)] public static unsafe class IVectorChangedEventArgsMethods { - /// + /// [MethodImpl(MethodImplOptions.NoInlining)] public static CollectionChange CollectionChange(WindowsRuntimeObjectReference thisReference) { @@ -63,7 +81,7 @@ public static CollectionChange CollectionChange(WindowsRuntimeObjectReference th return result; } - /// + /// public static uint Index(WindowsRuntimeObjectReference thisReference) { using WindowsRuntimeObjectReferenceValue thisValue = thisReference.AsValue(); @@ -78,7 +96,7 @@ public static uint Index(WindowsRuntimeObjectReference thisReference) } /// -/// Binding type for . +/// Binding type for . /// /// [StructLayout(LayoutKind.Sequential)] @@ -95,7 +113,7 @@ internal unsafe struct IVectorChangedEventArgsVftbl } /// -/// The implementation. +/// The implementation. /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -104,7 +122,7 @@ internal unsafe struct IVectorChangedEventArgsVftbl public static unsafe class IVectorChangedEventArgsImpl { /// - /// The value for the managed implementation. + /// The value for the managed implementation. /// [FixedAddressValueType] private static readonly IVectorChangedEventArgsVftbl Vftbl; @@ -121,7 +139,7 @@ static IVectorChangedEventArgsImpl() } /// - /// Gets a pointer to the managed implementation. + /// Gets a pointer to the managed implementation. /// public static nint Vtable { @@ -135,13 +153,13 @@ private static HRESULT get_CollectionChange(void* thisPtr, CollectionChange* res { try { - var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); *result = unboxedValue.CollectionChange; return WellKnownErrorCodes.S_OK; } - catch (global::System.Exception e) + catch (Exception e) { return RestrictedErrorInfoExceptionMarshaller.ConvertToUnmanaged(e); } @@ -153,13 +171,13 @@ private static HRESULT get_Index(void* thisPtr, uint* result) { try { - var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); *result = unboxedValue.Index; return WellKnownErrorCodes.S_OK; } - catch (global::System.Exception e) + catch (Exception e) { return RestrictedErrorInfoExceptionMarshaller.ConvertToUnmanaged(e); } @@ -167,28 +185,28 @@ private static HRESULT get_Index(void* thisPtr, uint* result) } /// -/// The implementation for . +/// The implementation for . /// [DynamicInterfaceCastableImplementation] -file interface IVectorChangedEventArgsInterfaceImpl : IVectorChangedEventArgs +file interface IVectorChangedEventArgsInterfaceImpl : global::Windows.Foundation.Collections.IVectorChangedEventArgs { /// - CollectionChange IVectorChangedEventArgs.CollectionChange + CollectionChange global::Windows.Foundation.Collections.IVectorChangedEventArgs.CollectionChange { get { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IVectorChangedEventArgs).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::Windows.Foundation.Collections.IVectorChangedEventArgs).TypeHandle); return IVectorChangedEventArgsMethods.CollectionChange(thisReference); } } /// - uint IVectorChangedEventArgs.Index + uint global::Windows.Foundation.Collections.IVectorChangedEventArgs.Index { get { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IVectorChangedEventArgs).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::Windows.Foundation.Collections.IVectorChangedEventArgs).TypeHandle); return IVectorChangedEventArgsMethods.Index(thisReference); } diff --git a/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncAction.cs b/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncAction.cs index ccf338616..9ccaf7a9d 100644 --- a/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncAction.cs +++ b/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncAction.cs @@ -14,6 +14,13 @@ #pragma warning disable IDE0008, IDE1006, CA2256 +#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Windows.Foundation.IAsyncAction", + target: typeof(ABI.Windows.Foundation.IAsyncAction), + trimTarget: typeof(IAsyncAction))] +#pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code + [assembly: TypeMapAssociation( source: typeof(IAsyncAction), proxy: typeof(ABI.Windows.Foundation.IAsyncActionInterfaceImpl))] @@ -21,7 +28,14 @@ namespace ABI.Windows.Foundation; /// -/// Marshaller for . +/// ABI type for . +/// +[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeMetadataTypeName("Windows.Foundation.IAsyncAction")] +file static class IAsyncAction; + +/// +/// Marshaller for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -30,20 +44,20 @@ namespace ABI.Windows.Foundation; public static unsafe class IAsyncActionMarshaller { /// - public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(IAsyncAction? value) + public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(global::Windows.Foundation.IAsyncAction? value) { - return WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged(value, in WellKnownWindowsInterfaceIIDs.IID_IAsyncAction); + return WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged(value, in WellKnownWindowsInterfaceIIDs.IID_IAsyncAction); } /// - public static IAsyncAction? ConvertToManaged(void* value) + public static global::Windows.Foundation.IAsyncAction? ConvertToManaged(void* value) { - return (IAsyncAction?)WindowsRuntimeUnsealedObjectMarshaller.ConvertToManaged(value); + return (global::Windows.Foundation.IAsyncAction?)WindowsRuntimeUnsealedObjectMarshaller.ConvertToManaged(value); } } /// -/// A custom implementation for . +/// A custom implementation for . /// file abstract unsafe class IAsyncActionComWrappersCallback : IWindowsRuntimeUnsealedObjectComWrappersCallback { @@ -75,7 +89,7 @@ public static unsafe bool TryCreateObject( } /// -/// A custom implementation for . +/// A custom implementation for . /// internal sealed unsafe class IAsyncActionComWrappersMarshallerAttribute : WindowsRuntimeComWrappersMarshallerAttribute { @@ -92,7 +106,7 @@ public override object CreateObject(void* value, out CreatedWrapperFlags wrapper } /// -/// Interop methods for . +/// Interop methods for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -100,7 +114,7 @@ public override object CreateObject(void* value, out CreatedWrapperFlags wrapper [EditorBrowsable(EditorBrowsableState.Never)] public static unsafe class IAsyncActionMethods { - /// + /// [MethodImpl(MethodImplOptions.NoInlining)] public static AsyncActionCompletedHandler? Completed(WindowsRuntimeObjectReference thisReference) { @@ -123,7 +137,7 @@ public static unsafe class IAsyncActionMethods } } - /// + /// [MethodImpl(MethodImplOptions.NoInlining)] public static void Completed(WindowsRuntimeObjectReference thisReference, AsyncActionCompletedHandler? handler) { @@ -137,7 +151,7 @@ public static void Completed(WindowsRuntimeObjectReference thisReference, AsyncA RestrictedErrorInfo.ThrowExceptionForHR(hresult); } - /// + /// [MethodImpl(MethodImplOptions.NoInlining)] public static void GetResults(WindowsRuntimeObjectReference thisReference) { @@ -152,7 +166,7 @@ public static void GetResults(WindowsRuntimeObjectReference thisReference) } /// -/// Binding type for . +/// Binding type for . /// [StructLayout(LayoutKind.Sequential)] internal unsafe struct IAsyncActionVftbl @@ -169,7 +183,7 @@ internal unsafe struct IAsyncActionVftbl } /// -/// The implementation. +/// The implementation. /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -178,7 +192,7 @@ internal unsafe struct IAsyncActionVftbl public static unsafe class IAsyncActionImpl { /// - /// The value for the managed implementation. + /// The value for the managed implementation. /// [FixedAddressValueType] private static readonly IAsyncActionVftbl Vftbl; @@ -196,7 +210,7 @@ static IAsyncActionImpl() } /// - /// Gets a pointer to the managed implementation. + /// Gets a pointer to the managed implementation. /// public static nint Vtable { @@ -215,7 +229,7 @@ private static HRESULT get_Completed(void* thisPtr, void** handler) try { - var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); *handler = AsyncActionCompletedHandlerMarshaller.ConvertToUnmanaged(unboxedValue.Completed).DetachThisPtrUnsafe(); @@ -233,7 +247,7 @@ private static HRESULT set_Completed(void* thisPtr, void* handler) { try { - var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); unboxedValue.Completed = AsyncActionCompletedHandlerMarshaller.ConvertToManaged(handler); @@ -251,7 +265,7 @@ private static HRESULT GetResults(void* thisPtr) { try { - var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); unboxedValue.GetResults(); @@ -265,32 +279,32 @@ private static HRESULT GetResults(void* thisPtr) } /// -/// The implementation for . +/// The implementation for . /// [DynamicInterfaceCastableImplementation] -file interface IAsyncActionInterfaceImpl : IAsyncAction +file interface IAsyncActionInterfaceImpl : global::Windows.Foundation.IAsyncAction { /// - AsyncActionCompletedHandler? IAsyncAction.Completed + AsyncActionCompletedHandler? global::Windows.Foundation.IAsyncAction.Completed { get { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IAsyncAction).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::Windows.Foundation.IAsyncAction).TypeHandle); return IAsyncActionMethods.Completed(thisReference); } set { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IAsyncAction).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::Windows.Foundation.IAsyncAction).TypeHandle); IAsyncActionMethods.Completed(thisReference, value); } } /// - void IAsyncAction.GetResults() + void global::Windows.Foundation.IAsyncAction.GetResults() { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IAsyncAction).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::Windows.Foundation.IAsyncAction).TypeHandle); IAsyncActionMethods.GetResults(thisReference); } diff --git a/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncInfo.cs b/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncInfo.cs index c4f6832db..31e885b4e 100644 --- a/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncInfo.cs +++ b/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncInfo.cs @@ -13,10 +13,28 @@ #pragma warning disable IDE0008, IDE1006 +#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Windows.Foundation.IAsyncInfo", + target: typeof(ABI.Windows.Foundation.IAsyncInfo), + trimTarget: typeof(IAsyncInfo))] +#pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code + +[assembly: TypeMapAssociation( + source: typeof(IAsyncInfo), + proxy: typeof(ABI.Windows.Foundation.IAsyncInfoInterfaceImpl))] + namespace ABI.Windows.Foundation; /// -/// Marshaller for . +/// ABI type for . +/// +[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeMetadataTypeName("Windows.Foundation.IAsyncInfo")] +file static class IAsyncInfo; + +/// +/// Marshaller for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -25,20 +43,20 @@ namespace ABI.Windows.Foundation; public static unsafe class IAsyncInfoMarshaller { /// - public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(IAsyncInfo? value) + public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(global::Windows.Foundation.IAsyncInfo? value) { - return WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged(value, in WellKnownWindowsInterfaceIIDs.IID_IAsyncInfo); + return WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged(value, in WellKnownWindowsInterfaceIIDs.IID_IAsyncInfo); } /// - public static IAsyncInfo? ConvertToManaged(void* value) + public static global::Windows.Foundation.IAsyncInfo? ConvertToManaged(void* value) { - return (IAsyncInfo?)WindowsRuntimeObjectMarshaller.ConvertToManaged(value); + return (global::Windows.Foundation.IAsyncInfo?)WindowsRuntimeObjectMarshaller.ConvertToManaged(value); } } /// -/// Interop methods for . +/// Interop methods for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -46,7 +64,7 @@ public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(IAsyncInfo? [EditorBrowsable(EditorBrowsableState.Never)] public static unsafe class IAsyncInfoMethods { - /// + /// [MethodImpl(MethodImplOptions.NoInlining)] public static uint Id(WindowsRuntimeObjectReference thisReference) { @@ -62,7 +80,7 @@ public static uint Id(WindowsRuntimeObjectReference thisReference) return result; } - /// + /// [MethodImpl(MethodImplOptions.NoInlining)] public static AsyncStatus Status(WindowsRuntimeObjectReference thisReference) { @@ -78,7 +96,7 @@ public static AsyncStatus Status(WindowsRuntimeObjectReference thisReference) return result; } - /// + /// [MethodImpl(MethodImplOptions.NoInlining)] public static Exception? ErrorCode(WindowsRuntimeObjectReference thisReference) { @@ -94,7 +112,7 @@ public static AsyncStatus Status(WindowsRuntimeObjectReference thisReference) return System.ExceptionMarshaller.ConvertToManaged(result); } - /// + /// [MethodImpl(MethodImplOptions.NoInlining)] public static void Cancel(WindowsRuntimeObjectReference thisReference) { @@ -107,7 +125,7 @@ public static void Cancel(WindowsRuntimeObjectReference thisReference) RestrictedErrorInfo.ThrowExceptionForHR(hresult); } - /// + /// [MethodImpl(MethodImplOptions.NoInlining)] public static void Close(WindowsRuntimeObjectReference thisReference) { @@ -122,7 +140,7 @@ public static void Close(WindowsRuntimeObjectReference thisReference) } /// -/// Binding type for . +/// Binding type for . /// [StructLayout(LayoutKind.Sequential)] internal unsafe struct IAsyncInfoVftbl @@ -141,7 +159,7 @@ internal unsafe struct IAsyncInfoVftbl } /// -/// The implementation. +/// The implementation. /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -150,7 +168,7 @@ internal unsafe struct IAsyncInfoVftbl public static unsafe class IAsyncInfoImpl { /// - /// The value for the managed implementation. + /// The value for the managed implementation. /// [FixedAddressValueType] private static readonly IAsyncInfoVftbl Vftbl; @@ -170,7 +188,7 @@ static IAsyncInfoImpl() } /// - /// Gets a pointer to the managed implementation. + /// Gets a pointer to the managed implementation. /// public static nint Vtable { @@ -189,7 +207,7 @@ private static HRESULT get_ErrorCode(void* thisPtr, System.Exception* errorCode) try { - var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); *errorCode = System.ExceptionMarshaller.ConvertToUnmanaged(unboxedValue.ErrorCode); @@ -212,7 +230,7 @@ private static HRESULT get_Id(void* thisPtr, uint* id) try { - var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); *id = unboxedValue.Id; @@ -235,7 +253,7 @@ private static HRESULT get_Status(void* thisPtr, AsyncStatus* status) try { - var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); *status = unboxedValue.Status; @@ -253,7 +271,7 @@ private static HRESULT Cancel(void* thisPtr) { try { - var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); unboxedValue.Cancel(); @@ -271,7 +289,7 @@ private static HRESULT Close(void* thisPtr) { try { - var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); unboxedValue.Close(); @@ -285,56 +303,56 @@ private static HRESULT Close(void* thisPtr) } /// -/// The implementation for . +/// The implementation for . /// [DynamicInterfaceCastableImplementation] -file interface IAsyncInfoInterfaceImpl : IAsyncInfo +file interface IAsyncInfoInterfaceImpl : global::Windows.Foundation.IAsyncInfo { /// - uint IAsyncInfo.Id + uint global::Windows.Foundation.IAsyncInfo.Id { get { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IAsyncInfo).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::Windows.Foundation.IAsyncInfo).TypeHandle); return IAsyncInfoMethods.Id(thisReference); } } /// - AsyncStatus IAsyncInfo.Status + AsyncStatus global::Windows.Foundation.IAsyncInfo.Status { get { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IAsyncInfo).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::Windows.Foundation.IAsyncInfo).TypeHandle); return IAsyncInfoMethods.Status(thisReference); } } /// - Exception? IAsyncInfo.ErrorCode + Exception? global::Windows.Foundation.IAsyncInfo.ErrorCode { get { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IAsyncInfo).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::Windows.Foundation.IAsyncInfo).TypeHandle); return IAsyncInfoMethods.ErrorCode(thisReference); } } /// - void IAsyncInfo.Cancel() + void global::Windows.Foundation.IAsyncInfo.Cancel() { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IAsyncInfo).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::Windows.Foundation.IAsyncInfo).TypeHandle); IAsyncInfoMethods.Cancel(thisReference); } /// - void IAsyncInfo.Close() + void global::Windows.Foundation.IAsyncInfo.Close() { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IAsyncInfo).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::Windows.Foundation.IAsyncInfo).TypeHandle); IAsyncInfoMethods.Close(thisReference); } diff --git a/src/WinRT.Runtime2/ABI/Windows.Foundation/Point.cs b/src/WinRT.Runtime2/ABI/Windows.Foundation/Point.cs index e4e069314..46501138c 100644 --- a/src/WinRT.Runtime2/ABI/Windows.Foundation/Point.cs +++ b/src/WinRT.Runtime2/ABI/Windows.Foundation/Point.cs @@ -14,6 +14,11 @@ #pragma warning disable IDE1006, CA1416 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Windows.Foundation.Point", + target: typeof(Point), + trimTarget: typeof(Point))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(Point), diff --git a/src/WinRT.Runtime2/ABI/Windows.Foundation/Rect.cs b/src/WinRT.Runtime2/ABI/Windows.Foundation/Rect.cs index 017a7ee92..b4a72cb80 100644 --- a/src/WinRT.Runtime2/ABI/Windows.Foundation/Rect.cs +++ b/src/WinRT.Runtime2/ABI/Windows.Foundation/Rect.cs @@ -14,6 +14,11 @@ #pragma warning disable IDE1006, CA1416 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Windows.Foundation.Rect", + target: typeof(Rect), + trimTarget: typeof(Rect))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(Rect), diff --git a/src/WinRT.Runtime2/ABI/Windows.Foundation/Size.cs b/src/WinRT.Runtime2/ABI/Windows.Foundation/Size.cs index 2e0aa9ce7..8ce9f4c19 100644 --- a/src/WinRT.Runtime2/ABI/Windows.Foundation/Size.cs +++ b/src/WinRT.Runtime2/ABI/Windows.Foundation/Size.cs @@ -14,6 +14,11 @@ #pragma warning disable IDE1006, CA1416 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Windows.Foundation.Size", + target: typeof(Size), + trimTarget: typeof(Size))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(Size), diff --git a/src/WinRT.Runtime2/Windows.Foundation/Collections/CollectionChange.cs b/src/WinRT.Runtime2/Windows.Foundation/Collections/CollectionChange.cs index 23f64d690..ad9076508 100644 --- a/src/WinRT.Runtime2/Windows.Foundation/Collections/CollectionChange.cs +++ b/src/WinRT.Runtime2/Windows.Foundation/Collections/CollectionChange.cs @@ -19,6 +19,8 @@ namespace Windows.Foundation.Collections; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("Windows.Foundation.Collections.CollectionChange")] +[WindowsRuntimeReferenceType(typeof(CollectionChange?))] [SupportedOSPlatform("Windows10.0.10240.0")] [ContractVersion(typeof(FoundationContract), 65536u)] [ABI.Windows.Foundation.Collections.CollectionChangeComWrappersMarshaller] diff --git a/src/WinRT.Runtime2/Windows.Foundation/Point.cs b/src/WinRT.Runtime2/Windows.Foundation/Point.cs index d46441d08..526b1a0af 100644 --- a/src/WinRT.Runtime2/Windows.Foundation/Point.cs +++ b/src/WinRT.Runtime2/Windows.Foundation/Point.cs @@ -19,6 +19,8 @@ namespace Windows.Foundation; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("Windows.Foundation.Point")] +[WindowsRuntimeReferenceType(typeof(Point?))] [SupportedOSPlatform("Windows10.0.10240.0")] [ContractVersion(typeof(FoundationContract), 65536u)] [ABI.Windows.Foundation.PointComWrappersMarshaller] diff --git a/src/WinRT.Runtime2/Windows.Foundation/Rect.cs b/src/WinRT.Runtime2/Windows.Foundation/Rect.cs index 68c339bd2..e5b607b35 100644 --- a/src/WinRT.Runtime2/Windows.Foundation/Rect.cs +++ b/src/WinRT.Runtime2/Windows.Foundation/Rect.cs @@ -21,6 +21,8 @@ namespace Windows.Foundation; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("Windows.Foundation.Rect")] +[WindowsRuntimeReferenceType(typeof(Rect?))] [SupportedOSPlatform("Windows10.0.10240.0")] [ContractVersion(typeof(FoundationContract), 65536u)] [ABI.Windows.Foundation.RectComWrappersMarshaller] diff --git a/src/WinRT.Runtime2/Windows.Foundation/Size.cs b/src/WinRT.Runtime2/Windows.Foundation/Size.cs index 94534d0d1..d78c1e8db 100644 --- a/src/WinRT.Runtime2/Windows.Foundation/Size.cs +++ b/src/WinRT.Runtime2/Windows.Foundation/Size.cs @@ -18,6 +18,8 @@ namespace Windows.Foundation; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("Windows.Foundation.Size")] +[WindowsRuntimeReferenceType(typeof(Size?))] [SupportedOSPlatform("Windows10.0.10240.0")] [ContractVersion(typeof(FoundationContract), 65536u)] [ABI.Windows.Foundation.SizeComWrappersMarshaller] From ea6c7f45023d2edb2238b2da2a92553ec6edc6fc Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 5 Dec 2025 16:10:02 -0800 Subject: [PATCH 51/76] Improve runtime class name retrieval logic Refactored TypeMarshaller and WindowsRuntimeMarshallingInfo to use a new TryGetRuntimeClassName method for safer and more flexible runtime class name retrieval. This change improves handling of cases where metadata type names are unavailable and ensures better error reporting for unsupported types. --- src/WinRT.Runtime2/ABI/System/Type.cs | 15 +++- .../WindowsRuntimeMarshallingInfo.cs | 69 +++++++++++++++---- 2 files changed, 67 insertions(+), 17 deletions(-) diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index 2f8d5bd52..023c5897e 100644 --- a/src/WinRT.Runtime2/ABI/System/Type.cs +++ b/src/WinRT.Runtime2/ABI/System/Type.cs @@ -137,9 +137,18 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR return; } - // In all other cases, just use the runtime class name, which will always be present. This will also - // account for all constructed 'Nullable' instantiations, which will report their boxed type name. - reference = new TypeReference { Name = marshallingInfo.GetRuntimeClassName(), Kind = kind }; + // If we don't have a metadata type name, try to get the runtime class name. This will handle + // cases such as constructed 'Nullable' types, which will report their boxed type name. + if (marshallingInfo.TryGetRuntimeClassName(out string? runtimeClassName)) + { + reference = new TypeReference { Name = runtimeClassName, Kind = kind }; + + return; + } + + // Otherwise, use the type name directly. This will handle all remaining cases, such as projected + // runtime classes and interface types. For all of those, the projected type name will be correct. + reference = new TypeReference { Name = typeOrUnderlyingType.FullName, Kind = kind }; // TODO: handle 'Nullable>' here diff --git a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs index 809dff808..6f2699b61 100644 --- a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs +++ b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs @@ -550,8 +550,34 @@ unsafe WindowsRuntimeVtableInfo InitializeVtableInfo() /// This method is only meant to be used on managed types passed to native. public string GetRuntimeClassName() { + if (!TryGetRuntimeClassName(out string? runtimeClassName)) + { + // Analogous validation as for when retrieving the marshaller attribute + [DoesNotReturn] + [StackTraceHidden] + void ThrowNotSupportedException() + { + throw new NotSupportedException( + $"The metadata provider type '{_metadataProviderType}' does not have any runtime class name info. " + + $"This should never be the case. Please file an issue at https://github.com/microsoft/CsWinRT."); + } + + ThrowNotSupportedException(); + } + + return runtimeClassName; + } + + /// + /// Tries to get the runtime class name for the public type associated with the current metadata provider type. + /// + /// The resulting runtime class name, if available. + /// Whether was retrieved successfully. + public bool TryGetRuntimeClassName([NotNullWhen(true)] out string? runtimeClassName) + { + // Initializes the runtime class name, if present [MethodImpl(MethodImplOptions.NoInlining)] - string InitializeRuntimeClassName() + bool Load([NotNullWhen(true)] out string? runtimeClassName) { WindowsRuntimeClassNameAttribute? runtimeClassNameAttribute = _metadataProviderType.GetCustomAttribute(inherit: false) @@ -559,23 +585,38 @@ string InitializeRuntimeClassName() if (runtimeClassNameAttribute is null) { - // Analogous validation as for when retrieving the marshaller attribute - [DoesNotReturn] - [StackTraceHidden] - void ThrowNotSupportedException() - { - throw new NotSupportedException( - $"The metadata provider type '{_metadataProviderType}' does not have any runtime class name info. " + - $"This should never be the case. Please file an issue at https://github.com/microsoft/CsWinRT."); - } + _runtimeClassName ??= ""; + + runtimeClassName = null; + + return false; + } + + _runtimeClassName = runtimeClassNameAttribute.RuntimeClassName; + + runtimeClassName = runtimeClassNameAttribute.RuntimeClassName; + + return true; + } + + string? value = _metadataTypeName; - ThrowNotSupportedException(); + // We have a cached runtime class name, so return it immediately + if (value is not null) + { + if (value is "") + { + runtimeClassName = null; + + return false; } - return _runtimeClassName ??= runtimeClassNameAttribute.RuntimeClassName; + runtimeClassName = value; + + return true; } - return _runtimeClassName ?? InitializeRuntimeClassName(); + return Load(out runtimeClassName); } /// @@ -610,7 +651,7 @@ void ThrowNotSupportedException() /// Whether was retrieved successfully. public bool TryGetMetadataTypeName([NotNullWhen(true)] out string? metadataTypeName) { - // Initializes the reference type instance, if present + // Initializes the metadata type name, if present [MethodImpl(MethodImplOptions.NoInlining)] bool Load([NotNullWhen(true)] out string? metadataTypeName) { From 9165db52066aa1d1e8f27c7ac4988aeb0b98dfd2 Mon Sep 17 00:00:00 2001 From: Will Thant Date: Fri, 5 Dec 2025 16:15:11 -0800 Subject: [PATCH 52/76] Convert TestProperty tests to use InlineData --- .../UnitTest/TestComponentCSharp_Tests.cs | 177 +++--------------- 1 file changed, 30 insertions(+), 147 deletions(-) diff --git a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs index db9d83d3f..3eab42a34 100644 --- a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs +++ b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs @@ -546,155 +546,38 @@ public void TestBufferTryGetArraySubset() Assert.Equal(2, array.Count); } - [Fact] - public void TestTypePropertyWithTestComponentNested() - { - TestObject.TypeProperty = typeof(TestComponent.Nested); - Assert.Equal("TestComponent.Nested", TestObject.GetTypePropertyAbiName()); - Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); - } - - [Fact] - public void TestTypePropertyWithTestComponentParamHandlers() - { - TestObject.TypeProperty = typeof(TestComponent.Param6Handler); - Assert.Equal("TestComponent.Param6Handler", TestObject.GetTypePropertyAbiName()); - Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); - - TestObject.TypeProperty = typeof(TestComponent.Param7Handler); - Assert.Equal("TestComponent.Param7Handler", TestObject.GetTypePropertyAbiName()); - Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); - } - - [Fact] - public void TestTypePropertyWithTestComponentCSharpEnumValue() - { - TestObject.TypeProperty = typeof(TestComponentCSharp.EnumValue); - Assert.Equal("TestComponentCSharp.EnumValue", TestObject.GetTypePropertyAbiName()); - Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); - } - - [Fact] - public void TestTypePropertyWithTestComponentIComposable() - { - TestObject.TypeProperty = typeof(TestComponent.IComposable); - Assert.Equal("TestComponent.IComposable", TestObject.GetTypePropertyAbiName()); - Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); - } - - [Fact] - public void TestTypePropertyWithTestComponentCSharpClass() - { - TestObject.TypeProperty = typeof(TestComponentCSharp.Class); - Assert.Equal("TestComponentCSharp.Class", TestObject.GetTypePropertyAbiName()); - Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); - } - - [Fact] - public void TestTypePropertyWithSystemType() - { - TestObject.TypeProperty = typeof(System.Type); - Assert.Equal("Windows.UI.Xaml.Interop.TypeName", TestObject.GetTypePropertyAbiName()); - Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); - } - - [Fact] - public void TestTypePropertyWithGuidType() - { - TestObject.TypeProperty = typeof(System.Guid); - Assert.Equal("Guid", TestObject.GetTypePropertyAbiName()); - Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); - } - - [Fact] - public void TestTypePropertyWithObjectType() - { - TestObject.TypeProperty = typeof(System.Object); - Assert.Equal("Object", TestObject.GetTypePropertyAbiName()); - Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); + [Theory] + [InlineData(typeof(TestComponent.Nested), "TestComponent.Nested", "Metadata")] + [InlineData(typeof(TestComponent.Param6Handler), "TestComponent.Param6Handler", "Metadata")] + [InlineData(typeof(TestComponent.Param7Handler), "TestComponent.Param7Handler", "Metadata")] + [InlineData(typeof(TestComponent.Class), "TestComponent.Class", "Metadata")] + [InlineData(typeof(TestComponentCSharp.EnumValue), "TestComponentCSharp.EnumValue", "Metadata")] + [InlineData(typeof(Type), "Type", "Metadata")] + [InlineData(typeof(Guid), "Guid", "Metadata")] + [InlineData(typeof(Object), "Object", "Metadata")] + [InlineData(typeof(String), "String", "Metadata")] + [InlineData(typeof(TimeSpan), "TimeSpan", "Metadata")] + [InlineData(typeof(long), "Int64", "Primitive")] + [InlineData(typeof(int), "Int32", "Primitive")] + [InlineData(typeof(short), "Int16", "Primitive")] + [InlineData(typeof(ulong), "UInt64", "Primitive")] + [InlineData(typeof(uint), "UInt32", "Primitive")] + [InlineData(typeof(ushort), "UInt16", "Primitive")] + [InlineData(typeof(byte), "UInt8", "Primitive")] + [InlineData(typeof(char), "Char16", "Primitive")] + [InlineData(typeof(float), "Single", "Primitive")] + [InlineData(typeof(double), "Double", "Primitive")] + [InlineData(typeof(bool), "Boolean", "Primitive")] + [InlineData(typeof(IServiceProvider), "Microsoft.UI.Xaml.IXamlServiceProvider", "Metadata")] + [InlineData(typeof(IDisposable), "Windows.Foundation.IClosable", "Metadata")] + public void TestTypePropertyConvertToUnmanaged(Type type, string name, string kind) + { + // test method here + TestObject.TypeProperty = type; + Assert.Equal(name, TestObject.GetTypePropertyAbiName()); + Assert.Equal(kind, TestObject.GetTypePropertyKind()); } - [Fact] - public void TestTypePropertyWithStringType() - { - TestObject.TypeProperty = typeof(System.String); - Assert.Equal("String", TestObject.GetTypePropertyAbiName()); - Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); - } - - [Fact] - public void TestTypePropertyWithPrimitiveType() - { - TestObject.TypeProperty = typeof(long); - Assert.Equal("Int64", TestObject.GetTypePropertyAbiName()); - Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); - - TestObject.TypeProperty = typeof(int); - Assert.Equal("Int32", TestObject.GetTypePropertyAbiName()); - Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); - - TestObject.TypeProperty = typeof(short); - Assert.Equal("Int16", TestObject.GetTypePropertyAbiName()); - Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); - - TestObject.TypeProperty = typeof(ulong); - Assert.Equal("UInt64", TestObject.GetTypePropertyAbiName()); - Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); - - TestObject.TypeProperty = typeof(uint); - Assert.Equal("UInt32", TestObject.GetTypePropertyAbiName()); - Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); - - TestObject.TypeProperty = typeof(ushort); - Assert.Equal("UInt16", TestObject.GetTypePropertyAbiName()); - Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); - - TestObject.TypeProperty = typeof(byte); - Assert.Equal("UInt8", TestObject.GetTypePropertyAbiName()); - Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); - - TestObject.TypeProperty = typeof(char); - Assert.Equal("Char16", TestObject.GetTypePropertyAbiName()); - Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); - - TestObject.TypeProperty = typeof(float); - Assert.Equal("Single", TestObject.GetTypePropertyAbiName()); - Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); - - TestObject.TypeProperty = typeof(double); - Assert.Equal("Double", TestObject.GetTypePropertyAbiName()); - Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); - - TestObject.TypeProperty = typeof(bool); - Assert.Equal("Boolean", TestObject.GetTypePropertyAbiName()); - Assert.Equal("Primitive", TestObject.GetTypePropertyKind()); - } - - [Fact] - public void TestTypePropertyWithIServiceProvider() - { - TestObject.TypeProperty = typeof(IServiceProvider); - Assert.Equal("Microsoft.UI.Xaml.IXamlServiceProvider", TestObject.GetTypePropertyAbiName()); - Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); - } - - [Fact] - public void TestTypePropertyWithIDisposable() - { - TestObject.TypeProperty = typeof(IDisposable); - Assert.Equal("Windows.Foundation.IClosable", TestObject.GetTypePropertyAbiName()); - Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); - } - - [Fact] - public void TestTypePropertyWithTimespan() - { - TestObject.TypeProperty = typeof(TimeSpan); - Assert.Equal("TimeSpan", TestObject.GetTypePropertyAbiName()); - Assert.Equal("Metadata", TestObject.GetTypePropertyKind()); - } - - class CustomDictionary : Dictionary { } [Fact] From 411f047dbbd6e5f8af100f302c0895e9205be5d9 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 5 Dec 2025 16:21:32 -0800 Subject: [PATCH 53/76] Handle custom-mapped interface types in TypeMarshaller Added logic to use WindowsRuntimeMetadataInfo lookup for interface types that do not have proxy type map entries or projected types, ensuring correct metadata type name is used during marshalling. --- src/WinRT.Runtime2/ABI/System/Type.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index 023c5897e..eb61e058d 100644 --- a/src/WinRT.Runtime2/ABI/System/Type.cs +++ b/src/WinRT.Runtime2/ABI/System/Type.cs @@ -114,6 +114,17 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR // underlying type. Instead, for 'Nullable' values we need the runtime class name, which in this case // would be the 'IReference' type name for boxed instances of this type. global::System.Type? nullableUnderlyingType = Nullable.GetUnderlyingType(value); + + // Use the metadata info lookup first to handle custom-mapped interface types. These would not have a proxy + // type map entry for normal marshalling (because they're interfaces), and they would also not show up as + // being projected types from there. So we handle them here first to get the right metadata type name. + if (nullableUnderlyingType is null && WindowsRuntimeMetadataInfo.TryGetInfo(value, out WindowsRuntimeMetadataInfo? metadataInfo)) + { + reference = new TypeReference { Name = metadataInfo.GetMetadataTypeName(), Kind = TypeKind.Metadata }; + + return; + } + global::System.Type typeOrUnderlyingType = nullableUnderlyingType ?? value; // Use the marshalling info lookup to detect projected or custom-mapped Windows Runtime types. From 4ffdc4e5a930c8c15f5193fd8489f0c7f7a6b978 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 5 Dec 2025 16:21:38 -0800 Subject: [PATCH 54/76] Add WindowsRuntimeMetadataTypeMapGroup associations Introduced TypeMapAssociation attributes for WindowsRuntimeMetadataTypeMapGroup in ABI types including IDisposable, IServiceProvider, AsyncActionCompletedHandler, IVectorChangedEventArgs, IAsyncAction, and IAsyncInfo to improve type mapping and metadata handling. --- src/WinRT.Runtime2/ABI/System/IDisposable.cs | 4 ++++ src/WinRT.Runtime2/ABI/System/IServiceProvider.cs | 4 ++++ .../ABI/Windows.Foundation/AsyncActionCompletedHandler.cs | 5 +++++ .../Collections/IVectorChangedEventArgs.cs | 4 ++++ src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncAction.cs | 4 ++++ src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncInfo.cs | 4 ++++ 6 files changed, 25 insertions(+) diff --git a/src/WinRT.Runtime2/ABI/System/IDisposable.cs b/src/WinRT.Runtime2/ABI/System/IDisposable.cs index 06aa10d89..4cf79c0ff 100644 --- a/src/WinRT.Runtime2/ABI/System/IDisposable.cs +++ b/src/WinRT.Runtime2/ABI/System/IDisposable.cs @@ -20,6 +20,10 @@ trimTarget: typeof(IDisposable))] #pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMapAssociation( + source: typeof(IDisposable), + proxy: typeof(ABI.System.IDisposable))] + [assembly: TypeMapAssociation( source: typeof(IDisposable), proxy: typeof(ABI.System.IDisposableInterfaceImpl))] diff --git a/src/WinRT.Runtime2/ABI/System/IServiceProvider.cs b/src/WinRT.Runtime2/ABI/System/IServiceProvider.cs index 34214f0b5..cab9f26d7 100644 --- a/src/WinRT.Runtime2/ABI/System/IServiceProvider.cs +++ b/src/WinRT.Runtime2/ABI/System/IServiceProvider.cs @@ -20,6 +20,10 @@ trimTarget: typeof(IServiceProvider))] #pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMapAssociation( + source: typeof(IServiceProvider), + proxy: typeof(ABI.System.IServiceProvider))] + [assembly: TypeMapAssociation( source: typeof(IServiceProvider), proxy: typeof(ABI.System.IServiceProviderInterfaceImpl))] diff --git a/src/WinRT.Runtime2/ABI/Windows.Foundation/AsyncActionCompletedHandler.cs b/src/WinRT.Runtime2/ABI/Windows.Foundation/AsyncActionCompletedHandler.cs index 5d5b8d1a5..e06b41ddd 100644 --- a/src/WinRT.Runtime2/ABI/Windows.Foundation/AsyncActionCompletedHandler.cs +++ b/src/WinRT.Runtime2/ABI/Windows.Foundation/AsyncActionCompletedHandler.cs @@ -14,6 +14,11 @@ #pragma warning disable IDE0008, IDE1006 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Windows.Foundation.AsyncActionCompletedHandler", + target: typeof(AsyncActionCompletedHandler), + trimTarget: typeof(AsyncActionCompletedHandler))] + [assembly: TypeMap( value: "Windows.Foundation.IReference", target: typeof(AsyncActionCompletedHandler), diff --git a/src/WinRT.Runtime2/ABI/Windows.Foundation/Collections/IVectorChangedEventArgs.cs b/src/WinRT.Runtime2/ABI/Windows.Foundation/Collections/IVectorChangedEventArgs.cs index 158fffdcf..f8634894f 100644 --- a/src/WinRT.Runtime2/ABI/Windows.Foundation/Collections/IVectorChangedEventArgs.cs +++ b/src/WinRT.Runtime2/ABI/Windows.Foundation/Collections/IVectorChangedEventArgs.cs @@ -21,6 +21,10 @@ trimTarget: typeof(IVectorChangedEventArgs))] #pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMapAssociation( + source: typeof(IVectorChangedEventArgs), + proxy: typeof(ABI.Windows.Foundation.Collections.IVectorChangedEventArgs))] + [assembly: TypeMapAssociation( source: typeof(IVectorChangedEventArgs), proxy: typeof(ABI.Windows.Foundation.Collections.IVectorChangedEventArgs))] diff --git a/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncAction.cs b/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncAction.cs index 9ccaf7a9d..413756f18 100644 --- a/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncAction.cs +++ b/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncAction.cs @@ -21,6 +21,10 @@ trimTarget: typeof(IAsyncAction))] #pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMapAssociation( + source: typeof(IAsyncAction), + proxy: typeof(ABI.Windows.Foundation.IAsyncAction))] + [assembly: TypeMapAssociation( source: typeof(IAsyncAction), proxy: typeof(ABI.Windows.Foundation.IAsyncActionInterfaceImpl))] diff --git a/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncInfo.cs b/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncInfo.cs index 31e885b4e..1b502265c 100644 --- a/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncInfo.cs +++ b/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncInfo.cs @@ -20,6 +20,10 @@ trimTarget: typeof(IAsyncInfo))] #pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMapAssociation( + source: typeof(IAsyncInfo), + proxy: typeof(ABI.Windows.Foundation.IAsyncInfo))] + [assembly: TypeMapAssociation( source: typeof(IAsyncInfo), proxy: typeof(ABI.Windows.Foundation.IAsyncInfoInterfaceImpl))] From 684bd3c5f13f7f5c91d0d958d7ab7427e0ebc8aa Mon Sep 17 00:00:00 2001 From: Will Thant Date: Fri, 5 Dec 2025 18:45:36 -0800 Subject: [PATCH 55/76] Fix Expected result for Timespan and Type --- src/Tests/UnitTest/TestComponentCSharp_Tests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs index 3eab42a34..0a44f63ef 100644 --- a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs +++ b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs @@ -552,11 +552,11 @@ public void TestBufferTryGetArraySubset() [InlineData(typeof(TestComponent.Param7Handler), "TestComponent.Param7Handler", "Metadata")] [InlineData(typeof(TestComponent.Class), "TestComponent.Class", "Metadata")] [InlineData(typeof(TestComponentCSharp.EnumValue), "TestComponentCSharp.EnumValue", "Metadata")] - [InlineData(typeof(Type), "Type", "Metadata")] + [InlineData(typeof(Type), "Windows.UI.Xaml.Interop.TypeName", "Metadata")] [InlineData(typeof(Guid), "Guid", "Metadata")] [InlineData(typeof(Object), "Object", "Metadata")] [InlineData(typeof(String), "String", "Metadata")] - [InlineData(typeof(TimeSpan), "TimeSpan", "Metadata")] + [InlineData(typeof(TimeSpan), "Windows.Foundation.TimeSpan", "Metadata")] [InlineData(typeof(long), "Int64", "Primitive")] [InlineData(typeof(int), "Int32", "Primitive")] [InlineData(typeof(short), "Int16", "Primitive")] From 49d8522b153c7a417f46e6aaa490940ebba0c030 Mon Sep 17 00:00:00 2001 From: Will Thant Date: Fri, 5 Dec 2025 18:59:04 -0800 Subject: [PATCH 56/76] Add WindowsRuntimeMetadataTypeName attribute in Object.cs --- src/WinRT.Runtime2/ABI/System/Object.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/WinRT.Runtime2/ABI/System/Object.cs b/src/WinRT.Runtime2/ABI/System/Object.cs index d73d86d9c..1e4a0df37 100644 --- a/src/WinRT.Runtime2/ABI/System/Object.cs +++ b/src/WinRT.Runtime2/ABI/System/Object.cs @@ -23,6 +23,7 @@ namespace ABI.System; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Object")] +[WindowsRuntimeMetadataTypeName("Object")] [ObjectComWrappersMarshaller] file static class Object; From fecf1f47bd2a52b34893b4eb7f9d39d4d3fafa02 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sat, 6 Dec 2025 14:05:03 -0800 Subject: [PATCH 57/76] Update type map attribute to MetadataTypeMapGroup Replaces WindowsRuntimeComWrappersTypeMapGroup with WindowsRuntimeMetadataTypeMapGroup in Matrix3x2, Matrix4x4, Plane, Quaternion, and Vector2 type map attributes for improved metadata handling. --- src/WinRT.Runtime2/ABI/System/Numerics/Matrix3x2.cs | 2 +- src/WinRT.Runtime2/ABI/System/Numerics/Matrix4x4.cs | 2 +- src/WinRT.Runtime2/ABI/System/Numerics/Plane.cs | 2 +- src/WinRT.Runtime2/ABI/System/Numerics/Quaternion.cs | 2 +- src/WinRT.Runtime2/ABI/System/Numerics/Vector2.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Matrix3x2.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Matrix3x2.cs index 6cafd1181..731f2ee43 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Matrix3x2.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Matrix3x2.cs @@ -15,7 +15,7 @@ #pragma warning disable IDE1006 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code -[assembly: TypeMap( +[assembly: TypeMap( value: "Windows.Foundation.Numerics.Matrix3x2", target: typeof(ABI.System.Numerics.Matrix3x2), trimTarget: typeof(Matrix3x2))] diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Matrix4x4.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Matrix4x4.cs index cc60d6e18..386ad0976 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Matrix4x4.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Matrix4x4.cs @@ -15,7 +15,7 @@ #pragma warning disable IDE1006 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code -[assembly: TypeMap( +[assembly: TypeMap( value: "Windows.Foundation.Numerics.Matrix4x4", target: typeof(ABI.System.Numerics.Matrix4x4), trimTarget: typeof(Matrix4x4))] diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Plane.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Plane.cs index baf0c702a..8264c0549 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Plane.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Plane.cs @@ -15,7 +15,7 @@ #pragma warning disable IDE1006 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code -[assembly: TypeMap( +[assembly: TypeMap( value: "Windows.Foundation.Numerics.Plane", target: typeof(ABI.System.Numerics.Plane), trimTarget: typeof(Plane))] diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Quaternion.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Quaternion.cs index 9e56747ad..f1c013cbc 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Quaternion.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Quaternion.cs @@ -15,7 +15,7 @@ #pragma warning disable IDE1006 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code -[assembly: TypeMap( +[assembly: TypeMap( value: "Windows.Foundation.Numerics.Quaternion", target: typeof(ABI.System.Numerics.Quaternion), trimTarget: typeof(Quaternion))] diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Vector2.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Vector2.cs index 9f8e74ae0..63ba8d0f0 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Vector2.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Vector2.cs @@ -15,7 +15,7 @@ #pragma warning disable IDE1006 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code -[assembly: TypeMap( +[assembly: TypeMap( value: "Windows.Foundation.Numerics.Vector2", target: typeof(ABI.System.Numerics.Vector2), trimTarget: typeof(Vector2))] From 5558480e9c53d9f4e2e30bf87666c7670d671337 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sat, 6 Dec 2025 14:05:33 -0800 Subject: [PATCH 58/76] Remove redundant metadata attribute from Object.cs Deleted the [WindowsRuntimeMetadataTypeName("Object")] attribute from the Object class as it was unnecessary. This helps clean up the code and avoid redundant metadata. --- src/WinRT.Runtime2/ABI/System/Object.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/WinRT.Runtime2/ABI/System/Object.cs b/src/WinRT.Runtime2/ABI/System/Object.cs index 1e4a0df37..d73d86d9c 100644 --- a/src/WinRT.Runtime2/ABI/System/Object.cs +++ b/src/WinRT.Runtime2/ABI/System/Object.cs @@ -23,7 +23,6 @@ namespace ABI.System; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Object")] -[WindowsRuntimeMetadataTypeName("Object")] [ObjectComWrappersMarshaller] file static class Object; From 3faa61ff452b3e56f5252b00b596687075c89f57 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sat, 6 Dec 2025 14:07:03 -0800 Subject: [PATCH 59/76] Add new TypeMapAssemblyTarget attributes Added TypeMapAssemblyTarget attributes for WindowsRuntimeMetadataTypeMapGroup and DynamicInterfaceCastableImplementationTypeMapGroup to support additional type mapping scenarios in generated assemblies. --- .../TypeMapAssemblyTargetGenerator.Execute.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Authoring/WinRT.SourceGenerator2/TypeMapAssemblyTargetGenerator.Execute.cs b/src/Authoring/WinRT.SourceGenerator2/TypeMapAssemblyTargetGenerator.Execute.cs index aba7fa179..7d45685d5 100644 --- a/src/Authoring/WinRT.SourceGenerator2/TypeMapAssemblyTargetGenerator.Execute.cs +++ b/src/Authoring/WinRT.SourceGenerator2/TypeMapAssemblyTargetGenerator.Execute.cs @@ -104,6 +104,8 @@ public static void EmitPrivateProjectionsTypeMapAssemblyTargetAttributes(SourceP { _ = builder.AppendLine($""" [assembly: global::System.Runtime.InteropServices.TypeMapAssemblyTarget("{assemblyName}")] + [assembly: global::System.Runtime.InteropServices.TypeMapAssemblyTarget("{assemblyName}")] + [assembly: global::System.Runtime.InteropServices.TypeMapAssemblyTarget("{assemblyName}")] """); } @@ -129,6 +131,14 @@ public static void EmitDefaultTypeMapAssemblyTargetAttributes(SourceProductionCo [assembly: global::System.Runtime.InteropServices.TypeMapAssemblyTarget("WinRT.Interop")] //[assembly: global::System.Runtime.InteropServices.TypeMapAssemblyTarget("WinRT.Projection")] [assembly: global::System.Runtime.InteropServices.TypeMapAssemblyTarget("WinRT.Runtime2")] + + [assembly: global::System.Runtime.InteropServices.TypeMapAssemblyTarget("WinRT.Interop")] + //[assembly: global::System.Runtime.InteropServices.TypeMapAssemblyTarget("WinRT.Projection")] + [assembly: global::System.Runtime.InteropServices.TypeMapAssemblyTarget("WinRT.Runtime2")] + + [assembly: global::System.Runtime.InteropServices.TypeMapAssemblyTarget("WinRT.Interop")] + //[assembly: global::System.Runtime.InteropServices.TypeMapAssemblyTarget("WinRT.Projection")] + [assembly: global::System.Runtime.InteropServices.TypeMapAssemblyTarget("WinRT.Runtime2")] """; context.AddSource("TypeMapAssemblyTarget.g.cs", source); From 6eba922069754431cbc98db8d83e50231ac6c9fd Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sat, 6 Dec 2025 14:16:17 -0800 Subject: [PATCH 60/76] Update ABI for INotifyDataErrorInfo to use fully qualified names Refactored ABI.System.ComponentModel.INotifyDataErrorInfo to consistently use fully qualified type names for global::System.ComponentModel.INotifyDataErrorInfo throughout the file. Added new TypeMap and TypeMapAssociation attributes for WindowsRuntimeMetadataTypeMapGroup, and improved documentation comments for clarity. This enhances type safety and interoperability with Windows Runtime metadata. --- .../ComponentModel/INotifyDataErrorInfo.cs | 80 +++++++++++-------- 1 file changed, 48 insertions(+), 32 deletions(-) diff --git a/src/WinRT.Runtime2/ABI/System/ComponentModel/INotifyDataErrorInfo.cs b/src/WinRT.Runtime2/ABI/System/ComponentModel/INotifyDataErrorInfo.cs index 265706302..772c30b45 100644 --- a/src/WinRT.Runtime2/ABI/System/ComponentModel/INotifyDataErrorInfo.cs +++ b/src/WinRT.Runtime2/ABI/System/ComponentModel/INotifyDataErrorInfo.cs @@ -16,6 +16,17 @@ #pragma warning disable IDE0008, IDE1006 +#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +[assembly: TypeMap( + value: "Microsoft.UI.Xaml.Data.INotifyDataErrorInfo", + target: typeof(ABI.System.ComponentModel.INotifyDataErrorInfo), + trimTarget: typeof(INotifyDataErrorInfo))] +#pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code + +[assembly: TypeMapAssociation( + source: typeof(INotifyDataErrorInfo), + proxy: typeof(ABI.System.ComponentModel.INotifyDataErrorInfo))] + [assembly: TypeMapAssociation( source: typeof(INotifyDataErrorInfo), proxy: typeof(ABI.System.ComponentModel.INotifyDataErrorInfoInterfaceImpl))] @@ -23,7 +34,14 @@ namespace ABI.System.ComponentModel; /// -/// Marshaller for . +/// ABI type for . +/// +[WindowsRuntimeMetadata("Microsoft.UI.Xaml.WinUIContract")] +[WindowsRuntimeMetadataTypeName("Microsoft.UI.Xaml.Data.INotifyDataErrorInfo")] +file static class INotifyDataErrorInfo; + +/// +/// Marshaller for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -32,22 +50,22 @@ namespace ABI.System.ComponentModel; public static unsafe class INotifyDataErrorInfoMarshaller { /// - public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(INotifyDataErrorInfo? value) + public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(global::System.ComponentModel.INotifyDataErrorInfo? value) { - return WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged( + return WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged( value: value, iid: in WellKnownWindowsInterfaceIIDs.IID_INotifyDataErrorInfo); } /// - public static INotifyDataErrorInfo? ConvertToManaged(void* value) + public static global::System.ComponentModel.INotifyDataErrorInfo? ConvertToManaged(void* value) { - return (INotifyDataErrorInfo?)WindowsRuntimeObjectMarshaller.ConvertToManaged(value); + return (global::System.ComponentModel.INotifyDataErrorInfo?)WindowsRuntimeObjectMarshaller.ConvertToManaged(value); } } /// -/// Interop methods for . +/// Interop methods for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -56,7 +74,7 @@ public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(INotifyDataE public static unsafe class INotifyDataErrorInfoMethods { /// - /// The table for . + /// The table for . /// private static ConditionalWeakTable> ErrorsChangedTable { @@ -75,7 +93,7 @@ static ConditionalWeakTable + /// [MethodImpl(MethodImplOptions.NoInlining)] public static bool HasErrors(WindowsRuntimeObjectReference thisReference) { @@ -89,7 +107,7 @@ public static bool HasErrors(WindowsRuntimeObjectReference thisReference) return Unsafe.BitCast(result) != 0; } - /// + /// public static EventHandlerEventSource ErrorsChanged(WindowsRuntimeObject thisObject, WindowsRuntimeObjectReference thisReference) { [UnsafeAccessor(UnsafeAccessorKind.Constructor)] @@ -102,7 +120,7 @@ public static EventHandlerEventSource ErrorsChanged( factoryArgument: thisReference); } - /// + /// [MethodImpl(MethodImplOptions.NoInlining)] public static IEnumerable GetErrors(WindowsRuntimeObjectReference thisReference, string? propertyName) { @@ -135,7 +153,7 @@ public static IEnumerable GetErrors(WindowsRuntimeObjectReference thisReference, } /// -/// Binding type for . +/// Binding type for . /// [StructLayout(LayoutKind.Sequential)] internal unsafe struct INotifyDataErrorInfoVftbl @@ -153,7 +171,7 @@ internal unsafe struct INotifyDataErrorInfoVftbl } /// -/// The implementation. +/// The implementation. /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -162,7 +180,7 @@ internal unsafe struct INotifyDataErrorInfoVftbl public static unsafe class INotifyDataErrorInfoImpl { /// - /// The value for the managed implementation. + /// The value for the managed implementation. /// [FixedAddressValueType] private static readonly INotifyDataErrorInfoVftbl Vftbl; @@ -181,7 +199,7 @@ static INotifyDataErrorInfoImpl() } /// - /// Gets a pointer to the managed implementation. + /// Gets a pointer to the managed implementation. /// public static nint Vtable { @@ -190,15 +208,15 @@ public static nint Vtable } /// - /// The table for . + /// The table for . /// - private static ConditionalWeakTable>> ErrorsChanged + private static ConditionalWeakTable>> ErrorsChanged { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { [MethodImpl(MethodImplOptions.NoInlining)] - static ConditionalWeakTable>> MakeErrorsChanged() + static ConditionalWeakTable>> MakeErrorsChanged() { _ = Interlocked.CompareExchange(ref field, [], null); @@ -217,7 +235,7 @@ private static HRESULT get_HasErrors(void* thisPtr, bool* result) try { - var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); *result = unboxedValue.HasErrors; @@ -237,7 +255,7 @@ private static HRESULT add_ErrorsChanged(void* thisPtr, void* handler, EventRegi try { - var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); [UnsafeAccessor(UnsafeAccessorKind.StaticMethod)] static extern EventHandler? ConvertToManaged( @@ -264,7 +282,7 @@ private static HRESULT remove_ErrorsChanged(void* thisPtr, EventRegistrationToke { try { - var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); if (unboxedValue is not null && ErrorsChanged.TryGetValue(unboxedValue, out var table) && table.RemoveEventHandler(token, out EventHandler? managedHandler)) { @@ -287,7 +305,7 @@ private static HRESULT GetErrors(void* thisPtr, HSTRING propertyName, void** res try { - var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); IEnumerable managedResult = unboxedValue.GetErrors(HStringMarshaller.ConvertToManaged(propertyName)); @@ -308,47 +326,45 @@ static extern WindowsRuntimeObjectReferenceValue ConvertToUnmanaged( } /// -/// The implementation for . +/// The implementation for . /// -[WindowsRuntimeMetadata("Microsoft.UI.Xaml.WinUIContract")] -[WindowsRuntimeClassName("Microsoft.UI.Xaml.Data.INotifyDataErrorInfo")] [DynamicInterfaceCastableImplementation] -file interface INotifyDataErrorInfoInterfaceImpl : INotifyDataErrorInfo +file interface INotifyDataErrorInfoInterfaceImpl : global::System.ComponentModel.INotifyDataErrorInfo { /// - event EventHandler? INotifyDataErrorInfo.ErrorsChanged + event EventHandler? global::System.ComponentModel.INotifyDataErrorInfo.ErrorsChanged { add { var thisObject = (WindowsRuntimeObject)this; - var thisReference = thisObject.GetObjectReferenceForInterface(typeof(INotifyDataErrorInfo).TypeHandle); + var thisReference = thisObject.GetObjectReferenceForInterface(typeof(global::System.ComponentModel.INotifyDataErrorInfo).TypeHandle); INotifyDataErrorInfoMethods.ErrorsChanged((WindowsRuntimeObject)this, thisReference).Subscribe(value); } remove { var thisObject = (WindowsRuntimeObject)this; - var thisReference = thisObject.GetObjectReferenceForInterface(typeof(INotifyDataErrorInfo).TypeHandle); + var thisReference = thisObject.GetObjectReferenceForInterface(typeof(global::System.ComponentModel.INotifyDataErrorInfo).TypeHandle); INotifyDataErrorInfoMethods.ErrorsChanged(thisObject, thisReference).Unsubscribe(value); } } /// - bool INotifyDataErrorInfo.HasErrors + bool global::System.ComponentModel.INotifyDataErrorInfo.HasErrors { get { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(INotifyDataErrorInfo).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::System.ComponentModel.INotifyDataErrorInfo).TypeHandle); return INotifyDataErrorInfoMethods.HasErrors(thisReference); } } /// - IEnumerable INotifyDataErrorInfo.GetErrors(string? propertyName) + IEnumerable global::System.ComponentModel.INotifyDataErrorInfo.GetErrors(string? propertyName) { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(INotifyDataErrorInfo).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::System.ComponentModel.INotifyDataErrorInfo).TypeHandle); return INotifyDataErrorInfoMethods.GetErrors(thisReference, propertyName); } From 8d4ca16c6200b95dd18a3c63007c203ee6e4755e Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sat, 6 Dec 2025 14:19:12 -0800 Subject: [PATCH 61/76] Refactor placeholder marshaller attribute implementation Replaces PlaceholderWindowsRuntimeComWrappersMarshallerAttribute with WindowsRuntimeComWrappersMarshallerAttributePlaceholder in a new file and updates all references. Removes the old placeholder and related reference type attribute from WindowsRuntimeMarshallingInfo.cs for improved clarity and maintainability. --- ...mWrappersMarshallerAttributePlaceholder.cs | 39 +++++++++++++++ .../WindowsRuntimeMarshallingInfo.cs | 50 ++----------------- 2 files changed, 42 insertions(+), 47 deletions(-) create mode 100644 src/WinRT.Runtime2/InteropServices/Placeholders/WindowsRuntimeComWrappersMarshallerAttributePlaceholder.cs diff --git a/src/WinRT.Runtime2/InteropServices/Placeholders/WindowsRuntimeComWrappersMarshallerAttributePlaceholder.cs b/src/WinRT.Runtime2/InteropServices/Placeholders/WindowsRuntimeComWrappersMarshallerAttributePlaceholder.cs new file mode 100644 index 000000000..796157bcd --- /dev/null +++ b/src/WinRT.Runtime2/InteropServices/Placeholders/WindowsRuntimeComWrappersMarshallerAttributePlaceholder.cs @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Runtime.InteropServices; + +namespace WindowsRuntime.InteropServices; + +/// +/// A placeholder type. +/// +internal sealed unsafe class WindowsRuntimeComWrappersMarshallerAttributePlaceholder : WindowsRuntimeComWrappersMarshallerAttribute +{ + /// + /// The shared placeholder instance. + /// + public static readonly WindowsRuntimeComWrappersMarshallerAttributePlaceholder Instance = new(); + + /// + public override void* GetOrCreateComInterfaceForObject(object value) + { + return null; + } + + /// + public override ComWrappers.ComInterfaceEntry* ComputeVtables(out int count) + { + count = 0; + + return null; + } + + /// + public override object CreateObject(void* value, out CreatedWrapperFlags wrapperFlags) + { + wrapperFlags = CreatedWrapperFlags.None; + + return null!; + } +} diff --git a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs index 6f2699b61..7e796296e 100644 --- a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs +++ b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs @@ -477,11 +477,11 @@ bool Load([NotNullWhen(true)] out WindowsRuntimeComWrappersMarshallerAttribute? { WindowsRuntimeComWrappersMarshallerAttribute? value = _metadataProviderType.GetCustomAttribute(inherit: false); - value ??= PlaceholderWindowsRuntimeComWrappersMarshallerAttribute.Instance; + value ??= WindowsRuntimeComWrappersMarshallerAttributePlaceholder.Instance; _comWrappersMarshaller = value; - if (value is not (null or PlaceholderWindowsRuntimeComWrappersMarshallerAttribute)) + if (value is not (null or WindowsRuntimeComWrappersMarshallerAttributePlaceholder)) { marshaller = value; @@ -498,7 +498,7 @@ bool Load([NotNullWhen(true)] out WindowsRuntimeComWrappersMarshallerAttribute? // We have a cached marshaller, so return it immediately if (value is not null) { - if (value is PlaceholderWindowsRuntimeComWrappersMarshallerAttribute) + if (value is WindowsRuntimeComWrappersMarshallerAttributePlaceholder) { marshaller = null; @@ -742,48 +742,4 @@ private static WindowsRuntimeMarshallingInfo CreateMarshallingInfo(Type metadata // We don't have a metadata provider for the type (we'll just marshal it as a generic 'IInspectable') return null; } -} - -/// -/// A placeholder type. -/// -file sealed unsafe class PlaceholderWindowsRuntimeComWrappersMarshallerAttribute : WindowsRuntimeComWrappersMarshallerAttribute -{ - /// - /// The shared placeholder instance. - /// - public static readonly PlaceholderWindowsRuntimeComWrappersMarshallerAttribute Instance = new(); - - /// - public override void* GetOrCreateComInterfaceForObject(object value) - { - return null; - } - - /// - public override ComWrappers.ComInterfaceEntry* ComputeVtables(out int count) - { - count = 0; - - return null; - } - - /// - public override object CreateObject(void* value, out CreatedWrapperFlags wrapperFlags) - { - wrapperFlags = CreatedWrapperFlags.None; - - return null!; - } -} - -/// -/// A placeholder type. -/// -file sealed class PlaceholderWindowsRuntimeReferenceTypeAttribute -{ - /// - /// The shared instance (it will return for its reference type). - /// - public static readonly WindowsRuntimeReferenceTypeAttribute Instance = new(null!); } \ No newline at end of file From ecf418a263ea18ea0ea09baf4679e632cfd2162d Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sat, 6 Dec 2025 14:21:41 -0800 Subject: [PATCH 62/76] Refactor placeholder attribute for dynamic interface castable Replaces PlaceholderDynamicInterfaceCastableImplementationForwarderAttribute with DynamicInterfaceCastableImplementationForwarderAttributePlaceholder and moves its implementation to a new file. Updates all references to use the new class name, improving clarity and organization. --- ...ementationForwarderAttributePlaceholder.cs | 30 +++++++++++++++++++ ...amicInterfaceCastableImplementationInfo.cs | 29 ++---------------- 2 files changed, 33 insertions(+), 26 deletions(-) create mode 100644 src/WinRT.Runtime2/InteropServices/Placeholders/DynamicInterfaceCastableImplementationForwarderAttributePlaceholder.cs diff --git a/src/WinRT.Runtime2/InteropServices/Placeholders/DynamicInterfaceCastableImplementationForwarderAttributePlaceholder.cs b/src/WinRT.Runtime2/InteropServices/Placeholders/DynamicInterfaceCastableImplementationForwarderAttributePlaceholder.cs new file mode 100644 index 000000000..df1a1dacb --- /dev/null +++ b/src/WinRT.Runtime2/InteropServices/Placeholders/DynamicInterfaceCastableImplementationForwarderAttributePlaceholder.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace WindowsRuntime.InteropServices; + +/// +/// A placeholder type. +/// +internal sealed class DynamicInterfaceCastableImplementationForwarderAttributePlaceholder : DynamicInterfaceCastableImplementationForwarderAttribute +{ + /// + /// The shared placeholder instance. + /// + public static DynamicInterfaceCastableImplementationForwarderAttributePlaceholder Instance = new(); + + /// + public override bool TryGetImplementationType( + WindowsRuntimeObjectReference thisReference, + [NotNullWhen(true)] out WindowsRuntimeObjectReference? interfaceReference, + [NotNullWhen(true)] out Type? implementationType) + { + interfaceReference = null; + implementationType = null; + + return false; + } +} diff --git a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/DynamicInterfaceCastableImplementationInfo.cs b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/DynamicInterfaceCastableImplementationInfo.cs index 40a39d19e..c8d68687c 100644 --- a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/DynamicInterfaceCastableImplementationInfo.cs +++ b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/DynamicInterfaceCastableImplementationInfo.cs @@ -127,11 +127,11 @@ bool Load([NotNullWhen(true)] out DynamicInterfaceCastableImplementationForwarde { DynamicInterfaceCastableImplementationForwarderAttribute? value = ImplementationType.GetCustomAttribute(inherit: false); - value ??= PlaceholderDynamicInterfaceCastableImplementationForwarderAttribute.Instance; + value ??= DynamicInterfaceCastableImplementationForwarderAttributePlaceholder.Instance; _implementationForwarder = value; - if (value is not (null or PlaceholderDynamicInterfaceCastableImplementationForwarderAttribute)) + if (value is not (null or DynamicInterfaceCastableImplementationForwarderAttributePlaceholder)) { forwarder = value; @@ -148,7 +148,7 @@ bool Load([NotNullWhen(true)] out DynamicInterfaceCastableImplementationForwarde // We have a cached forwarder, so return it immediately if (value is not null) { - if (value is PlaceholderDynamicInterfaceCastableImplementationForwarderAttribute) + if (value is DynamicInterfaceCastableImplementationForwarderAttributePlaceholder) { forwarder = null; @@ -179,27 +179,4 @@ bool Load([NotNullWhen(true)] out DynamicInterfaceCastableImplementationForwarde // There's no '[DynamicCastableImplementation]' info for the provided interface type return null; } -} - -/// -/// A placeholder type. -/// -file sealed class PlaceholderDynamicInterfaceCastableImplementationForwarderAttribute : DynamicInterfaceCastableImplementationForwarderAttribute -{ - /// - /// The shared placeholder instance. - /// - public static PlaceholderDynamicInterfaceCastableImplementationForwarderAttribute Instance = new(); - - /// - public override bool TryGetImplementationType( - WindowsRuntimeObjectReference thisReference, - [NotNullWhen(true)] out WindowsRuntimeObjectReference? interfaceReference, - [NotNullWhen(true)] out Type? implementationType) - { - interfaceReference = null; - implementationType = null; - - return false; - } } \ No newline at end of file From adceccf83f2529981df28d19223fee0c98b50597 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sat, 6 Dec 2025 14:22:08 -0800 Subject: [PATCH 63/76] Replace PlaceholderNullAgileReference with NullPlaceholder Refactors ContextAwareObjectReference to use NullPlaceholder.Instance instead of PlaceholderNullAgileReference.Instance. Removes the now-unused PlaceholderNullAgileReference class. --- .../ContextAwareObjectReference.cs | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/WinRT.Runtime2/InteropServices/ObjectReference/ContextAwareObjectReference.cs b/src/WinRT.Runtime2/InteropServices/ObjectReference/ContextAwareObjectReference.cs index cb3720428..21847dffc 100644 --- a/src/WinRT.Runtime2/InteropServices/ObjectReference/ContextAwareObjectReference.cs +++ b/src/WinRT.Runtime2/InteropServices/ObjectReference/ContextAwareObjectReference.cs @@ -132,7 +132,7 @@ static void InitializeAgileReference(object state) // trying again every time. To do this, we just set the field to a placeholder if it's still 'null'. _ = Interlocked.CompareExchange( location1: ref _agileReference, - value: PlaceholderNullAgileReference.Instance, + value: NullPlaceholder.Instance, comparand: null); // At this point we can return whatever the updated value is @@ -146,7 +146,7 @@ static void InitializeAgileReference(object state) // Check if we got the placeholder value, and return 'null' if so. // Otherwise, we can rely on the instance being an object reference. - return agileReference == PlaceholderNullAgileReference.Instance + return agileReference == NullPlaceholder.Instance ? null : Unsafe.As(agileReference); } @@ -302,15 +302,4 @@ private static class CachedContextsObjectReferenceFactory } } } -} - -/// -/// A placeholder object for . -/// -file static class PlaceholderNullAgileReference -{ - /// - /// The shared placeholder instance. - /// - public static object Instance = new(); } \ No newline at end of file From 93f5f3ad878a8245f56b20343502b3f717e348e7 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 6 Dec 2025 19:33:27 -0800 Subject: [PATCH 64/76] Fix tests --- .../UnitTest/TestComponentCSharp_Tests.cs | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs index 0a44f63ef..fdcda0651 100644 --- a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs +++ b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs @@ -35,6 +35,7 @@ using WindowsRuntime.InteropServices; using WindowsRuntime; using System.Runtime.InteropServices.Marshalling; +using Windows.Foundation.Tasks; // Test SupportedOSPlatform warnings for APIs targeting 10.0.19041.0: [assembly: global::System.Runtime.Versioning.SupportedOSPlatform("Windows10.0.18362.0")] @@ -2036,18 +2037,18 @@ public void TestAsyncActionWait() { var asyncAction = TestObject.DoitAsync(); TestObject.CompleteAsync(); - asyncAction.Wait(); + asyncAction.AsTask().Wait(); Assert.Equal(AsyncStatus.Completed, asyncAction.Status); asyncAction = TestObject.DoitAsync(); TestObject.CompleteAsync(E_FAIL); - var e = Assert.Throws(() => asyncAction.Wait()); + var e = Assert.Throws(() => asyncAction.AsTask().Wait()); Assert.Equal(E_FAIL, e.InnerException.HResult); Assert.Equal(AsyncStatus.Error, asyncAction.Status); asyncAction = TestObject.DoitAsync(); asyncAction.Cancel(); - e = Assert.Throws(() => asyncAction.Wait()); + e = Assert.Throws(() => asyncAction.AsTask().Wait()); Assert.True(e.InnerException is TaskCanceledException); Assert.Equal(AsyncStatus.Canceled, asyncAction.Status); } @@ -2124,18 +2125,18 @@ public void TestAsyncActionWithProgressWait() { var asyncAction = TestObject.DoitAsyncWithProgress(); TestObject.CompleteAsync(); - asyncAction.Wait(); + asyncAction.AsTask().Wait(); Assert.Equal(AsyncStatus.Completed, asyncAction.Status); asyncAction = TestObject.DoitAsyncWithProgress(); TestObject.CompleteAsync(E_FAIL); - var e = Assert.Throws(() => asyncAction.Wait()); + var e = Assert.Throws(() => asyncAction.AsTask().Wait()); Assert.Equal(E_FAIL, e.InnerException.HResult); Assert.Equal(AsyncStatus.Error, asyncAction.Status); asyncAction = TestObject.DoitAsyncWithProgress(); asyncAction.Cancel(); - e = Assert.Throws(() => asyncAction.Wait()); + e = Assert.Throws(() => asyncAction.AsTask().Wait()); Assert.True(e.InnerException is TaskCanceledException); Assert.Equal(AsyncStatus.Canceled, asyncAction.Status); } @@ -2176,18 +2177,18 @@ public void TestAsyncOperationWait() { var asyncOperation = TestObject.AddAsync(42, 8); TestObject.CompleteAsync(); - asyncOperation.Wait(); + asyncOperation.AsTask().Wait(); Assert.Equal(AsyncStatus.Completed, asyncOperation.Status); asyncOperation = TestObject.AddAsync(42, 8); TestObject.CompleteAsync(E_FAIL); - var e = Assert.Throws(() => asyncOperation.Wait()); + var e = Assert.Throws(() => asyncOperation.AsTask().Wait()); Assert.Equal(E_FAIL, e.InnerException.HResult); Assert.Equal(AsyncStatus.Error, asyncOperation.Status); asyncOperation = TestObject.AddAsync(42, 8); asyncOperation.Cancel(); - e = Assert.Throws(() => asyncOperation.Wait()); + e = Assert.Throws(() => asyncOperation.AsTask().Wait()); Assert.True(e.InnerException is TaskCanceledException); Assert.Equal(AsyncStatus.Canceled, asyncOperation.Status); } @@ -2267,18 +2268,18 @@ public void TestAsyncOperationWithProgressWait() { var asyncOperation = TestObject.AddAsyncWithProgress(42, 8); TestObject.CompleteAsync(); - asyncOperation.Wait(); + asyncOperation.AsTask().Wait(); Assert.Equal(AsyncStatus.Completed, asyncOperation.Status); asyncOperation = TestObject.AddAsyncWithProgress(42, 8); TestObject.CompleteAsync(E_FAIL); - var e = Assert.Throws(() => asyncOperation.Wait()); + var e = Assert.Throws(() => asyncOperation.AsTask().Wait()); Assert.Equal(E_FAIL, e.InnerException.HResult); Assert.Equal(AsyncStatus.Error, asyncOperation.Status); asyncOperation = TestObject.AddAsyncWithProgress(42, 8); asyncOperation.Cancel(); - e = Assert.Throws(() => asyncOperation.Wait()); + e = Assert.Throws(() => asyncOperation.AsTask().Wait()); Assert.True(e.InnerException is TaskCanceledException); Assert.Equal(AsyncStatus.Canceled, asyncOperation.Status); } From 1a5a08d3f4ed99d593529b52bb19ae836df5d5b0 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 7 Dec 2025 11:30:00 -0800 Subject: [PATCH 65/76] Add WindowsRuntimeMappedType attributes to ABI types Added [WindowsRuntimeMappedType] attributes to various ABI types in the WinRT.Runtime2 project. This change improves type mapping between .NET types and their Windows Runtime counterparts, enhancing interop and metadata clarity. --- src/WinRT.Runtime2/ABI/System/Boolean.cs | 1 + src/WinRT.Runtime2/ABI/System/Byte.cs | 1 + src/WinRT.Runtime2/ABI/System/Char.cs | 1 + .../ABI/System/ComponentModel/INotifyDataErrorInfo.cs | 1 + src/WinRT.Runtime2/ABI/System/DateTimeOffset.cs | 1 + src/WinRT.Runtime2/ABI/System/Double.cs | 1 + src/WinRT.Runtime2/ABI/System/Exception.cs | 1 + src/WinRT.Runtime2/ABI/System/Guid.cs | 1 + src/WinRT.Runtime2/ABI/System/IDisposable.cs | 1 + src/WinRT.Runtime2/ABI/System/IServiceProvider.cs | 1 + src/WinRT.Runtime2/ABI/System/Int16.cs | 1 + src/WinRT.Runtime2/ABI/System/Int32.cs | 1 + src/WinRT.Runtime2/ABI/System/Int64.cs | 1 + src/WinRT.Runtime2/ABI/System/Numerics/Matrix3x2.cs | 1 + src/WinRT.Runtime2/ABI/System/Numerics/Matrix4x4.cs | 1 + src/WinRT.Runtime2/ABI/System/Numerics/Plane.cs | 1 + src/WinRT.Runtime2/ABI/System/Numerics/Quaternion.cs | 1 + src/WinRT.Runtime2/ABI/System/Numerics/Vector2.cs | 1 + src/WinRT.Runtime2/ABI/System/Numerics/Vector3.cs | 1 + src/WinRT.Runtime2/ABI/System/Numerics/Vector4.cs | 1 + src/WinRT.Runtime2/ABI/System/Object.cs | 1 + src/WinRT.Runtime2/ABI/System/Single.cs | 1 + src/WinRT.Runtime2/ABI/System/String.cs | 1 + src/WinRT.Runtime2/ABI/System/TimeSpan.cs | 1 + src/WinRT.Runtime2/ABI/System/Type.cs | 3 ++- src/WinRT.Runtime2/ABI/System/UInt16.cs | 1 + src/WinRT.Runtime2/ABI/System/UInt32.cs | 1 + src/WinRT.Runtime2/ABI/System/UInt64.cs | 1 + src/WinRT.Runtime2/ABI/System/Uri.cs | 1 + 29 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/WinRT.Runtime2/ABI/System/Boolean.cs b/src/WinRT.Runtime2/ABI/System/Boolean.cs index 421f3f67e..d3e3f764f 100644 --- a/src/WinRT.Runtime2/ABI/System/Boolean.cs +++ b/src/WinRT.Runtime2/ABI/System/Boolean.cs @@ -35,6 +35,7 @@ namespace ABI.System; [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Boolean")] +[WindowsRuntimeMappedType(typeof(bool))] [WindowsRuntimeReferenceType(typeof(bool?))] [BooleanComWrappersMarshaller] file static class Boolean; diff --git a/src/WinRT.Runtime2/ABI/System/Byte.cs b/src/WinRT.Runtime2/ABI/System/Byte.cs index 57dde057c..d88184d27 100644 --- a/src/WinRT.Runtime2/ABI/System/Byte.cs +++ b/src/WinRT.Runtime2/ABI/System/Byte.cs @@ -35,6 +35,7 @@ namespace ABI.System; [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("UInt8")] +[WindowsRuntimeMappedType(typeof(byte))] [WindowsRuntimeReferenceType(typeof(byte?))] [ByteComWrappersMarshaller] file static class Byte; diff --git a/src/WinRT.Runtime2/ABI/System/Char.cs b/src/WinRT.Runtime2/ABI/System/Char.cs index 3dede0117..8ef16af5a 100644 --- a/src/WinRT.Runtime2/ABI/System/Char.cs +++ b/src/WinRT.Runtime2/ABI/System/Char.cs @@ -35,6 +35,7 @@ namespace ABI.System; [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Char16")] +[WindowsRuntimeMappedType(typeof(char))] [WindowsRuntimeReferenceType(typeof(char?))] [CharComWrappersMarshaller] file static class Char; diff --git a/src/WinRT.Runtime2/ABI/System/ComponentModel/INotifyDataErrorInfo.cs b/src/WinRT.Runtime2/ABI/System/ComponentModel/INotifyDataErrorInfo.cs index 772c30b45..5aa8618c6 100644 --- a/src/WinRT.Runtime2/ABI/System/ComponentModel/INotifyDataErrorInfo.cs +++ b/src/WinRT.Runtime2/ABI/System/ComponentModel/INotifyDataErrorInfo.cs @@ -38,6 +38,7 @@ namespace ABI.System.ComponentModel; /// [WindowsRuntimeMetadata("Microsoft.UI.Xaml.WinUIContract")] [WindowsRuntimeMetadataTypeName("Microsoft.UI.Xaml.Data.INotifyDataErrorInfo")] +[WindowsRuntimeMappedType(typeof(global::System.ComponentModel.INotifyDataErrorInfo))] file static class INotifyDataErrorInfo; /// diff --git a/src/WinRT.Runtime2/ABI/System/DateTimeOffset.cs b/src/WinRT.Runtime2/ABI/System/DateTimeOffset.cs index 92280835f..53db774ee 100644 --- a/src/WinRT.Runtime2/ABI/System/DateTimeOffset.cs +++ b/src/WinRT.Runtime2/ABI/System/DateTimeOffset.cs @@ -36,6 +36,7 @@ namespace ABI.System; [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Windows.Foundation.DateTime")] +[WindowsRuntimeMappedType(typeof(global::System.DateTimeOffset))] [WindowsRuntimeReferenceType(typeof(global::System.DateTimeOffset?))] [DateTimeOffsetComWrappersMarshaller] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, diff --git a/src/WinRT.Runtime2/ABI/System/Double.cs b/src/WinRT.Runtime2/ABI/System/Double.cs index 0dcf53d17..37e1630f3 100644 --- a/src/WinRT.Runtime2/ABI/System/Double.cs +++ b/src/WinRT.Runtime2/ABI/System/Double.cs @@ -35,6 +35,7 @@ namespace ABI.System; [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Double")] +[WindowsRuntimeMappedType(typeof(double))] [WindowsRuntimeReferenceType(typeof(double?))] [DoubleComWrappersMarshaller] file static class Double; diff --git a/src/WinRT.Runtime2/ABI/System/Exception.cs b/src/WinRT.Runtime2/ABI/System/Exception.cs index 458afacbe..5f9887947 100644 --- a/src/WinRT.Runtime2/ABI/System/Exception.cs +++ b/src/WinRT.Runtime2/ABI/System/Exception.cs @@ -36,6 +36,7 @@ namespace ABI.System; [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Windows.Foundation.HResult")] +[WindowsRuntimeMappedType(typeof(global::System.Exception))] [ExceptionComWrappersMarshaller] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, diff --git a/src/WinRT.Runtime2/ABI/System/Guid.cs b/src/WinRT.Runtime2/ABI/System/Guid.cs index ec27c04bd..582ddecee 100644 --- a/src/WinRT.Runtime2/ABI/System/Guid.cs +++ b/src/WinRT.Runtime2/ABI/System/Guid.cs @@ -35,6 +35,7 @@ namespace ABI.System; [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Guid")] +[WindowsRuntimeMappedType(typeof(global::System.Guid))] [WindowsRuntimeReferenceType(typeof(global::System.Guid?))] [GuidComWrappersMarshaller] file static class Guid; diff --git a/src/WinRT.Runtime2/ABI/System/IDisposable.cs b/src/WinRT.Runtime2/ABI/System/IDisposable.cs index 4cf79c0ff..b117ffe51 100644 --- a/src/WinRT.Runtime2/ABI/System/IDisposable.cs +++ b/src/WinRT.Runtime2/ABI/System/IDisposable.cs @@ -35,6 +35,7 @@ namespace ABI.System; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeMetadataTypeName("Windows.Foundation.IClosable")] +[WindowsRuntimeMappedType(typeof(global::System.IDisposable))] file static class IDisposable; /// diff --git a/src/WinRT.Runtime2/ABI/System/IServiceProvider.cs b/src/WinRT.Runtime2/ABI/System/IServiceProvider.cs index cab9f26d7..e478e55af 100644 --- a/src/WinRT.Runtime2/ABI/System/IServiceProvider.cs +++ b/src/WinRT.Runtime2/ABI/System/IServiceProvider.cs @@ -35,6 +35,7 @@ namespace ABI.System; /// [WindowsRuntimeMetadata("Microsoft.UI.Xaml.WinUIContract")] [WindowsRuntimeMetadataTypeName("Microsoft.UI.Xaml.IXamlServiceProvider")] +[WindowsRuntimeMappedType(typeof(global::System.IServiceProvider))] file static class IServiceProvider; /// diff --git a/src/WinRT.Runtime2/ABI/System/Int16.cs b/src/WinRT.Runtime2/ABI/System/Int16.cs index 4b786846e..0c6f75ee0 100644 --- a/src/WinRT.Runtime2/ABI/System/Int16.cs +++ b/src/WinRT.Runtime2/ABI/System/Int16.cs @@ -35,6 +35,7 @@ namespace ABI.System; [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Int16")] +[WindowsRuntimeMappedType(typeof(short))] [WindowsRuntimeReferenceType(typeof(short?))] [Int16ComWrappersMarshaller] file static class Int16; diff --git a/src/WinRT.Runtime2/ABI/System/Int32.cs b/src/WinRT.Runtime2/ABI/System/Int32.cs index 2bcc88436..49de1a291 100644 --- a/src/WinRT.Runtime2/ABI/System/Int32.cs +++ b/src/WinRT.Runtime2/ABI/System/Int32.cs @@ -35,6 +35,7 @@ namespace ABI.System; [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Int32")] +[WindowsRuntimeMappedType(typeof(int))] [WindowsRuntimeReferenceType(typeof(int?))] [Int32ComWrappersMarshaller] file static class Int32; diff --git a/src/WinRT.Runtime2/ABI/System/Int64.cs b/src/WinRT.Runtime2/ABI/System/Int64.cs index 7387896aa..ff588e65e 100644 --- a/src/WinRT.Runtime2/ABI/System/Int64.cs +++ b/src/WinRT.Runtime2/ABI/System/Int64.cs @@ -35,6 +35,7 @@ namespace ABI.System; [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Int64")] +[WindowsRuntimeMappedType(typeof(long))] [WindowsRuntimeReferenceType(typeof(long?))] [Int64ComWrappersMarshaller] file static class Int64; diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Matrix3x2.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Matrix3x2.cs index 731f2ee43..6a0268621 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Matrix3x2.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Matrix3x2.cs @@ -37,6 +37,7 @@ namespace ABI.System.Numerics; [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Windows.Foundation.Numerics.Matrix3x2")] +[WindowsRuntimeMappedType(typeof(global::System.Numerics.Matrix3x2))] [WindowsRuntimeReferenceType(typeof(global::System.Numerics.Matrix3x2?))] [Matrix3x2ComWrappersMarshaller] file static class Matrix3x2; diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Matrix4x4.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Matrix4x4.cs index 386ad0976..3e3efe965 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Matrix4x4.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Matrix4x4.cs @@ -37,6 +37,7 @@ namespace ABI.System.Numerics; [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Windows.Foundation.Numerics.Matrix4x4")] +[WindowsRuntimeMappedType(typeof(global::System.Numerics.Matrix4x4))] [WindowsRuntimeReferenceType(typeof(global::System.Numerics.Matrix4x4?))] [Matrix4x4ComWrappersMarshaller] file static class Matrix4x4; diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Plane.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Plane.cs index 8264c0549..93074afff 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Plane.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Plane.cs @@ -37,6 +37,7 @@ namespace ABI.System.Numerics; [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Windows.Foundation.Numerics.Plane")] +[WindowsRuntimeMappedType(typeof(global::System.Numerics.Plane))] [WindowsRuntimeReferenceType(typeof(global::System.Numerics.Plane?))] [PlaneComWrappersMarshaller] file static class Plane; diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Quaternion.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Quaternion.cs index f1c013cbc..246893e9c 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Quaternion.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Quaternion.cs @@ -37,6 +37,7 @@ namespace ABI.System.Numerics; [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Windows.Foundation.Numerics.Quaternion")] +[WindowsRuntimeMappedType(typeof(global::System.Numerics.Quaternion))] [WindowsRuntimeReferenceType(typeof(global::System.Numerics.Quaternion?))] [QuaternionComWrappersMarshaller] file static class Quaternion; diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Vector2.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Vector2.cs index 63ba8d0f0..8e7115664 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Vector2.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Vector2.cs @@ -37,6 +37,7 @@ namespace ABI.System.Numerics; [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Windows.Foundation.Numerics.Vector2")] +[WindowsRuntimeMappedType(typeof(global::System.Numerics.Vector2))] [WindowsRuntimeReferenceType(typeof(global::System.Numerics.Vector2?))] [Vector2ComWrappersMarshaller] file static class Vector2; diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Vector3.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Vector3.cs index 706e43293..547798c06 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Vector3.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Vector3.cs @@ -37,6 +37,7 @@ namespace ABI.System.Numerics; [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Windows.Foundation.Numerics.Vector3")] +[WindowsRuntimeMappedType(typeof(global::System.Numerics.Vector3))] [WindowsRuntimeReferenceType(typeof(global::System.Numerics.Vector3?))] [Vector3ComWrappersMarshaller] file static class Vector3; diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Vector4.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Vector4.cs index 1c80cd97d..be27a08e0 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Vector4.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Vector4.cs @@ -37,6 +37,7 @@ namespace ABI.System.Numerics; [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Windows.Foundation.Numerics.Vector4")] +[WindowsRuntimeMappedType(typeof(global::System.Numerics.Vector4))] [WindowsRuntimeReferenceType(typeof(global::System.Numerics.Vector4?))] [Vector4ComWrappersMarshaller] file static class Vector4; diff --git a/src/WinRT.Runtime2/ABI/System/Object.cs b/src/WinRT.Runtime2/ABI/System/Object.cs index 59bcff845..b4e20301f 100644 --- a/src/WinRT.Runtime2/ABI/System/Object.cs +++ b/src/WinRT.Runtime2/ABI/System/Object.cs @@ -23,6 +23,7 @@ namespace ABI.System; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Object")] +[WindowsRuntimeMappedType(typeof(object))] [ObjectComWrappersMarshaller] file static class Object; diff --git a/src/WinRT.Runtime2/ABI/System/Single.cs b/src/WinRT.Runtime2/ABI/System/Single.cs index 5f97c84ad..d52b42e77 100644 --- a/src/WinRT.Runtime2/ABI/System/Single.cs +++ b/src/WinRT.Runtime2/ABI/System/Single.cs @@ -35,6 +35,7 @@ namespace ABI.System; [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Single")] +[WindowsRuntimeMappedType(typeof(float))] [WindowsRuntimeReferenceType(typeof(float?))] [SingleComWrappersMarshaller] file static class Single; diff --git a/src/WinRT.Runtime2/ABI/System/String.cs b/src/WinRT.Runtime2/ABI/System/String.cs index 4e7e9f7f9..5c1ce2ffa 100644 --- a/src/WinRT.Runtime2/ABI/System/String.cs +++ b/src/WinRT.Runtime2/ABI/System/String.cs @@ -36,6 +36,7 @@ namespace ABI.System; [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("String")] +[WindowsRuntimeMappedType(typeof(string))] [StringComWrappersMarshaller] file static class String; diff --git a/src/WinRT.Runtime2/ABI/System/TimeSpan.cs b/src/WinRT.Runtime2/ABI/System/TimeSpan.cs index 59d00a8d9..d4d9b841e 100644 --- a/src/WinRT.Runtime2/ABI/System/TimeSpan.cs +++ b/src/WinRT.Runtime2/ABI/System/TimeSpan.cs @@ -36,6 +36,7 @@ namespace ABI.System; [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Windows.Foundation.TimeSpan")] +[WindowsRuntimeMappedType(typeof(global::System.TimeSpan))] [WindowsRuntimeReferenceType(typeof(global::System.TimeSpan?))] [TimeSpanComWrappersMarshaller] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index 063cafd7a..ced909d1e 100644 --- a/src/WinRT.Runtime2/ABI/System/Type.cs +++ b/src/WinRT.Runtime2/ABI/System/Type.cs @@ -20,7 +20,7 @@ #pragma warning disable IDE0008, IDE1006, CA1416 #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code -[assembly: TypeMap( +[assembly: TypeMap( value: "Windows.UI.Xaml.Interop.TypeName", target: typeof(ABI.System.Type), trimTarget: typeof(Type))] @@ -42,6 +42,7 @@ namespace ABI.System; [WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Windows.UI.Xaml.Interop.TypeName")] +[WindowsRuntimeMappedType(typeof(global::System.Type))] [TypeComWrappersMarshaller] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, diff --git a/src/WinRT.Runtime2/ABI/System/UInt16.cs b/src/WinRT.Runtime2/ABI/System/UInt16.cs index 864395cd2..39de29047 100644 --- a/src/WinRT.Runtime2/ABI/System/UInt16.cs +++ b/src/WinRT.Runtime2/ABI/System/UInt16.cs @@ -35,6 +35,7 @@ namespace ABI.System; [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("UInt16")] +[WindowsRuntimeMappedType(typeof(ushort))] [WindowsRuntimeReferenceType(typeof(ushort?))] [UInt16ComWrappersMarshaller] file static class UInt16; diff --git a/src/WinRT.Runtime2/ABI/System/UInt32.cs b/src/WinRT.Runtime2/ABI/System/UInt32.cs index 79d23d76d..c80119aff 100644 --- a/src/WinRT.Runtime2/ABI/System/UInt32.cs +++ b/src/WinRT.Runtime2/ABI/System/UInt32.cs @@ -35,6 +35,7 @@ namespace ABI.System; [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("UInt32")] +[WindowsRuntimeMappedType(typeof(uint))] [WindowsRuntimeReferenceType(typeof(uint?))] [UInt32ComWrappersMarshaller] file static class UInt32; diff --git a/src/WinRT.Runtime2/ABI/System/UInt64.cs b/src/WinRT.Runtime2/ABI/System/UInt64.cs index e9965b845..d912ecbd4 100644 --- a/src/WinRT.Runtime2/ABI/System/UInt64.cs +++ b/src/WinRT.Runtime2/ABI/System/UInt64.cs @@ -35,6 +35,7 @@ namespace ABI.System; [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("UInt64")] +[WindowsRuntimeMappedType(typeof(ulong))] [WindowsRuntimeReferenceType(typeof(ulong?))] [UInt64ComWrappersMarshaller] file static class UInt64; diff --git a/src/WinRT.Runtime2/ABI/System/Uri.cs b/src/WinRT.Runtime2/ABI/System/Uri.cs index 6074aff0a..416de3df5 100644 --- a/src/WinRT.Runtime2/ABI/System/Uri.cs +++ b/src/WinRT.Runtime2/ABI/System/Uri.cs @@ -28,6 +28,7 @@ namespace ABI.System; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.Uri")] +[WindowsRuntimeMappedType(typeof(global::System.Uri))] [UriComWrappersMarshaller] file static class Uri; From 1a9d36dc61fc0aa36356c69b9d9a64cf4ff0b927 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 7 Dec 2025 11:56:49 -0800 Subject: [PATCH 66/76] Add WindowsRuntimeMappedMetadataAttribute class Introduces the WindowsRuntimeMappedMetadataAttribute for annotating custom-mapped types with their source Windows Runtime metadata file. The attribute is marked obsolete and is intended for internal use. --- .../WindowsRuntimeMappedMetadataAttribute.cs | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/WinRT.Runtime2/Attributes/WindowsRuntimeMappedMetadataAttribute.cs diff --git a/src/WinRT.Runtime2/Attributes/WindowsRuntimeMappedMetadataAttribute.cs b/src/WinRT.Runtime2/Attributes/WindowsRuntimeMappedMetadataAttribute.cs new file mode 100644 index 000000000..abec34fd5 --- /dev/null +++ b/src/WinRT.Runtime2/Attributes/WindowsRuntimeMappedMetadataAttribute.cs @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.ComponentModel; + +namespace WindowsRuntime; + +/// +/// Indicates the mapped source Windows Runtime metadata file (.winmd) that a given custom-mapped type is from. +/// +[AttributeUsage( + AttributeTargets.Class | + AttributeTargets.Struct | + AttributeTargets.Enum | + AttributeTargets.Interface | + AttributeTargets.Delegate, + AllowMultiple = false, + Inherited = false)] +[Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, + DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, + UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] +[EditorBrowsable(EditorBrowsableState.Never)] +public sealed class WindowsRuntimeMappedMetadataAttribute : Attribute +{ + /// + /// Creates a new instance with the specified parameters. + /// + /// The name of the mapped source Windows Runtime metadata file (.winmd) that the current custom-mapped type is from. + public WindowsRuntimeMappedMetadataAttribute(string name) + { + Name = name; + } + + /// + /// Gets the name of the mapped source Windows Runtime metadata file (.winmd) that the current custom-mapped type is from. + /// + public string Name { get; } +} \ No newline at end of file From 836429bc5c3a6d3046f822ce5f933ee999e5dde5 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 7 Dec 2025 11:57:03 -0800 Subject: [PATCH 67/76] Update metadata type detection for custom-mapped types Replaces the check for WindowsRuntimeMetadataAttribute with WindowsRuntimeMappedMetadataAttribute for proxy types, ensuring correct identification of custom-mapped types. Adds a Debug.Assert to verify the code path is only triggered for proxy types. Also updates a comment for clarity and removes the unused isMetadataType argument in one constructor call. --- .../TypeMapInfo/WindowsRuntimeMarshallingInfo.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs index 7e796296e..7b070a7c5 100644 --- a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs +++ b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs @@ -243,7 +243,11 @@ public bool IsMetadataType [MethodImpl(MethodImplOptions.NoInlining)] bool InitializeIsMetadataType() { - bool isMetadataType = _metadataProviderType.IsDefined(typeof(WindowsRuntimeMetadataAttribute), inherit: false); + // We want to make sure that this code path is actually only triggered for proxy types, which + // are only for custom-mapped types. So '[WindowsRuntimeMetadata]' should not be defined here. + Debug.Assert(!_metadataProviderType.IsDefined(typeof(WindowsRuntimeMetadataAttribute), inherit: false)); + + bool isMetadataType = _metadataProviderType.IsDefined(typeof(WindowsRuntimeMappedMetadataAttribute), inherit: false); _isMetadataType = isMetadataType ? 1 : 0; @@ -703,10 +707,10 @@ private static WindowsRuntimeMarshallingInfo CreateMarshallingInfo(Type metadata // If '[WindowsRuntimeMetadata]' is defined, this is a projected type, so it's the public type too. // Otherwise, we don't know what the public type is at this point. We could look it up now, but // since we don't need that information right away, we can delay this to later to reduce the - // overhead at startup. That value is only needed eg. when associating native memory for vtables. + // overhead at startup. That value is only needed e.g. when associating native memory for vtables. return metadataProviderType.IsDefined(typeof(WindowsRuntimeMetadataAttribute), inherit: false) ? new(metadataProviderType, metadataProviderType, isMetadataType: true) - : new(metadataProviderType, publicType: null, isMetadataType: false); + : new(metadataProviderType, publicType: null); } /// From 1ed06a905fa2d2fb4aa2f067cf4bb2fea2a64fdf Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 7 Dec 2025 12:03:33 -0800 Subject: [PATCH 68/76] Replace WindowsRuntimeMetadata with WindowsRuntimeMappedMetadata Updated all ABI type files to use the [WindowsRuntimeMappedMetadata] attribute instead of [WindowsRuntimeMetadata] for contract mapping. This change standardizes the attribute usage across all relevant types in the WinRT.Runtime2 ABI layer. --- src/WinRT.Runtime2/ABI/System/Boolean.cs | 2 +- src/WinRT.Runtime2/ABI/System/Byte.cs | 2 +- src/WinRT.Runtime2/ABI/System/Char.cs | 2 +- .../ABI/System/ComponentModel/INotifyDataErrorInfo.cs | 2 +- src/WinRT.Runtime2/ABI/System/DateTimeOffset.cs | 2 +- src/WinRT.Runtime2/ABI/System/Double.cs | 2 +- src/WinRT.Runtime2/ABI/System/EventHandler.cs | 2 +- src/WinRT.Runtime2/ABI/System/Exception.cs | 2 +- src/WinRT.Runtime2/ABI/System/Guid.cs | 2 +- src/WinRT.Runtime2/ABI/System/IDisposable.cs | 4 ++-- src/WinRT.Runtime2/ABI/System/IServiceProvider.cs | 2 +- src/WinRT.Runtime2/ABI/System/Int16.cs | 2 +- src/WinRT.Runtime2/ABI/System/Int32.cs | 2 +- src/WinRT.Runtime2/ABI/System/Int64.cs | 2 +- src/WinRT.Runtime2/ABI/System/Numerics/Matrix3x2.cs | 2 +- src/WinRT.Runtime2/ABI/System/Numerics/Matrix4x4.cs | 2 +- src/WinRT.Runtime2/ABI/System/Numerics/Plane.cs | 2 +- src/WinRT.Runtime2/ABI/System/Numerics/Quaternion.cs | 2 +- src/WinRT.Runtime2/ABI/System/Numerics/Vector2.cs | 2 +- src/WinRT.Runtime2/ABI/System/Numerics/Vector3.cs | 2 +- src/WinRT.Runtime2/ABI/System/Numerics/Vector4.cs | 2 +- src/WinRT.Runtime2/ABI/System/Object.cs | 2 +- src/WinRT.Runtime2/ABI/System/Single.cs | 2 +- src/WinRT.Runtime2/ABI/System/String.cs | 2 +- src/WinRT.Runtime2/ABI/System/TimeSpan.cs | 2 +- src/WinRT.Runtime2/ABI/System/Type.cs | 2 +- src/WinRT.Runtime2/ABI/System/UInt16.cs | 2 +- src/WinRT.Runtime2/ABI/System/UInt32.cs | 2 +- src/WinRT.Runtime2/ABI/System/UInt64.cs | 2 +- src/WinRT.Runtime2/ABI/System/Uri.cs | 2 +- 30 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/WinRT.Runtime2/ABI/System/Boolean.cs b/src/WinRT.Runtime2/ABI/System/Boolean.cs index d3e3f764f..d9df97c93 100644 --- a/src/WinRT.Runtime2/ABI/System/Boolean.cs +++ b/src/WinRT.Runtime2/ABI/System/Boolean.cs @@ -32,7 +32,7 @@ namespace ABI.System; /// /// ABI type for . /// -[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Boolean")] [WindowsRuntimeMappedType(typeof(bool))] diff --git a/src/WinRT.Runtime2/ABI/System/Byte.cs b/src/WinRT.Runtime2/ABI/System/Byte.cs index d88184d27..2c77a64e4 100644 --- a/src/WinRT.Runtime2/ABI/System/Byte.cs +++ b/src/WinRT.Runtime2/ABI/System/Byte.cs @@ -32,7 +32,7 @@ namespace ABI.System; /// /// ABI type for . /// -[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("UInt8")] [WindowsRuntimeMappedType(typeof(byte))] diff --git a/src/WinRT.Runtime2/ABI/System/Char.cs b/src/WinRT.Runtime2/ABI/System/Char.cs index 8ef16af5a..4ff1ae205 100644 --- a/src/WinRT.Runtime2/ABI/System/Char.cs +++ b/src/WinRT.Runtime2/ABI/System/Char.cs @@ -32,7 +32,7 @@ namespace ABI.System; /// /// ABI type for . /// -[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Char16")] [WindowsRuntimeMappedType(typeof(char))] diff --git a/src/WinRT.Runtime2/ABI/System/ComponentModel/INotifyDataErrorInfo.cs b/src/WinRT.Runtime2/ABI/System/ComponentModel/INotifyDataErrorInfo.cs index 5aa8618c6..3e6d1098f 100644 --- a/src/WinRT.Runtime2/ABI/System/ComponentModel/INotifyDataErrorInfo.cs +++ b/src/WinRT.Runtime2/ABI/System/ComponentModel/INotifyDataErrorInfo.cs @@ -36,7 +36,7 @@ namespace ABI.System.ComponentModel; /// /// ABI type for . /// -[WindowsRuntimeMetadata("Microsoft.UI.Xaml.WinUIContract")] +[WindowsRuntimeMappedMetadata("Microsoft.UI.Xaml.WinUIContract")] [WindowsRuntimeMetadataTypeName("Microsoft.UI.Xaml.Data.INotifyDataErrorInfo")] [WindowsRuntimeMappedType(typeof(global::System.ComponentModel.INotifyDataErrorInfo))] file static class INotifyDataErrorInfo; diff --git a/src/WinRT.Runtime2/ABI/System/DateTimeOffset.cs b/src/WinRT.Runtime2/ABI/System/DateTimeOffset.cs index 53db774ee..6cc2676cc 100644 --- a/src/WinRT.Runtime2/ABI/System/DateTimeOffset.cs +++ b/src/WinRT.Runtime2/ABI/System/DateTimeOffset.cs @@ -33,7 +33,7 @@ namespace ABI.System; /// ABI type for . /// /// -[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Windows.Foundation.DateTime")] [WindowsRuntimeMappedType(typeof(global::System.DateTimeOffset))] diff --git a/src/WinRT.Runtime2/ABI/System/Double.cs b/src/WinRT.Runtime2/ABI/System/Double.cs index 37e1630f3..691f09b6b 100644 --- a/src/WinRT.Runtime2/ABI/System/Double.cs +++ b/src/WinRT.Runtime2/ABI/System/Double.cs @@ -32,7 +32,7 @@ namespace ABI.System; /// /// ABI type for . /// -[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Double")] [WindowsRuntimeMappedType(typeof(double))] diff --git a/src/WinRT.Runtime2/ABI/System/EventHandler.cs b/src/WinRT.Runtime2/ABI/System/EventHandler.cs index dac41d584..b1364542b 100644 --- a/src/WinRT.Runtime2/ABI/System/EventHandler.cs +++ b/src/WinRT.Runtime2/ABI/System/EventHandler.cs @@ -38,7 +38,7 @@ namespace ABI.System; /// ABI type for . /// /// -[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference>")] [EventHandlerComWrappersMarshaller] file static class EventHandler; diff --git a/src/WinRT.Runtime2/ABI/System/Exception.cs b/src/WinRT.Runtime2/ABI/System/Exception.cs index 5f9887947..47e96d4c6 100644 --- a/src/WinRT.Runtime2/ABI/System/Exception.cs +++ b/src/WinRT.Runtime2/ABI/System/Exception.cs @@ -33,7 +33,7 @@ namespace ABI.System; /// ABI type for . /// /// -[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Windows.Foundation.HResult")] [WindowsRuntimeMappedType(typeof(global::System.Exception))] diff --git a/src/WinRT.Runtime2/ABI/System/Guid.cs b/src/WinRT.Runtime2/ABI/System/Guid.cs index 582ddecee..1d799070c 100644 --- a/src/WinRT.Runtime2/ABI/System/Guid.cs +++ b/src/WinRT.Runtime2/ABI/System/Guid.cs @@ -32,7 +32,7 @@ namespace ABI.System; /// /// ABI type for . /// -[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Guid")] [WindowsRuntimeMappedType(typeof(global::System.Guid))] diff --git a/src/WinRT.Runtime2/ABI/System/IDisposable.cs b/src/WinRT.Runtime2/ABI/System/IDisposable.cs index b117ffe51..b5af6e7cf 100644 --- a/src/WinRT.Runtime2/ABI/System/IDisposable.cs +++ b/src/WinRT.Runtime2/ABI/System/IDisposable.cs @@ -33,7 +33,7 @@ namespace ABI.System; /// /// ABI type for . /// -[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeMetadataTypeName("Windows.Foundation.IClosable")] [WindowsRuntimeMappedType(typeof(global::System.IDisposable))] file static class IDisposable; @@ -150,7 +150,7 @@ private static HRESULT Close(void* thisPtr) /// /// The implementation for . /// -[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IClosable")] [DynamicInterfaceCastableImplementation] file interface IDisposableInterfaceImpl : global::System.IDisposable diff --git a/src/WinRT.Runtime2/ABI/System/IServiceProvider.cs b/src/WinRT.Runtime2/ABI/System/IServiceProvider.cs index e478e55af..2f00a707c 100644 --- a/src/WinRT.Runtime2/ABI/System/IServiceProvider.cs +++ b/src/WinRT.Runtime2/ABI/System/IServiceProvider.cs @@ -33,7 +33,7 @@ namespace ABI.System; /// /// ABI type for . /// -[WindowsRuntimeMetadata("Microsoft.UI.Xaml.WinUIContract")] +[WindowsRuntimeMappedMetadata("Microsoft.UI.Xaml.WinUIContract")] [WindowsRuntimeMetadataTypeName("Microsoft.UI.Xaml.IXamlServiceProvider")] [WindowsRuntimeMappedType(typeof(global::System.IServiceProvider))] file static class IServiceProvider; diff --git a/src/WinRT.Runtime2/ABI/System/Int16.cs b/src/WinRT.Runtime2/ABI/System/Int16.cs index 0c6f75ee0..8e791b62f 100644 --- a/src/WinRT.Runtime2/ABI/System/Int16.cs +++ b/src/WinRT.Runtime2/ABI/System/Int16.cs @@ -32,7 +32,7 @@ namespace ABI.System; /// /// ABI type for . /// -[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Int16")] [WindowsRuntimeMappedType(typeof(short))] diff --git a/src/WinRT.Runtime2/ABI/System/Int32.cs b/src/WinRT.Runtime2/ABI/System/Int32.cs index 49de1a291..209bcca17 100644 --- a/src/WinRT.Runtime2/ABI/System/Int32.cs +++ b/src/WinRT.Runtime2/ABI/System/Int32.cs @@ -32,7 +32,7 @@ namespace ABI.System; /// /// ABI type for . /// -[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Int32")] [WindowsRuntimeMappedType(typeof(int))] diff --git a/src/WinRT.Runtime2/ABI/System/Int64.cs b/src/WinRT.Runtime2/ABI/System/Int64.cs index ff588e65e..c302b1d34 100644 --- a/src/WinRT.Runtime2/ABI/System/Int64.cs +++ b/src/WinRT.Runtime2/ABI/System/Int64.cs @@ -32,7 +32,7 @@ namespace ABI.System; /// /// ABI type for . /// -[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Int64")] [WindowsRuntimeMappedType(typeof(long))] diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Matrix3x2.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Matrix3x2.cs index 6a0268621..57625efca 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Matrix3x2.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Matrix3x2.cs @@ -34,7 +34,7 @@ namespace ABI.System.Numerics; /// ABI type for . /// /// -[WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Windows.Foundation.Numerics.Matrix3x2")] [WindowsRuntimeMappedType(typeof(global::System.Numerics.Matrix3x2))] diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Matrix4x4.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Matrix4x4.cs index 3e3efe965..b72a81daa 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Matrix4x4.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Matrix4x4.cs @@ -34,7 +34,7 @@ namespace ABI.System.Numerics; /// ABI type for . /// /// -[WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Windows.Foundation.Numerics.Matrix4x4")] [WindowsRuntimeMappedType(typeof(global::System.Numerics.Matrix4x4))] diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Plane.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Plane.cs index 93074afff..8b4c49e9e 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Plane.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Plane.cs @@ -34,7 +34,7 @@ namespace ABI.System.Numerics; /// ABI type for . /// /// -[WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Windows.Foundation.Numerics.Plane")] [WindowsRuntimeMappedType(typeof(global::System.Numerics.Plane))] diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Quaternion.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Quaternion.cs index 246893e9c..4e2f1b5d1 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Quaternion.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Quaternion.cs @@ -34,7 +34,7 @@ namespace ABI.System.Numerics; /// ABI type for . /// /// -[WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Windows.Foundation.Numerics.Quaternion")] [WindowsRuntimeMappedType(typeof(global::System.Numerics.Quaternion))] diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Vector2.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Vector2.cs index 8e7115664..c240304e9 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Vector2.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Vector2.cs @@ -34,7 +34,7 @@ namespace ABI.System.Numerics; /// ABI type for . /// /// -[WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Windows.Foundation.Numerics.Vector2")] [WindowsRuntimeMappedType(typeof(global::System.Numerics.Vector2))] diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Vector3.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Vector3.cs index 547798c06..ef1475ed6 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Vector3.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Vector3.cs @@ -34,7 +34,7 @@ namespace ABI.System.Numerics; /// ABI type for . /// /// -[WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Windows.Foundation.Numerics.Vector3")] [WindowsRuntimeMappedType(typeof(global::System.Numerics.Vector3))] diff --git a/src/WinRT.Runtime2/ABI/System/Numerics/Vector4.cs b/src/WinRT.Runtime2/ABI/System/Numerics/Vector4.cs index be27a08e0..820bd4259 100644 --- a/src/WinRT.Runtime2/ABI/System/Numerics/Vector4.cs +++ b/src/WinRT.Runtime2/ABI/System/Numerics/Vector4.cs @@ -34,7 +34,7 @@ namespace ABI.System.Numerics; /// ABI type for . /// /// -[WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Windows.Foundation.Numerics.Vector4")] [WindowsRuntimeMappedType(typeof(global::System.Numerics.Vector4))] diff --git a/src/WinRT.Runtime2/ABI/System/Object.cs b/src/WinRT.Runtime2/ABI/System/Object.cs index b4e20301f..ecfd3b21e 100644 --- a/src/WinRT.Runtime2/ABI/System/Object.cs +++ b/src/WinRT.Runtime2/ABI/System/Object.cs @@ -21,7 +21,7 @@ namespace ABI.System; /// /// ABI type for . /// -[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Object")] [WindowsRuntimeMappedType(typeof(object))] [ObjectComWrappersMarshaller] diff --git a/src/WinRT.Runtime2/ABI/System/Single.cs b/src/WinRT.Runtime2/ABI/System/Single.cs index d52b42e77..39d60c417 100644 --- a/src/WinRT.Runtime2/ABI/System/Single.cs +++ b/src/WinRT.Runtime2/ABI/System/Single.cs @@ -32,7 +32,7 @@ namespace ABI.System; /// /// ABI type for . /// -[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Single")] [WindowsRuntimeMappedType(typeof(float))] diff --git a/src/WinRT.Runtime2/ABI/System/String.cs b/src/WinRT.Runtime2/ABI/System/String.cs index 5c1ce2ffa..4747c680d 100644 --- a/src/WinRT.Runtime2/ABI/System/String.cs +++ b/src/WinRT.Runtime2/ABI/System/String.cs @@ -33,7 +33,7 @@ namespace ABI.System; /// /// ABI type for . /// -[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("String")] [WindowsRuntimeMappedType(typeof(string))] diff --git a/src/WinRT.Runtime2/ABI/System/TimeSpan.cs b/src/WinRT.Runtime2/ABI/System/TimeSpan.cs index d4d9b841e..326d4502c 100644 --- a/src/WinRT.Runtime2/ABI/System/TimeSpan.cs +++ b/src/WinRT.Runtime2/ABI/System/TimeSpan.cs @@ -33,7 +33,7 @@ namespace ABI.System; /// ABI type for . /// /// -[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Windows.Foundation.TimeSpan")] [WindowsRuntimeMappedType(typeof(global::System.TimeSpan))] diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index ced909d1e..3cc6e1eac 100644 --- a/src/WinRT.Runtime2/ABI/System/Type.cs +++ b/src/WinRT.Runtime2/ABI/System/Type.cs @@ -39,7 +39,7 @@ namespace ABI.System; /// ABI type for . /// /// -[WindowsRuntimeMetadata("Windows.Foundation.UniversalApiContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("Windows.UI.Xaml.Interop.TypeName")] [WindowsRuntimeMappedType(typeof(global::System.Type))] diff --git a/src/WinRT.Runtime2/ABI/System/UInt16.cs b/src/WinRT.Runtime2/ABI/System/UInt16.cs index 39de29047..115c03c99 100644 --- a/src/WinRT.Runtime2/ABI/System/UInt16.cs +++ b/src/WinRT.Runtime2/ABI/System/UInt16.cs @@ -32,7 +32,7 @@ namespace ABI.System; /// /// ABI type for . /// -[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("UInt16")] [WindowsRuntimeMappedType(typeof(ushort))] diff --git a/src/WinRT.Runtime2/ABI/System/UInt32.cs b/src/WinRT.Runtime2/ABI/System/UInt32.cs index c80119aff..db1058693 100644 --- a/src/WinRT.Runtime2/ABI/System/UInt32.cs +++ b/src/WinRT.Runtime2/ABI/System/UInt32.cs @@ -32,7 +32,7 @@ namespace ABI.System; /// /// ABI type for . /// -[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("UInt32")] [WindowsRuntimeMappedType(typeof(uint))] diff --git a/src/WinRT.Runtime2/ABI/System/UInt64.cs b/src/WinRT.Runtime2/ABI/System/UInt64.cs index d912ecbd4..afd2e36c2 100644 --- a/src/WinRT.Runtime2/ABI/System/UInt64.cs +++ b/src/WinRT.Runtime2/ABI/System/UInt64.cs @@ -32,7 +32,7 @@ namespace ABI.System; /// /// ABI type for . /// -[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] [WindowsRuntimeMetadataTypeName("UInt64")] [WindowsRuntimeMappedType(typeof(ulong))] diff --git a/src/WinRT.Runtime2/ABI/System/Uri.cs b/src/WinRT.Runtime2/ABI/System/Uri.cs index 416de3df5..ed0659fc8 100644 --- a/src/WinRT.Runtime2/ABI/System/Uri.cs +++ b/src/WinRT.Runtime2/ABI/System/Uri.cs @@ -26,7 +26,7 @@ namespace ABI.System; /// ABI type for . /// /// -[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.Uri")] [WindowsRuntimeMappedType(typeof(global::System.Uri))] [UriComWrappersMarshaller] From 609ca5e9dd02265f4ff23720bbf0e03332dda891 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 7 Dec 2025 12:12:47 -0800 Subject: [PATCH 69/76] Rename TypeToMarshallingInfoTable to TypeToMetadataInfoTable Refactored the static ConditionalWeakTable field to improve naming consistency and clarity. Updated all references to use the new name, reflecting its purpose of mapping types to metadata info rather than marshalling info. --- .../TypeMapInfo/WindowsRuntimeMetadataInfo.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMetadataInfo.cs b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMetadataInfo.cs index b825a54ae..788bc6213 100644 --- a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMetadataInfo.cs +++ b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMetadataInfo.cs @@ -36,7 +36,7 @@ internal sealed class WindowsRuntimeMetadataInfo /// /// This will only have non values for types needing special metadata handling. /// - private static readonly ConditionalWeakTable TypeToMarshallingInfoTable = []; + private static readonly ConditionalWeakTable TypeToMetadataInfoTable = []; /// /// Cached creation factory for . @@ -133,7 +133,7 @@ public static bool TryGetInfo(ReadOnlySpan metadataTypeName, [NotNullWhen( // We found a mapped external type, return its associated marshalling info if (externalType is not null) { - info = TypeToMarshallingInfoTable.GetOrAdd(externalType, CreateMetadataInfoCallback)!; + info = TypeToMetadataInfoTable.GetOrAdd(externalType, CreateMetadataInfoCallback)!; return true; } @@ -151,7 +151,7 @@ public static bool TryGetInfo(ReadOnlySpan metadataTypeName, [NotNullWhen( /// Whether was retrieved successfully. public static bool TryGetInfo(Type managedType, [NotNullWhen(true)] out WindowsRuntimeMetadataInfo? info) { - WindowsRuntimeMetadataInfo? result = TypeToMarshallingInfoTable.GetOrAdd(managedType, GetMetadataProviderTypeCallback); + WindowsRuntimeMetadataInfo? result = TypeToMetadataInfoTable.GetOrAdd(managedType, GetMetadataProviderTypeCallback); info = result; @@ -209,7 +209,7 @@ private static WindowsRuntimeMetadataInfo CreateMetadataInfo(Type metadataProvid return new(proxyType, managedType); } - // We don't have a metadata provider for the type (we'll just marshal it as a generic 'IInspectable') + // We don't have a metadata provider for the type return null; } } \ No newline at end of file From c7874d861ec2fd21e9b4c205660d87a79e43060c Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 7 Dec 2025 12:35:58 -0800 Subject: [PATCH 70/76] Add metadata attributes to EventRegistrationToken struct Added WindowsRuntimeMetadataTypeName and WindowsRuntimeReferenceType attributes to the EventRegistrationToken struct to enhance metadata and type information for interop scenarios. --- .../InteropServices/Events/EventRegistrationToken.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/WinRT.Runtime2/InteropServices/Events/EventRegistrationToken.cs b/src/WinRT.Runtime2/InteropServices/Events/EventRegistrationToken.cs index 34af098d3..e7304d1f1 100644 --- a/src/WinRT.Runtime2/InteropServices/Events/EventRegistrationToken.cs +++ b/src/WinRT.Runtime2/InteropServices/Events/EventRegistrationToken.cs @@ -13,6 +13,8 @@ namespace WindowsRuntime.InteropServices; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] +[WindowsRuntimeMetadataTypeName("Windows.Foundation.EventRegistrationToken")] +[WindowsRuntimeReferenceType(typeof(EventRegistrationToken?))] [ABI.WindowsRuntime.InteropServices.EventRegistrationTokenComWrappersMarshaller] public struct EventRegistrationToken : IEquatable { From eeee82b5fa6fb43436365809d44ddecf8d0da357 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 7 Dec 2025 12:39:55 -0800 Subject: [PATCH 71/76] Refactor ABI type mappings to use non-global type names Updated ABI files for IVectorChangedEventArgs, IAsyncAction, and IAsyncInfo to use direct type references instead of global::Windows.Foundation.* type names. Removed redundant TypeMapAssociation attributes and adjusted marshaller and interface implementation code accordingly. Also removed an unused attribute from EventRegistrationToken. These changes improve code clarity and maintainability by reducing reliance on global type names and streamlining type mapping. --- .../Collections/IVectorChangedEventArgs.cs | 55 ++++++------- .../ABI/Windows.Foundation/IAsyncAction.cs | 63 +++++++-------- .../ABI/Windows.Foundation/IAsyncInfo.cs | 77 ++++++++----------- .../Events/EventRegistrationToken.cs | 1 - 4 files changed, 81 insertions(+), 115 deletions(-) diff --git a/src/WinRT.Runtime2/ABI/Windows.Foundation/Collections/IVectorChangedEventArgs.cs b/src/WinRT.Runtime2/ABI/Windows.Foundation/Collections/IVectorChangedEventArgs.cs index f8634894f..10dc34211 100644 --- a/src/WinRT.Runtime2/ABI/Windows.Foundation/Collections/IVectorChangedEventArgs.cs +++ b/src/WinRT.Runtime2/ABI/Windows.Foundation/Collections/IVectorChangedEventArgs.cs @@ -17,29 +17,18 @@ #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code [assembly: TypeMap( value: "Windows.Foundation.Collections.IVectorChangedEventArgs", - target: typeof(ABI.Windows.Foundation.Collections.IVectorChangedEventArgs), + target: typeof(IVectorChangedEventArgs), trimTarget: typeof(IVectorChangedEventArgs))] #pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code -[assembly: TypeMapAssociation( - source: typeof(IVectorChangedEventArgs), - proxy: typeof(ABI.Windows.Foundation.Collections.IVectorChangedEventArgs))] - [assembly: TypeMapAssociation( source: typeof(IVectorChangedEventArgs), - proxy: typeof(ABI.Windows.Foundation.Collections.IVectorChangedEventArgs))] + proxy: typeof(ABI.Windows.Foundation.Collections.IVectorChangedEventArgsInterfaceImpl))] namespace ABI.Windows.Foundation.Collections; /// -/// ABI type for . -/// -[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] -[WindowsRuntimeMetadataTypeName("Windows.Foundation.Collections.IVectorChangedEventArgs")] -file static class IVectorChangedEventArgs; - -/// -/// Marshaller for . +/// Marshaller for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -48,22 +37,22 @@ namespace ABI.Windows.Foundation.Collections; public static unsafe class IVectorChangedEventArgsMarshaller { /// - public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(global::Windows.Foundation.Collections.IVectorChangedEventArgs? value) + public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(IVectorChangedEventArgs? value) { - return WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged( + return WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged( value: value, iid: in WellKnownWindowsInterfaceIIDs.IID_IVectorChangedEventArgs); } /// - public static global::Windows.Foundation.Collections.IVectorChangedEventArgs? ConvertToManaged(void* value) + public static IVectorChangedEventArgs? ConvertToManaged(void* value) { - return (global::Windows.Foundation.Collections.IVectorChangedEventArgs?)WindowsRuntimeObjectMarshaller.ConvertToManaged(value); + return (IVectorChangedEventArgs?)WindowsRuntimeObjectMarshaller.ConvertToManaged(value); } } /// -/// Interop methods for . +/// Interop methods for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -71,7 +60,7 @@ public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(global::Wind [EditorBrowsable(EditorBrowsableState.Never)] public static unsafe class IVectorChangedEventArgsMethods { - /// + /// [MethodImpl(MethodImplOptions.NoInlining)] public static CollectionChange CollectionChange(WindowsRuntimeObjectReference thisReference) { @@ -85,7 +74,7 @@ public static CollectionChange CollectionChange(WindowsRuntimeObjectReference th return result; } - /// + /// public static uint Index(WindowsRuntimeObjectReference thisReference) { using WindowsRuntimeObjectReferenceValue thisValue = thisReference.AsValue(); @@ -100,7 +89,7 @@ public static uint Index(WindowsRuntimeObjectReference thisReference) } /// -/// Binding type for . +/// Binding type for . /// /// [StructLayout(LayoutKind.Sequential)] @@ -117,7 +106,7 @@ internal unsafe struct IVectorChangedEventArgsVftbl } /// -/// The implementation. +/// The implementation. /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -126,7 +115,7 @@ internal unsafe struct IVectorChangedEventArgsVftbl public static unsafe class IVectorChangedEventArgsImpl { /// - /// The value for the managed implementation. + /// The value for the managed implementation. /// [FixedAddressValueType] private static readonly IVectorChangedEventArgsVftbl Vftbl; @@ -143,7 +132,7 @@ static IVectorChangedEventArgsImpl() } /// - /// Gets a pointer to the managed implementation. + /// Gets a pointer to the managed implementation. /// public static nint Vtable { @@ -157,7 +146,7 @@ private static HRESULT get_CollectionChange(void* thisPtr, CollectionChange* res { try { - var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); *result = unboxedValue.CollectionChange; @@ -175,7 +164,7 @@ private static HRESULT get_Index(void* thisPtr, uint* result) { try { - var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); *result = unboxedValue.Index; @@ -189,28 +178,28 @@ private static HRESULT get_Index(void* thisPtr, uint* result) } /// -/// The implementation for . +/// The implementation for . /// [DynamicInterfaceCastableImplementation] -file interface IVectorChangedEventArgsInterfaceImpl : global::Windows.Foundation.Collections.IVectorChangedEventArgs +file interface IVectorChangedEventArgsInterfaceImpl : IVectorChangedEventArgs { /// - CollectionChange global::Windows.Foundation.Collections.IVectorChangedEventArgs.CollectionChange + CollectionChange IVectorChangedEventArgs.CollectionChange { get { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::Windows.Foundation.Collections.IVectorChangedEventArgs).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IVectorChangedEventArgs).TypeHandle); return IVectorChangedEventArgsMethods.CollectionChange(thisReference); } } /// - uint global::Windows.Foundation.Collections.IVectorChangedEventArgs.Index + uint IVectorChangedEventArgs.Index { get { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::Windows.Foundation.Collections.IVectorChangedEventArgs).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IVectorChangedEventArgs).TypeHandle); return IVectorChangedEventArgsMethods.Index(thisReference); } diff --git a/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncAction.cs b/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncAction.cs index 413756f18..ce93a5060 100644 --- a/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncAction.cs +++ b/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncAction.cs @@ -17,14 +17,10 @@ #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code [assembly: TypeMap( value: "Windows.Foundation.IAsyncAction", - target: typeof(ABI.Windows.Foundation.IAsyncAction), + target: typeof(IAsyncInfo), trimTarget: typeof(IAsyncAction))] #pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code -[assembly: TypeMapAssociation( - source: typeof(IAsyncAction), - proxy: typeof(ABI.Windows.Foundation.IAsyncAction))] - [assembly: TypeMapAssociation( source: typeof(IAsyncAction), proxy: typeof(ABI.Windows.Foundation.IAsyncActionInterfaceImpl))] @@ -32,14 +28,7 @@ namespace ABI.Windows.Foundation; /// -/// ABI type for . -/// -[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] -[WindowsRuntimeMetadataTypeName("Windows.Foundation.IAsyncAction")] -file static class IAsyncAction; - -/// -/// Marshaller for . +/// Marshaller for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -48,20 +37,20 @@ namespace ABI.Windows.Foundation; public static unsafe class IAsyncActionMarshaller { /// - public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(global::Windows.Foundation.IAsyncAction? value) + public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(IAsyncAction? value) { - return WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged(value, in WellKnownWindowsInterfaceIIDs.IID_IAsyncAction); + return WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged(value, in WellKnownWindowsInterfaceIIDs.IID_IAsyncAction); } /// - public static global::Windows.Foundation.IAsyncAction? ConvertToManaged(void* value) + public static IAsyncAction? ConvertToManaged(void* value) { - return (global::Windows.Foundation.IAsyncAction?)WindowsRuntimeUnsealedObjectMarshaller.ConvertToManaged(value); + return (IAsyncAction?)WindowsRuntimeUnsealedObjectMarshaller.ConvertToManaged(value); } } /// -/// A custom implementation for . +/// A custom implementation for . /// file abstract unsafe class IAsyncActionComWrappersCallback : IWindowsRuntimeUnsealedObjectComWrappersCallback { @@ -93,7 +82,7 @@ public static unsafe bool TryCreateObject( } /// -/// A custom implementation for . +/// A custom implementation for . /// internal sealed unsafe class IAsyncActionComWrappersMarshallerAttribute : WindowsRuntimeComWrappersMarshallerAttribute { @@ -110,7 +99,7 @@ public override object CreateObject(void* value, out CreatedWrapperFlags wrapper } /// -/// Interop methods for . +/// Interop methods for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -118,7 +107,7 @@ public override object CreateObject(void* value, out CreatedWrapperFlags wrapper [EditorBrowsable(EditorBrowsableState.Never)] public static unsafe class IAsyncActionMethods { - /// + /// [MethodImpl(MethodImplOptions.NoInlining)] public static AsyncActionCompletedHandler? Completed(WindowsRuntimeObjectReference thisReference) { @@ -141,7 +130,7 @@ public static unsafe class IAsyncActionMethods } } - /// + /// [MethodImpl(MethodImplOptions.NoInlining)] public static void Completed(WindowsRuntimeObjectReference thisReference, AsyncActionCompletedHandler? handler) { @@ -155,7 +144,7 @@ public static void Completed(WindowsRuntimeObjectReference thisReference, AsyncA RestrictedErrorInfo.ThrowExceptionForHR(hresult); } - /// + /// [MethodImpl(MethodImplOptions.NoInlining)] public static void GetResults(WindowsRuntimeObjectReference thisReference) { @@ -170,7 +159,7 @@ public static void GetResults(WindowsRuntimeObjectReference thisReference) } /// -/// Binding type for . +/// Binding type for . /// [StructLayout(LayoutKind.Sequential)] internal unsafe struct IAsyncActionVftbl @@ -187,7 +176,7 @@ internal unsafe struct IAsyncActionVftbl } /// -/// The implementation. +/// The implementation. /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -196,7 +185,7 @@ internal unsafe struct IAsyncActionVftbl public static unsafe class IAsyncActionImpl { /// - /// The value for the managed implementation. + /// The value for the managed implementation. /// [FixedAddressValueType] private static readonly IAsyncActionVftbl Vftbl; @@ -214,7 +203,7 @@ static IAsyncActionImpl() } /// - /// Gets a pointer to the managed implementation. + /// Gets a pointer to the managed implementation. /// public static nint Vtable { @@ -233,7 +222,7 @@ private static HRESULT get_Completed(void* thisPtr, void** handler) try { - var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); *handler = AsyncActionCompletedHandlerMarshaller.ConvertToUnmanaged(unboxedValue.Completed).DetachThisPtrUnsafe(); @@ -251,7 +240,7 @@ private static HRESULT set_Completed(void* thisPtr, void* handler) { try { - var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); unboxedValue.Completed = AsyncActionCompletedHandlerMarshaller.ConvertToManaged(handler); @@ -269,7 +258,7 @@ private static HRESULT GetResults(void* thisPtr) { try { - var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); unboxedValue.GetResults(); @@ -283,32 +272,32 @@ private static HRESULT GetResults(void* thisPtr) } /// -/// The implementation for . +/// The implementation for . /// [DynamicInterfaceCastableImplementation] -file interface IAsyncActionInterfaceImpl : global::Windows.Foundation.IAsyncAction +file interface IAsyncActionInterfaceImpl : IAsyncAction { /// - AsyncActionCompletedHandler? global::Windows.Foundation.IAsyncAction.Completed + AsyncActionCompletedHandler? IAsyncAction.Completed { get { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::Windows.Foundation.IAsyncAction).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IAsyncAction).TypeHandle); return IAsyncActionMethods.Completed(thisReference); } set { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::Windows.Foundation.IAsyncAction).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IAsyncAction).TypeHandle); IAsyncActionMethods.Completed(thisReference, value); } } /// - void global::Windows.Foundation.IAsyncAction.GetResults() + void IAsyncAction.GetResults() { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::Windows.Foundation.IAsyncAction).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IAsyncAction).TypeHandle); IAsyncActionMethods.GetResults(thisReference); } diff --git a/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncInfo.cs b/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncInfo.cs index 1b502265c..1d9384d2a 100644 --- a/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncInfo.cs +++ b/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncInfo.cs @@ -16,14 +16,10 @@ #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code [assembly: TypeMap( value: "Windows.Foundation.IAsyncInfo", - target: typeof(ABI.Windows.Foundation.IAsyncInfo), + target: typeof(IAsyncInfo), trimTarget: typeof(IAsyncInfo))] #pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code -[assembly: TypeMapAssociation( - source: typeof(IAsyncInfo), - proxy: typeof(ABI.Windows.Foundation.IAsyncInfo))] - [assembly: TypeMapAssociation( source: typeof(IAsyncInfo), proxy: typeof(ABI.Windows.Foundation.IAsyncInfoInterfaceImpl))] @@ -31,14 +27,7 @@ namespace ABI.Windows.Foundation; /// -/// ABI type for . -/// -[WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] -[WindowsRuntimeMetadataTypeName("Windows.Foundation.IAsyncInfo")] -file static class IAsyncInfo; - -/// -/// Marshaller for . +/// Marshaller for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -47,20 +36,20 @@ namespace ABI.Windows.Foundation; public static unsafe class IAsyncInfoMarshaller { /// - public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(global::Windows.Foundation.IAsyncInfo? value) + public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(IAsyncInfo? value) { - return WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged(value, in WellKnownWindowsInterfaceIIDs.IID_IAsyncInfo); + return WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged(value, in WellKnownWindowsInterfaceIIDs.IID_IAsyncInfo); } /// - public static global::Windows.Foundation.IAsyncInfo? ConvertToManaged(void* value) + public static IAsyncInfo? ConvertToManaged(void* value) { - return (global::Windows.Foundation.IAsyncInfo?)WindowsRuntimeObjectMarshaller.ConvertToManaged(value); + return (IAsyncInfo?)WindowsRuntimeObjectMarshaller.ConvertToManaged(value); } } /// -/// Interop methods for . +/// Interop methods for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -68,7 +57,7 @@ public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(global::Wind [EditorBrowsable(EditorBrowsableState.Never)] public static unsafe class IAsyncInfoMethods { - /// + /// [MethodImpl(MethodImplOptions.NoInlining)] public static uint Id(WindowsRuntimeObjectReference thisReference) { @@ -84,7 +73,7 @@ public static uint Id(WindowsRuntimeObjectReference thisReference) return result; } - /// + /// [MethodImpl(MethodImplOptions.NoInlining)] public static AsyncStatus Status(WindowsRuntimeObjectReference thisReference) { @@ -100,7 +89,7 @@ public static AsyncStatus Status(WindowsRuntimeObjectReference thisReference) return result; } - /// + /// [MethodImpl(MethodImplOptions.NoInlining)] public static Exception? ErrorCode(WindowsRuntimeObjectReference thisReference) { @@ -116,7 +105,7 @@ public static AsyncStatus Status(WindowsRuntimeObjectReference thisReference) return System.ExceptionMarshaller.ConvertToManaged(result); } - /// + /// [MethodImpl(MethodImplOptions.NoInlining)] public static void Cancel(WindowsRuntimeObjectReference thisReference) { @@ -129,7 +118,7 @@ public static void Cancel(WindowsRuntimeObjectReference thisReference) RestrictedErrorInfo.ThrowExceptionForHR(hresult); } - /// + /// [MethodImpl(MethodImplOptions.NoInlining)] public static void Close(WindowsRuntimeObjectReference thisReference) { @@ -144,7 +133,7 @@ public static void Close(WindowsRuntimeObjectReference thisReference) } /// -/// Binding type for . +/// Binding type for . /// [StructLayout(LayoutKind.Sequential)] internal unsafe struct IAsyncInfoVftbl @@ -163,7 +152,7 @@ internal unsafe struct IAsyncInfoVftbl } /// -/// The implementation. +/// The implementation. /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -172,7 +161,7 @@ internal unsafe struct IAsyncInfoVftbl public static unsafe class IAsyncInfoImpl { /// - /// The value for the managed implementation. + /// The value for the managed implementation. /// [FixedAddressValueType] private static readonly IAsyncInfoVftbl Vftbl; @@ -192,7 +181,7 @@ static IAsyncInfoImpl() } /// - /// Gets a pointer to the managed implementation. + /// Gets a pointer to the managed implementation. /// public static nint Vtable { @@ -211,7 +200,7 @@ private static HRESULT get_ErrorCode(void* thisPtr, System.Exception* errorCode) try { - var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); *errorCode = System.ExceptionMarshaller.ConvertToUnmanaged(unboxedValue.ErrorCode); @@ -234,7 +223,7 @@ private static HRESULT get_Id(void* thisPtr, uint* id) try { - var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); *id = unboxedValue.Id; @@ -257,7 +246,7 @@ private static HRESULT get_Status(void* thisPtr, AsyncStatus* status) try { - var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); *status = unboxedValue.Status; @@ -275,7 +264,7 @@ private static HRESULT Cancel(void* thisPtr) { try { - var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); unboxedValue.Cancel(); @@ -293,7 +282,7 @@ private static HRESULT Close(void* thisPtr) { try { - var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var unboxedValue = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); unboxedValue.Close(); @@ -307,56 +296,56 @@ private static HRESULT Close(void* thisPtr) } /// -/// The implementation for . +/// The implementation for . /// [DynamicInterfaceCastableImplementation] -file interface IAsyncInfoInterfaceImpl : global::Windows.Foundation.IAsyncInfo +file interface IAsyncInfoInterfaceImpl : IAsyncInfo { /// - uint global::Windows.Foundation.IAsyncInfo.Id + uint IAsyncInfo.Id { get { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::Windows.Foundation.IAsyncInfo).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IAsyncInfo).TypeHandle); return IAsyncInfoMethods.Id(thisReference); } } /// - AsyncStatus global::Windows.Foundation.IAsyncInfo.Status + AsyncStatus IAsyncInfo.Status { get { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::Windows.Foundation.IAsyncInfo).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IAsyncInfo).TypeHandle); return IAsyncInfoMethods.Status(thisReference); } } /// - Exception? global::Windows.Foundation.IAsyncInfo.ErrorCode + Exception? IAsyncInfo.ErrorCode { get { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::Windows.Foundation.IAsyncInfo).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IAsyncInfo).TypeHandle); return IAsyncInfoMethods.ErrorCode(thisReference); } } /// - void global::Windows.Foundation.IAsyncInfo.Cancel() + void IAsyncInfo.Cancel() { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::Windows.Foundation.IAsyncInfo).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IAsyncInfo).TypeHandle); IAsyncInfoMethods.Cancel(thisReference); } /// - void global::Windows.Foundation.IAsyncInfo.Close() + void IAsyncInfo.Close() { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::Windows.Foundation.IAsyncInfo).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IAsyncInfo).TypeHandle); IAsyncInfoMethods.Close(thisReference); } diff --git a/src/WinRT.Runtime2/InteropServices/Events/EventRegistrationToken.cs b/src/WinRT.Runtime2/InteropServices/Events/EventRegistrationToken.cs index e7304d1f1..57868f260 100644 --- a/src/WinRT.Runtime2/InteropServices/Events/EventRegistrationToken.cs +++ b/src/WinRT.Runtime2/InteropServices/Events/EventRegistrationToken.cs @@ -13,7 +13,6 @@ namespace WindowsRuntime.InteropServices; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] -[WindowsRuntimeMetadataTypeName("Windows.Foundation.EventRegistrationToken")] [WindowsRuntimeReferenceType(typeof(EventRegistrationToken?))] [ABI.WindowsRuntime.InteropServices.EventRegistrationTokenComWrappersMarshaller] public struct EventRegistrationToken : IEquatable From eb1888087a4b3c45941374480af6f711782f7739 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Tue, 6 Jan 2026 13:49:26 -0800 Subject: [PATCH 72/76] Refactor marshalling info retrieval for anonymous objects Introduced GetAnonymousInspectableMarshallingInfo to centralize logic for retrieving marshalling info for anonymous objects, including special cases for Exception and Type. This improves code clarity and maintainability by removing repeated logic and handling custom exception and Type instances more explicitly. --- .../WindowsRuntimeComWrappers.cs | 45 ++++++++++++++----- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/src/WinRT.Runtime2/InteropServices/WindowsRuntimeComWrappers.cs b/src/WinRT.Runtime2/InteropServices/WindowsRuntimeComWrappers.cs index aa5d3c3e1..96d6edb41 100644 --- a/src/WinRT.Runtime2/InteropServices/WindowsRuntimeComWrappers.cs +++ b/src/WinRT.Runtime2/InteropServices/WindowsRuntimeComWrappers.cs @@ -3,6 +3,7 @@ using System; using System.Collections; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using WindowsRuntime.InteropServices.Marshalling; @@ -117,11 +118,9 @@ public nint GetOrCreateComInterfaceForObject(object instance) } else { - // Special case 'Exception', see notes in 'ComputeVtables' below for more details. Repeating this here - // allows us to still skip the repeated lookup, as we already know we won't find a matching key pair. - MarshallingInfo = instance is Exception - ? WindowsRuntimeMarshallingInfo.GetInfo(typeof(Exception)) - : WindowsRuntimeMarshallingInfo.GetInfo(typeof(object)); + // If we couldn't retrieve the marshalling info, get the one to marshal anonymous objects. + // E.g. this would be the case when marshalling a custom exception type, or some 'Type'. + MarshallingInfo = GetAnonymousInspectableMarshallingInfo(instance); thisPtr = (void*)GetOrCreateComInterfaceForObject(instance, CreateComInterfaceFlags.TrackerSupport); } @@ -222,11 +221,7 @@ public object GetOrCreateObjectForComInstanceUnsafe( // If we already have one available passed by callers up the stack, we can skip the lookup and just use it. if (marshallingInfo is null && !WindowsRuntimeMarshallingInfo.TryGetInfo(obj.GetType(), out marshallingInfo)) { - // Special case for exception types, which won't have their own type map entry, but should all map to the - // same marshalling info for 'Exception'. Since we have an instance here, we can just check directly. - marshallingInfo = obj is Exception - ? WindowsRuntimeMarshallingInfo.GetInfo(typeof(Exception)) - : WindowsRuntimeMarshallingInfo.GetInfo(typeof(object)); + marshallingInfo = GetAnonymousInspectableMarshallingInfo(obj); } // Get the vtable from the current marshalling info (it will get cached in that instance) @@ -345,4 +340,34 @@ protected override void ReleaseObjects(IEnumerable objects) } } } + + /// + /// Gets the value to marshal an anonymous (managed) object. + /// + /// The managed object to expose outside the .NET runtime. + /// The value to use to marshal . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static WindowsRuntimeMarshallingInfo GetAnonymousInspectableMarshallingInfo(object instance) + { + // Special case for (derived) exception types, which won't have their own type map entry, but should all map + // to the same marshalling info for 'Exception'. Since we have an instance here, we can just check directly. + // Note that custom exception types that might implement additional interfaces will still just be marshalled + // as any other exception type (i.e. as just 'HResult'). This is intended and by design. + if (instance is Exception) + { + return WindowsRuntimeMarshallingInfo.GetInfo(typeof(Exception)); + } + + // Special case for 'Type' instances too. This is needed even without considering custom user-defined types + // (which shouldn't really be common anyway), because 'Type' itself is just a base type and not instantiated. + // That is, when e.g. doing 'typeof(Foo)', the actual object is some 'RuntimeType' object itself (non public). + if (instance is Type) + { + return WindowsRuntimeMarshallingInfo.GetInfo(typeof(Type)); + } + + // For all other cases, we fallback to the marshalling info for 'object'. This is the + // shared marshalling mode for all unknown objects, ie. just an opaque 'IInspectable'. + return WindowsRuntimeMarshallingInfo.GetInfo(typeof(object)); + } } \ No newline at end of file From cffc5cf8f0a25e6a9f1e7a4a389573d6f12f29d9 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Tue, 6 Jan 2026 20:28:23 -0800 Subject: [PATCH 73/76] Enhance TypeMarshaller with special case handling Added special handling for projected types, exceptions, and System.Type in TypeMarshaller. Improved logic for mapping metadata types to CLR types, including handling for KeyValuePair and delegate types. These changes improve accuracy and round-tripping of type information during marshalling. --- src/WinRT.Runtime2/ABI/System/Type.cs | 90 ++++++++++++++++++++++++--- 1 file changed, 83 insertions(+), 7 deletions(-) diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index 3cc6e1eac..ea4f96057 100644 --- a/src/WinRT.Runtime2/ABI/System/Type.cs +++ b/src/WinRT.Runtime2/ABI/System/Type.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; @@ -116,6 +117,20 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR // would be the 'IReference' type name for boxed instances of this type. global::System.Type? nullableUnderlyingType = Nullable.GetUnderlyingType(value); + // For projected types (not custom-mapped, but possibly manually projected, like e.g. 'IAsyncInfo'), we + // can always just use the fully qualified type name (as it will always match the one in the .winmd file). + // We can check if a given type matches this by just checking whether it has '[WindowsRuntimeMetadata]'. + // Note that we're intentionally skipping generic types, as for those we need the 'cswinrtgen' info. + // Additionally, this path isn't taken if we have a nullable value type, which avoids the lookup too. + if (nullableUnderlyingType is null && !value.IsGenericType && value.IsDefined(typeof(WindowsRuntimeMetadataAttribute))) + { + reference = new TypeReference { Name = value.FullName, Kind = TypeKind.Metadata }; + + return; + } + + // TODO: for generic interfaces, 'cswinrtgen' will emit an entry with the metadata name in the metadata type map. + // Use the metadata info lookup first to handle custom-mapped interface types. These would not have a proxy // type map entry for normal marshalling (because they're interfaces), and they would also not show up as // being projected types from there. So we handle them here first to get the right metadata type name. @@ -126,6 +141,22 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR return; } + // Special case 'Exception' types, since we also need to handle all derived types (e.g. user-defined) + if (value.IsAssignableTo(typeof(global::System.Exception))) + { + reference = new TypeReference { Name = "Windows.Foundation.HResult", Kind = TypeKind.Metadata }; + + return; + } + + // Special case 'Type' as well, for the same reason (e.g. 'typeof(Foo)' would return a 'RuntimeType' instance) + if (value.IsAssignableTo(typeof(global::System.Type))) + { + reference = new TypeReference { Name = "Windows.UI.Xaml.Interop.TypeName", Kind = TypeKind.Metadata }; + + return; + } + global::System.Type typeOrUnderlyingType = nullableUnderlyingType ?? value; // Use the marshalling info lookup to detect projected or custom-mapped Windows Runtime types. @@ -144,11 +175,16 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR // will ensure that e.g. 'typeof(int)' will report 'Int32', rather than 'Windows.Foundation.IReference'. if (nullableUnderlyingType is null && marshallingInfo.TryGetMetadataTypeName(out string? metadataTypeName)) { + // TODO: check for value types, and if so use the fullname as a fallback. + // TODO: also check for delegates here. Also skip 'KVP<,>'. + reference = new TypeReference { Name = metadataTypeName, Kind = kind }; return; } + // TODO: Detect 'Nullable>' and bypass and go to custom + // If we don't have a metadata type name, try to get the runtime class name. This will handle // cases such as constructed 'Nullable' types, which will report their boxed type name. if (marshallingInfo.TryGetRuntimeClassName(out string? runtimeClassName)) @@ -162,8 +198,6 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR // runtime classes and interface types. For all of those, the projected type name will be correct. reference = new TypeReference { Name = typeOrUnderlyingType.FullName, Kind = kind }; - // TODO: handle 'Nullable>' here - return; } @@ -208,10 +242,28 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR return global::System.Type.GetType(typeName.ToString()); } + // Handle special-cases metadata types after checking the type kind + if (value.Kind is TypeKind.Metadata) + { + // For any 'HResult' type, we return 'Exception'. If a user had marshalled + // any derived exception type, that will not actually round-trip exactly. + // This is expected and by design. We don't try to preserve the original. + if (typeName.SequenceEqual("Windows.Foundation.HResult")) + { + return typeof(global::System.Exception); + } + + // Same as above for 'Type'. We intentionally don't perfectly round-trip. + if (typeName.SequenceEqual("Windows.UI.Xaml.Interop.TypeName")) + { + return typeof(global::System.Type); + } + } + global::System.Type? type = null; - // TODO: handle 'IReference', 'IReference' and 'IReference'. - // Those should all be reported as 'NoMetadataTypeInfo', not as the custom-mapped C# type. + // TODO: put type map entries for non-generic interfaces in the metadata type map. + // This also needs to have entries for all value types and delegate types // If the type was handled by the metadata lookup, get the public type from there if (WindowsRuntimeMetadataInfo.TryGetInfo(typeName, out WindowsRuntimeMetadataInfo? metadataInfo)) @@ -224,9 +276,33 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR // This will work for both 'Primitive' and 'Metadata' types, same as above. global::System.Type publicType = marshallingInfo.PublicType; - // For value types, we get the reference type (i.e. the constructed 'Nullable' type) - // from the marshalling info. This will perform a lookup for '[WindowsRuntimeReferenceType]'. - type = publicType.IsValueType ? marshallingInfo.ReferenceType : publicType; + // If we got here, it means we have some 'IReference' instance with the + // element type being some delegate, exception, or 'Type' type. Because we + // only support marshalling them as 'TypeName' by value (not references), + // we're intentionally always just returning missing metadata for them. + if (publicType.IsAssignableTo(typeof(Delegate)) || + publicType.IsAssignableTo(typeof(global::System.Exception)) || + publicType.IsAssignableTo(typeof(global::System.Type))) + { + return NoMetadataTypeInfo.GetOrCreate(typeName); + } + + // Special case 'KeyValuePair<,>' instances, where we always want to return the public type + // directly here, and not its nullable version. This is because 'KeyValuePair<,>' is an + // interface type in the Windows Runtime type system, so the type name we got here from + // the marshalling type map wouldn't actually represent an 'IReference' instantiation. + if (publicType.IsValueType && + publicType.IsGenericType && + publicType.GetGenericTypeDefinition() == typeof(KeyValuePair<,>)) + { + type = publicType; + } + else + { + // For value types, we get the reference type (i.e. the constructed 'Nullable' type) + // from the marshalling info. This will perform a lookup for '[WindowsRuntimeReferenceType]'. + type = publicType.IsValueType ? marshallingInfo.ReferenceType : publicType; + } } // Handle the case of C# primitive types that are not Windows Runtime types. From a57306446e8197aba42483f9f0d9cca2c6ac3ef6 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Tue, 6 Jan 2026 21:09:34 -0800 Subject: [PATCH 74/76] Improve type marshalling and remove redundant attributes Enhanced TypeMarshaller to better handle value types and delegates without explicit metadata names, and to properly bypass marshalling for Nullable> types. Removed redundant [WindowsRuntimeMetadataTypeName] attributes from Point, Rect, and Size to align with updated marshalling logic. --- src/WinRT.Runtime2/ABI/System/Type.cs | 51 +++++++++++++++---- .../Windows.Foundation/Point.cs | 1 - src/WinRT.Runtime2/Windows.Foundation/Rect.cs | 1 - src/WinRT.Runtime2/Windows.Foundation/Size.cs | 1 - 4 files changed, 40 insertions(+), 14 deletions(-) diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index ea4f96057..eb33a41a6 100644 --- a/src/WinRT.Runtime2/ABI/System/Type.cs +++ b/src/WinRT.Runtime2/ABI/System/Type.cs @@ -170,20 +170,47 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR ? TypeKind.Primitive : TypeKind.Metadata; - // Special case primitive types that are of types that can be boxed. That is, if the input type is not - // some 'Nullable' type, check if we have an explicit metadata type name, and use that if so. This - // will ensure that e.g. 'typeof(int)' will report 'Int32', rather than 'Windows.Foundation.IReference'. - if (nullableUnderlyingType is null && marshallingInfo.TryGetMetadataTypeName(out string? metadataTypeName)) + // We need special handling for several cases that represent non-boxed types + if (nullableUnderlyingType is null) { - // TODO: check for value types, and if so use the fullname as a fallback. - // TODO: also check for delegates here. Also skip 'KVP<,>'. - - reference = new TypeReference { Name = metadataTypeName, Kind = kind }; - - return; + // Special case primitive types that are of types that can be boxed. That is, if the input type is not + // some 'Nullable' type, check if we have an explicit metadata type name, and use that if so. This + // will ensure that e.g. 'typeof(int)' will report 'Int32', not 'Windows.Foundation.IReference'. + if (marshallingInfo.TryGetMetadataTypeName(out string? metadataTypeName)) + { + reference = new TypeReference { Name = metadataTypeName, Kind = kind }; + + return; + } + + // If we don't have a metadata type name, check if we have a value type or a delegate type. + // Note that this path can only be reached for those if either is true: + // - The value type is not generic (otherwise the proxy type would've had the metadata name) + // - The delegate is not generic (for the same reason as above, or we would've had a proxy) + // So in either case, we can just use the fully qualified type name here, which will match + // the .winmd type name. We don't have to worry about custom-mapped types here, as those will + // have already been handled above. This special case ensures we don't get the boxed type name. + if (typeOrUnderlyingType.IsValueType || + typeOrUnderlyingType.IsAssignableTo(typeof(Delegate))) + { + reference = new TypeReference { Name = typeOrUnderlyingType.FullName, Kind = kind }; + + return; + } + + // TODO: Skip 'KVP<,>'. } - // TODO: Detect 'Nullable>' and bypass and go to custom + // We don't support marshalling a 'KeyValuePair<,>?' type, as that is not a valid Windows Runtime + // type (since 'KeyValuePair<,>' is an interface in the Windows Runtime type system. So if we get + // one, we just treat it like any other custom (e.g. user-defined) types instead. + if (nullableUnderlyingType is not null && + nullableUnderlyingType.IsValueType && + nullableUnderlyingType.IsGenericType && + nullableUnderlyingType.GetGenericTypeDefinition() == typeof(KeyValuePair<,>)) + { + goto CustomType; + } // If we don't have a metadata type name, try to get the runtime class name. This will handle // cases such as constructed 'Nullable' types, which will report their boxed type name. @@ -214,6 +241,8 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR return; } + CustomType: + // All other cases are treated as custom types (e.g. user-defined types) reference = new TypeReference { Name = value.AssemblyQualifiedName, Kind = TypeKind.Custom }; } diff --git a/src/WinRT.Runtime2/Windows.Foundation/Point.cs b/src/WinRT.Runtime2/Windows.Foundation/Point.cs index 526b1a0af..8b14cdd48 100644 --- a/src/WinRT.Runtime2/Windows.Foundation/Point.cs +++ b/src/WinRT.Runtime2/Windows.Foundation/Point.cs @@ -19,7 +19,6 @@ namespace Windows.Foundation; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] -[WindowsRuntimeMetadataTypeName("Windows.Foundation.Point")] [WindowsRuntimeReferenceType(typeof(Point?))] [SupportedOSPlatform("Windows10.0.10240.0")] [ContractVersion(typeof(FoundationContract), 65536u)] diff --git a/src/WinRT.Runtime2/Windows.Foundation/Rect.cs b/src/WinRT.Runtime2/Windows.Foundation/Rect.cs index e5b607b35..eaed310d5 100644 --- a/src/WinRT.Runtime2/Windows.Foundation/Rect.cs +++ b/src/WinRT.Runtime2/Windows.Foundation/Rect.cs @@ -21,7 +21,6 @@ namespace Windows.Foundation; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] -[WindowsRuntimeMetadataTypeName("Windows.Foundation.Rect")] [WindowsRuntimeReferenceType(typeof(Rect?))] [SupportedOSPlatform("Windows10.0.10240.0")] [ContractVersion(typeof(FoundationContract), 65536u)] diff --git a/src/WinRT.Runtime2/Windows.Foundation/Size.cs b/src/WinRT.Runtime2/Windows.Foundation/Size.cs index d78c1e8db..f3519caf5 100644 --- a/src/WinRT.Runtime2/Windows.Foundation/Size.cs +++ b/src/WinRT.Runtime2/Windows.Foundation/Size.cs @@ -18,7 +18,6 @@ namespace Windows.Foundation; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference")] -[WindowsRuntimeMetadataTypeName("Windows.Foundation.Size")] [WindowsRuntimeReferenceType(typeof(Size?))] [SupportedOSPlatform("Windows10.0.10240.0")] [ContractVersion(typeof(FoundationContract), 65536u)] From 2935cb9a4b0b434a6c511182efbf51488572c5bf Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 9 Jan 2026 14:01:00 -0800 Subject: [PATCH 75/76] Fix runtime class name retrieval in marshalling info Replaces usage of _metadataTypeName with _runtimeClassName when retrieving the cached runtime class name, ensuring the correct value is returned. --- .../TypeMapInfo/WindowsRuntimeMarshallingInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs index 7b070a7c5..c9f5e304f 100644 --- a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs +++ b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs @@ -603,7 +603,7 @@ bool Load([NotNullWhen(true)] out string? runtimeClassName) return true; } - string? value = _metadataTypeName; + string? value = _runtimeClassName; // We have a cached runtime class name, so return it immediately if (value is not null) From 1b90d1e21f426eedde48f7c0c9106e362d5293db Mon Sep 17 00:00:00 2001 From: Will Thant Date: Fri, 9 Jan 2026 14:08:25 -0800 Subject: [PATCH 76/76] Fix IXamlServiceProvider not being excluded correctly --- src/cswinrt/helpers.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cswinrt/helpers.h b/src/cswinrt/helpers.h index 458528b63..57e67518f 100644 --- a/src/cswinrt/helpers.h +++ b/src/cswinrt/helpers.h @@ -714,8 +714,8 @@ namespace cswinrt { "IGridLengthHelperStatics" }, { "IThicknessHelper" }, { "IThicknessHelperStatics" }, - { "ThicknessHelper" }, { "IXamlServiceProvider", "System", "IServiceProvider" }, + { "ThicknessHelper" }, } }, { "Microsoft.UI.Xaml.Controls.Primitives", @@ -866,8 +866,8 @@ namespace cswinrt { "IGridLengthHelperStatics" }, { "IThicknessHelper" }, { "IThicknessHelperStatics" }, - { "ThicknessHelper" }, { "IXamlServiceProvider", "System", "IServiceProvider" }, + { "ThicknessHelper" }, } }, { "Windows.UI.Xaml.Controls.Primitives",