diff --git a/src/Authoring/WinRT.SourceGenerator2/TypeMapAssemblyTargetGenerator.Execute.cs b/src/Authoring/WinRT.SourceGenerator2/TypeMapAssemblyTargetGenerator.Execute.cs index f64554ec1..73ea894b4 100644 --- a/src/Authoring/WinRT.SourceGenerator2/TypeMapAssemblyTargetGenerator.Execute.cs +++ b/src/Authoring/WinRT.SourceGenerator2/TypeMapAssemblyTargetGenerator.Execute.cs @@ -104,6 +104,7 @@ 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}")] """); } @@ -130,6 +131,11 @@ 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")] diff --git a/src/Projections/Test/Test.csproj b/src/Projections/Test/Test.csproj index d15aa7b43..98c13569d 100644 --- a/src/Projections/Test/Test.csproj +++ b/src/Projections/Test/Test.csproj @@ -20,6 +20,7 @@ TestComponentCSharp.AnotherAssembly; + TestComponentCSharp.TestTypeTrimmed; TestComponent; diff --git a/src/Tests/FunctionalTests/TypeMarshaling/Program.cs b/src/Tests/FunctionalTests/TypeMarshaling/Program.cs new file mode 100644 index 000000000..75232be5e --- /dev/null +++ b/src/Tests/FunctionalTests/TypeMarshaling/Program.cs @@ -0,0 +1,57 @@ +using System; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +using TestComponent; +using TestComponentCSharp; + +SetTypeProperties setTypeProperties = new(); + +// Convert to Managed Metadata Marshalling Info Test Case +String expectedMetadataPropertyInfo = "TestComponentCSharp.TestType Metadata"; +CustomTestType TestType = new(); +if (setTypeProperties.GetPropertyInfoTestType(TestType) != expectedMetadataPropertyInfo) +{ + return 101; +} + +// Convert to Managed Trimmed Metadata NoMetadataTypeInfo Test Case +// Goes into NoMetadataTypeInfo codepath for Type.cs ConvertToManaged +// Do not reference TestComponentCSharp::TestType1 in managed because it needs to be trimmed to test the Metadata TypeKind scenario +String expectedMetadataPropertyInfoTrimmed = "TestComponentCSharp.TestTypeTrimmed Metadata"; +CustomTestType TestTypeTrimmed = new(); +if (setTypeProperties.GetPropertyInfoTestTypeTrimmed(TestTypeTrimmed) != expectedMetadataPropertyInfoTrimmed) +{ + return 102; +} + +// Custom TypeKind test case +String expectedCustomTypePropertyInfo = "CustomTestType, TypeMarshaling, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null Custom"; +SetTypeProperties customSetTypeProperties = new(); +if (setTypeProperties.GetPropertyInfoWithType(typeof(CustomTestType)) != expectedCustomTypePropertyInfo) +{ + return 103; +} + +// Primitive TypeKind test case +String expectedPrimitiveTypePropertyInfo = "Int32 Primitive"; +SetTypeProperties primitiveSetTypeProperties = new(); +if (setTypeProperties.GetPropertyInfoWithType(typeof(int)) != expectedPrimitiveTypePropertyInfo) +{ + return 104; +} + +// Primitive TypeKind test case 2 +String expectedPrimitiveTypePropertyInfo2 = "Int64 Primitive"; +SetTypeProperties primitiveSetTypeProperties2 = new(); +if (setTypeProperties.GetPropertyInfoWithType(typeof(System.Int64)) != expectedPrimitiveTypePropertyInfo2) +{ + return 105; +} + +return 100; + +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/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..b644bf85f 100644 --- a/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.cpp +++ b/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.cpp @@ -5,9 +5,62 @@ #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::GetPropertyInfoTestTypeTrimmed(IType testObject) + { + testObject.TypeProperty(winrt::xaml_typename()); + winrt::hstring kind; + switch (testObject.TypeProperty().Kind) + { + case Windows::UI::Xaml::Interop::TypeKind::Custom: + kind = winrt::hstring(L"Custom"); + break; + case Windows::UI::Xaml::Interop::TypeKind::Metadata: + kind = winrt::hstring(L"Metadata"); + break; + default: + kind = winrt::hstring(L"Primitive"); + break; + } + return testObject.TypeProperty().Name + L" " + kind; + } + + winrt::hstring SetTypeProperties::GetPropertyInfoTestType(IType testObject) + { + testObject.TypeProperty(winrt::xaml_typename()); + winrt::hstring kind; + switch (testObject.TypeProperty().Kind) + { + case Windows::UI::Xaml::Interop::TypeKind::Custom: + kind = winrt::hstring(L"Custom"); + break; + case Windows::UI::Xaml::Interop::TypeKind::Metadata: + kind = winrt::hstring(L"Metadata"); + break; + default: + kind = winrt::hstring(L"Primitive"); + break; + } + return testObject.TypeProperty().Name + L" " + kind; + } + + + winrt::hstring SetTypeProperties::GetPropertyInfoWithType(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 ab37f5a75..eada197fc 100644 --- a/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.h +++ b/src/Tests/TestComponentCSharp/ManualProjectionTestClasses.h @@ -4,9 +4,19 @@ #include "CustomBindableVectorTest.g.h" #include "CustomBindableObservableVectorTest.g.h" #include "CustomIteratorTest.g.h" +#include "SetTypeProperties.g.h" +#include namespace winrt::TestComponentCSharp::implementation { + struct SetTypeProperties : SetTypePropertiesT + { + SetTypeProperties(); + winrt::hstring GetPropertyInfoTestType(IType testObject); + winrt::hstring GetPropertyInfoTestTypeTrimmed(IType testObject); + winrt::hstring GetPropertyInfoWithType(winrt::Windows::UI::Xaml::Interop::TypeName typeName); + }; + struct CustomBindableIteratorTest : CustomBindableIteratorTestT { CustomBindableIteratorTest(); @@ -72,6 +82,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..e78437a03 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; }; @@ -152,6 +157,26 @@ namespace TestComponentCSharp static ISingleton Instance; } + [default_interface] + runtimeclass SetTypeProperties + { + SetTypeProperties(); + String GetPropertyInfoTestTypeTrimmed(IType testObject); + String GetPropertyInfoTestType(IType testObject); + String GetPropertyInfoWithType(Windows.UI.Xaml.Interop.TypeName typeName); + } + + // Do not reference TestComponentCSharp::TestTypeTrimmed in managed because it needs to be trimmed to test the Metadata TypeKind scenario in the TypeHandling project + runtimeclass TestTypeTrimmed + { + void f(); + } + + runtimeclass TestType + { + void f(); + } + [default_interface, gc_pressure(Windows.Foundation.Metadata.GCPressureAmount.High)] runtimeclass Class : Windows.Foundation.IStringable 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 ce41edf1a..b0a455b54 100644 --- a/src/Tests/UnitTest/TestComponentCSharp_Tests.cs +++ b/src/Tests/UnitTest/TestComponentCSharp_Tests.cs @@ -547,12 +547,39 @@ public void TestBufferTryGetArraySubset() Assert.Equal(2, array.Count); } - [Fact] - public void TestTypePropertyWithSystemType() - { - TestObject.TypeProperty = typeof(System.Type); - Assert.Equal("Windows.UI.Xaml.Interop.TypeName", 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), "Windows.UI.Xaml.Interop.TypeName", "Metadata")] + [InlineData(typeof(Guid), "Guid", "Metadata")] + [InlineData(typeof(Object), "Object", "Metadata")] + [InlineData(typeof(String), "String", "Metadata")] + [InlineData(typeof(TimeSpan), "Windows.Foundation.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")] + [InlineData(typeof(Exception), "Windows.Foundation.HResult", "Metadata")] + [InlineData(typeof(TestCSharp), "UnitTest.TestCSharp, UnitTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", "Custom")] + [InlineData(typeof(Nullable), "Windows.Foundation.IReference`1", "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()); } class CustomDictionary : Dictionary { } @@ -3428,34 +3455,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 94a990f33..7d4aab198 100644 --- a/src/Tests/UnitTest/UnitTest.csproj +++ b/src/Tests/UnitTest/UnitTest.csproj @@ -10,11 +10,12 @@ + - + diff --git a/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.cs b/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.cs index 8b23ff529..b80b606f6 100644 --- a/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.cs +++ b/src/WinRT.Interop.Generator/Builders/DynamicCustomMappedTypeMapEntriesBuilder.cs @@ -9,8 +9,11 @@ using WindowsRuntime.InteropGenerator.Errors; using WindowsRuntime.InteropGenerator.Factories; using WindowsRuntime.InteropGenerator.Generation; +using WindowsRuntime.InteropGenerator.Helpers; using WindowsRuntime.InteropGenerator.References; +#pragma warning disable IDE0046 + namespace WindowsRuntime.InteropGenerator.Builders; /// @@ -29,109 +32,114 @@ public static void AssemblyAttributes( InteropReferences interopReferences, ModuleDefinition module) { - ManagedOnlyTypeOrInterface( - args: args, - windowsUIXamlTypeName: "Windows.UI.Xaml.Interop.IBindableIterable", - microsoftUIXamlTypeName: "Microsoft.UI.Xaml.Interop.IBindableIterable", - target: interopReferences.WindowsRuntimeModule.CreateTypeReference("ABI.System.Collections"u8, "IEnumerable"u8).ToReferenceTypeSignature(), + InterfaceType( + windowsUIXamlMetadata: "Windows.Foundation.UniversalApiContract", + microsoftUIXamlMetadata: "Microsoft.UI.Xaml.WinUIContract", trimTarget: interopReferences.IEnumerable.ToReferenceTypeSignature(), interopReferences: interopReferences, - module: module); + module: module, + useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections); - ManagedOnlyTypeOrInterface( - args: args, - windowsUIXamlTypeName: "Windows.UI.Xaml.Interop.IBindableIterator", - microsoftUIXamlTypeName: "Microsoft.UI.Xaml.Interop.IBindableIterator", - target: interopReferences.WindowsRuntimeModule.CreateTypeReference("ABI.System.Collections"u8, "IEnumerator"u8).ToReferenceTypeSignature(), + InterfaceType( + windowsUIXamlMetadata: "Windows.Foundation.UniversalApiContract", + microsoftUIXamlMetadata: "Microsoft.UI.Xaml.WinUIContract", trimTarget: interopReferences.IEnumerator.ToReferenceTypeSignature(), interopReferences: interopReferences, - module: module); + module: module, + useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections); - ManagedOnlyTypeOrInterface( - args: args, - windowsUIXamlTypeName: "Windows.UI.Xaml.Interop.IBindableVector", - microsoftUIXamlTypeName: "Microsoft.UI.Xaml.Interop.IBindableVector", - target: interopReferences.WindowsRuntimeModule.CreateTypeReference("ABI.System.Collections"u8, "IList"u8).ToReferenceTypeSignature(), + InterfaceType( + windowsUIXamlMetadata: "Windows.Foundation.UniversalApiContract", + microsoftUIXamlMetadata: "Microsoft.UI.Xaml.WinUIContract", trimTarget: interopReferences.IList.ToReferenceTypeSignature(), interopReferences: interopReferences, - module: module); + module: module, + useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections); - ManagedOnlyTypeOrInterface( - args: args, - windowsUIXamlTypeName: "Windows.UI.Xaml.Interop.NotifyCollectionChangedEventArgs", - microsoftUIXamlTypeName: "Microsoft.UI.Xaml.Interop.NotifyCollectionChangedEventArgs", - target: interopReferences.WindowsRuntimeModule.CreateTypeReference("ABI.System.Collections.Specialized"u8, "NotifyCollectionChangedEventArgs"u8).ToReferenceTypeSignature(), + ClassType( + windowsUIXamlMetadata: "Windows.Foundation.UniversalApiContract", + microsoftUIXamlMetadata: "Microsoft.UI.Xaml.WinUIContract", trimTarget: interopReferences.NotifyCollectionChangedEventArgs.ToReferenceTypeSignature(), interopReferences: interopReferences, - module: module); + module: module, + useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections); - ManagedOnlyTypeOrInterface( - args: args, - windowsUIXamlTypeName: "Windows.UI.Xaml.Data.PropertyChangedEventArgs", - microsoftUIXamlTypeName: "Microsoft.UI.Xaml.Data.PropertyChangedEventArgs", - target: interopReferences.WindowsRuntimeModule.CreateTypeReference("ABI.System.ComponentModel"u8, "PropertyChangedEventArgs"u8).ToReferenceTypeSignature(), + ClassType( + windowsUIXamlMetadata: "Windows.Foundation.UniversalApiContract", + microsoftUIXamlMetadata: "Microsoft.UI.Xaml.WinUIContract", trimTarget: interopReferences.PropertyChangedEventArgs.ToReferenceTypeSignature(), interopReferences: interopReferences, - module: module); + module: module, + useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections); - WindowsRuntimeExposedType( - args: args, - windowsUIXamlTypeName: "Windows.Foundation.IReference`1", - microsoftUIXamlTypeName: "Windows.Foundation.IReference`1", + DelegateType( + windowsUIXamlMetadata: "Windows.Foundation.UniversalApiContract", + microsoftUIXamlMetadata: "Microsoft.UI.Xaml.WinUIContract", trimTarget: interopReferences.NotifyCollectionChangedEventHandler.ToReferenceTypeSignature(), interopReferences: interopReferences, - module: module); + module: module, + useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections); - WindowsRuntimeExposedType( - args: args, - windowsUIXamlTypeName: "Windows.Foundation.IReference`1", - microsoftUIXamlTypeName: "Windows.Foundation.IReference`1", + DelegateType( + windowsUIXamlMetadata: "Windows.Foundation.UniversalApiContract", + microsoftUIXamlMetadata: "Microsoft.UI.Xaml.WinUIContract", trimTarget: interopReferences.PropertyChangedEventHandler.ToReferenceTypeSignature(), interopReferences: interopReferences, - module: module); + module: module, + useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections); - WindowsRuntimeExposedType( - args: args, - windowsUIXamlTypeName: "Windows.UI.Xaml.Interop.IBindableVectorView", - microsoftUIXamlTypeName: "Microsoft.UI.Xaml.Interop.IBindableVectorView", - trimTarget: interopReferences.BindableIReadOnlyListAdapter.ToReferenceTypeSignature(), + IBindableVectorViewType( interopReferences: interopReferences, - module: module); + module: module, + useWindowsUIXamlProjections: args.UseWindowsUIXamlProjections); } /// - /// Creates a new custom attribute value for for a given custom-mapped type that is never marshalled or instantiated. + /// Creates a new custom attribute value for for a given custom-mapped interface type. /// - /// The arguments for this invocation. - /// The runtime class name for Windows.UI.Xaml. - /// The runtime class name for Microsoft.UI.Xaml. - /// + /// The metadata name for Windows.UI.Xaml. + /// The metadata name for Microsoft.UI.Xaml. /// /// The instance to use. /// The module that the attribute will be used from. - private static void ManagedOnlyTypeOrInterface( - InteropGeneratorArgs args, - string windowsUIXamlTypeName, - string microsoftUIXamlTypeName, - TypeSignature target, + /// Whether to use Windows.UI.Xaml projections. + private static void InterfaceType( + string windowsUIXamlMetadata, + string microsoftUIXamlMetadata, TypeSignature trimTarget, InteropReferences interopReferences, - ModuleDefinition module) + ModuleDefinition module, + bool useWindowsUIXamlProjections) { - // This method is used for two kinds of custom-mapped types: - // - "Managed-only" types (such as 'PropertyChangedEventArgs'), which don't need CCW support, because they are - // marshalled by activating a fully native instance. Because of this, the proxy type for these types doesn't - // need the runtime class name annotation on them, which allows it to be defined in 'WinRT.Runtime.dll'. That - // in turn also allows the '[TypeMapAssociation]' attribute to be defined there. So here we - // only need the '[TypeMap]' attribute to handle untyped native to managed marshalling. - // - Interface types (such as 'IEnumerable'), which also don't need CCW support (because they are interfaces). - // For those, the IDIC attributes are in 'WinRT.Runtime.dll', so here we again only need the external type map. + string metadata = useWindowsUIXamlProjections ? windowsUIXamlMetadata : microsoftUIXamlMetadata; + + // Define the proxy type for the interface type. Because the metadata type name depends on the XAML configuration + // that is used, we can't define this proxy type in advance even if the interface type itself is not generic. + InteropTypeDefinitionBuilder.Proxy( + ns: InteropUtf8NameFactory.TypeNamespace(trimTarget), + name: InteropUtf8NameFactory.TypeName(trimTarget), + mappedMetadata: metadata, + runtimeClassName: null, + metadataTypeName: MetadataTypeNameGenerator.GetMetadataTypeName(trimTarget, useWindowsUIXamlProjections), + mappedType: trimTarget, + comWrappersMarshallerAttributeType: GetMarshallerAttributeType(trimTarget, interopReferences, module), + interopReferences: interopReferences, + module: module, + proxyType: out TypeDefinition proxyType); + + // For interface types (such as 'IEnumerable'), which don't need CCW support (because they are interfaces), we just + // need the marshalling type map entry to support anonymous objects, and a metadata proxy type map entry to retrieve + // the correct metadata info when marshalling 'Type' instances. We don't need to emit entries in the dynamic interface + // castable type map, because those attributes are in 'WinRT.Runtime.dll' already (as the types are not generic). InteropTypeDefinitionBuilder.TypeMapAttributes( - runtimeClassName: args.UseWindowsUIXamlProjections ? windowsUIXamlTypeName : microsoftUIXamlTypeName, - externalTypeMapTargetType: target, + runtimeClassName: RuntimeClassNameGenerator.GetRuntimeClassName(trimTarget, useWindowsUIXamlProjections), + metadataTypeName: null, + externalTypeMapTargetType: proxyType.ToTypeSignature(), externalTypeMapTrimTargetType: trimTarget, - proxyTypeMapSourceType: null, - proxyTypeMapProxyType: null, + marshallingTypeMapSourceType: null, + marshallingTypeMapProxyType: null, + metadataTypeMapSourceType: trimTarget, + metadataTypeMapProxyType: proxyType.ToTypeSignature(), interfaceTypeMapSourceType: null, interfaceTypeMapProxyType: null, interopReferences: interopReferences, @@ -139,53 +147,219 @@ private static void ManagedOnlyTypeOrInterface( } /// - /// Creates a new custom attribute value for for a given custom-mapped type that can be marshalled to native. + /// Creates a new custom attribute value for for a given custom-mapped class type. /// - /// The arguments for this invocation. - /// The runtime class name for Windows.UI.Xaml. - /// The runtime class name for Microsoft.UI.Xaml. + /// The metadata name for Windows.UI.Xaml. + /// The metadata name for Microsoft.UI.Xaml. /// /// The instance to use. /// The module that the attribute will be used from. - private static void WindowsRuntimeExposedType( - InteropGeneratorArgs args, - string windowsUIXamlTypeName, - string microsoftUIXamlTypeName, + /// Whether to use Windows.UI.Xaml projections. + private static void ClassType( + string windowsUIXamlMetadata, + string microsoftUIXamlMetadata, TypeSignature trimTarget, InteropReferences interopReferences, - ModuleDefinition module) + ModuleDefinition module, + bool useWindowsUIXamlProjections) { - string runtimeClassName = args.UseWindowsUIXamlProjections ? windowsUIXamlTypeName : microsoftUIXamlTypeName; + string metadata = useWindowsUIXamlProjections ? windowsUIXamlMetadata : microsoftUIXamlMetadata; - // Retrieve the '[ComWrappersMarshaller]' type from 'WinRT.Runtime.dll', which always follows this naming convention - TypeReference comWrappersMarshallerTypeReference = interopReferences.WindowsRuntimeModule.CreateTypeReference( + // Define the proxy type for the class type. Same as above, we need to define this proxy type here, as the + // metadata type name is not fixed. We define a runtime class name so that 'TypeName' marshalling will be + // able to do lookups correctly (this attribute will be used, since the input type is a normal class type). + InteropTypeDefinitionBuilder.Proxy( ns: InteropUtf8NameFactory.TypeNamespace(trimTarget), - name: (Utf8String)$"{trimTarget.Name}ComWrappersMarshallerAttribute"); + name: InteropUtf8NameFactory.TypeName(trimTarget), + mappedMetadata: metadata, + runtimeClassName: RuntimeClassNameGenerator.GetRuntimeClassName(trimTarget, useWindowsUIXamlProjections), + metadataTypeName: null, + mappedType: trimTarget, + comWrappersMarshallerAttributeType: GetMarshallerAttributeType(trimTarget, interopReferences, module), + interopReferences: interopReferences, + module: module, + proxyType: out TypeDefinition proxyType); - // The '[ComWrappersMarshaller]' type should always exist for all custom-mapped types, throw if it doesn't - if (comWrappersMarshallerTypeReference.Import(module).Resolve() is not TypeDefinition comWrappersMarshallerType) - { - throw WellKnownInteropExceptions.CustomMappedTypeComWrappersMarshallerAttributeTypeResolveError(comWrappersMarshallerTypeReference); - } + // This is similar to interfaces above, with the difference being that because class objects can be instantiated, + // the proxy type map used will only be with the marshalling type map group, and the metadata type map group is + // not needed here. Same goes for the external type map: we just have a normal entry for marshalling there. + InteropTypeDefinitionBuilder.TypeMapAttributes( + runtimeClassName: RuntimeClassNameGenerator.GetRuntimeClassName(trimTarget, useWindowsUIXamlProjections), + metadataTypeName: null, + externalTypeMapTargetType: proxyType.ToTypeSignature(), + externalTypeMapTrimTargetType: trimTarget, + marshallingTypeMapSourceType: trimTarget, + marshallingTypeMapProxyType: proxyType.ToTypeSignature(), + metadataTypeMapSourceType: null, + metadataTypeMapProxyType: null, + interfaceTypeMapSourceType: null, + interfaceTypeMapProxyType: null, + interopReferences: interopReferences, + module: module); + } + + /// + /// Creates a new custom attribute value for for a given custom-mapped delegate type. + /// + /// The metadata name for Windows.UI.Xaml. + /// The metadata name for Microsoft.UI.Xaml. + /// + /// The instance to use. + /// The module that the attribute will be used from. + /// Whether to use Windows.UI.Xaml projections. + private static void DelegateType( + string windowsUIXamlMetadata, + string microsoftUIXamlMetadata, + TypeSignature trimTarget, + InteropReferences interopReferences, + ModuleDefinition module, + bool useWindowsUIXamlProjections) + { + string metadata = useWindowsUIXamlProjections ? windowsUIXamlMetadata : microsoftUIXamlMetadata; - // Because these types can be instantiated and marshalled to native, but their runtime class name changes between 'Windows.UI.Xaml' and - // 'Microsoft.UI.Xaml', we also need to generate a proxy type for them, so that we can annotate it with '[WindowsRuntimeClassName]' with - // the correct runtime class name for the configuration actually being used at runtime by the current application or published library. + // Define the proxy type for the delegate type. Same as above, we need to define this proxy type here, as the + // metadata type name is not fixed. We don't need a runtime class name because the type is managed-only. That + // is, when marshalled to native it will be converted into a fully native object, so we don't need name lookups. InteropTypeDefinitionBuilder.Proxy( ns: InteropUtf8NameFactory.TypeNamespace(trimTarget), - name: trimTarget.Name!, + name: InteropUtf8NameFactory.TypeName(trimTarget), + mappedMetadata: metadata, + runtimeClassName: null, + metadataTypeName: MetadataTypeNameGenerator.GetMetadataTypeName(trimTarget, useWindowsUIXamlProjections), mappedType: trimTarget, + comWrappersMarshallerAttributeType: GetMarshallerAttributeType(trimTarget, interopReferences, module), + interopReferences: interopReferences, + module: module, + proxyType: out TypeDefinition proxyType); + + // Same as above for class types, the only difference here is in the proxy type definition for delegates + InteropTypeDefinitionBuilder.TypeMapAttributes( + runtimeClassName: RuntimeClassNameGenerator.GetRuntimeClassName(trimTarget, useWindowsUIXamlProjections), + metadataTypeName: null, + externalTypeMapTargetType: proxyType.ToTypeSignature(), + externalTypeMapTrimTargetType: trimTarget, + marshallingTypeMapSourceType: trimTarget, + marshallingTypeMapProxyType: proxyType.ToTypeSignature(), + metadataTypeMapSourceType: null, + metadataTypeMapProxyType: null, + interfaceTypeMapSourceType: null, + interfaceTypeMapProxyType: null, + interopReferences: interopReferences, + module: module); + } + + /// + /// Creates a new custom attribute value for for IBindableVectorView. + /// + /// The instance to use. + /// The module that the attribute will be used from. + /// Whether to use Windows.UI.Xaml projections. + private static void IBindableVectorViewType( + InteropReferences interopReferences, + ModuleDefinition module, + bool useWindowsUIXamlProjections) + { + const string windowsUIXamlTypeName = "Windows.UI.Xaml.Interop.IBindableVectorView"; + const string microsoftUIXamlTypeName = "Microsoft.UI.Xaml.Interop.IBindableVectorView"; + + TypeSignature adapterType = interopReferences.BindableIReadOnlyListAdapter.ToReferenceTypeSignature(); + string runtimeClassName = useWindowsUIXamlProjections ? windowsUIXamlTypeName : microsoftUIXamlTypeName; + + // The 'BindableIReadOnlyListAdapter' type is a special type that is only used by the 'IBindableVector.GetView()' + // implementation (as it returns an 'IBindableVectorView' instance). This type is only used as a CCW. So we need + // a proxy type for it, with the correct runtime class name, and an entry just in the marshalling proxy type map. + InteropTypeDefinitionBuilder.Proxy( + ns: InteropUtf8NameFactory.TypeNamespace(adapterType), + name: InteropUtf8NameFactory.TypeName(adapterType), + mappedMetadata: null, runtimeClassName: runtimeClassName, + metadataTypeName: null, + mappedType: null, + comWrappersMarshallerAttributeType: GetMarshallerAttributeType(adapterType, interopReferences, module), + interopReferences: interopReferences, + module: module, + out TypeDefinition adapterProxyType); + + InteropTypeDefinitionBuilder.TypeMapAttributes( + runtimeClassName: null, + metadataTypeName: null, + externalTypeMapTargetType: null, + externalTypeMapTrimTargetType: null, + marshallingTypeMapSourceType: adapterType, + marshallingTypeMapProxyType: adapterProxyType.ToTypeSignature(), + metadataTypeMapSourceType: null, + metadataTypeMapProxyType: null, + interfaceTypeMapSourceType: null, + interfaceTypeMapProxyType: null, + interopReferences: interopReferences, + module: module); + + // Retrieve the '[IReadOnlyListComWrappersMarshallerAttribute]' type from 'WinRT.Runtime.dll', which is specialized + TypeReference comWrappersMarshallerTypeReference = interopReferences.WindowsRuntimeModule.CreateTypeReference( + ns: "ABI.System.Collections"u8, + name: "IReadOnlyListComWrappersMarshallerAttribute"u8); + + // Verify that this marshaller attribute does exist correctly and can be resolved + if (comWrappersMarshallerTypeReference.Resolve(module) is not TypeDefinition comWrappersMarshallerType) + { + throw WellKnownInteropExceptions.NonProjectedTypeComWrappersMarshallerAttributeTypeResolveError(comWrappersMarshallerTypeReference, "IBindableVectorView"); + } + + // Create the proxy type to support RCW marshalling as well + InteropTypeDefinitionBuilder.Proxy( + ns: "ABI.System.Collections"u8, + name: "<#corlib>IReadOnlyList", + mappedMetadata: null, + runtimeClassName: null, + metadataTypeName: null, + mappedType: null, comWrappersMarshallerAttributeType: comWrappersMarshallerType, interopReferences: interopReferences, module: module, - out TypeDefinition proxyType); + out TypeDefinition nativeObjectProxyType); - module.Assembly!.CustomAttributes.Add(InteropCustomAttributeFactory.TypeMapWindowsRuntimeComWrappersTypeMapGroup( - value: args.UseWindowsUIXamlProjections ? windowsUIXamlTypeName : microsoftUIXamlTypeName, - target: proxyType.ToTypeSignature(), - trimTarget: trimTarget, + // Define the type map entries. We only need one in the marshalling external type map. We can use 'IEnumerable' + // as the trim target for the specialized RCW type (since the 'IReadOnlyList' interface does not exist in .NET). + InteropTypeDefinitionBuilder.TypeMapAttributes( + runtimeClassName: runtimeClassName, + metadataTypeName: null, + externalTypeMapTargetType: nativeObjectProxyType.ToTypeSignature(), + externalTypeMapTrimTargetType: interopReferences.IEnumerable.ToReferenceTypeSignature(), + marshallingTypeMapSourceType: null, + marshallingTypeMapProxyType: null, + metadataTypeMapSourceType: null, + metadataTypeMapProxyType: null, + interfaceTypeMapSourceType: null, + interfaceTypeMapProxyType: null, interopReferences: interopReferences, - module: module)); + module: module); + } + + /// + /// Retrieves the marshaller attribute associated with a specified custom-mapped type. + /// interop. + /// + /// The custom-mapped type to retrieve the marshaller attribute for. + /// The instance to use. + /// The module that the attribute will be used from. + /// The marshaller attribute type for the input type. + /// Thrown if resolving the marshaller attribute type fails. + private static TypeDefinition GetMarshallerAttributeType( + TypeSignature type, + InteropReferences interopReferences, + ModuleDefinition module) + { + // Retrieve the '[ComWrappersMarshaller]' type from 'WinRT.Runtime.dll', which always follows this naming convention + TypeReference comWrappersMarshallerTypeReference = interopReferences.WindowsRuntimeModule.CreateTypeReference( + ns: InteropUtf8NameFactory.TypeNamespace(type), + name: (Utf8String)$"{type.Name}ComWrappersMarshallerAttribute"); + + // The '[ComWrappersMarshaller]' type should always exist for all custom-mapped types, throw if it doesn't + if (comWrappersMarshallerTypeReference.Resolve(module) is not TypeDefinition comWrappersMarshallerType) + { + throw WellKnownInteropExceptions.CustomMappedTypeComWrappersMarshallerAttributeTypeResolveError(type); + } + + return comWrappersMarshallerType; } } \ No newline at end of file diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs index 164572cf5..ab01c3faa 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs @@ -899,6 +899,39 @@ public static void Marshaller( marshallerType.Methods.Add(unboxToUnmanagedMethod); } + /// + /// Creates a new type definition for the proxy type for some type. + /// + /// The for the type. + /// The instance returned by . + /// The instance to use. + /// The module that will contain the type being created. + /// Whether to use Windows.UI.Xaml projections. + /// The resulting proxy type. + public static void Proxy( + TypeSignature delegateType, + TypeDefinition comWrappersMarshallerAttributeType, + InteropReferences interopReferences, + ModuleDefinition module, + bool useWindowsUIXamlProjections, + out TypeDefinition proxyType) + { + // For delegate types, we need to both specify the mapped metadata name, so that when marshalling 'Type' instances to + // native we can correctly detect the mapped type to be a metadata type, and also annotate the proxy types with the + // '[WindowsRuntimeMetadataTypeName]', as that's different than the runtime class name (which uses 'IReference'). + InteropTypeDefinitionBuilder.Proxy( + ns: InteropUtf8NameFactory.TypeNamespace(delegateType), + name: InteropUtf8NameFactory.TypeName(delegateType), + mappedMetadata: "Windows.Foundation.FoundationContract", + runtimeClassName: RuntimeClassNameGenerator.GetRuntimeClassName(delegateType, useWindowsUIXamlProjections), + metadataTypeName: MetadataTypeNameGenerator.GetMetadataTypeName(delegateType, useWindowsUIXamlProjections), + mappedType: delegateType, + comWrappersMarshallerAttributeType: comWrappersMarshallerAttributeType, + interopReferences: interopReferences, + module: module, + out proxyType); + } + /// /// Creates the type map attributes for some type. /// @@ -908,18 +941,24 @@ public static void Marshaller( /// The module that will contain the type being created. /// Whether to use Windows.UI.Xaml projections. public static void TypeMapAttributes( - GenericInstanceTypeSignature delegateType, + TypeSignature delegateType, TypeDefinition proxyType, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections) { + // For delegate types, we also need to pass the metadata type name when setting up the type map + // attributes, as we need '[TypeMap]' entries in the metadata type map as well. + // This allows marshalling a 'TypeName' representing a Windows Runtime delegate type correctly. InteropTypeDefinitionBuilder.TypeMapAttributes( runtimeClassName: RuntimeClassNameGenerator.GetRuntimeClassName(delegateType, useWindowsUIXamlProjections), + metadataTypeName: MetadataTypeNameGenerator.GetMetadataTypeName(delegateType, useWindowsUIXamlProjections), externalTypeMapTargetType: proxyType.ToReferenceTypeSignature(), externalTypeMapTrimTargetType: delegateType, - proxyTypeMapSourceType: delegateType, - proxyTypeMapProxyType: proxyType.ToReferenceTypeSignature(), + marshallingTypeMapSourceType: delegateType, + marshallingTypeMapProxyType: proxyType.ToReferenceTypeSignature(), + metadataTypeMapSourceType: null, + metadataTypeMapProxyType: null, interfaceTypeMapSourceType: null, interfaceTypeMapProxyType: null, interopReferences: interopReferences, diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.ICollectionKeyValuePair2.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.ICollectionKeyValuePair2.cs index 322bb8b28..425735df9 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.ICollectionKeyValuePair2.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.ICollectionKeyValuePair2.cs @@ -250,10 +250,13 @@ public static void TypeMapAttributes( { InteropTypeDefinitionBuilder.TypeMapAttributes( runtimeClassName: null, + metadataTypeName: null, externalTypeMapTargetType: null, externalTypeMapTrimTargetType: null, - proxyTypeMapSourceType: null, - proxyTypeMapProxyType: null, + marshallingTypeMapSourceType: null, + marshallingTypeMapProxyType: null, + metadataTypeMapSourceType: null, + metadataTypeMapProxyType: null, interfaceTypeMapSourceType: collectionType, interfaceTypeMapProxyType: interfaceImplType.ToReferenceTypeSignature(), interopReferences: interopReferences, diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs index 62f44cf2e..7383d6fa1 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IList1.cs @@ -1091,10 +1091,13 @@ public static void TypeMapAttributes( { InteropTypeDefinitionBuilder.TypeMapAttributes( runtimeClassName: RuntimeClassNameGenerator.GetRuntimeClassName(listType, useWindowsUIXamlProjections), + metadataTypeName: null, externalTypeMapTargetType: proxyType.ToReferenceTypeSignature(), externalTypeMapTrimTargetType: listType, - proxyTypeMapSourceType: null, - proxyTypeMapProxyType: null, + marshallingTypeMapSourceType: null, + marshallingTypeMapProxyType: null, + metadataTypeMapSourceType: listType, + metadataTypeMapProxyType: proxyType.ToReferenceTypeSignature(), interfaceTypeMapSourceType: listType, interfaceTypeMapProxyType: interfaceImplType.ToReferenceTypeSignature(), interopReferences: interopReferences, @@ -1108,10 +1111,13 @@ public static void TypeMapAttributes( { InteropTypeDefinitionBuilder.TypeMapAttributes( runtimeClassName: null, + metadataTypeName: null, externalTypeMapTargetType: null, externalTypeMapTrimTargetType: null, - proxyTypeMapSourceType: null, - proxyTypeMapProxyType: null, + marshallingTypeMapSourceType: null, + marshallingTypeMapProxyType: null, + metadataTypeMapSourceType: null, + metadataTypeMapProxyType: null, interfaceTypeMapSourceType: interopReferences.ICollection1.MakeGenericReferenceType(elementType), interfaceTypeMapProxyType: interfaceImplType.ToReferenceTypeSignature(), interopReferences: interopReferences, diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyCollectionKeyValuePair2.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyCollectionKeyValuePair2.cs index 612b188b6..6f976dd83 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyCollectionKeyValuePair2.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyCollectionKeyValuePair2.cs @@ -136,10 +136,13 @@ public static void TypeMapAttributes( { InteropTypeDefinitionBuilder.TypeMapAttributes( runtimeClassName: null, + metadataTypeName: null, externalTypeMapTargetType: null, externalTypeMapTrimTargetType: null, - proxyTypeMapSourceType: null, - proxyTypeMapProxyType: null, + marshallingTypeMapSourceType: null, + marshallingTypeMapProxyType: null, + metadataTypeMapSourceType: null, + metadataTypeMapProxyType: null, interfaceTypeMapSourceType: readOnlyCollectionType, interfaceTypeMapProxyType: interfaceImplType.ToReferenceTypeSignature(), interopReferences: interopReferences, diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyList1.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyList1.cs index a431d01a0..86b5ffc0e 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyList1.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyList1.cs @@ -472,10 +472,13 @@ public static void TypeMapAttributes( { InteropTypeDefinitionBuilder.TypeMapAttributes( runtimeClassName: RuntimeClassNameGenerator.GetRuntimeClassName(readOnlyListType, useWindowsUIXamlProjections), + metadataTypeName: null, externalTypeMapTargetType: proxyType.ToReferenceTypeSignature(), externalTypeMapTrimTargetType: readOnlyListType, - proxyTypeMapSourceType: null, - proxyTypeMapProxyType: null, + marshallingTypeMapSourceType: null, + marshallingTypeMapProxyType: null, + metadataTypeMapSourceType: readOnlyListType, + metadataTypeMapProxyType: proxyType.ToReferenceTypeSignature(), interfaceTypeMapSourceType: readOnlyListType, interfaceTypeMapProxyType: interfaceImplType.ToReferenceTypeSignature(), interopReferences: interopReferences, @@ -490,10 +493,13 @@ public static void TypeMapAttributes( { InteropTypeDefinitionBuilder.TypeMapAttributes( runtimeClassName: null, + metadataTypeName: null, externalTypeMapTargetType: null, externalTypeMapTrimTargetType: null, - proxyTypeMapSourceType: null, - proxyTypeMapProxyType: null, + marshallingTypeMapSourceType: null, + marshallingTypeMapProxyType: null, + metadataTypeMapSourceType: null, + metadataTypeMapProxyType: null, interfaceTypeMapSourceType: interopReferences.IReadOnlyCollection1.MakeGenericReferenceType(elementType), interfaceTypeMapProxyType: interfaceImplType.ToReferenceTypeSignature(), interopReferences: interopReferences, diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.KeyValuePair.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.KeyValuePair.cs index 097797bab..f14a202bf 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.KeyValuePair.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.KeyValuePair.cs @@ -431,16 +431,49 @@ public static void ComWrappersMarshallerAttribute( marshallerAttributeType.Methods.Add(createObjectMethod); } + /// + /// Creates a new type definition for the proxy type of some type. + /// + /// The for the type. + /// The instance returned by . + /// The instance to use. + /// The module that will contain the type being created. + /// Whether to use Windows.UI.Xaml projections. + /// The resulting proxy type. + public static void Proxy( + TypeSignature keyValuePairType, + TypeDefinition comWrappersMarshallerAttributeType, + InteropReferences interopReferences, + ModuleDefinition module, + bool useWindowsUIXamlProjections, + out TypeDefinition proxyType) + { + // For 'KeyValuePair' types, we need to specify the mapped metadata name, so that when marshalling + // 'Type' instances to native we can correctly detect the mapped type to be a metadata type. We also need to + // reference the mapped type, so that we can retrieve the original 'Type' instance when marshalling from native. + InteropTypeDefinitionBuilder.Proxy( + ns: InteropUtf8NameFactory.TypeNamespace(keyValuePairType), + name: InteropUtf8NameFactory.TypeName(keyValuePairType), + mappedMetadata: "Windows.Foundation.FoundationContract", + runtimeClassName: RuntimeClassNameGenerator.GetRuntimeClassName(keyValuePairType, useWindowsUIXamlProjections), + metadataTypeName: null, + mappedType: keyValuePairType, + comWrappersMarshallerAttributeType: comWrappersMarshallerAttributeType, + interopReferences: interopReferences, + module: module, + out proxyType); + } + /// /// Creates the type map attributes for some type. /// /// The for the type. - /// The instance returned by . + /// The instance returned by . /// The instance to use. /// The module that will contain the type being created. /// Whether to use Windows.UI.Xaml projections. public static void TypeMapAttributes( - GenericInstanceTypeSignature keyValuePairType, + TypeSignature keyValuePairType, TypeDefinition proxyType, InteropReferences interopReferences, ModuleDefinition module, @@ -448,10 +481,13 @@ public static void TypeMapAttributes( { InteropTypeDefinitionBuilder.TypeMapAttributes( runtimeClassName: RuntimeClassNameGenerator.GetRuntimeClassName(keyValuePairType, useWindowsUIXamlProjections), + metadataTypeName: null, externalTypeMapTargetType: proxyType.ToReferenceTypeSignature(), externalTypeMapTrimTargetType: keyValuePairType, - proxyTypeMapSourceType: keyValuePairType, - proxyTypeMapProxyType: proxyType.ToReferenceTypeSignature(), + marshallingTypeMapSourceType: keyValuePairType, + marshallingTypeMapProxyType: proxyType.ToReferenceTypeSignature(), + metadataTypeMapSourceType: null, + metadataTypeMapProxyType: null, interfaceTypeMapSourceType: null, interfaceTypeMapProxyType: null, interopReferences: interopReferences, diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.SzArray.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.SzArray.cs index ca0638351..cc4aa9809 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.SzArray.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.SzArray.cs @@ -530,11 +530,45 @@ public static void ComWrappersMarshallerAttribute( marshallerType.Methods.Add(createObjectMethod); } + /// + /// Creates a new type definition for the proxy type for some SZ array type. + /// + /// The for the SZ array type. + /// The instance for the marshaller attribute type. + /// The instance to use. + /// The module that will contain the type being created. + /// Whether to use Windows.UI.Xaml projections. + /// The resulting proxy type. + public static void Proxy( + SzArrayTypeSignature arrayType, + TypeDefinition comWrappersMarshallerAttributeType, + InteropReferences interopReferences, + ModuleDefinition module, + bool useWindowsUIXamlProjections, + out TypeDefinition proxyType) + { + // This is a proxy for Windows Runtime arrays, so we also need to emit the '[WindowsRuntimeMappedMetadata]' + // attribute, so that during 'TypeName' marshalling we can detect whether the type is a metadata type. Note + // that arrays with element types that are not Windows Runtime types will still have entries in the marshalling + // type map (as they're treated the same as normal user-defined types), so this allows us to distinguish them. + InteropTypeDefinitionBuilder.Proxy( + ns: InteropUtf8NameFactory.TypeNamespace(arrayType), + name: InteropUtf8NameFactory.TypeName(arrayType), + mappedMetadata: "Windows.Foundation.FoundationContract", + runtimeClassName: RuntimeClassNameGenerator.GetRuntimeClassName(arrayType, useWindowsUIXamlProjections), + metadataTypeName: null, + mappedType: arrayType, + comWrappersMarshallerAttributeType: comWrappersMarshallerAttributeType, + interopReferences: interopReferences, + module: module, + proxyType: out proxyType); + } + /// /// Creates the type map attributes for some SZ array type. /// /// The for the SZ array type. - /// The instance returned by . + /// The instance returned by . /// The instance to use. /// Whether to use Windows.UI.Xaml projections. /// The module that will contain the type being created. @@ -547,10 +581,13 @@ public static void TypeMapAttributes( { InteropTypeDefinitionBuilder.TypeMapAttributes( runtimeClassName: RuntimeClassNameGenerator.GetRuntimeClassName(arrayType, useWindowsUIXamlProjections), + metadataTypeName: null, externalTypeMapTargetType: proxyType.ToReferenceTypeSignature(), externalTypeMapTrimTargetType: arrayType, - proxyTypeMapSourceType: arrayType, - proxyTypeMapProxyType: proxyType.ToReferenceTypeSignature(), + marshallingTypeMapSourceType: arrayType, + marshallingTypeMapProxyType: proxyType.ToReferenceTypeSignature(), + metadataTypeMapSourceType: null, + metadataTypeMapProxyType: null, interfaceTypeMapSourceType: null, interfaceTypeMapProxyType: null, interopReferences: interopReferences, diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.UserDefinedType.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.UserDefinedType.cs index c2f412b07..a93cc1618 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.UserDefinedType.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.UserDefinedType.cs @@ -272,8 +272,10 @@ public static void Proxy( InteropTypeDefinitionBuilder.Proxy( ns: InteropUtf8NameFactory.TypeNamespace(userDefinedType), name: InteropUtf8NameFactory.TypeName(userDefinedType), - mappedType: userDefinedType, + mappedMetadata: null, runtimeClassName: null, + metadataTypeName: null, + mappedType: userDefinedType, comWrappersMarshallerAttributeType: comWrappersMarshallerAttributeType, interopReferences: interopReferences, module: module, @@ -296,8 +298,10 @@ public static void Proxy( InteropTypeDefinitionBuilder.Proxy( ns: InteropUtf8NameFactory.TypeNamespace(userDefinedType), name: InteropUtf8NameFactory.TypeName(userDefinedType), - mappedType: userDefinedType, + mappedMetadata: null, runtimeClassName: RuntimeClassNameGenerator.GetRuntimeClassName(interfaceType, useWindowsUIXamlProjections), + metadataTypeName: null, + mappedType: null, comWrappersMarshallerAttributeType: comWrappersMarshallerAttributeType, interopReferences: interopReferences, module: module, @@ -320,10 +324,13 @@ public static void TypeMapAttributes( { InteropTypeDefinitionBuilder.TypeMapAttributes( runtimeClassName: null, + metadataTypeName: null, externalTypeMapTargetType: null, externalTypeMapTrimTargetType: null, - proxyTypeMapSourceType: userDefinedType, - proxyTypeMapProxyType: proxyType.ToReferenceTypeSignature(), + marshallingTypeMapSourceType: userDefinedType, + marshallingTypeMapProxyType: proxyType.ToReferenceTypeSignature(), + metadataTypeMapSourceType: null, + metadataTypeMapProxyType: null, interfaceTypeMapSourceType: null, interfaceTypeMapProxyType: null, interopReferences: interopReferences, diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.cs index 510153aa7..b3a796e66 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.cs @@ -679,27 +679,34 @@ private static void InterfaceEntriesImpl( } /// - /// Creates a new type definition for the proxy type of some managed type. + /// Creates a new type definition for the proxy type of some interface type. /// - /// The for the mapped type the proxy type is for. + /// The for the mapped type the proxy type is for. /// The instance for the marshaller attribute type. /// The instance to use. /// The module that will contain the type being created. /// Whether to use Windows.UI.Xaml projections. /// The resulting proxy type. public static void Proxy( - TypeSignature mappedType, + TypeSignature interfaceType, TypeDefinition comWrappersMarshallerAttributeType, InteropReferences interopReferences, ModuleDefinition module, bool useWindowsUIXamlProjections, out TypeDefinition proxyType) { + // This method is only used with interface types. Because of this, we need also emit the + // '[WindowsRuntimeMappedType]' attribute, so that 'TypeName' marshalling can retrieve + // the proxy type containing the runtime class name from the input managed type. We also + // emit '[WindowsRuntimeMetadataTypeName]', to support mapping the generic interface name + // when marshalling 'TypeName' instances. Nobody would need a runtime class name here. Proxy( - ns: InteropUtf8NameFactory.TypeNamespace(mappedType), - name: InteropUtf8NameFactory.TypeName(mappedType), - mappedType: mappedType, - runtimeClassName: RuntimeClassNameGenerator.GetRuntimeClassName(mappedType, useWindowsUIXamlProjections), + ns: InteropUtf8NameFactory.TypeNamespace(interfaceType), + name: InteropUtf8NameFactory.TypeName(interfaceType), + mappedMetadata: null, + runtimeClassName: null, + metadataTypeName: MetadataTypeNameGenerator.GetMetadataTypeName(interfaceType, useWindowsUIXamlProjections), + mappedType: interfaceType, comWrappersMarshallerAttributeType: comWrappersMarshallerAttributeType, interopReferences: interopReferences, module: module, @@ -711,8 +718,10 @@ public static void Proxy( /// /// The namespace for the type. /// The type name. - /// The for the mapped type the proxy type is for. - /// The runtime class name for the managed type (if null, the source type will be used). + /// The name of the mapped metadata for the proxy type (if , the attribute will be omitted). + /// The runtime class name for the managed type (if , the attribute will be omitted). + /// The metadata type name for the managed type (if , the attribute will be omitted). + /// The for the mapped type the proxy type is for (if , the attribute will be omitted). /// The instance for the marshaller attribute type. /// The instance to use. /// The module that will contain the type being created. @@ -720,8 +729,10 @@ public static void Proxy( public static void Proxy( Utf8String ns, Utf8String name, - TypeSignature mappedType, + string? mappedMetadata, string? runtimeClassName, + string? metadataTypeName, + TypeSignature? mappedType, TypeDefinition comWrappersMarshallerAttributeType, InteropReferences interopReferences, ModuleDefinition module, @@ -736,19 +747,40 @@ public static void Proxy( module.TopLevelTypes.Add(proxyType); + // Add the '[WindowsRuntimeMappedMetadata]' attribute with the provided .winmd name, if available + if (mappedMetadata is not null) + { + proxyType.CustomAttributes.Add(new CustomAttribute( + constructor: interopReferences.WindowsRuntimeMappedMetadataAttribute_ctor.Import(module), + signature: new CustomAttributeSignature(new CustomAttributeArgument( + argumentType: module.CorLibTypeFactory.String, + value: mappedMetadata)))); + } + + // Add the '[WindowsRuntimeClassName]' attribute with the provided runtime class name, if available if (runtimeClassName is not null) { - // Add the '[WindowsRuntimeClassName]' attribute with the provided runtime class name proxyType.CustomAttributes.Add(new CustomAttribute( constructor: interopReferences.WindowsRuntimeClassNameAttribute_ctor.Import(module), signature: new CustomAttributeSignature(new CustomAttributeArgument( argumentType: module.CorLibTypeFactory.String, value: runtimeClassName)))); } - else + + // Add the '[WindowsRuntimeMetadataTypeName]' attribute with the provided metadata type name, if available + if (metadataTypeName is not null) + { + proxyType.CustomAttributes.Add(new CustomAttribute( + constructor: interopReferences.WindowsRuntimeMetadataTypeNameAttribute_ctor.Import(module), + signature: new CustomAttributeSignature(new CustomAttributeArgument( + argumentType: module.CorLibTypeFactory.String, + value: metadataTypeName)))); + } + + // Add the '[WindowsRuntimeMappedType]' attribute with the provided mapped type, if available. + // This allows retrieving the user-provided runtime class name from the original managed type. + if (mappedType is not null) { - // Add the '[WindowsRuntimeMappedType]' attribute with the provided mapped type. This allows - // the runtime to retrieve the user-provided runtime class name from the original type. proxyType.CustomAttributes.Add(new CustomAttribute( constructor: interopReferences.WindowsRuntimeMappedTypeAttribute_ctor.Import(module), signature: new CustomAttributeSignature(new CustomAttributeArgument( @@ -779,10 +811,13 @@ public static void TypeMapAttributes( { TypeMapAttributes( runtimeClassName: RuntimeClassNameGenerator.GetRuntimeClassName(interfaceType, useWindowsUIXamlProjections), + metadataTypeName: null, externalTypeMapTargetType: proxyType.ToReferenceTypeSignature(), externalTypeMapTrimTargetType: interfaceType, - proxyTypeMapSourceType: null, - proxyTypeMapProxyType: null, + marshallingTypeMapSourceType: null, + marshallingTypeMapProxyType: null, + metadataTypeMapSourceType: interfaceType, + metadataTypeMapProxyType: proxyType.ToReferenceTypeSignature(), interfaceTypeMapSourceType: interfaceType, interfaceTypeMapProxyType: interfaceImplType.ToReferenceTypeSignature(), interopReferences: interopReferences, @@ -792,28 +827,34 @@ public static void TypeMapAttributes( /// /// Creates the type map attributes for a given type. /// - /// The runtime class name for the managed type. + /// The runtime class name for the managed type (if , the attribute will be omitted). + /// The metadata type name for the managed type (if , the attribute will be omitted). /// The target type for . /// The trim target type for . - /// The source type for . - /// The proxy type for . + /// The source type for . + /// The proxy type for . + /// The source type for . + /// The proxy type for . /// The IDIC source type for . /// The IDIC proxy type for . /// The instance to use. /// The module that will contain the type being created. public static void TypeMapAttributes( string? runtimeClassName, + string? metadataTypeName, [NotNullIfNotNull(nameof(runtimeClassName))] TypeSignature? externalTypeMapTargetType, [NotNullIfNotNull(nameof(runtimeClassName))] TypeSignature? externalTypeMapTrimTargetType, - [NotNullIfNotNull(nameof(proxyTypeMapProxyType))] TypeSignature? proxyTypeMapSourceType, - [NotNullIfNotNull(nameof(proxyTypeMapSourceType))] TypeSignature? proxyTypeMapProxyType, + [NotNullIfNotNull(nameof(marshallingTypeMapProxyType))] TypeSignature? marshallingTypeMapSourceType, + [NotNullIfNotNull(nameof(marshallingTypeMapSourceType))] TypeSignature? marshallingTypeMapProxyType, + [NotNullIfNotNull(nameof(metadataTypeMapProxyType))] TypeSignature? metadataTypeMapSourceType, + [NotNullIfNotNull(nameof(metadataTypeMapSourceType))] TypeSignature? metadataTypeMapProxyType, [NotNullIfNotNull(nameof(interfaceTypeMapProxyType))] TypeSignature? interfaceTypeMapSourceType, [NotNullIfNotNull(nameof(interfaceTypeMapSourceType))] TypeSignature? interfaceTypeMapProxyType, InteropReferences interopReferences, ModuleDefinition module) { // Emit the '[TypeMap]' attribute for the external type map. - // This is optional, only needed for projected types. + // This is optional, only needed for custom-mapped or projected types. if (runtimeClassName is not null) { module.Assembly!.CustomAttributes.Add(InteropCustomAttributeFactory.TypeMapWindowsRuntimeComWrappersTypeMapGroup( @@ -824,13 +865,36 @@ public static void TypeMapAttributes( module: module)); } + // Emit the '[TypeMap]' attribute for the metadata type map. + // This is also optional, only needed for some 'TypeName' marshalling cases. + if (metadataTypeName is not null) + { + module.Assembly!.CustomAttributes.Add(InteropCustomAttributeFactory.TypeMapWindowsRuntimeMetadataTypeMapGroup( + value: metadataTypeName, + target: externalTypeMapTargetType!, + trimTarget: externalTypeMapTrimTargetType!, + interopReferences: interopReferences, + module: module)); + } + // Emit the '[TypeMapAssociation]' attribute for the proxy type map. - // This is only needed for types that can actually be instantiated. - if (proxyTypeMapSourceType is not null) + // This is only needed for types that can actually be instantiated (e.g. classes). + if (marshallingTypeMapSourceType is not null) { module.Assembly!.CustomAttributes.Add(InteropCustomAttributeFactory.TypeMapAssociationWindowsRuntimeComWrappersTypeMapGroup( - source: proxyTypeMapSourceType, - proxy: proxyTypeMapProxyType!, + source: marshallingTypeMapSourceType, + proxy: marshallingTypeMapProxyType!, + interopReferences: interopReferences, + module: module)); + } + + // Emit the '[TypeMapAssociation]' attribute for the metadata type map. + // This is not always needed, but it is for types that cannot actually be instantiated. + if (metadataTypeMapSourceType is not null) + { + module.Assembly!.CustomAttributes.Add(InteropCustomAttributeFactory.TypeMapAssociationWindowsRuntimeMetadataTypeMapGroup( + source: metadataTypeMapSourceType, + proxy: metadataTypeMapProxyType!, interopReferences: interopReferences, module: module)); } diff --git a/src/WinRT.Interop.Generator/Errors/WellKnownInteropExceptions.cs b/src/WinRT.Interop.Generator/Errors/WellKnownInteropExceptions.cs index 6f89ef7b2..f3cea8eea 100644 --- a/src/WinRT.Interop.Generator/Errors/WellKnownInteropExceptions.cs +++ b/src/WinRT.Interop.Generator/Errors/WellKnownInteropExceptions.cs @@ -424,7 +424,7 @@ public static WellKnownInteropException DynamicDynamicCustomMappedTypeMapEntries /// /// Failed to resolve the associated ComWrappersMarshallerAttribute type for a custom-mapped type. /// - public static WellKnownInteropException CustomMappedTypeComWrappersMarshallerAttributeTypeResolveError(TypeReference type) + public static WellKnownInteropException CustomMappedTypeComWrappersMarshallerAttributeTypeResolveError(TypeSignature type) { return Exception(48, $"Failed to resolve the associated 'ComWrappersMarshallerAttribute' type for the custom-mapped type '{type}'."); } @@ -633,6 +633,22 @@ public static WellKnownInteropException TrackedMethodDefinitionLookupError(TypeS return Exception(73, $"Failed to find a tracked method definition for signature '{typeSignature}' and key '{key}'."); } + /// + /// Failed to generate the runtime class name of some Windows Runtime type. + /// + public static Exception RuntimeClassNameGenerationError(TypeSignature type) + { + return Exception(74, $"Failed to generate the runtime class name for type '{type}'."); + } + + /// + /// Failed to resolve the target ComWrappersMarshallerAttribute type for a non-projected Windows Runtime type. + /// + public static WellKnownInteropException NonProjectedTypeComWrappersMarshallerAttributeTypeResolveError(TypeReference attributeType, string nativeType) + { + return Exception(75, $"Failed to resolve the 'ComWrappersMarshallerAttribute' type '{attributeType}' for a non-projected Windows Runtime type '{nativeType}'."); + } + /// /// Creates a new exception with the specified id and message. /// diff --git a/src/WinRT.Interop.Generator/Extensions/TypeSignatureExtensions.cs b/src/WinRT.Interop.Generator/Extensions/TypeSignatureExtensions.cs index eb1cdfa5a..83d20d61b 100644 --- a/src/WinRT.Interop.Generator/Extensions/TypeSignatureExtensions.cs +++ b/src/WinRT.Interop.Generator/Extensions/TypeSignatureExtensions.cs @@ -16,6 +16,11 @@ internal static class TypeSignatureExtensions { extension(TypeSignature signature) { + /// + /// Gets whether the current type is a (constructed) generic type. + /// + public bool IsGenericType => signature.ElementType is ElementType.GenericInst; + /// /// Determines whether the current type is assignable from the provided type. /// diff --git a/src/WinRT.Interop.Generator/Factories/InteropCustomAttributeFactory.cs b/src/WinRT.Interop.Generator/Factories/InteropCustomAttributeFactory.cs index 5ca037d71..239539962 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropCustomAttributeFactory.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropCustomAttributeFactory.cs @@ -193,6 +193,65 @@ public static CustomAttribute TypeMapAssociationWindowsRuntimeComWrappersTypeMap value: proxy.Import(module))])); } + /// + /// Creates a new custom attribute value for (and imports all metadata elements for it). + /// + /// + /// + /// + /// The instance to use. + /// The module that the attribute will be used from. + /// The resulting instance. + public static CustomAttribute TypeMapWindowsRuntimeMetadataTypeMapGroup( + string value, + TypeSignature target, + TypeSignature trimTarget, + InteropReferences interopReferences, + ModuleDefinition module) + { + // Create the following attribute: + // + // [TypeMap(, , )] + return new(interopReferences.TypeMapAttributeWindowsRuntimeMetadataTypeMapGroup_ctor_TrimTarget.Import(module), new CustomAttributeSignature( + fixedArguments: [ + new CustomAttributeArgument( + argumentType: module.CorLibTypeFactory.String, + value: value), + new CustomAttributeArgument( + argumentType: interopReferences.Type.Import(module).ToReferenceTypeSignature(), + value: target.Import(module)), + new CustomAttributeArgument( + argumentType: interopReferences.Type.Import(module).ToReferenceTypeSignature(), + value: trimTarget.Import(module))])); + } + + /// + /// Creates a new custom attribute value for (and imports all metadata elements for it). + /// + /// + /// + /// The instance to use. + /// The module that the attribute will be used from. + /// The resulting instance. + public static CustomAttribute TypeMapAssociationWindowsRuntimeMetadataTypeMapGroup( + TypeSignature source, + TypeSignature proxy, + InteropReferences interopReferences, + ModuleDefinition module) + { + // Create the following attribute: + // + // [TypeMap(, )] + return new(interopReferences.TypeMapAssociationAttributeWindowsRuntimeMetadataTypeMapGroup_ctor.Import(module), new CustomAttributeSignature( + fixedArguments: [ + new CustomAttributeArgument( + argumentType: interopReferences.Type.Import(module).ToReferenceTypeSignature(), + value: source.Import(module)), + new CustomAttributeArgument( + argumentType: interopReferences.Type.Import(module).ToReferenceTypeSignature(), + value: proxy.Import(module))])); + } + /// /// Creates a new custom attribute value for (and imports all metadata elements for it). /// diff --git a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs index 071c94ff6..93eabbf99 100644 --- a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs +++ b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs @@ -354,8 +354,8 @@ private static void DefineGenericDelegateTypes( module: module, out TypeDefinition delegateComWrappersMarshallerType); - InteropTypeDefinitionBuilder.Proxy( - mappedType: typeSignature, + InteropTypeDefinitionBuilder.Delegate.Proxy( + delegateType: typeSignature, comWrappersMarshallerAttributeType: delegateComWrappersMarshallerType, interopReferences: interopReferences, module: module, @@ -520,7 +520,7 @@ private static void DefineIEnumeratorTypes( interfaceImplType: out TypeDefinition interfaceImplType); InteropTypeDefinitionBuilder.Proxy( - mappedType: typeSignature, + interfaceType: typeSignature, comWrappersMarshallerAttributeType: enumeratorComWrappersMarshallerType, interopReferences: interopReferences, module: module, @@ -646,7 +646,7 @@ private static void DefineIEnumerableTypes( interfaceImplType: out TypeDefinition interfaceImplType); InteropTypeDefinitionBuilder.Proxy( - mappedType: typeSignature, + interfaceType: typeSignature, comWrappersMarshallerAttributeType: enumerableComWrappersMarshallerType, interopReferences: interopReferences, module: module, @@ -775,7 +775,7 @@ private static void DefineIReadOnlyListTypes( interfaceImplType: out TypeDefinition interfaceImplType); InteropTypeDefinitionBuilder.Proxy( - mappedType: typeSignature, + interfaceType: typeSignature, comWrappersMarshallerAttributeType: readOnlyListComWrappersMarshallerType, interopReferences: interopReferences, module: module, @@ -912,7 +912,7 @@ private static void DefineIListTypes( interfaceImplType: out TypeDefinition interfaceImplType); InteropTypeDefinitionBuilder.Proxy( - mappedType: typeSignature, + interfaceType: typeSignature, comWrappersMarshallerAttributeType: listComWrappersMarshallerType, interopReferences: interopReferences, module: module, @@ -1041,7 +1041,7 @@ private static void DefineIReadOnlyDictionaryTypes( interfaceImplType: out TypeDefinition interfaceImplType); InteropTypeDefinitionBuilder.Proxy( - mappedType: typeSignature, + interfaceType: typeSignature, comWrappersMarshallerAttributeType: readOnlyDictionaryComWrappersMarshallerType, interopReferences: interopReferences, module: module, @@ -1178,7 +1178,7 @@ private static void DefineIDictionaryTypes( interfaceImplType: out TypeDefinition interfaceImplType); InteropTypeDefinitionBuilder.Proxy( - mappedType: typeSignature, + interfaceType: typeSignature, comWrappersMarshallerAttributeType: dictionaryComWrappersMarshallerType, interopReferences: interopReferences, module: module, @@ -1294,8 +1294,8 @@ private static void DefineKeyValuePairTypes( module: module, marshallerAttributeType: out TypeDefinition marshallerAttributeType); - InteropTypeDefinitionBuilder.Proxy( - mappedType: typeSignature, + InteropTypeDefinitionBuilder.KeyValuePair.Proxy( + keyValuePairType: typeSignature, comWrappersMarshallerAttributeType: marshallerAttributeType, interopReferences: interopReferences, module: module, @@ -1405,7 +1405,7 @@ private static void DefineIMapChangedEventArgsTypes( interfaceImplType: out TypeDefinition interfaceImplType); InteropTypeDefinitionBuilder.Proxy( - mappedType: typeSignature, + interfaceType: typeSignature, comWrappersMarshallerAttributeType: argsComWrappersMarshallerType, interopReferences: interopReferences, module: module, @@ -1526,7 +1526,7 @@ private static void DefineIObservableVectorTypes( interfaceImplType: out TypeDefinition interfaceImplType); InteropTypeDefinitionBuilder.Proxy( - mappedType: typeSignature, + interfaceType: typeSignature, comWrappersMarshallerAttributeType: comWrappersMarshallerType, interopReferences: interopReferences, module: module, @@ -1647,7 +1647,7 @@ private static void DefineIObservableMapTypes( interfaceImplType: out TypeDefinition interfaceImplType); InteropTypeDefinitionBuilder.Proxy( - mappedType: typeSignature, + interfaceType: typeSignature, comWrappersMarshallerAttributeType: comWrappersMarshallerType, interopReferences: interopReferences, module: module, @@ -1758,7 +1758,7 @@ private static void DefineIAsyncActionWithProgressTypes( interfaceImplType: out TypeDefinition interfaceImplType); InteropTypeDefinitionBuilder.Proxy( - mappedType: typeSignature, + interfaceType: typeSignature, comWrappersMarshallerAttributeType: actionComWrappersMarshallerType, interopReferences: interopReferences, module: module, @@ -1869,7 +1869,7 @@ private static void DefineIAsyncOperationTypes( interfaceImplType: out TypeDefinition interfaceImplType); InteropTypeDefinitionBuilder.Proxy( - mappedType: typeSignature, + interfaceType: typeSignature, comWrappersMarshallerAttributeType: operationComWrappersMarshallerType, interopReferences: interopReferences, module: module, @@ -1980,7 +1980,7 @@ private static void DefineIAsyncOperationWithProgressTypes( interfaceImplType: out TypeDefinition interfaceImplType); InteropTypeDefinitionBuilder.Proxy( - mappedType: typeSignature, + interfaceType: typeSignature, comWrappersMarshallerAttributeType: operationComWrappersMarshallerType, interopReferences: interopReferences, module: module, @@ -2190,8 +2190,8 @@ private static void DefineSzArrayTypes( module: module, out TypeDefinition arrayComWrappersMarshallerType); - InteropTypeDefinitionBuilder.Proxy( - mappedType: typeSignature, + InteropTypeDefinitionBuilder.SzArray.Proxy( + arrayType: typeSignature, comWrappersMarshallerAttributeType: arrayComWrappersMarshallerType, interopReferences: interopReferences, module: module, diff --git a/src/WinRT.Interop.Generator/Helpers/MetadataTypeNameGenerator.cs b/src/WinRT.Interop.Generator/Helpers/MetadataTypeNameGenerator.cs new file mode 100644 index 000000000..59a83dae6 --- /dev/null +++ b/src/WinRT.Interop.Generator/Helpers/MetadataTypeNameGenerator.cs @@ -0,0 +1,92 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Runtime.CompilerServices; +using AsmResolver.DotNet.Signatures; + +namespace WindowsRuntime.InteropGenerator.Helpers; + +/// +/// A generator for metadata type names of Windows Runtime types. +/// +internal static class MetadataTypeNameGenerator +{ + /// + /// Generates the Windows Runtime metadata type name for a (potentially generic) type, + /// applying known type-name mappings and recursively formatting generic arguments. + /// + /// The to generate the Windows Runtime metadata type name for. + /// Whether to use Windows.UI.Xaml projections. + /// The resulting Windows Runtime metadata type name for . + public static string GetMetadataTypeName(TypeSignature type, bool useWindowsUIXamlProjections) + { + DefaultInterpolatedStringHandler handler = new(0, 0, null, stackalloc char[256]); + + AppendMetadataTypeName(ref handler, type, useWindowsUIXamlProjections); + + return handler.ToStringAndClear(); + } + + /// + /// Appends the Windows Runtime metadata type name for a (potentially generic) type, + /// applying known type-name mappings and recursively formatting generic arguments. + /// + /// The value to append to. + /// The to generate the Windows Runtime metadata type name for. + /// Whether to use Windows.UI.Xaml projections. + /// The resulting Windows Runtime metadata type name for . + public static void AppendMetadataTypeName( + ref DefaultInterpolatedStringHandler interpolatedStringHandler, + TypeSignature type, + bool useWindowsUIXamlProjections) + { + // Handle SZ array types and map them to 'IReferenceArray' type names + if (type is SzArrayTypeSignature szArrayTypeSignature) + { + interpolatedStringHandler.AppendLiteral("Windows.Foundation.IReferenceArray`1<"); + + AppendMetadataTypeName(ref interpolatedStringHandler, szArrayTypeSignature.BaseType, useWindowsUIXamlProjections); + + interpolatedStringHandler.AppendLiteral(">"); + } + else if (type is GenericInstanceTypeSignature genericInstanceTypeSignature) + { + // For constructed generic types, we first format the generic type (with a mapped + // name, if applicable), and then recursively process all generic type arguments. + if (TypeMapping.TryFindMappedTypeName(genericInstanceTypeSignature.GenericType.FullName, useWindowsUIXamlProjections, out string? mappedTypeName)) + { + interpolatedStringHandler.AppendLiteral(mappedTypeName); + } + else + { + interpolatedStringHandler.AppendLiteral(genericInstanceTypeSignature.GenericType.FullName); + } + + interpolatedStringHandler.AppendLiteral("<"); + + // Recursively format each type argument + for (int i = 0; i < genericInstanceTypeSignature.TypeArguments.Count; i++) + { + // Add the ', ' separator after the first type argument + if (i > 0) + { + interpolatedStringHandler.AppendLiteral(", "); + } + + AppendMetadataTypeName(ref interpolatedStringHandler, genericInstanceTypeSignature.TypeArguments[i], useWindowsUIXamlProjections); + } + + interpolatedStringHandler.AppendLiteral(">"); + } + else if (TypeMapping.TryFindMappedTypeName(type.FullName, useWindowsUIXamlProjections, out string? simpleMappedTypeName)) + { + // We have a simple, non-generic type, so format its mapped type if available + interpolatedStringHandler.AppendLiteral(simpleMappedTypeName); + } + else + { + // Otherwise the type must be a projected type, so just format the full name + interpolatedStringHandler.AppendLiteral(type.FullName); + } + } +} diff --git a/src/WinRT.Interop.Generator/Helpers/RuntimeClassNameGenerator.cs b/src/WinRT.Interop.Generator/Helpers/RuntimeClassNameGenerator.cs index a586814cc..0aef68361 100644 --- a/src/WinRT.Interop.Generator/Helpers/RuntimeClassNameGenerator.cs +++ b/src/WinRT.Interop.Generator/Helpers/RuntimeClassNameGenerator.cs @@ -2,7 +2,9 @@ // Licensed under the MIT License. using System.Runtime.CompilerServices; +using AsmResolver.DotNet; using AsmResolver.DotNet.Signatures; +using WindowsRuntime.InteropGenerator.Errors; namespace WindowsRuntime.InteropGenerator.Helpers; @@ -22,64 +24,33 @@ public static string GetRuntimeClassName(TypeSignature type, bool useWindowsUIXa { DefaultInterpolatedStringHandler handler = new(0, 0, null, stackalloc char[256]); - // Helper to format a full type signature into a target interpolated handler - static void AppendRuntimeClassName( - ref DefaultInterpolatedStringHandler interpolatedStringHandler, - TypeSignature type, - bool useWindowsUIXamlProjections) + // We need to be able to resolve the type definition to determine whether we need + // to wrap the metadata type name within "IReference`1<...>" (e.g. for delegates). + if (type.Resolve() is not TypeDefinition typeDefinition) { - // Handle SZ array types and map them to 'IReferenceArray' type names - if (type is SzArrayTypeSignature szArrayTypeSignature) - { - interpolatedStringHandler.AppendLiteral("Windows.Foundation.IReferenceArray`1<"); - - AppendRuntimeClassName(ref interpolatedStringHandler, szArrayTypeSignature.BaseType, useWindowsUIXamlProjections); + throw WellKnownInteropExceptions.RuntimeClassNameGenerationError(type); + } - interpolatedStringHandler.AppendLiteral(">"); - } - else if (type is GenericInstanceTypeSignature genericInstanceTypeSignature) - { - // For constructed generic types, we first format the generic type (with a mapped - // name, if applicable), and then recursively process all generic type arguments. - if (TypeMapping.TryFindMappedTypeName(genericInstanceTypeSignature.GenericType.FullName, useWindowsUIXamlProjections, out string? mappedTypeName)) - { - interpolatedStringHandler.AppendLiteral(mappedTypeName); - } - else - { - interpolatedStringHandler.AppendLiteral(genericInstanceTypeSignature.GenericType.FullName); - } + // We need to wrap the metadata name with "IReference`1<...>" only for non-generic + // value types, and for delegate types. We skip generic value types because the only + // possible type is 'KeyValuePair', but that is a Windows Runtime interface. + bool isReference = (type.IsValueType && !type.IsGenericType) || typeDefinition.IsDelegate; - interpolatedStringHandler.AppendLiteral("<"); + if (isReference) + { + handler.AppendLiteral("Windows.Foundation.IReference`1<"); + } - // Recursively format each type argument - for (int i = 0; i < genericInstanceTypeSignature.TypeArguments.Count; i++) - { - // Add the ', ' separator after the first type argument - if (i > 0) - { - interpolatedStringHandler.AppendLiteral(", "); - } + // Aside from the possible "IReference`1<...>" prefix, the runtime class name will be the same + // as the metadata type name for all cases, so here we just forward to that to generate it. + MetadataTypeNameGenerator.AppendMetadataTypeName(ref handler, type, useWindowsUIXamlProjections); - AppendRuntimeClassName(ref interpolatedStringHandler, genericInstanceTypeSignature.TypeArguments[i], useWindowsUIXamlProjections); - } + if (isReference) + { + handler.AppendLiteral(">"); - interpolatedStringHandler.AppendLiteral(">"); - } - else if (TypeMapping.TryFindMappedTypeName(type.FullName, useWindowsUIXamlProjections, out string? simpleMappedTypeName)) - { - // We have a simple, non-generic type, so format its mapped type if available - interpolatedStringHandler.AppendLiteral(simpleMappedTypeName); - } - else - { - // Otherwise the type must be a projected type, so just format the full name - interpolatedStringHandler.AppendLiteral(type.FullName); - } } - AppendRuntimeClassName(ref handler, type, useWindowsUIXamlProjections); - return handler.ToStringAndClear(); } } diff --git a/src/WinRT.Interop.Generator/References/InteropReferences.cs b/src/WinRT.Interop.Generator/References/InteropReferences.cs index 4e61e0488..cf26cb55b 100644 --- a/src/WinRT.Interop.Generator/References/InteropReferences.cs +++ b/src/WinRT.Interop.Generator/References/InteropReferences.cs @@ -588,6 +588,11 @@ public InteropReferences( /// public TypeReference WindowsRuntimeClassNameAttribute => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime"u8, "WindowsRuntimeClassNameAttribute"u8); + /// + /// Gets the for WindowsRuntime.WindowsRuntimeMetadataTypeNameAttribute. + /// + public TypeReference WindowsRuntimeMetadataTypeNameAttribute => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime"u8, "WindowsRuntimeMetadataTypeNameAttribute"u8); + /// /// Gets the for . /// @@ -598,6 +603,11 @@ public InteropReferences( /// public TypeReference WindowsRuntimeMetadataAttribute => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime"u8, "WindowsRuntimeMetadataAttribute"u8); + /// + /// Gets the for WindowsRuntime.WindowsRuntimeMappedMetadataAttribute. + /// + public TypeReference WindowsRuntimeMappedMetadataAttribute => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime"u8, "WindowsRuntimeMappedMetadataAttribute"u8); + /// /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeManagedOnlyTypeAttribute. /// @@ -613,6 +623,11 @@ public InteropReferences( /// public TypeReference WindowsRuntimeComWrappersTypeMapGroup => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "WindowsRuntimeComWrappersTypeMapGroup"u8); + /// + /// Gets the for WindowsRuntime.InteropServices.WindowsRuntimeMetadataTypeMapGroup. + /// + public TypeReference WindowsRuntimeMetadataTypeMapGroup => field ??= _windowsRuntimeModule.CreateTypeReference("WindowsRuntime.InteropServices"u8, "WindowsRuntimeMetadataTypeMapGroup"u8); + /// /// Gets the for WindowsRuntime.InteropServices.DynamicInterfaceCastableImplementationTypeMapGroup. /// @@ -1430,6 +1445,16 @@ public InteropReferences( /// public MemberReference TypeMapAssociationAttributeWindowsRuntimeComWrappersTypeMapGroup_ctor => field ??= TypeMapAssociationAttribute1_ctor(WindowsRuntimeComWrappersTypeMapGroup.ToReferenceTypeSignature()); + /// + /// Gets the for , using . + /// + public MemberReference TypeMapAttributeWindowsRuntimeMetadataTypeMapGroup_ctor_TrimTarget => field ??= TypeMapAttribute1_ctor_TrimTarget(WindowsRuntimeMetadataTypeMapGroup.ToReferenceTypeSignature()); + + /// + /// Gets the for , using . + /// + public MemberReference TypeMapAssociationAttributeWindowsRuntimeMetadataTypeMapGroup_ctor => field ??= TypeMapAssociationAttribute1_ctor(WindowsRuntimeMetadataTypeMapGroup.ToReferenceTypeSignature()); + /// /// Gets the for , using . /// @@ -2225,6 +2250,22 @@ public InteropReferences( returnType: _corLibTypeFactory.Void, parameterTypes: [_corLibTypeFactory.String])); + /// + /// Gets the for 's constructor. + /// + public MemberReference WindowsRuntimeMetadataTypeNameAttribute_ctor => field ??= WindowsRuntimeMetadataTypeNameAttribute + .CreateMemberReference(".ctor", MethodSignature.CreateInstance( + returnType: _corLibTypeFactory.Void, + parameterTypes: [_corLibTypeFactory.String])); + + /// + /// Gets the for 's constructor. + /// + public MemberReference WindowsRuntimeMappedMetadataAttribute_ctor => field ??= WindowsRuntimeMappedMetadataAttribute + .CreateMemberReference(".ctor", MethodSignature.CreateInstance( + returnType: _corLibTypeFactory.Void, + parameterTypes: [_corLibTypeFactory.String])); + /// /// Gets the for 's constructor. /// diff --git a/src/WinRT.Runtime2/ABI/System/Boolean.cs b/src/WinRT.Runtime2/ABI/System/Boolean.cs index 080ad37f4..6c668aa2c 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`1", target: typeof(ABI.System.Boolean), @@ -27,7 +32,11 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[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 c314c66bf..4cbe37317 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`1", target: typeof(ABI.System.Byte), @@ -27,7 +32,11 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[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 521a2bf35..9161ddd52 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`1", target: typeof(ABI.System.Char), @@ -27,7 +32,11 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[WindowsRuntimeMetadataTypeName("Char16")] +[WindowsRuntimeMappedType(typeof(char))] +[WindowsRuntimeReferenceType(typeof(char?))] [CharComWrappersMarshaller] file static class Char; diff --git a/src/WinRT.Runtime2/ABI/System/Collections/IEnumerable.cs b/src/WinRT.Runtime2/ABI/System/Collections/IEnumerable.cs index beb586a29..bd476ff32 100644 --- a/src/WinRT.Runtime2/ABI/System/Collections/IEnumerable.cs +++ b/src/WinRT.Runtime2/ABI/System/Collections/IEnumerable.cs @@ -21,21 +21,7 @@ namespace ABI.System.Collections; /// -/// ABI type for . -/// -/// -/// This interface is equivalent to . -/// -/// -[IEnumerableComWrappersMarshaller] -[Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, - DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, - UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] -[EditorBrowsable(EditorBrowsableState.Never)] -public static class IEnumerable; - -/// -/// Marshaller for . +/// Marshaller for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -44,20 +30,20 @@ public static class IEnumerable; public static unsafe class IEnumerableMarshaller { /// - public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(global::System.Collections.IEnumerable? value) + public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(IEnumerable? value) { - return WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged(value, in WellKnownWindowsInterfaceIIDs.IID_IBindableIterable); + return WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged(value, in WellKnownWindowsInterfaceIIDs.IID_IBindableIterable); } /// - public static global::System.Collections.IEnumerable? ConvertToManaged(void* value) + public static IEnumerable? ConvertToManaged(void* value) { - return (global::System.Collections.IEnumerable?)WindowsRuntimeUnsealedObjectMarshaller.ConvertToManaged(value); + return (IEnumerable?)WindowsRuntimeUnsealedObjectMarshaller.ConvertToManaged(value); } } /// -/// The implementation for . +/// The implementation for . /// file abstract class IEnumerableComWrappersCallback : IWindowsRuntimeUnsealedObjectComWrappersCallback { @@ -88,9 +74,13 @@ public static unsafe bool TryCreateObject( } /// -/// A custom implementation for . +/// A custom implementation for . /// -file sealed unsafe class IEnumerableComWrappersMarshallerAttribute : WindowsRuntimeComWrappersMarshallerAttribute +[Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, + DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, + UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] +[EditorBrowsable(EditorBrowsableState.Never)] +public sealed unsafe class IEnumerableComWrappersMarshallerAttribute : WindowsRuntimeComWrappersMarshallerAttribute { /// public override object CreateObject(void* value, out CreatedWrapperFlags wrapperFlags) @@ -105,7 +95,7 @@ public override object CreateObject(void* value, out CreatedWrapperFlags wrapper } /// -/// Interop methods for . +/// Interop methods for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -113,7 +103,7 @@ public override object CreateObject(void* value, out CreatedWrapperFlags wrapper [EditorBrowsable(EditorBrowsableState.Never)] public static class IEnumerableMethods { - /// + /// public static global::System.Collections.IEnumerator GetEnumerator(WindowsRuntimeObjectReference thisReference) { return IBindableIterableMethods.First(thisReference); @@ -121,11 +111,11 @@ public static class IEnumerableMethods } /// -/// Interop methods for invoked over constructed iterator types. +/// Interop methods for invoked over constructed iterator types. /// file static class IEnumerableInstanceMethods { - /// + /// public static global::System.Collections.IEnumerator GetEnumerator(WindowsRuntimeObjectReference thisReference) { return global::WindowsRuntime.InteropServices.IEnumerableMethods.GetEnumerator(thisReference); @@ -133,7 +123,7 @@ file static class IEnumerableInstanceMethods } /// -/// The implementation. +/// The implementation. /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -142,7 +132,7 @@ file static class IEnumerableInstanceMethods public static unsafe class IEnumerableImpl { /// - /// The value for the managed implementation. + /// The value for the managed implementation. /// [FixedAddressValueType] private static readonly IBindableIterableVftbl Vftbl; @@ -158,7 +148,7 @@ static IEnumerableImpl() } /// - /// Gets a pointer to the managed implementation. + /// Gets a pointer to the managed implementation. /// public static nint Vtable { @@ -177,7 +167,7 @@ private static HRESULT First(void* thisPtr, void** result) try { - var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); global::System.Collections.IEnumerator enumerator = thisObject.GetEnumerator(); @@ -193,18 +183,18 @@ private static HRESULT First(void* thisPtr, void** result) } /// -/// The implementation for . +/// The implementation for . /// [DynamicInterfaceCastableImplementation] -file interface IEnumerableInterfaceImpl : global::System.Collections.IEnumerable +file interface IEnumerableInterfaceImpl : IEnumerable { - global::System.Collections.IEnumerator global::System.Collections.IEnumerable.GetEnumerator() + global::System.Collections.IEnumerator IEnumerable.GetEnumerator() { WindowsRuntimeObject thisObject = (WindowsRuntimeObject)this; // First, try to lookup for the actual 'IEnumerable' interface being implemented if (thisObject.TryGetObjectReferenceForInterface( - interfaceType: typeof(global::System.Collections.IEnumerable).TypeHandle, + interfaceType: typeof(IEnumerable).TypeHandle, interfaceReference: out WindowsRuntimeObjectReference? interfaceReference)) { return IEnumerableMethods.GetEnumerator(interfaceReference); diff --git a/src/WinRT.Runtime2/ABI/System/Collections/IEnumerator.cs b/src/WinRT.Runtime2/ABI/System/Collections/IEnumerator.cs index 0fedadd7f..16f80328c 100644 --- a/src/WinRT.Runtime2/ABI/System/Collections/IEnumerator.cs +++ b/src/WinRT.Runtime2/ABI/System/Collections/IEnumerator.cs @@ -21,21 +21,7 @@ namespace ABI.System.Collections; /// -/// ABI type for . -/// -/// -/// This interface is equivalent to . -/// -/// -[IEnumeratorComWrappersMarshaller] -[Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, - DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, - UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] -[EditorBrowsable(EditorBrowsableState.Never)] -public static class IEnumerator; - -/// -/// Marshaller for . +/// Marshaller for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -44,20 +30,20 @@ public static class IEnumerator; public static unsafe class IEnumeratorMarshaller { /// - public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(global::System.Collections.IEnumerator? value) + public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(IEnumerator? value) { - return WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged(value, in WellKnownWindowsInterfaceIIDs.IID_IBindableIterator); + return WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged(value, in WellKnownWindowsInterfaceIIDs.IID_IBindableIterator); } /// - public static global::System.Collections.IEnumerator? ConvertToManaged(void* value) + public static IEnumerator? ConvertToManaged(void* value) { - return (global::System.Collections.IEnumerator?)WindowsRuntimeUnsealedObjectMarshaller.ConvertToManaged(value); + return (IEnumerator?)WindowsRuntimeUnsealedObjectMarshaller.ConvertToManaged(value); } } /// -/// The implementation for . +/// The implementation for . /// file abstract class IEnumeratorComWrappersCallback : IWindowsRuntimeUnsealedObjectComWrappersCallback { @@ -75,7 +61,7 @@ public static unsafe bool TryCreateObject( iid: in WellKnownWindowsInterfaceIIDs.IID_IBindableIterator, wrapperFlags: out wrapperFlags); - wrapperObject = new WindowsRuntimeIterator(valueReference); + wrapperObject = new WindowsRuntimeEnumerator(valueReference); return true; } @@ -88,9 +74,13 @@ public static unsafe bool TryCreateObject( } /// -/// A custom implementation for . +/// A custom implementation for . /// -file sealed unsafe class IEnumeratorComWrappersMarshallerAttribute : WindowsRuntimeComWrappersMarshallerAttribute +[Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, + DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, + UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] +[EditorBrowsable(EditorBrowsableState.Never)] +public sealed unsafe class IEnumeratorComWrappersMarshallerAttribute : WindowsRuntimeComWrappersMarshallerAttribute { /// public override object CreateObject(void* value, out CreatedWrapperFlags wrapperFlags) @@ -100,12 +90,12 @@ public override object CreateObject(void* value, out CreatedWrapperFlags wrapper iid: in WellKnownWindowsInterfaceIIDs.IID_IBindableIterator, wrapperFlags: out wrapperFlags); - return new WindowsRuntimeIterator(valueReference); + return new WindowsRuntimeEnumerator(valueReference); } } /// -/// Interop methods for . +/// Interop methods for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -113,13 +103,13 @@ public override object CreateObject(void* value, out CreatedWrapperFlags wrapper [EditorBrowsable(EditorBrowsableState.Never)] public static class IEnumeratorMethods { - /// + /// public static object? Current(WindowsRuntimeObjectReference thisReference) { return IBindableIteratorMethods.Current(thisReference); } - /// + /// [MethodImpl(MethodImplOptions.NoInlining)] public static bool MoveNext(WindowsRuntimeObjectReference thisReference) { @@ -128,7 +118,7 @@ public static bool MoveNext(WindowsRuntimeObjectReference thisReference) } /// -/// The implementation. +/// The implementation. /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -137,7 +127,7 @@ public static bool MoveNext(WindowsRuntimeObjectReference thisReference) public static unsafe class IEnumeratorImpl { /// - /// The value for the managed implementation. + /// The value for the managed implementation. /// [FixedAddressValueType] private static readonly IBindableIteratorVftbl Vftbl; @@ -156,7 +146,7 @@ static IEnumeratorImpl() } /// - /// Gets a pointer to the managed implementation. + /// Gets a pointer to the managed implementation. /// public static nint Vtable { @@ -175,7 +165,7 @@ private static HRESULT get_Current(void* thisPtr, void** result) try { - var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); object? current = IBindableIteratorAdapter.GetInstance(thisObject).Current; @@ -200,7 +190,7 @@ private static HRESULT get_HasCurrent(void* thisPtr, bool* result) try { - var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); *result = IBindableIteratorAdapter.GetInstance(thisObject).HasCurrent; @@ -223,7 +213,7 @@ private static HRESULT MoveNext(void* thisPtr, bool* result) try { - var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); *result = IBindableIteratorAdapter.GetInstance(thisObject).MoveNext(); @@ -244,32 +234,32 @@ private static HRESULT GetMany(void* thisPtr, uint index, void* items, uint* cou } /// -/// The implementation for . +/// The implementation for . /// [DynamicInterfaceCastableImplementation] -file interface IEnumeratorInterfaceImpl : global::System.Collections.IEnumerator +file interface IEnumeratorInterfaceImpl : IEnumerator { /// - object? global::System.Collections.IEnumerator.Current + object? IEnumerator.Current { get { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::System.Collections.IEnumerator).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IEnumerator).TypeHandle); return IEnumeratorMethods.Current(thisReference); } } /// - bool global::System.Collections.IEnumerator.MoveNext() + bool IEnumerator.MoveNext() { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::System.Collections.IEnumerator).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IEnumerator).TypeHandle); return IEnumeratorMethods.MoveNext(thisReference); } /// - void global::System.Collections.IEnumerator.Reset() + void IEnumerator.Reset() { throw new NotSupportedException(); } diff --git a/src/WinRT.Runtime2/ABI/System/Collections/IList.cs b/src/WinRT.Runtime2/ABI/System/Collections/IList.cs index 203a54f96..ac7482989 100644 --- a/src/WinRT.Runtime2/ABI/System/Collections/IList.cs +++ b/src/WinRT.Runtime2/ABI/System/Collections/IList.cs @@ -25,21 +25,7 @@ namespace ABI.System.Collections; /// -/// ABI type for . -/// -/// -/// This interface is equivalent to . -/// -/// -[IListComWrappersMarshaller] -[Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, - DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, - UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] -[EditorBrowsable(EditorBrowsableState.Never)] -public static class IList; - -/// -/// Marshaller for . +/// Marshaller for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -48,20 +34,20 @@ public static class IList; public static unsafe class IListMarshaller { /// - public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(global::System.Collections.IList? value) + public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(IList? value) { - return WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged(value, in WellKnownWindowsInterfaceIIDs.IID_IBindableVector); + return WindowsRuntimeInterfaceMarshaller.ConvertToUnmanaged(value, in WellKnownWindowsInterfaceIIDs.IID_IBindableVector); } /// - public static global::System.Collections.IList? ConvertToManaged(void* value) + public static IList? ConvertToManaged(void* value) { - return (global::System.Collections.IList?)WindowsRuntimeUnsealedObjectMarshaller.ConvertToManaged(value); + return (IList?)WindowsRuntimeUnsealedObjectMarshaller.ConvertToManaged(value); } } /// -/// The implementation for . +/// The implementation for . /// file abstract class IListComWrappersCallback : IWindowsRuntimeUnsealedObjectComWrappersCallback { @@ -92,9 +78,13 @@ public static unsafe bool TryCreateObject( } /// -/// A custom implementation for . +/// A custom implementation for . /// -file sealed unsafe class IListComWrappersMarshallerAttribute : WindowsRuntimeComWrappersMarshallerAttribute +[Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, + DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, + UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] +[EditorBrowsable(EditorBrowsableState.Never)] +public sealed unsafe class IListComWrappersMarshallerAttribute : WindowsRuntimeComWrappersMarshallerAttribute { /// public override object CreateObject(void* value, out CreatedWrapperFlags wrapperFlags) @@ -109,7 +99,7 @@ public override object CreateObject(void* value, out CreatedWrapperFlags wrapper } /// -/// Interop methods for . +/// Interop methods for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -129,55 +119,55 @@ public static void CopyTo(WindowsRuntimeObjectReference thisReference, Array arr BindableIListMethods.CopyTo(thisReference, array, index); } - /// + /// public static object? Item(WindowsRuntimeObjectReference thisReference, int index) { return BindableIListMethods.Item(thisReference, index); } - /// + /// public static void Item(WindowsRuntimeObjectReference thisReference, int index, object? value) { BindableIListMethods.Item(thisReference, index, value); } - /// + /// public static int Add(WindowsRuntimeObjectReference thisReference, object? value) { return BindableIListMethods.Add(thisReference, value); } - /// + /// public static bool Contains(WindowsRuntimeObjectReference thisReference, object? value) { return BindableIListMethods.Contains(thisReference, value); } - /// + /// public static int IndexOf(WindowsRuntimeObjectReference thisReference, object? value) { return BindableIListMethods.IndexOf(thisReference, value); } - /// + /// public static void Insert(WindowsRuntimeObjectReference thisReference, int index, object? value) { BindableIListMethods.Insert(thisReference, index, value); } - /// + /// public static void Remove(WindowsRuntimeObjectReference thisReference, object? value) { BindableIListMethods.Remove(thisReference, value); } - /// + /// public static void RemoveAt(WindowsRuntimeObjectReference thisReference, int index) { BindableIListMethods.RemoveAt(thisReference, index); } - /// + /// public static void Clear(WindowsRuntimeObjectReference thisReference) { BindableIListMethods.Clear(thisReference); @@ -185,7 +175,7 @@ public static void Clear(WindowsRuntimeObjectReference thisReference) } /// -/// The implementation. +/// The implementation. /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -194,7 +184,7 @@ public static void Clear(WindowsRuntimeObjectReference thisReference) public static unsafe class IListImpl { /// - /// The value for the managed implementation. + /// The value for the managed implementation. /// [FixedAddressValueType] private static readonly IBindableVectorVftbl Vftbl; @@ -219,7 +209,7 @@ static IListImpl() } /// - /// Gets a pointer to the managed implementation. + /// Gets a pointer to the managed implementation. /// public static nint Vtable { @@ -238,7 +228,7 @@ private static HRESULT GetAt(void* thisPtr, uint index, void** result) try { - var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); object? value = BindableIListAdapter.GetAt(thisObject, index); @@ -263,7 +253,7 @@ private static HRESULT get_Size(void* thisPtr, uint* size) try { - var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); *size = BindableIListAdapter.Size(thisObject); @@ -286,7 +276,7 @@ private static HRESULT GetView(void* thisPtr, void** view) try { - var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); BindableIReadOnlyListAdapter adapter = BindableIListAdapter.GetView(thisObject); @@ -311,7 +301,7 @@ private static HRESULT IndexOf(void* thisPtr, void* value, uint* index, bool* re try { - var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); object? item = WindowsRuntimeObjectMarshaller.ConvertToManaged(value); @@ -331,7 +321,7 @@ private static HRESULT SetAt(void* thisPtr, uint index, void* value) { try { - var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); object? item = WindowsRuntimeObjectMarshaller.ConvertToManaged(value); @@ -351,7 +341,7 @@ private static HRESULT InsertAt(void* thisPtr, uint index, void* value) { try { - var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); object? item = WindowsRuntimeObjectMarshaller.ConvertToManaged(value); @@ -371,7 +361,7 @@ private static HRESULT RemoveAt(void* thisPtr, uint index) { try { - var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); BindableIListAdapter.RemoveAt(thisObject, index); @@ -389,7 +379,7 @@ private static HRESULT Append(void* thisPtr, void* value) { try { - var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); object? item = WindowsRuntimeObjectMarshaller.ConvertToManaged(value); @@ -409,7 +399,7 @@ private static HRESULT RemoveAtEnd(void* thisPtr) { try { - var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); BindableIListAdapter.RemoveAtEnd(thisObject); @@ -427,7 +417,7 @@ private static HRESULT Clear(void* thisPtr) { try { - var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); BindableIListAdapter.Clear(thisObject); @@ -441,86 +431,86 @@ private static HRESULT Clear(void* thisPtr) } /// -/// The implementation for . +/// The implementation for . /// [DynamicInterfaceCastableImplementation] -file interface IListInterfaceImpl : global::System.Collections.IList +file interface IListInterfaceImpl : IList { /// - object? global::System.Collections.IList.this[int index] + object? IList.this[int index] { get { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::System.Collections.IList).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IList).TypeHandle); return BindableIListMethods.Item(thisReference, index); } set { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::System.Collections.IList).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IList).TypeHandle); BindableIListMethods.Item(thisReference, index, value); } } /// - bool global::System.Collections.IList.IsFixedSize => false; + bool IList.IsFixedSize => false; /// - bool global::System.Collections.IList.IsReadOnly => false; + bool IList.IsReadOnly => false; /// - int global::System.Collections.IList.Add(object? value) + int IList.Add(object? value) { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::System.Collections.IList).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IList).TypeHandle); return BindableIListMethods.Add(thisReference, value); } /// - void global::System.Collections.IList.Clear() + void IList.Clear() { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::System.Collections.IList).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IList).TypeHandle); BindableIListMethods.Clear(thisReference); } /// - bool global::System.Collections.IList.Contains(object? value) + bool IList.Contains(object? value) { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::System.Collections.IList).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IList).TypeHandle); return BindableIListMethods.Contains(thisReference, value); } /// - int global::System.Collections.IList.IndexOf(object? value) + int IList.IndexOf(object? value) { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::System.Collections.IList).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IList).TypeHandle); return BindableIListMethods.IndexOf(thisReference, value); } /// - void global::System.Collections.IList.Insert(int index, object? value) + void IList.Insert(int index, object? value) { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::System.Collections.IList).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IList).TypeHandle); BindableIListMethods.Insert(thisReference, index, value); } /// - void global::System.Collections.IList.Remove(object? value) + void IList.Remove(object? value) { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::System.Collections.IList).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IList).TypeHandle); BindableIListMethods.Remove(thisReference, value); } /// - void global::System.Collections.IList.RemoveAt(int index) + void IList.RemoveAt(int index) { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::System.Collections.IList).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IList).TypeHandle); BindableIListMethods.RemoveAt(thisReference, index); } @@ -530,7 +520,7 @@ int ICollection.Count { get { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::System.Collections.IList).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IList).TypeHandle); return BindableIListMethods.Count(thisReference); } @@ -545,7 +535,7 @@ int ICollection.Count /// void ICollection.CopyTo(Array array, int index) { - var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(global::System.Collections.IList).TypeHandle); + var thisReference = ((WindowsRuntimeObject)this).GetObjectReferenceForInterface(typeof(IList).TypeHandle); BindableIListMethods.CopyTo(thisReference, array, index); } diff --git a/src/WinRT.Runtime2/ABI/System/Collections/IReadOnlyList.cs b/src/WinRT.Runtime2/ABI/System/Collections/IReadOnlyList.cs new file mode 100644 index 000000000..fce2dcfe0 --- /dev/null +++ b/src/WinRT.Runtime2/ABI/System/Collections/IReadOnlyList.cs @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; +using WindowsRuntime; +using WindowsRuntime.InteropServices; + +namespace ABI.System.Collections; + +/// +/// A custom implementation for IReadOnlyList. +/// +/// +/// +/// There is no non-generic type in .NET, however this +/// type still uses "IReadOnlyList" in its name to match the naming convention of adapter types matching .NET type names. +/// +/// +/// Because this interface is not projected, only the marshaller attribute type and the proxy type are needed. The proxy +/// type will be generated at compile time, as its runtime class name will depend on the XAML configuration being used. +/// +/// +[Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, + DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, + UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] +[EditorBrowsable(EditorBrowsableState.Never)] +public sealed unsafe class IReadOnlyListComWrappersMarshallerAttribute : WindowsRuntimeComWrappersMarshallerAttribute +{ + /// + public override object CreateObject(void* value, out CreatedWrapperFlags wrapperFlags) + { + WindowsRuntimeObjectReference valueReference = WindowsRuntimeComWrappersMarshal.CreateObjectReference( + externalComObject: value, + iid: in WellKnownWindowsInterfaceIIDs.IID_IBindableVectorView, + wrapperFlags: out wrapperFlags); + + return new WindowsRuntimeReadOnlyList(valueReference); + } +} \ No newline at end of file diff --git a/src/WinRT.Runtime2/ABI/System/Collections/Specialized/NotifyCollectionChangedEventArgs.cs b/src/WinRT.Runtime2/ABI/System/Collections/Specialized/NotifyCollectionChangedEventArgs.cs index e955235cf..a93f5fa5d 100644 --- a/src/WinRT.Runtime2/ABI/System/Collections/Specialized/NotifyCollectionChangedEventArgs.cs +++ b/src/WinRT.Runtime2/ABI/System/Collections/Specialized/NotifyCollectionChangedEventArgs.cs @@ -12,26 +12,10 @@ #pragma warning disable IDE0008, IDE0055 -[assembly: TypeMapAssociation( - typeof(NotifyCollectionChangedEventArgs), - typeof(ABI.System.Collections.Specialized.NotifyCollectionChangedEventArgs))] - namespace ABI.System.Collections.Specialized; /// -/// ABI type for . -/// -/// -/// -[NotifyCollectionChangedEventArgsComWrappersMarshaller] -[Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, - DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, - UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] -[EditorBrowsable(EditorBrowsableState.Never)] -public static class NotifyCollectionChangedEventArgs; - -/// -/// Marshaller for . +/// Marshaller for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -40,7 +24,7 @@ public static class NotifyCollectionChangedEventArgs; public static unsafe class NotifyCollectionChangedEventArgsMarshaller { /// - public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(global::System.Collections.Specialized.NotifyCollectionChangedEventArgs? value) + public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(NotifyCollectionChangedEventArgs? value) { if (value is null) { @@ -59,7 +43,7 @@ public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(global::Syst /// [MethodImpl(MethodImplOptions.NoInlining)] - public static global::System.Collections.Specialized.NotifyCollectionChangedEventArgs? ConvertToManaged(void* value) + public static NotifyCollectionChangedEventArgs? ConvertToManaged(void* value) { if (value is null) { @@ -165,14 +149,18 @@ static int GetOldStartingIndex(void* value) } /// -/// A custom implementation for . +/// A custom implementation for . /// -file sealed unsafe class NotifyCollectionChangedEventArgsComWrappersMarshallerAttribute : WindowsRuntimeComWrappersMarshallerAttribute +[Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, + DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, + UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] +[EditorBrowsable(EditorBrowsableState.Never)] +public sealed unsafe class NotifyCollectionChangedEventArgsComWrappersMarshallerAttribute : WindowsRuntimeComWrappersMarshallerAttribute { /// public override void* GetOrCreateComInterfaceForObject(object value) { - var args = (global::System.Collections.Specialized.NotifyCollectionChangedEventArgs)value; + var args = (NotifyCollectionChangedEventArgs)value; return NotifyCollectionChangedEventArgsRuntimeClassFactory.CreateInstance( args.Action, @@ -205,7 +193,7 @@ public override object CreateObject(void* value, out CreatedWrapperFlags wrapper } /// -/// The runtime class factory for . +/// The runtime class factory for . /// file static unsafe class NotifyCollectionChangedEventArgsRuntimeClassFactory { @@ -217,14 +205,14 @@ file static unsafe class NotifyCollectionChangedEventArgsRuntimeClassFactory iid: in WellKnownXamlInterfaceIIDs.IID_INotifyCollectionChangedEventArgsFactory); /// - /// Creates a new native instance for . + /// Creates a new native instance for . /// - /// - /// - /// - /// - /// - /// The new native instance for . + /// + /// + /// + /// + /// + /// The new native instance for . [MethodImpl(MethodImplOptions.NoInlining)] public static void* CreateInstance( NotifyCollectionChangedAction action, diff --git a/src/WinRT.Runtime2/ABI/System/ComponentModel/DataErrorsChangedEventArgs.cs b/src/WinRT.Runtime2/ABI/System/ComponentModel/DataErrorsChangedEventArgs.cs index 28d3bb6fc..c6b7d0d4b 100644 --- a/src/WinRT.Runtime2/ABI/System/ComponentModel/DataErrorsChangedEventArgs.cs +++ b/src/WinRT.Runtime2/ABI/System/ComponentModel/DataErrorsChangedEventArgs.cs @@ -26,6 +26,8 @@ namespace ABI.System.ComponentModel; /// ABI type for . /// /// +[WindowsRuntimeMappedMetadata("Microsoft.UI.Xaml.WinUIContract")] +[WindowsRuntimeMappedType(typeof(global::System.ComponentModel.DataErrorsChangedEventArgs))] [DataErrorsChangedEventArgsComWrappersMarshaller] file static class DataErrorsChangedEventArgs; diff --git a/src/WinRT.Runtime2/ABI/System/ComponentModel/INotifyDataErrorInfo.cs b/src/WinRT.Runtime2/ABI/System/ComponentModel/INotifyDataErrorInfo.cs index fbe8b9f4b..473aa0926 100644 --- a/src/WinRT.Runtime2/ABI/System/ComponentModel/INotifyDataErrorInfo.cs +++ b/src/WinRT.Runtime2/ABI/System/ComponentModel/INotifyDataErrorInfo.cs @@ -16,10 +16,33 @@ #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))] + namespace ABI.System.ComponentModel; /// -/// Marshaller for . +/// ABI type for . +/// +[WindowsRuntimeMappedMetadata("Microsoft.UI.Xaml.WinUIContract")] +[WindowsRuntimeMetadataTypeName("Microsoft.UI.Xaml.Data.INotifyDataErrorInfo")] +[WindowsRuntimeMappedType(typeof(global::System.ComponentModel.INotifyDataErrorInfo))] +file static class INotifyDataErrorInfo; + +/// +/// Marshaller for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -28,22 +51,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, @@ -52,7 +75,7 @@ public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(INotifyDataE public static unsafe class INotifyDataErrorInfoMethods { /// - /// The table for . + /// The table for . /// private static ConditionalWeakTable> ErrorsChangedTable { @@ -71,7 +94,7 @@ static ConditionalWeakTable + /// [MethodImpl(MethodImplOptions.NoInlining)] public static bool HasErrors(WindowsRuntimeObjectReference thisReference) { @@ -85,7 +108,7 @@ public static bool HasErrors(WindowsRuntimeObjectReference thisReference) return Unsafe.BitCast(result) != 0; } - /// + /// public static EventHandlerEventSource ErrorsChanged(WindowsRuntimeObject thisObject, WindowsRuntimeObjectReference thisReference) { [UnsafeAccessor(UnsafeAccessorKind.Constructor)] @@ -98,7 +121,7 @@ public static EventHandlerEventSource ErrorsChanged( factoryArgument: thisReference); } - /// + /// [MethodImpl(MethodImplOptions.NoInlining)] public static IEnumerable GetErrors(WindowsRuntimeObjectReference thisReference, string? propertyName) { @@ -131,7 +154,7 @@ public static IEnumerable GetErrors(WindowsRuntimeObjectReference thisReference, } /// -/// Binding type for . +/// Binding type for . /// [StructLayout(LayoutKind.Sequential)] internal unsafe struct INotifyDataErrorInfoVftbl @@ -149,7 +172,7 @@ internal unsafe struct INotifyDataErrorInfoVftbl } /// -/// The implementation. +/// The implementation. /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -158,7 +181,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; @@ -177,7 +200,7 @@ static INotifyDataErrorInfoImpl() } /// - /// Gets a pointer to the managed implementation. + /// Gets a pointer to the managed implementation. /// public static nint Vtable { @@ -186,15 +209,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); @@ -213,7 +236,7 @@ private static HRESULT get_HasErrors(void* thisPtr, bool* result) try { - var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); *result = thisObject.HasErrors; @@ -233,7 +256,7 @@ private static HRESULT add_ErrorsChanged(void* thisPtr, void* handler, EventRegi try { - var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); [UnsafeAccessor(UnsafeAccessorKind.StaticMethod)] static extern EventHandler? ConvertToManaged( @@ -260,7 +283,7 @@ private static HRESULT remove_ErrorsChanged(void* thisPtr, EventRegistrationToke { try { - var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); if (thisObject is not null && ErrorsChanged.TryGetValue(thisObject, out var table) && table.RemoveEventHandler(token, out EventHandler? managedHandler)) { @@ -283,7 +306,7 @@ private static HRESULT GetErrors(void* thisPtr, HSTRING propertyName, void** res try { - var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); IEnumerable managedResult = thisObject.GetErrors(HStringMarshaller.ConvertToManaged(propertyName)); @@ -304,45 +327,45 @@ static extern WindowsRuntimeObjectReferenceValue ConvertToUnmanaged( } /// -/// The implementation for . +/// The implementation for . /// [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); } diff --git a/src/WinRT.Runtime2/ABI/System/ComponentModel/PropertyChangedEventArgs.cs b/src/WinRT.Runtime2/ABI/System/ComponentModel/PropertyChangedEventArgs.cs index f2726af89..72e458041 100644 --- a/src/WinRT.Runtime2/ABI/System/ComponentModel/PropertyChangedEventArgs.cs +++ b/src/WinRT.Runtime2/ABI/System/ComponentModel/PropertyChangedEventArgs.cs @@ -9,26 +9,10 @@ using WindowsRuntime.InteropServices; using WindowsRuntime.InteropServices.Marshalling; -[assembly: TypeMapAssociation( - typeof(PropertyChangedEventArgs), - typeof(ABI.System.ComponentModel.PropertyChangedEventArgs))] - namespace ABI.System.ComponentModel; /// -/// ABI type for . -/// -/// -/// -[PropertyChangedEventArgsComWrappersMarshaller] -[Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, - DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, - UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] -[EditorBrowsable(EditorBrowsableState.Never)] -public static class PropertyChangedEventArgs; - -/// -/// Marshaller for . +/// Marshaller for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -37,14 +21,14 @@ public static class PropertyChangedEventArgs; public static unsafe class PropertyChangedEventArgsMarshaller { /// - public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(global::System.ComponentModel.PropertyChangedEventArgs? value) + public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(PropertyChangedEventArgs? value) { return value is null ? default : new(PropertyChangedEventArgsRuntimeClassFactory.CreateInstance(value.PropertyName)); } /// [MethodImpl(MethodImplOptions.NoInlining)] - public static global::System.ComponentModel.PropertyChangedEventArgs? ConvertToManaged(void* value) + public static PropertyChangedEventArgs? ConvertToManaged(void* value) { if (value is null) { @@ -59,7 +43,7 @@ public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(global::Syst // Convert to a managed 'string' and create the managed object for the args as well try { - return new global::System.ComponentModel.PropertyChangedEventArgs(HStringMarshaller.ConvertToManaged(propertyName)); + return new PropertyChangedEventArgs(HStringMarshaller.ConvertToManaged(propertyName)); } finally { @@ -69,14 +53,18 @@ public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(global::Syst } /// -/// A custom implementation for . +/// A custom implementation for . /// -file sealed unsafe class PropertyChangedEventArgsComWrappersMarshallerAttribute : WindowsRuntimeComWrappersMarshallerAttribute +[Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, + DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, + UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] +[EditorBrowsable(EditorBrowsableState.Never)] +public sealed unsafe class PropertyChangedEventArgsComWrappersMarshallerAttribute : WindowsRuntimeComWrappersMarshallerAttribute { /// public override void* GetOrCreateComInterfaceForObject(object value) { - return PropertyChangedEventArgsRuntimeClassFactory.CreateInstance(((global::System.ComponentModel.PropertyChangedEventArgs)value).PropertyName); + return PropertyChangedEventArgsRuntimeClassFactory.CreateInstance(((PropertyChangedEventArgs)value).PropertyName); } /// @@ -102,7 +90,7 @@ public override object CreateObject(void* value, out CreatedWrapperFlags wrapper } /// -/// The runtime class factory for . +/// The runtime class factory for . /// file static unsafe class PropertyChangedEventArgsRuntimeClassFactory { @@ -114,10 +102,10 @@ file static unsafe class PropertyChangedEventArgsRuntimeClassFactory iid: in WellKnownXamlInterfaceIIDs.IID_PropertyChangedEventArgsRuntimeClassFactory); /// - /// Creates a new native instance for . + /// Creates a new native instance for . /// /// The property name to use. - /// The new native instance for . + /// The new native instance for . [MethodImpl(MethodImplOptions.NoInlining)] public static void* CreateInstance(string? propertyName) { diff --git a/src/WinRT.Runtime2/ABI/System/DateTimeOffset.cs b/src/WinRT.Runtime2/ABI/System/DateTimeOffset.cs index cdb80ba2d..e0e9ff87b 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`1", target: typeof(ABI.System.DateTimeOffset), @@ -28,7 +33,11 @@ namespace ABI.System; /// ABI type for . /// /// +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[WindowsRuntimeMetadataTypeName("Windows.Foundation.DateTime")] +[WindowsRuntimeMappedType(typeof(global::System.DateTimeOffset))] +[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 324296fff..3cb89fb29 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`1", target: typeof(ABI.System.Double), @@ -27,7 +32,11 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[WindowsRuntimeMetadataTypeName("Double")] +[WindowsRuntimeMappedType(typeof(double))] +[WindowsRuntimeReferenceType(typeof(double?))] [DoubleComWrappersMarshaller] file static class Double; diff --git a/src/WinRT.Runtime2/ABI/System/EventHandler.cs b/src/WinRT.Runtime2/ABI/System/EventHandler.cs index b4d4d930b..98ff5d138 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 . /// /// +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1>")] [EventHandlerComWrappersMarshaller] file static class EventHandler; diff --git a/src/WinRT.Runtime2/ABI/System/Exception.cs b/src/WinRT.Runtime2/ABI/System/Exception.cs index 35c491ae9..a2f634699 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`1", target: typeof(ABI.System.Exception), @@ -28,7 +33,10 @@ namespace ABI.System; /// ABI type for . /// /// +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[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 ee3d42801..6dad33cc6 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`1", target: typeof(ABI.System.Guid), @@ -27,7 +32,11 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[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 c57f72f9e..b5af6e7cf 100644 --- a/src/WinRT.Runtime2/ABI/System/IDisposable.cs +++ b/src/WinRT.Runtime2/ABI/System/IDisposable.cs @@ -13,10 +13,33 @@ #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.IDisposable))] + +[assembly: TypeMapAssociation( + source: typeof(IDisposable), + proxy: typeof(ABI.System.IDisposableInterfaceImpl))] + namespace ABI.System; /// -/// Marshaller for . +/// ABI type for . +/// +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] +[WindowsRuntimeMetadataTypeName("Windows.Foundation.IClosable")] +[WindowsRuntimeMappedType(typeof(global::System.IDisposable))] +file static class IDisposable; + +/// +/// Marshaller for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -25,20 +48,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, @@ -46,7 +69,7 @@ public static WindowsRuntimeObjectReferenceValue ConvertToUnmanaged(IDisposable? [EditorBrowsable(EditorBrowsableState.Never)] public static unsafe class IDisposableMethods { - /// + /// [MethodImpl(MethodImplOptions.NoInlining)] public static void Dispose(WindowsRuntimeObjectReference thisReference) { @@ -59,7 +82,7 @@ public static void Dispose(WindowsRuntimeObjectReference thisReference) } /// -/// Binding type for . +/// Binding type for . /// [StructLayout(LayoutKind.Sequential)] internal unsafe struct IDisposableVftbl @@ -74,7 +97,7 @@ internal unsafe struct IDisposableVftbl } /// -/// The implementation. +/// The implementation. /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -83,7 +106,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; @@ -99,7 +122,7 @@ static IDisposableImpl() } /// - /// Gets a pointer to the managed implementation. + /// Gets a pointer to the managed implementation. /// public static nint Vtable { @@ -113,7 +136,7 @@ private static HRESULT Close(void* thisPtr) { try { - ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr).Dispose(); + ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr).Dispose(); return WellKnownErrorCodes.S_OK; } @@ -125,15 +148,17 @@ private static HRESULT Close(void* thisPtr) } /// -/// The implementation for . +/// The implementation for . /// +[WindowsRuntimeMappedMetadata("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 efe35d588..eb80f13ac 100644 --- a/src/WinRT.Runtime2/ABI/System/IServiceProvider.cs +++ b/src/WinRT.Runtime2/ABI/System/IServiceProvider.cs @@ -13,10 +13,33 @@ #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.IServiceProvider))] + +[assembly: TypeMapAssociation( + source: typeof(IServiceProvider), + proxy: typeof(ABI.System.IServiceProviderInterfaceImpl))] + namespace ABI.System; /// -/// Marshaller for . +/// ABI type for . +/// +[WindowsRuntimeMappedMetadata("Microsoft.UI.Xaml.WinUIContract")] +[WindowsRuntimeMetadataTypeName("Microsoft.UI.Xaml.IXamlServiceProvider")] +[WindowsRuntimeMappedType(typeof(global::System.IServiceProvider))] +file static class IServiceProvider; + +/// +/// Marshaller for . /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -25,20 +48,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, @@ -46,7 +69,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) { @@ -74,7 +97,7 @@ public static unsafe class IServiceProviderMethods } /// -/// Binding type for . +/// Binding type for . /// [StructLayout(LayoutKind.Sequential)] internal unsafe struct IServiceProviderVftbl @@ -89,7 +112,7 @@ internal unsafe struct IServiceProviderVftbl } /// -/// The implementation. +/// The implementation. /// [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -98,7 +121,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; @@ -114,7 +137,7 @@ static IServiceProviderImpl() } /// - /// Gets a pointer to the managed implementation. + /// Gets a pointer to the managed implementation. /// public static nint Vtable { @@ -133,7 +156,7 @@ private static HRESULT GetService(void* thisPtr, Type serviceType, void** result try { - var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); + var thisObject = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr); global::System.Type? managedType = TypeMarshaller.ConvertToManaged(serviceType); @@ -157,15 +180,15 @@ private static HRESULT GetService(void* thisPtr, Type serviceType, void** result } /// -/// The implementation for . +/// The implementation for . /// [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 04a9eceec..737f8f0b2 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`1", target: typeof(ABI.System.Int16), @@ -27,7 +32,11 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[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 059387d4e..8027851cb 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`1", target: typeof(ABI.System.Int32), @@ -27,7 +32,11 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[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 90b5e5066..16e56d333 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`1", target: typeof(ABI.System.Int64), @@ -27,7 +32,11 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[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 961c84282..749ddbf80 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`1", target: typeof(ABI.System.Numerics.Matrix3x2), @@ -29,7 +34,11 @@ namespace ABI.System.Numerics; /// ABI type for . /// /// +[WindowsRuntimeMappedMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[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 6ae0ad045..9f94ecaf3 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`1", target: typeof(ABI.System.Numerics.Matrix4x4), @@ -29,7 +34,11 @@ namespace ABI.System.Numerics; /// ABI type for . /// /// +[WindowsRuntimeMappedMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[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 fdc3561b7..fe5ff5323 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`1", target: typeof(ABI.System.Numerics.Plane), @@ -29,7 +34,11 @@ namespace ABI.System.Numerics; /// ABI type for . /// /// +[WindowsRuntimeMappedMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[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 3d433e97e..dced508ef 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`1", target: typeof(ABI.System.Numerics.Quaternion), @@ -29,7 +34,11 @@ namespace ABI.System.Numerics; /// ABI type for . /// /// +[WindowsRuntimeMappedMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[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 d38c10f1e..dabd87f76 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`1", target: typeof(ABI.System.Numerics.Vector2), @@ -29,7 +34,11 @@ namespace ABI.System.Numerics; /// ABI type for . /// /// +[WindowsRuntimeMappedMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[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 b98d37e25..e463900f3 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`1", target: typeof(ABI.System.Numerics.Vector3), @@ -29,7 +34,11 @@ namespace ABI.System.Numerics; /// ABI type for . /// /// +[WindowsRuntimeMappedMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[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 93037f809..8368e3f2a 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`1", target: typeof(ABI.System.Numerics.Vector4), @@ -29,7 +34,11 @@ namespace ABI.System.Numerics; /// ABI type for . /// /// +[WindowsRuntimeMappedMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[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 94b486110..ecfd3b21e 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; @@ -14,7 +21,9 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMappedMetadata("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 6785bbb21..a051b2ee1 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`1", target: typeof(ABI.System.Single), @@ -27,7 +32,11 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[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 24b7b8f18..372401f90 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`1", target: typeof(ABI.System.String), @@ -28,7 +33,10 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[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 67672353b..27fb0b68c 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`1", target: typeof(ABI.System.TimeSpan), @@ -28,7 +33,11 @@ namespace ABI.System; /// ABI type for . /// /// +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[WindowsRuntimeMetadataTypeName("Windows.Foundation.TimeSpan")] +[WindowsRuntimeMappedType(typeof(global::System.TimeSpan))] +[WindowsRuntimeReferenceType(typeof(global::System.TimeSpan?))] [TimeSpanComWrappersMarshaller] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, diff --git a/src/WinRT.Runtime2/ABI/System/Type.cs b/src/WinRT.Runtime2/ABI/System/Type.cs index c2637c68d..6ea224173 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; @@ -20,6 +21,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: "Windows.UI.Xaml.Interop.TypeName", + target: typeof(ABI.System.Type), + trimTarget: typeof(Type))] + [assembly: TypeMap( value: "Windows.Foundation.IReference`1", target: typeof(ABI.System.Type), @@ -34,7 +40,10 @@ namespace ABI.System; /// ABI type for . /// /// +[WindowsRuntimeMappedMetadata("Windows.Foundation.UniversalApiContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[WindowsRuntimeMetadataTypeName("Windows.UI.Xaml.Interop.TypeName")] +[WindowsRuntimeMappedType(typeof(global::System.Type))] [TypeComWrappersMarshaller] [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, @@ -92,10 +101,164 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR { ArgumentNullException.ThrowIfNull(value); - string abiName = ""; // TODO - TypeKind kind = default; // TODO + // 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; + } + + // 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); + + // Special handling for some types which can never be used in a 'Nullable' instantiation (e.g. interfaces) + if (nullableUnderlyingType is null) + { + // 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 (!value.IsGenericType && value.IsDefined(typeof(WindowsRuntimeMetadataAttribute))) + { + reference = new TypeReference { Name = value.FullName, Kind = TypeKind.Metadata }; + + return; + } + + // 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 (WindowsRuntimeMetadataInfo.TryGetInfo(value, out WindowsRuntimeMetadataInfo? metadataInfo)) + { + reference = new TypeReference { Name = metadataInfo.GetMetadataTypeName(), Kind = TypeKind.Metadata }; + + 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; + } - reference = new TypeReference { Name = abiName, Kind = kind }; + 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) + { + // 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; + + // We need special handling for several cases that represent non-boxed types + if (nullableUnderlyingType is null) + { + // 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'. + // This will also handle generic delegate types, which will also use '[WindowsRuntimeMetadataTypeName]'. + if (marshallingInfo.TryGetMetadataTypeName(out string? metadataTypeName)) + { + reference = new TypeReference { Name = metadataTypeName, Kind = kind }; + + return; + } + + // If the type is 'KeyValuePair<,>', we are guaranteed to have a runtime class name on the proxy type. + // Note that because this type is a reference type in the Windows Runtime type system, the runtime class + // name will be the correct name to use here, as it will just be the 'IKeyValuePair<,>' interface type. + // This is why we don't need additional attributes for the metadata type name in this specific scenario. + if (typeOrUnderlyingType.IsValueType && + typeOrUnderlyingType.IsGenericType && + typeOrUnderlyingType.GetGenericTypeDefinition() == typeof(KeyValuePair<,>)) + { + reference = new TypeReference { Name = marshallingInfo.GetRuntimeClassName(), 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 of these is true: + // - The value type is not generic (the only possible case would've been 'KeyValuePair<,>') + // - The delegate is not generic (or the proxy type would've had a metadata name on it) + // 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; + } + } + + // 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. + 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 }; + + 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. + // 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) + { + reference = new TypeReference { Name = value.FullName, Kind = TypeKind.Primitive }; + + return; + } + + CustomType: + + // All other cases are treated as custom types (e.g. user-defined types) + reference = new TypeReference { Name = value.AssemblyQualifiedName, Kind = TypeKind.Custom }; } /// @@ -122,7 +285,89 @@ public static void ConvertToUnmanagedUnsafe(global::System.Type value, out TypeR return global::System.Type.GetType(typeName.ToString()); } - global::System.Type? type = null; // TODO + // 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); + } + + // 'IBindableVectorView' has no equivalent .NET type, so we just return 'null' here. This needs + // to be special-cased, or it would end up resolving a marshalling info instance (because the + // external type map still has an entry for this name, for marshalling), and then fail because + // there's no associated public type for the resulting proxy type retrieved from the type map. + if (typeName.SequenceEqual(WellKnownXamlRuntimeClassNames.IBindableVectorView)) + { + return null; + } + } + + global::System.Type? type = null; + + // 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)) + { + // 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; + + // 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); + } + + if (publicType.IsValueType) + { + // 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.IsGenericType && + publicType.GetGenericTypeDefinition() == typeof(KeyValuePair<,>)) + { + type = publicType; + } + else + { + // For other 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 = marshallingInfo.ReferenceType; + } + } + else + { + // Otherwise, just use the public type directly + type = 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 diff --git a/src/WinRT.Runtime2/ABI/System/UInt16.cs b/src/WinRT.Runtime2/ABI/System/UInt16.cs index 83ae103e9..236f032b3 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`1", target: typeof(ABI.System.UInt16), @@ -27,7 +32,11 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[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 00ffe4090..1789d62bf 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`1", target: typeof(ABI.System.UInt32), @@ -27,7 +32,11 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[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 a2565417d..66bff493e 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`1", target: typeof(ABI.System.UInt64), @@ -27,7 +32,11 @@ namespace ABI.System; /// /// ABI type for . /// +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[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 08691d722..ed0659fc8 100644 --- a/src/WinRT.Runtime2/ABI/System/Uri.cs +++ b/src/WinRT.Runtime2/ABI/System/Uri.cs @@ -26,7 +26,9 @@ namespace ABI.System; /// ABI type for . /// /// +[WindowsRuntimeMappedMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.Uri")] +[WindowsRuntimeMappedType(typeof(global::System.Uri))] [UriComWrappersMarshaller] file static class Uri; diff --git a/src/WinRT.Runtime2/ABI/Windows.Foundation/AsyncActionCompletedHandler.cs b/src/WinRT.Runtime2/ABI/Windows.Foundation/AsyncActionCompletedHandler.cs index 544859c4c..1b28d99b7 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`1", target: typeof(AsyncActionCompletedHandler), diff --git a/src/WinRT.Runtime2/ABI/Windows.Foundation/Collections/CollectionChange.cs b/src/WinRT.Runtime2/ABI/Windows.Foundation/Collections/CollectionChange.cs index bf5ab1107..7528ac029 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`1", 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 ad9fdc704..d838435ff 100644 --- a/src/WinRT.Runtime2/ABI/Windows.Foundation/Collections/IVectorChangedEventArgs.cs +++ b/src/WinRT.Runtime2/ABI/Windows.Foundation/Collections/IVectorChangedEventArgs.cs @@ -14,7 +14,18 @@ #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(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.IVectorChangedEventArgsInterfaceImpl))] + +namespace ABI.Windows.Foundation.Collections; /// /// Marshaller for . @@ -141,7 +152,7 @@ private static HRESULT get_CollectionChange(void* thisPtr, CollectionChange* res return WellKnownErrorCodes.S_OK; } - catch (global::System.Exception e) + catch (Exception e) { return RestrictedErrorInfoExceptionMarshaller.ConvertToUnmanaged(e); } @@ -159,7 +170,7 @@ private static HRESULT get_Index(void* thisPtr, uint* result) return WellKnownErrorCodes.S_OK; } - catch (global::System.Exception e) + catch (Exception e) { return RestrictedErrorInfoExceptionMarshaller.ConvertToUnmanaged(e); } diff --git a/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncAction.cs b/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncAction.cs index 94d905a2c..ce91772d7 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(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.IAsyncActionInterfaceImpl))] diff --git a/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncInfo.cs b/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncInfo.cs index 58a2a514d..3bac615c1 100644 --- a/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncInfo.cs +++ b/src/WinRT.Runtime2/ABI/Windows.Foundation/IAsyncInfo.cs @@ -13,6 +13,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: "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.IAsyncInfoInterfaceImpl))] + namespace ABI.Windows.Foundation; /// diff --git a/src/WinRT.Runtime2/ABI/Windows.Foundation/Point.cs b/src/WinRT.Runtime2/ABI/Windows.Foundation/Point.cs index 0fe3f087f..2b08feac8 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`1", target: typeof(Point), diff --git a/src/WinRT.Runtime2/ABI/Windows.Foundation/Rect.cs b/src/WinRT.Runtime2/ABI/Windows.Foundation/Rect.cs index 316d54c11..49de7b265 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`1", target: typeof(Rect), diff --git a/src/WinRT.Runtime2/ABI/Windows.Foundation/Size.cs b/src/WinRT.Runtime2/ABI/Windows.Foundation/Size.cs index c8a3c8e72..3e502df0a 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`1", target: typeof(Size), 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 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 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 diff --git a/src/WinRT.Runtime2/Bindables/WindowsRuntimeEnumerable.cs b/src/WinRT.Runtime2/Bindables/WindowsRuntimeEnumerable.cs index c7f81f8e8..3cfb05256 100644 --- a/src/WinRT.Runtime2/Bindables/WindowsRuntimeEnumerable.cs +++ b/src/WinRT.Runtime2/Bindables/WindowsRuntimeEnumerable.cs @@ -30,7 +30,7 @@ public WindowsRuntimeEnumerable(WindowsRuntimeObjectReference nativeObjectRefere DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] [EditorBrowsable(EditorBrowsableState.Never)] - protected internal sealed override bool HasUnwrappableNativeObjectReference => true; + protected internal override bool HasUnwrappableNativeObjectReference => true; /// public IEnumerator GetEnumerator() @@ -49,7 +49,7 @@ WindowsRuntimeObjectReferenceValue IWindowsRuntimeInterface.GetInte DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] [EditorBrowsable(EditorBrowsableState.Never)] - protected sealed override bool IsOverridableInterface(in Guid iid) + protected override bool IsOverridableInterface(in Guid iid) { return false; } diff --git a/src/WinRT.Runtime2/Bindables/WindowsRuntimeIterator.cs b/src/WinRT.Runtime2/Bindables/WindowsRuntimeEnumerator.cs similarity index 92% rename from src/WinRT.Runtime2/Bindables/WindowsRuntimeIterator.cs rename to src/WinRT.Runtime2/Bindables/WindowsRuntimeEnumerator.cs index 4cdd17d20..428ed44b1 100644 --- a/src/WinRT.Runtime2/Bindables/WindowsRuntimeIterator.cs +++ b/src/WinRT.Runtime2/Bindables/WindowsRuntimeEnumerator.cs @@ -16,7 +16,7 @@ namespace WindowsRuntime; /// /// [WindowsRuntimeManagedOnlyType] -internal sealed class WindowsRuntimeIterator : WindowsRuntimeObject, IEnumerator, IWindowsRuntimeInterface +internal sealed class WindowsRuntimeEnumerator : WindowsRuntimeObject, IEnumerator, IWindowsRuntimeInterface { /// /// Indicates whether the underlying enumerator has been initialized. @@ -29,11 +29,11 @@ internal sealed class WindowsRuntimeIterator : WindowsRuntimeObject, IEnumerator private bool _hadCurrent = true; /// - /// Creates a instance with the specified parameters. + /// Creates a instance with the specified parameters. /// /// The inner Windows Runtime object reference to wrap in the current instance. /// Thrown if is . - public WindowsRuntimeIterator(WindowsRuntimeObjectReference nativeObjectReference) + public WindowsRuntimeEnumerator(WindowsRuntimeObjectReference nativeObjectReference) : base(nativeObjectReference) { } diff --git a/src/WinRT.Runtime2/Bindables/WindowsRuntimeList.cs b/src/WinRT.Runtime2/Bindables/WindowsRuntimeList.cs index 47b275fd7..22c165c22 100644 --- a/src/WinRT.Runtime2/Bindables/WindowsRuntimeList.cs +++ b/src/WinRT.Runtime2/Bindables/WindowsRuntimeList.cs @@ -57,7 +57,7 @@ WindowsRuntimeObjectReference InitializeIIterableObjectReference() DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] [EditorBrowsable(EditorBrowsableState.Never)] - protected internal sealed override bool HasUnwrappableNativeObjectReference => true; + protected internal override bool HasUnwrappableNativeObjectReference => true; /// public bool IsFixedSize => false; @@ -152,7 +152,7 @@ WindowsRuntimeObjectReferenceValue IWindowsRuntimeInterface.GetInte DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] [EditorBrowsable(EditorBrowsableState.Never)] - protected sealed override bool IsOverridableInterface(in Guid iid) + protected override bool IsOverridableInterface(in Guid iid) { return false; } diff --git a/src/WinRT.Runtime2/Bindables/WindowsRuntimeReadOnlyList.cs b/src/WinRT.Runtime2/Bindables/WindowsRuntimeReadOnlyList.cs new file mode 100644 index 000000000..9fe64254e --- /dev/null +++ b/src/WinRT.Runtime2/Bindables/WindowsRuntimeReadOnlyList.cs @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Collections; +using System.ComponentModel; +using System.Runtime.CompilerServices; +using System.Threading; +using WindowsRuntime.InteropServices; + +namespace WindowsRuntime; + +/// +/// The implementation of all projected Windows Runtime readonly types. +/// +/// +/// +/// There is no IReadOnlyList interface in .NET, so this type only implements . +/// This still provides better performance when casting to that interface for enumeration than having to go through +/// an opaque marshalled object and using . +/// +[WindowsRuntimeManagedOnlyType] +internal sealed class WindowsRuntimeReadOnlyList : WindowsRuntimeObject, + IEnumerable, + IWindowsRuntimeInterface +{ + /// + /// Creates a instance with the specified parameters. + /// + /// The inner Windows Runtime object reference to wrap in the current instance. + /// Thrown if is . + public WindowsRuntimeReadOnlyList(WindowsRuntimeObjectReference nativeObjectReference) + : base(nativeObjectReference) + { + } + + /// + /// Gets the lazy-loaded, cached object reference for Windows.UI.Xaml.Interop.IBindableIterable for the current object. + /// + private WindowsRuntimeObjectReference IBindableIterableObjectReference + { + get + { + [MethodImpl(MethodImplOptions.NoInlining)] + WindowsRuntimeObjectReference InitializeIIterableObjectReference() + { + _ = Interlocked.CompareExchange( + location1: ref field, + value: NativeObjectReference.As(in WellKnownWindowsInterfaceIIDs.IID_IBindableIterable), + comparand: null); + + return field; + } + + return field ?? InitializeIIterableObjectReference(); + } + } + + /// + [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, + DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, + UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] + [EditorBrowsable(EditorBrowsableState.Never)] + protected internal override bool HasUnwrappableNativeObjectReference => true; + + /// + public IEnumerator GetEnumerator() + { + return ABI.System.Collections.IEnumerableMethods.GetEnumerator(IBindableIterableObjectReference); + } + + /// + WindowsRuntimeObjectReferenceValue IWindowsRuntimeInterface.GetInterface() + { + return IBindableIterableObjectReference.AsValue(); + } + + /// + [Obsolete(WindowsRuntimeConstants.PrivateImplementationDetailObsoleteMessage, + DiagnosticId = WindowsRuntimeConstants.PrivateImplementationDetailObsoleteDiagnosticId, + UrlFormat = WindowsRuntimeConstants.CsWinRTDiagnosticsUrlFormat)] + [EditorBrowsable(EditorBrowsableState.Never)] + protected override bool IsOverridableInterface(in Guid iid) + { + return false; + } +} \ No newline at end of file diff --git a/src/WinRT.Runtime2/InteropServices/Events/EventRegistrationToken.cs b/src/WinRT.Runtime2/InteropServices/Events/EventRegistrationToken.cs index 744eee580..8b590c358 100644 --- a/src/WinRT.Runtime2/InteropServices/Events/EventRegistrationToken.cs +++ b/src/WinRT.Runtime2/InteropServices/Events/EventRegistrationToken.cs @@ -13,6 +13,7 @@ namespace WindowsRuntime.InteropServices; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[WindowsRuntimeReferenceType(typeof(EventRegistrationToken?))] [ABI.WindowsRuntime.InteropServices.EventRegistrationTokenComWrappersMarshaller] public struct EventRegistrationToken : IEquatable { 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 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/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 diff --git a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMarshallingInfo.cs index 479a8f864..73f26e7df 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). /// /// /// @@ -94,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). /// @@ -111,7 +117,23 @@ 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; + + /// + /// 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). + /// + /// + /// A value of -1 indicates a value that has not been computed yet. + /// + private volatile int _isMetadataType; /// /// Creates a new instance with the specified parameters. @@ -122,6 +144,20 @@ private WindowsRuntimeMarshallingInfo(Type metadataProviderType, Type? publicTyp { _metadataProviderType = metadataProviderType; _publicType = publicType; + _isMetadataType = -1; + } + + /// + /// Creates a new instance with the specified parameters. + /// + /// + /// + /// + private WindowsRuntimeMarshallingInfo(Type metadataProviderType, Type? publicType, bool isMetadataType) + { + _metadataProviderType = metadataProviderType; + _publicType = publicType; + _isMetadataType = isMetadataType ? 1 : 0; } /// @@ -139,10 +175,23 @@ Type InitializePublicType() // public type yet. We can do that here. WindowsRuntimeMappedTypeAttribute mappedTypeAttribute = _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 public type. " + + $"This code path should have never been reached. Please file an issue at https://github.com/microsoft/CsWinRT."); + } + // In this scenario, it is guaranteed that the '[WindowsRuntimeMappedType]' attribute will be present on the // metadata provider type, as we would not have any way to go back to the associated public type otherwise, // which is needed in some cases. The attribute being missing would indicate some code generation error. - Debug.Assert(mappedTypeAttribute is not null); + if (mappedTypeAttribute is null) + { + ThrowNotSupportedException(); + } // Cache the public type for later. We don't need a compare exchange here, as even if we did concurrent // queries for this value, the result would always be the same. So we can skip that small overhead here. @@ -153,6 +202,81 @@ 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). + /// + 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() + { + // 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; + + 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. /// @@ -370,11 +494,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; @@ -391,7 +515,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; @@ -443,8 +567,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) @@ -452,23 +602,112 @@ 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 = _runtimeClassName; + + // We have a cached runtime class name, so return it immediately + if (value is not null) + { + if (value is "") + { + runtimeClassName = null; + + return false; + } - ThrowNotSupportedException(); + runtimeClassName = value; + + return true; + } + + return Load(out runtimeClassName); + } + + /// + /// 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."); } - return _runtimeClassName ??= runtimeClassNameAttribute.RuntimeClassName; + ThrowNotSupportedException(); } - return _runtimeClassName ?? InitializeRuntimeClassName(); + 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 metadata type name, 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); } /// @@ -481,24 +720,26 @@ 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) + ? new(metadataProviderType, metadataProviderType, isMetadataType: true) : new(metadataProviderType, publicType: null); } /// /// 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) { + 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 @@ -506,43 +747,16 @@ 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); + // 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') return null; } -} - -/// -/// A placeholder type. -/// -file sealed unsafe class PlaceholderWindowsRuntimeComWrappersMarshallerAttribute : WindowsRuntimeComWrappersMarshallerAttribute -{ - /// - /// The shared placeholder instance. - /// - public static 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!; - } } \ No newline at end of file diff --git a/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMetadataInfo.cs b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMetadataInfo.cs new file mode 100644 index 000000000..b8f13152f --- /dev/null +++ b/src/WinRT.Runtime2/InteropServices/TypeMapInfo/WindowsRuntimeMetadataInfo.cs @@ -0,0 +1,227 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +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 TypeToMetadataInfoTable = []; + + /// + /// 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; + + /// + private volatile Type? _publicType; + + /// + /// The cached metadata type name for the type. + /// + private volatile string? _metadataTypeName; + + /// + /// Creates a new instance with the specified parameters. + /// + /// + /// + private WindowsRuntimeMetadataInfo(Type metadataProviderType, Type? publicType) + { + _metadataProviderType = metadataProviderType; + _publicType = publicType; + } + + /// + public Type PublicType + { + get + { + // Same implementation as in 'WindowsRuntimeMarshallingInfo.PublicType', see notes there + [MethodImpl(MethodImplOptions.NoInlining)] + Type InitializePublicType() + { + WindowsRuntimeMappedTypeAttribute mappedTypeAttribute = _metadataProviderType.GetCustomAttribute(inherit: false)!; + + [DoesNotReturn] + [StackTraceHidden] + void ThrowNotSupportedException() + { + throw new NotSupportedException( + $"The metadata provider type '{_metadataProviderType}' does not have an associated public type. " + + $"This code path should have never been reached. Please file an issue at https://github.com/microsoft/CsWinRT."); + } + + if (mappedTypeAttribute is null) + { + ThrowNotSupportedException(); + } + + return _publicType ??= mappedTypeAttribute.PublicType; + } + + return _publicType ?? InitializePublicType(); + } + } + + /// + /// 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 = TypeToMetadataInfoTable.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 = TypeToMetadataInfoTable.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 metadataProviderType.IsDefined(typeof(WindowsRuntimeMetadataAttribute), inherit: false) + ? new(metadataProviderType, metadataProviderType) + : new(metadataProviderType, publicType: null); + } + + /// + /// 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, managedType); + } + + // If we have a proxy type, then that will be the metadata provider + if (ProxyTypeMapping.TryGetValue(managedType, out Type? proxyType)) + { + return new(proxyType, managedType); + } + + // We don't have a metadata provider for the type + return null; + } +} \ No newline at end of file diff --git a/src/WinRT.Runtime2/InteropServices/WindowsRuntimeComWrappers.cs b/src/WinRT.Runtime2/InteropServices/WindowsRuntimeComWrappers.cs index 0c931aa39..1587ce8a3 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; @@ -187,11 +188,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); } @@ -295,11 +294,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) @@ -418,4 +413,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 diff --git a/src/WinRT.Runtime2/Windows.Foundation/Collections/CollectionChange.cs b/src/WinRT.Runtime2/Windows.Foundation/Collections/CollectionChange.cs index a0607a86c..3f5b381c9 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`1")] +[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 4789b2fe7..23c0945b7 100644 --- a/src/WinRT.Runtime2/Windows.Foundation/Point.cs +++ b/src/WinRT.Runtime2/Windows.Foundation/Point.cs @@ -19,6 +19,7 @@ namespace Windows.Foundation; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[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 395ffbdd1..1f2d345de 100644 --- a/src/WinRT.Runtime2/Windows.Foundation/Rect.cs +++ b/src/WinRT.Runtime2/Windows.Foundation/Rect.cs @@ -21,6 +21,7 @@ namespace Windows.Foundation; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[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 e70216d41..e2afc8cdb 100644 --- a/src/WinRT.Runtime2/Windows.Foundation/Size.cs +++ b/src/WinRT.Runtime2/Windows.Foundation/Size.cs @@ -18,6 +18,7 @@ namespace Windows.Foundation; /// [WindowsRuntimeMetadata("Windows.Foundation.FoundationContract")] [WindowsRuntimeClassName("Windows.Foundation.IReference`1")] +[WindowsRuntimeReferenceType(typeof(Size?))] [SupportedOSPlatform("Windows10.0.10240.0")] [ContractVersion(typeof(FoundationContract), 65536u)] [ABI.Windows.Foundation.SizeComWrappersMarshaller] diff --git a/src/cswinrt.slnx b/src/cswinrt.slnx index 6e0af3fbc..f656521e7 100644 --- a/src/cswinrt.slnx +++ b/src/cswinrt.slnx @@ -324,6 +324,14 @@ + + + + + + + + diff --git a/src/cswinrt/code_writers.h b/src/cswinrt/code_writers.h index 453dcf76a..cdb56c099 100644 --- a/src/cswinrt/code_writers.h +++ b/src/cswinrt/code_writers.h @@ -4694,17 +4694,47 @@ R"(file static class %InterfaceEntriesImpl )", name, name, bind(type), name, bind(type), name); } + + 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"( +[assembly: TypeMap( + value: "%", + target: typeof(%), + trimTarget: typeof(%))] +)", + 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)); 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) @@ -4744,6 +4774,11 @@ R"(#pragma warning disable IL2026 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()); @@ -9271,13 +9306,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); { @@ -9336,10 +9372,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/helpers.h b/src/cswinrt/helpers.h index d7e6faa4f..fddf6539a 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", diff --git a/src/cswinrt/main.cpp b/src/cswinrt/main.cpp index e1d0a8916..0dd5e133f 100644 --- a/src/cswinrt/main.cpp +++ b/src/cswinrt/main.cpp @@ -275,26 +275,39 @@ Where is one or more of: { case category::class_type: // For both static and attributes, we don't need to pass them across the ABI. - if (!is_static(type) && - !is_attribute_type(type)) + 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; }