From 3d080db3915ede8224b3e30bf3d6818c32217332 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Wed, 31 Jan 2024 15:55:32 -0800 Subject: [PATCH 1/2] Hard-code the numeric scalar types in CoerceValue and simplify enum marshalling to remove any usage of Convert.ChangeType. Convert.ChangeType was rooting a significant amount of code that would never be used (such as string.IConvertible.ToDateTime). --- src/WinRT.Runtime/Marshalers.cs | 4 +- .../Projections/IPropertyValue.net5.cs | 47 ++++++++++++++++--- .../IPropertyValue.netstandard2.0.cs | 46 +++++++++++++++--- 3 files changed, 83 insertions(+), 14 deletions(-) diff --git a/src/WinRT.Runtime/Marshalers.cs b/src/WinRT.Runtime/Marshalers.cs index a3d930bbe..7e32c68a1 100644 --- a/src/WinRT.Runtime/Marshalers.cs +++ b/src/WinRT.Runtime/Marshalers.cs @@ -1720,11 +1720,11 @@ internal static class Marshaler private static object ReturnParameter(object arg) => arg; - private static unsafe void CopyIntEnum(object value, IntPtr dest) => *(int*)dest.ToPointer() = (int)Convert.ChangeType(value, typeof(int)); + private static unsafe void CopyIntEnum(object value, IntPtr dest) => *(int*)dest.ToPointer() = Convert.ToInt32(value); private static unsafe void CopyIntEnumDirect(object value, IntPtr dest) => *(int*)dest.ToPointer() = (int)value; - private static unsafe void CopyUIntEnum(object value, IntPtr dest) => *(uint*)dest.ToPointer() = (uint)Convert.ChangeType(value, typeof(uint)); + private static unsafe void CopyUIntEnum(object value, IntPtr dest) => *(uint*)dest.ToPointer() = Convert.ToUInt32(value); private static unsafe void CopyUIntEnumDirect(object value, IntPtr dest) => *(uint*)dest.ToPointer() = (uint)value; } diff --git a/src/WinRT.Runtime/Projections/IPropertyValue.net5.cs b/src/WinRT.Runtime/Projections/IPropertyValue.net5.cs index 817ef7e2a..04ea9a9f4 100644 --- a/src/WinRT.Runtime/Projections/IPropertyValue.net5.cs +++ b/src/WinRT.Runtime/Projections/IPropertyValue.net5.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using WinRT; @@ -106,8 +107,8 @@ internal static class ManagedIPropertyValueImpl private const int TYPE_E_TYPEMISMATCH = unchecked((int)0x80028CA0); private const int DISP_E_OVERFLOW = unchecked((int)0x8002000A); private static IPropertyValue.Vftbl AbiToProjectionVftable; - public static IntPtr AbiToProjectionVftablePtr; - + public static IntPtr AbiToProjectionVftablePtr; + internal static readonly Guid IID = new(0x4BD682DD, 0x7554, 0x40E9, 0x9A, 0x9B, 0x82, 0x65, 0x4E, 0xDE, 0x7E, 0x62); static unsafe ManagedIPropertyValueImpl() @@ -325,12 +326,46 @@ private static T CoerceValue(object value) { return (T)(object)guid.ToString("D", global::System.Globalization.CultureInfo.InvariantCulture); } + else if (typeof(T) == typeof(byte)) + { + return (T)(object)Convert.ToByte(value, global::System.Globalization.CultureInfo.InvariantCulture); + } + else if (typeof(T) == typeof(short)) + { + return (T)(object)Convert.ToInt16(value, global::System.Globalization.CultureInfo.InvariantCulture); + } + else if (typeof(T) == typeof(ushort)) + { + return (T)(object)Convert.ToUInt16(value, global::System.Globalization.CultureInfo.InvariantCulture); + } + else if (typeof(T) == typeof(int)) + { + return (T)(object)Convert.ToInt32(value, global::System.Globalization.CultureInfo.InvariantCulture); + } + else if (typeof(T) == typeof(uint)) + { + return (T)(object)Convert.ToUInt32(value, global::System.Globalization.CultureInfo.InvariantCulture); + } + else if (typeof(T) == typeof(long)) + { + return (T)(object)Convert.ToInt64(value, global::System.Globalization.CultureInfo.InvariantCulture); + } + else if (typeof(T) == typeof(ulong)) + { + return (T)(object)Convert.ToUInt64(value, global::System.Globalization.CultureInfo.InvariantCulture); + } + else if (typeof(T) == typeof(float)) + { + return (T)(object)Convert.ToSingle(value, global::System.Globalization.CultureInfo.InvariantCulture); + } + else if (typeof(T) == typeof(double)) + { + return (T)(object)Convert.ToDouble(value, global::System.Globalization.CultureInfo.InvariantCulture); + } else { - if (NumericScalarTypes.TryGetValue(typeof(T), out _)) - { - return (T)Convert.ChangeType(value, typeof(T), global::System.Globalization.CultureInfo.InvariantCulture); - } + Debug.Assert(!NumericScalarTypes.ContainsKey(typeof(T))); + throw new InvalidCastException("", TYPE_E_TYPEMISMATCH); } } catch (FormatException) diff --git a/src/WinRT.Runtime/Projections/IPropertyValue.netstandard2.0.cs b/src/WinRT.Runtime/Projections/IPropertyValue.netstandard2.0.cs index 4e1b4ff08..d16ea2dc0 100644 --- a/src/WinRT.Runtime/Projections/IPropertyValue.netstandard2.0.cs +++ b/src/WinRT.Runtime/Projections/IPropertyValue.netstandard2.0.cs @@ -106,8 +106,8 @@ internal static class ManagedIPropertyValueImpl private const int TYPE_E_TYPEMISMATCH = unchecked((int)0x80028CA0); private const int DISP_E_OVERFLOW = unchecked((int)0x8002000A); private static IPropertyValue.Vftbl AbiToProjectionVftable; - public static IntPtr AbiToProjectionVftablePtr; - + public static IntPtr AbiToProjectionVftablePtr; + internal static readonly Guid IID = new(0x4BD682DD, 0x7554, 0x40E9, 0x9A, 0x9B, 0x82, 0x65, 0x4E, 0xDE, 0x7E, 0x62); private static readonly Delegate[] DelegateCache = new Delegate[39]; @@ -327,12 +327,46 @@ private static T CoerceValue(object value) { return (T)(object)guid.ToString("D", global::System.Globalization.CultureInfo.InvariantCulture); } + else if (typeof(T) == typeof(byte)) + { + return (T)(object)Convert.ToByte(value, global::System.Globalization.CultureInfo.InvariantCulture); + } + else if (typeof(T) == typeof(short)) + { + return (T)(object)Convert.ToInt16(value, global::System.Globalization.CultureInfo.InvariantCulture); + } + else if (typeof(T) == typeof(ushort)) + { + return (T)(object)Convert.ToUInt16(value, global::System.Globalization.CultureInfo.InvariantCulture); + } + else if (typeof(T) == typeof(int)) + { + return (T)(object)Convert.ToInt32(value, global::System.Globalization.CultureInfo.InvariantCulture); + } + else if (typeof(T) == typeof(uint)) + { + return (T)(object)Convert.ToUInt32(value, global::System.Globalization.CultureInfo.InvariantCulture); + } + else if (typeof(T) == typeof(long)) + { + return (T)(object)Convert.ToInt64(value, global::System.Globalization.CultureInfo.InvariantCulture); + } + else if (typeof(T) == typeof(ulong)) + { + return (T)(object)Convert.ToUInt64(value, global::System.Globalization.CultureInfo.InvariantCulture); + } + else if (typeof(T) == typeof(float)) + { + return (T)(object)Convert.ToSingle(value, global::System.Globalization.CultureInfo.InvariantCulture); + } + else if (typeof(T) == typeof(double)) + { + return (T)(object)Convert.ToDouble(value, global::System.Globalization.CultureInfo.InvariantCulture); + } else { - if (NumericScalarTypes.TryGetValue(typeof(T), out _)) - { - return (T)Convert.ChangeType(value, typeof(T), global::System.Globalization.CultureInfo.InvariantCulture); - } + Debug.Assert(!NumericScalarTypes.ContainsKey(typeof(T))); + throw new InvalidCastException("", TYPE_E_TYPEMISMATCH); } } catch (FormatException) From adc52210cf826d3a82e8b742d40936800c303d9b Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Wed, 31 Jan 2024 16:35:36 -0800 Subject: [PATCH 2/2] Add missing using --- src/WinRT.Runtime/Projections/IPropertyValue.netstandard2.0.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/WinRT.Runtime/Projections/IPropertyValue.netstandard2.0.cs b/src/WinRT.Runtime/Projections/IPropertyValue.netstandard2.0.cs index d16ea2dc0..5508d1304 100644 --- a/src/WinRT.Runtime/Projections/IPropertyValue.netstandard2.0.cs +++ b/src/WinRT.Runtime/Projections/IPropertyValue.netstandard2.0.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using WinRT;