From f59216b6cd937abb127fbc746f15ca4bce0f1779 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 3 Aug 2024 01:43:03 -0700 Subject: [PATCH 1/3] Add support for nullable enums and structs and add some missed attributes in the WUX types --- src/Tests/AuthoringConsumptionTest/test.cpp | 2 + src/Tests/AuthoringTest/Program.cs | 4 +- .../MatchingRefApiCompatBaseline.txt | 3 +- src/WinRT.Runtime/Projections/Nullable.cs | 77 ++++++++++++++++++- src/cswinrt/code_writers.h | 9 ++- .../Microsoft.UI.Xaml.Media.Animation.cs | 3 + .../Microsoft.UI.Xaml/Microsoft.UI.Xaml.cs | 6 ++ .../Windows.UI.Xaml.Controls.Primitives.cs | 3 + .../Windows.UI.Xaml.Media.Animation.cs | 11 ++- .../Windows.UI.Xaml.Media.Media3D.cs | 3 + .../Windows.UI.Xaml.Media.cs | 3 + .../Windows.UI.Xaml/Windows.UI.Xaml.cs | 18 +++++ 12 files changed, 137 insertions(+), 5 deletions(-) diff --git a/src/Tests/AuthoringConsumptionTest/test.cpp b/src/Tests/AuthoringConsumptionTest/test.cpp index a4c74bab0..da4669c9a 100644 --- a/src/Tests/AuthoringConsumptionTest/test.cpp +++ b/src/Tests/AuthoringConsumptionTest/test.cpp @@ -720,4 +720,6 @@ TEST(AuthoringTest, XamlMetadataProvider) CustomXamlMetadataProvider provider; EXPECT_NE(provider.GetXamlType(winrt::xaml_typename>()), nullptr); EXPECT_NE(provider.GetXamlType(winrt::xaml_typename>()), nullptr); + EXPECT_NE(provider.GetXamlType(winrt::xaml_typename>()), nullptr); + EXPECT_NE(provider.GetXamlType(winrt::xaml_typename>()), nullptr); } \ No newline at end of file diff --git a/src/Tests/AuthoringTest/Program.cs b/src/Tests/AuthoringTest/Program.cs index 226824477..a287162c8 100644 --- a/src/Tests/AuthoringTest/Program.cs +++ b/src/Tests/AuthoringTest/Program.cs @@ -1112,7 +1112,9 @@ public sealed class CustomXamlMetadataProvider : IXamlMetadataProvider public IXamlType GetXamlType(Type type) { if (type == typeof(Nullable) || - type == typeof(TimeSpan?)) + type == typeof(TimeSpan?) || + type == typeof(BasicEnum?) || + type == typeof(FlagsEnum?)) { return new XamlType(type); } diff --git a/src/WinRT.Runtime/MatchingRefApiCompatBaseline.txt b/src/WinRT.Runtime/MatchingRefApiCompatBaseline.txt index 7021fe80b..1b3f9a5d2 100644 --- a/src/WinRT.Runtime/MatchingRefApiCompatBaseline.txt +++ b/src/WinRT.Runtime/MatchingRefApiCompatBaseline.txt @@ -272,4 +272,5 @@ TypesMustExist : Type 'Microsoft.UI.Xaml.Data.BindableCustomProperty' does not e TypesMustExist : Type 'WinRT.GeneratedBindableCustomPropertyAttribute' does not exist in the reference but it does exist in the implementation. TypesMustExist : Type 'Microsoft.UI.Xaml.Data.IBindableCustomPropertyImplementation' does not exist in the reference but it does exist in the implementation. MembersMustExist : Member 'public void ABI.System.Uri.DisposeAbiArray(System.Object)' does not exist in the reference but it does exist in the implementation. -Total Issues: 273 +TypesMustExist : Type 'WinRT.EnumTypeDetails' does not exist in the reference but it does exist in the implementation. +Total Issues: 274 diff --git a/src/WinRT.Runtime/Projections/Nullable.cs b/src/WinRT.Runtime/Projections/Nullable.cs index 20b878db8..c57f27771 100644 --- a/src/WinRT.Runtime/Projections/Nullable.cs +++ b/src/WinRT.Runtime/Projections/Nullable.cs @@ -2285,7 +2285,32 @@ private static Func GetValueFactoryInternal(global::System if (type == typeof(global::System.Numerics.Vector2)) return typeof(global::System.Nullable); if (type == typeof(global::System.Numerics.Vector3)) return typeof(global::System.Nullable); if (type == typeof(global::System.Numerics.Vector4)) return typeof(global::System.Nullable); - + +#if NET + var winrtExposedClassAttribute = type.GetCustomAttribute(false); + if (winrtExposedClassAttribute == null) + { + var authoringMetadaType = type.GetAuthoringMetadataType(); + if (authoringMetadaType != null) + { + winrtExposedClassAttribute = authoringMetadaType.GetCustomAttribute(false); + } + } + + if (winrtExposedClassAttribute != null && winrtExposedClassAttribute.WinRTExposedTypeDetails != null) + { + if (Activator.CreateInstance(winrtExposedClassAttribute.WinRTExposedTypeDetails) is IWinRTNullableTypeDetails nullableTypeDetails) + { + return nullableTypeDetails.GetNullableType(); + } + } + + if (!RuntimeFeature.IsDynamicCodeCompiled) + { + throw new NotSupportedException($"Failed to construct nullable with type '{type}'."); + } +#endif + return null; } } @@ -2311,6 +2336,7 @@ namespace WinRT internal interface IWinRTNullableTypeDetails { object GetNullableValue(IInspectable inspectable); + Type GetNullableType(); } public sealed class StructTypeDetails : IWinRTExposedTypeDetails, IWinRTNullableTypeDetails where T: struct where TAbi : unmanaged @@ -2364,6 +2390,8 @@ unsafe object IWinRTNullableTypeDetails.GetNullableValue(IInspectable inspectabl Marshal.Release(nullablePtr); } } + + Type IWinRTNullableTypeDetails.GetNullableType() => typeof(global::System.Nullable); } public abstract class DelegateTypeDetails : IWinRTExposedTypeDetails, IWinRTNullableTypeDetails where T : global::System.Delegate @@ -2418,6 +2446,53 @@ unsafe object IWinRTNullableTypeDetails.GetNullableValue(IInspectable inspectabl Marshal.Release(nullablePtr); } } + + // Delegates are handled separately. + Type IWinRTNullableTypeDetails.GetNullableType() => throw new NotImplementedException(); + } + + public sealed class EnumTypeDetails : IWinRTExposedTypeDetails, IWinRTNullableTypeDetails where T : struct, Enum + { + [SkipLocalsInit] + public ComWrappers.ComInterfaceEntry[] GetExposedInterfaces() + { + Span entries = stackalloc ComWrappers.ComInterfaceEntry[2]; + int count = 0; + + if (FeatureSwitches.EnableIReferenceSupport) + { + entries[count++] = new ComWrappers.ComInterfaceEntry + { + IID = global::WinRT.Interop.IID.IID_IPropertyValue, + Vtable = ABI.Windows.Foundation.ManagedIPropertyValueImpl.AbiToProjectionVftablePtr + }; + + var type = typeof(T); + if (type.IsDefined(typeof(FlagsAttribute))) + { + entries[count++] = new ComWrappers.ComInterfaceEntry + { + IID = ABI.System.Nullable_FlagsEnum.GetIID(type), + Vtable = ABI.System.Nullable_FlagsEnum.AbiToProjectionVftablePtr + }; + } + else + { + entries[count++] = new ComWrappers.ComInterfaceEntry + { + IID = ABI.System.Nullable_IntEnum.GetIID(type), + Vtable = ABI.System.Nullable_IntEnum.AbiToProjectionVftablePtr + }; + } + } + + return entries.Slice(0, count).ToArray(); + } + + Type IWinRTNullableTypeDetails.GetNullableType() => typeof(global::System.Nullable); + + // Unboxing enums are handled separately. + object IWinRTNullableTypeDetails.GetNullableValue(IInspectable inspectable) => throw new NotImplementedException(); } } #endif diff --git a/src/cswinrt/code_writers.h b/src/cswinrt/code_writers.h index 5a5117620..2697f704d 100644 --- a/src/cswinrt/code_writers.h +++ b/src/cswinrt/code_writers.h @@ -3606,6 +3606,7 @@ private % AsInternal(InterfaceTag<%> _) => % ?? Make_%(); return isFactory || get_category(type) == category::struct_type || + get_category(type) == category::enum_type || (get_category(type) == category::delegate_type && distance(type.GenericParam()) == 0); } @@ -3619,6 +3620,11 @@ private % AsInternal(InterfaceTag<%> _) => % ?? Make_%(); bind(type, typedef_name_type::Projected, false), bind(type, is_type_blittable(type) ? typedef_name_type::Projected : typedef_name_type::ABI, false)); } + else if (get_category(type) == category::enum_type) + { + w.write(R"([global::WinRT.WinRTExposedType(typeof(global::WinRT.EnumTypeDetails<%>))])", + bind(type, typedef_name_type::Projected, false)); + } else { w.write(R"([global::WinRT.WinRTExposedType(typeof(%%WinRTTypeDetails))])", @@ -9606,10 +9612,11 @@ return true; auto enum_underlying_type = is_flags_enum(type) ? "uint" : "int"; - w.write(R"(%%% enum % : % + w.write(R"(%%%% enum % : % { )", bind(type), + bind(type, false), bind(type, true), (settings.internal || settings.embedded) ? (settings.public_enums ? "public" : "internal") : "public", bind(type, typedef_name_type::Projected, false), enum_underlying_type); diff --git a/src/cswinrt/strings/additions/Microsoft.UI.Xaml.Media.Animation/Microsoft.UI.Xaml.Media.Animation.cs b/src/cswinrt/strings/additions/Microsoft.UI.Xaml.Media.Animation/Microsoft.UI.Xaml.Media.Animation.cs index 043c09d98..1ad2d3305 100644 --- a/src/cswinrt/strings/additions/Microsoft.UI.Xaml.Media.Animation/Microsoft.UI.Xaml.Media.Animation.cs +++ b/src/cswinrt/strings/additions/Microsoft.UI.Xaml.Media.Animation/Microsoft.UI.Xaml.Media.Animation.cs @@ -82,6 +82,9 @@ public TimeSpan TimeSpan } [global::WinRT.WindowsRuntimeType("Microsoft.UI")] +#if NET + [global::WinRT.WinRTExposedType(typeof(global::WinRT.EnumTypeDetails))] +#endif #if EMBED internal #else diff --git a/src/cswinrt/strings/additions/Microsoft.UI.Xaml/Microsoft.UI.Xaml.cs b/src/cswinrt/strings/additions/Microsoft.UI.Xaml/Microsoft.UI.Xaml.cs index e9cf7cf84..d9388a8f1 100644 --- a/src/cswinrt/strings/additions/Microsoft.UI.Xaml/Microsoft.UI.Xaml.cs +++ b/src/cswinrt/strings/additions/Microsoft.UI.Xaml/Microsoft.UI.Xaml.cs @@ -155,6 +155,9 @@ public double BottomLeft } [global::WinRT.WindowsRuntimeType("Microsoft.UI")] +#if NET + [global::WinRT.WinRTExposedType(typeof(global::WinRT.EnumTypeDetails))] +#endif #if EMBED internal #else @@ -406,6 +409,9 @@ public override int GetHashCode() } [global::WinRT.WindowsRuntimeType("Microsoft.UI")] +#if NET + [global::WinRT.WinRTExposedType(typeof(global::WinRT.EnumTypeDetails))] +#endif #if EMBED internal #else diff --git a/src/cswinrt/strings/additions/Windows.UI.Xaml.Controls/Windows.UI.Xaml.Controls.Primitives.cs b/src/cswinrt/strings/additions/Windows.UI.Xaml.Controls/Windows.UI.Xaml.Controls.Primitives.cs index ec28e9295..194a509a7 100644 --- a/src/cswinrt/strings/additions/Windows.UI.Xaml.Controls/Windows.UI.Xaml.Controls.Primitives.cs +++ b/src/cswinrt/strings/additions/Windows.UI.Xaml.Controls/Windows.UI.Xaml.Controls.Primitives.cs @@ -5,6 +5,9 @@ namespace Windows.UI.Xaml.Controls.Primitives [global::WinRT.WindowsRuntimeType("Windows.UI.Xaml")] [global::WinRT.WindowsRuntimeHelperType(typeof(global::ABI.Windows.UI.Xaml.Controls.Primitives.GeneratorPosition))] +#if NET + [global::WinRT.WinRTExposedType(typeof(global::WinRT.StructTypeDetails))] +#endif [StructLayout(LayoutKind.Sequential)] #if EMBED internal diff --git a/src/cswinrt/strings/additions/Windows.UI.Xaml.Media.Animation/Windows.UI.Xaml.Media.Animation.cs b/src/cswinrt/strings/additions/Windows.UI.Xaml.Media.Animation/Windows.UI.Xaml.Media.Animation.cs index 259898959..3170b4fb7 100644 --- a/src/cswinrt/strings/additions/Windows.UI.Xaml.Media.Animation/Windows.UI.Xaml.Media.Animation.cs +++ b/src/cswinrt/strings/additions/Windows.UI.Xaml.Media.Animation/Windows.UI.Xaml.Media.Animation.cs @@ -5,6 +5,9 @@ namespace Windows.UI.Xaml.Media.Animation [global::WinRT.WindowsRuntimeType("Windows.UI.Xaml")] [global::WinRT.WindowsRuntimeHelperType(typeof(global::ABI.Windows.UI.Xaml.Media.Animation.KeyTime))] +#if NET + [global::WinRT.WinRTExposedType(typeof(global::WinRT.StructTypeDetails))] +#endif [StructLayout(LayoutKind.Sequential)] #if EMBED internal @@ -79,6 +82,9 @@ public TimeSpan TimeSpan } [global::WinRT.WindowsRuntimeType("Windows.UI.Xaml")] +#if NET + [global::WinRT.WinRTExposedType(typeof(global::WinRT.EnumTypeDetails))] +#endif #if EMBED internal #else @@ -92,7 +98,10 @@ enum RepeatBehaviorType } [global::WinRT.WindowsRuntimeType("Windows.UI.Xaml")] - [global::WinRT.WindowsRuntimeHelperType(typeof(global::ABI.Windows.UI.Xaml.Media.Animation.RepeatBehavior))] + [global::WinRT.WindowsRuntimeHelperType(typeof(global::ABI.Windows.UI.Xaml.Media.Animation.RepeatBehavior))] +#if NET + [global::WinRT.WinRTExposedType(typeof(global::WinRT.StructTypeDetails))] +#endif [StructLayout(LayoutKind.Sequential)] #if EMBED internal diff --git a/src/cswinrt/strings/additions/Windows.UI.Xaml.Media.Media3D/Windows.UI.Xaml.Media.Media3D.cs b/src/cswinrt/strings/additions/Windows.UI.Xaml.Media.Media3D/Windows.UI.Xaml.Media.Media3D.cs index 98dfb069e..df02ccd76 100644 --- a/src/cswinrt/strings/additions/Windows.UI.Xaml.Media.Media3D/Windows.UI.Xaml.Media.Media3D.cs +++ b/src/cswinrt/strings/additions/Windows.UI.Xaml.Media.Media3D/Windows.UI.Xaml.Media.Media3D.cs @@ -5,6 +5,9 @@ namespace Windows.UI.Xaml.Media.Media3D [global::WinRT.WindowsRuntimeType("Windows.UI.Xaml")] [global::WinRT.WindowsRuntimeHelperType(typeof(global::ABI.Windows.UI.Xaml.Media.Media3D.Matrix3D))] +#if NET + [global::WinRT.WinRTExposedType(typeof(global::WinRT.StructTypeDetails))] +#endif [StructLayout(LayoutKind.Sequential)] #if EMBED internal diff --git a/src/cswinrt/strings/additions/Windows.UI.Xaml.Media/Windows.UI.Xaml.Media.cs b/src/cswinrt/strings/additions/Windows.UI.Xaml.Media/Windows.UI.Xaml.Media.cs index b156e5104..92a20c4d3 100644 --- a/src/cswinrt/strings/additions/Windows.UI.Xaml.Media/Windows.UI.Xaml.Media.cs +++ b/src/cswinrt/strings/additions/Windows.UI.Xaml.Media/Windows.UI.Xaml.Media.cs @@ -5,6 +5,9 @@ namespace Windows.UI.Xaml.Media [global::WinRT.WindowsRuntimeType("Windows.UI.Xaml")] [global::WinRT.WindowsRuntimeHelperType(typeof(global::ABI.Windows.UI.Xaml.Media.Matrix))] +#if NET + [global::WinRT.WinRTExposedType(typeof(global::WinRT.StructTypeDetails))] +#endif [StructLayout(LayoutKind.Sequential)] #if EMBED internal diff --git a/src/cswinrt/strings/additions/Windows.UI.Xaml/Windows.UI.Xaml.cs b/src/cswinrt/strings/additions/Windows.UI.Xaml/Windows.UI.Xaml.cs index 341d016d6..3fb1fabeb 100644 --- a/src/cswinrt/strings/additions/Windows.UI.Xaml/Windows.UI.Xaml.cs +++ b/src/cswinrt/strings/additions/Windows.UI.Xaml/Windows.UI.Xaml.cs @@ -5,6 +5,9 @@ namespace Windows.UI.Xaml [global::WinRT.WindowsRuntimeType("Windows.UI.Xaml")] [global::WinRT.WindowsRuntimeHelperType(typeof(global::ABI.Windows.UI.Xaml.CornerRadius))] +#if NET + [global::WinRT.WinRTExposedType(typeof(global::WinRT.StructTypeDetails))] +#endif [StructLayout(LayoutKind.Sequential)] #if EMBED internal @@ -152,6 +155,9 @@ public double BottomLeft } [global::WinRT.WindowsRuntimeType("Windows.UI.Xaml")] +#if NET + [global::WinRT.WinRTExposedType(typeof(global::WinRT.EnumTypeDetails))] +#endif #if EMBED internal #else @@ -166,6 +172,9 @@ enum GridUnitType [global::WinRT.WindowsRuntimeType("Windows.UI.Xaml")] [global::WinRT.WindowsRuntimeHelperType(typeof(global::ABI.Windows.UI.Xaml.GridLength))] +#if NET + [global::WinRT.WinRTExposedType(typeof(global::WinRT.StructTypeDetails))] +#endif [StructLayout(LayoutKind.Sequential)] #if EMBED internal @@ -284,6 +293,9 @@ internal string ToString(global::System.Globalization.CultureInfo cultureInfo) [global::WinRT.WindowsRuntimeType("Windows.UI.Xaml")] [global::WinRT.WindowsRuntimeHelperType(typeof(global::ABI.Windows.UI.Xaml.Thickness))] +#if NET + [global::WinRT.WinRTExposedType(typeof(global::WinRT.StructTypeDetails))] +#endif [StructLayout(LayoutKind.Sequential)] #if EMBED internal @@ -397,6 +409,9 @@ public override int GetHashCode() } [global::WinRT.WindowsRuntimeType("Windows.UI.Xaml")] +#if NET + [global::WinRT.WinRTExposedType(typeof(global::WinRT.EnumTypeDetails))] +#endif #if EMBED internal #else @@ -411,6 +426,9 @@ enum DurationType [global::WinRT.WindowsRuntimeType("Windows.UI.Xaml")] [global::WinRT.WindowsRuntimeHelperType(typeof(global::ABI.Windows.UI.Xaml.Duration))] +#if NET + [global::WinRT.WinRTExposedType(typeof(global::WinRT.StructTypeDetails))] +#endif [StructLayout(LayoutKind.Sequential)] #if EMBED internal From d0f00fe41b9b143a366697e8572371bc43518876 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sat, 3 Aug 2024 02:10:10 -0700 Subject: [PATCH 2/3] Remove exception that gets caught --- src/WinRT.Runtime/TypeNameSupport.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WinRT.Runtime/TypeNameSupport.cs b/src/WinRT.Runtime/TypeNameSupport.cs index 05452b36e..42e7704d0 100644 --- a/src/WinRT.Runtime/TypeNameSupport.cs +++ b/src/WinRT.Runtime/TypeNameSupport.cs @@ -267,7 +267,7 @@ static Type ResolveGenericType(Type resolvedType, Type[] genericTypes, string ru { if (type.IsValueType) { - throw new NotSupportedException($"Cannot provide generic type from '{runtimeClassName}'."); + return null; } } } From ba91b1a3c3803c0f4ff5032defc71f0ba556cd55 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Sun, 4 Aug 2024 17:59:40 -0700 Subject: [PATCH 3/3] PR feedback --- src/WinRT.Runtime/Projections/Nullable.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/WinRT.Runtime/Projections/Nullable.cs b/src/WinRT.Runtime/Projections/Nullable.cs index c57f27771..b19ecd696 100644 --- a/src/WinRT.Runtime/Projections/Nullable.cs +++ b/src/WinRT.Runtime/Projections/Nullable.cs @@ -2451,7 +2451,7 @@ unsafe object IWinRTNullableTypeDetails.GetNullableValue(IInspectable inspectabl Type IWinRTNullableTypeDetails.GetNullableType() => throw new NotImplementedException(); } - public sealed class EnumTypeDetails : IWinRTExposedTypeDetails, IWinRTNullableTypeDetails where T : struct, Enum + public sealed class EnumTypeDetails : IWinRTExposedTypeDetails, IWinRTNullableTypeDetails where T : unmanaged, Enum { [SkipLocalsInit] public ComWrappers.ComInterfaceEntry[] GetExposedInterfaces() @@ -2467,12 +2467,11 @@ public ComWrappers.ComInterfaceEntry[] GetExposedInterfaces() Vtable = ABI.Windows.Foundation.ManagedIPropertyValueImpl.AbiToProjectionVftablePtr }; - var type = typeof(T); - if (type.IsDefined(typeof(FlagsAttribute))) + if (typeof(T).IsDefined(typeof(FlagsAttribute))) { entries[count++] = new ComWrappers.ComInterfaceEntry { - IID = ABI.System.Nullable_FlagsEnum.GetIID(type), + IID = ABI.System.Nullable_FlagsEnum.GetIID(typeof(T)), Vtable = ABI.System.Nullable_FlagsEnum.AbiToProjectionVftablePtr }; } @@ -2480,7 +2479,7 @@ public ComWrappers.ComInterfaceEntry[] GetExposedInterfaces() { entries[count++] = new ComWrappers.ComInterfaceEntry { - IID = ABI.System.Nullable_IntEnum.GetIID(type), + IID = ABI.System.Nullable_IntEnum.GetIID(typeof(T)), Vtable = ABI.System.Nullable_IntEnum.AbiToProjectionVftablePtr }; }