diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj index 377157b709167..4531c27a2f6e6 100644 --- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -264,8 +264,8 @@ Common\System\Runtime\InteropServices\ComEventsSink.cs - - Common\System\Runtime\InteropServices\Variant.cs + + Common\System\Runtime\InteropServices\BuiltInVariantExtensions.cs diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/CustomMarshalers/EnumerableViewOfDispatch.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/CustomMarshalers/EnumerableViewOfDispatch.cs index fa94eefcfb6a8..3c152d5a3a7d3 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/CustomMarshalers/EnumerableViewOfDispatch.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/CustomMarshalers/EnumerableViewOfDispatch.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Runtime.InteropServices.ComTypes; +using System.Runtime.InteropServices.Marshalling; namespace System.Runtime.InteropServices.CustomMarshalers { @@ -22,7 +23,7 @@ public EnumerableViewOfDispatch(object dispatch) public Collections.IEnumerator GetEnumerator() { - Variant result; + ComVariant result; unsafe { void* resultLocal = &result; @@ -54,7 +55,7 @@ public Collections.IEnumerator GetEnumerator() } finally { - result.Clear(); + result.Dispose(); if (enumVariantPtr != IntPtr.Zero) Marshal.Release(enumVariantPtr); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/InteropHelpers.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/InteropHelpers.cs index faacce2ea5d14..2beac031c7864 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/InteropHelpers.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/InteropHelpers.cs @@ -9,6 +9,7 @@ using System.Runtime; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; using System.Runtime.InteropServices.ObjectiveC; using System.Runtime.Loader; using System.Text; @@ -576,8 +577,8 @@ internal static unsafe void CleanupVariant(IntPtr pDstNativeVariant) { #if TARGET_WINDOWS #pragma warning disable CA1416 - Variant* data = (Variant*)pDstNativeVariant; - data->Clear(); + ComVariant* data = (ComVariant*)pDstNativeVariant; + data->Dispose(); #pragma warning restore CA1416 #else throw new PlatformNotSupportedException(SR.PlatformNotSupported_ComInterop); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj index ec3a3363a511a..e1f1b75afc317 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -256,8 +256,8 @@ - - System\Runtime\InteropServices\Variant.cs + + System\Runtime\InteropServices\BuiltInVariantExtensions.cs Interop\Windows\Kernel32\Interop.IsDebuggerPresent.cs diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Com.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Com.cs index 18828c7ad17f7..97694ca5d6675 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Com.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Com.cs @@ -5,6 +5,7 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.InteropServices.ComTypes; +using System.Runtime.InteropServices.Marshalling; using System.Runtime.Versioning; namespace System.Runtime.InteropServices @@ -121,10 +122,10 @@ public static unsafe void GetNativeVariantForObject(object? obj, IntPtr pDstNati { ArgumentNullException.ThrowIfNull(pDstNativeVariant); - Variant* data = (Variant*)pDstNativeVariant; + ComVariant* data = (ComVariant*)pDstNativeVariant; if (obj == null) { - data->VariantType = VarEnum.VT_EMPTY; + *data = default; return; } @@ -132,132 +133,132 @@ public static unsafe void GetNativeVariantForObject(object? obj, IntPtr pDstNati { // Int and String most used types. case int value: - data->AsI4 = value; + *data = ComVariant.Create(value); break; case string value: - data->AsBstr = value; + *data = ComVariant.Create(new BStrWrapper(value)); break; case bool value: - data->AsBool = value; + *data = ComVariant.Create(value); break; case byte value: - data->AsUi1 = value; + *data = ComVariant.Create(value); break; case sbyte value: - data->AsI1 = value; + *data = ComVariant.Create(value); break; case short value: - data->AsI2 = value; + *data = ComVariant.Create(value); break; case ushort value: - data->AsUi2 = value; + *data = ComVariant.Create(value); break; case uint value: - data->AsUi4 = value; + *data = ComVariant.Create(value); break; case long value: - data->AsI8 = value; + *data = ComVariant.Create(value); break; case ulong value: - data->AsUi8 = value; + *data = ComVariant.Create(value); break; case float value: - data->AsR4 = value; + *data = ComVariant.Create(value); break; case double value: - data->AsR8 = value; + *data = ComVariant.Create(value); break; case DateTime value: - data->AsDate = value; + *data = ComVariant.Create(value); break; case decimal value: - data->AsDecimal = value; + *data = ComVariant.Create(value); break; case char value: - data->AsUi2 = value; + *data = ComVariant.Create(value); break; case BStrWrapper value: - data->AsBstr = value.WrappedObject; + *data = ComVariant.Create(value); break; #pragma warning disable 0618 // CurrencyWrapper is obsolete case CurrencyWrapper value: - data->AsCy = value.WrappedObject; + *data = ComVariant.Create(value); break; #pragma warning restore 0618 case UnknownWrapper value: - data->AsUnknown = value.WrappedObject; + *data = ComVariant.CreateRaw(VarEnum.VT_UNKNOWN, GetIUnknownForObject(value.WrappedObject)); break; case DispatchWrapper value: - data->AsDispatch = value.WrappedObject; + *data = ComVariant.CreateRaw(VarEnum.VT_DISPATCH, GetIDispatchForObject(value.WrappedObject)); break; case ErrorWrapper value: - data->AsError = value.ErrorCode; + *data = ComVariant.Create(value); break; case VariantWrapper value: throw new ArgumentException(); case DBNull value: - data->SetAsNULL(); + *data = ComVariant.Null; break; case Missing value: - data->AsError = DISP_E_PARAMNOTFOUND; + *data = ComVariant.CreateRaw(VarEnum.VT_ERROR, DISP_E_PARAMNOTFOUND); break; case IConvertible value: switch (value.GetTypeCode()) { case TypeCode.Empty: - data->VariantType = VarEnum.VT_EMPTY; + *data = default; break; case TypeCode.Object: - data->AsUnknown = value; + *data = ComVariant.CreateRaw(VarEnum.VT_UNKNOWN, GetIUnknownForObject(value)); break; case TypeCode.DBNull: - data->SetAsNULL(); + *data = ComVariant.Null; break; case TypeCode.Boolean: - data->AsBool = value.ToBoolean(null); + *data = ComVariant.Create(value.ToBoolean(null)); break; case TypeCode.Char: - data->AsUi2 = value.ToChar(null); + *data = ComVariant.Create(value.ToChar(null)); break; case TypeCode.SByte: - data->AsI1 = value.ToSByte(null); + *data = ComVariant.Create(value.ToSByte(null)); break; case TypeCode.Byte: - data->AsUi1 = value.ToByte(null); + *data = ComVariant.Create(value.ToByte(null)); break; case TypeCode.Int16: - data->AsI2 = value.ToInt16(null); + *data = ComVariant.Create(value.ToInt16(null)); break; case TypeCode.UInt16: - data->AsUi2 = value.ToUInt16(null); + *data = ComVariant.Create(value.ToUInt16(null)); break; case TypeCode.Int32: - data->AsI4 = value.ToInt32(null); + *data = ComVariant.Create(value.ToInt32(null)); break; case TypeCode.UInt32: - data->AsUi4 = value.ToUInt32(null); + *data = ComVariant.Create(value.ToUInt32(null)); break; case TypeCode.Int64: - data->AsI8 = value.ToInt64(null); + *data = ComVariant.Create(value.ToInt64(null)); break; case TypeCode.UInt64: - data->AsUi8 = value.ToUInt64(null); + *data = ComVariant.Create(value.ToUInt64(null)); break; case TypeCode.Single: - data->AsR4 = value.ToSingle(null); + *data = ComVariant.Create(value.ToSingle(null)); break; case TypeCode.Double: - data->AsR8 = value.ToDouble(null); + *data = ComVariant.Create(value.ToDouble(null)); break; case TypeCode.Decimal: - data->AsDecimal = value.ToDecimal(null); + *data = ComVariant.Create(value.ToDecimal(null)); break; case TypeCode.DateTime: - data->AsDate = value.ToDateTime(null); + *data = ComVariant.Create(value.ToDateTime(null)); break; case TypeCode.String: - data->AsBstr = value.ToString(); + *data = ComVariant.Create(new BStrWrapper(value.ToString(null))); break; default: throw new NotSupportedException(); @@ -273,7 +274,7 @@ public static unsafe void GetNativeVariantForObject(object? obj, IntPtr pDstNati case ValueType: throw new NotSupportedException("VT_RECORD"); default: - data->AsDispatch = obj; + *data = ComVariant.CreateRaw(VarEnum.VT_UNKNOWN, GetIDispatchForObject(obj)); break; } } @@ -303,38 +304,35 @@ public static object GetObjectForIUnknown(IntPtr pUnk) { ArgumentNullException.ThrowIfNull(pSrcNativeVariant); - Variant* data = (Variant*)pSrcNativeVariant; + ComVariant* data = (ComVariant*)pSrcNativeVariant; - if (data->IsEmpty) - { - return null; - } - - switch (data->VariantType) + switch (data->VarType) { + case VarEnum.VT_EMPTY: + return null; case VarEnum.VT_NULL: return DBNull.Value; - case VarEnum.VT_I1: return data->AsI1; - case VarEnum.VT_I2: return data->AsI2; - case VarEnum.VT_I4: return data->AsI4; - case VarEnum.VT_I8: return data->AsI8; - case VarEnum.VT_UI1: return data->AsUi1; - case VarEnum.VT_UI2: return data->AsUi2; - case VarEnum.VT_UI4: return data->AsUi4; - case VarEnum.VT_UI8: return data->AsUi8; - case VarEnum.VT_INT: return data->AsInt; - case VarEnum.VT_UINT: return data->AsUint; - case VarEnum.VT_BOOL: return data->AsBool; - case VarEnum.VT_ERROR: return data->AsError; - case VarEnum.VT_R4: return data->AsR4; - case VarEnum.VT_R8: return data->AsR8; - case VarEnum.VT_DECIMAL: return data->AsDecimal; - case VarEnum.VT_CY: return data->AsCy; - case VarEnum.VT_DATE: return data->AsDate; - case VarEnum.VT_BSTR: return data->AsBstr; - case VarEnum.VT_UNKNOWN: return data->AsUnknown; - case VarEnum.VT_DISPATCH: return data->AsDispatch; + case VarEnum.VT_I1: return data->As(); + case VarEnum.VT_I2: return data->As(); + case VarEnum.VT_I4: return data->As(); + case VarEnum.VT_I8: return data->As(); + case VarEnum.VT_UI1: return data->As(); + case VarEnum.VT_UI2: return data->As(); + case VarEnum.VT_UI4: return data->As(); + case VarEnum.VT_UI8: return data->As(); + case VarEnum.VT_INT: return data->As(); + case VarEnum.VT_UINT: return data->As(); + case VarEnum.VT_BOOL: return data->As() != -1; + case VarEnum.VT_ERROR: return data->As(); + case VarEnum.VT_R4: return data->As(); + case VarEnum.VT_R8: return data->As(); + case VarEnum.VT_DECIMAL: return data->As(); + case VarEnum.VT_CY: return decimal.FromOACurrency(data->GetRawDataRef()); + case VarEnum.VT_DATE: return data->As(); + case VarEnum.VT_BSTR: return PtrToStringBSTR(data->GetRawDataRef()); + case VarEnum.VT_UNKNOWN: return GetObjectForIUnknown(data->GetRawDataRef()); + case VarEnum.VT_DISPATCH: return GetObjectForIUnknown(data->GetRawDataRef()); default: // Other VARIANT types not supported yet. diff --git a/src/coreclr/tools/Common/TypeSystem/Interop/InteropTypes.cs b/src/coreclr/tools/Common/TypeSystem/Interop/InteropTypes.cs index 3beeb5f187a89..7fdd0f0659620 100644 --- a/src/coreclr/tools/Common/TypeSystem/Interop/InteropTypes.cs +++ b/src/coreclr/tools/Common/TypeSystem/Interop/InteropTypes.cs @@ -54,7 +54,7 @@ public static MetadataType GetMarshalDirectiveException(TypeSystemContext contex public static MetadataType GetVariant(TypeSystemContext context) { - return context.SystemModule.GetKnownType("System.Runtime.InteropServices", "Variant"); + return context.SystemModule.GetKnownType("System.Runtime.InteropServices.Marshalling", "ComVariant"); } public static bool IsSafeHandle(TypeSystemContext context, TypeDesc type) diff --git a/src/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs b/src/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs new file mode 100644 index 0000000000000..777a1c03b0a7a --- /dev/null +++ b/src/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs @@ -0,0 +1,172 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices.Marshalling; +using System.Runtime.Versioning; + +namespace System.Runtime.InteropServices +{ + [SupportedOSPlatform("windows")] + internal static class BuiltInInteropVariantExtensions + { + // VARIANT_BOOL constants. + internal const short VARIANT_TRUE = -1; + internal const short VARIANT_FALSE = 0; + private static unsafe ref T GetByRefDataRef(this ref ComVariant variant) + where T : unmanaged + { + Debug.Assert(variant.VarType.HasFlag(VarEnum.VT_BYREF)); + return ref Unsafe.AsRef((void*)variant.GetRawDataRef()); + } + + public static unsafe void CopyFromIndirect(this ref ComVariant variant, object value) + { + VarEnum vt = (VarEnum)(((int)variant.VarType) & ~((int)VarEnum.VT_BYREF)); + + if (value == null) + { + if (vt == VarEnum.VT_DISPATCH || vt == VarEnum.VT_UNKNOWN || vt == VarEnum.VT_BSTR) + { + variant.GetRawDataRef() = IntPtr.Zero; + } + return; + } + + if ((vt & VarEnum.VT_ARRAY) != 0) + { + ComVariant vArray; + Marshal.GetNativeVariantForObject(value, (IntPtr)(void*)&vArray); + variant.GetRawDataRef() = vArray.GetRawDataRef(); + return; + } + + switch (vt) + { + case VarEnum.VT_I1: + variant.GetByRefDataRef() = (sbyte)value; + break; + + case VarEnum.VT_UI1: + variant.GetByRefDataRef() = (byte)value; + break; + + case VarEnum.VT_I2: + variant.GetByRefDataRef() = (short)value; + break; + + case VarEnum.VT_UI2: + variant.GetByRefDataRef() = (ushort)value; + break; + + case VarEnum.VT_BOOL: + variant.GetByRefDataRef() = (bool)value ? VARIANT_TRUE : VARIANT_FALSE; + break; + + case VarEnum.VT_I4: + case VarEnum.VT_INT: + variant.GetByRefDataRef() = (int)value; + break; + + case VarEnum.VT_UI4: + case VarEnum.VT_UINT: + variant.GetByRefDataRef() = (uint)value; + break; + + case VarEnum.VT_ERROR: + variant.GetByRefDataRef() = ((ErrorWrapper)value).ErrorCode; + break; + + case VarEnum.VT_I8: + variant.GetByRefDataRef() = (long)value; + break; + + case VarEnum.VT_UI8: + variant.GetByRefDataRef() = (ulong)value; + break; + + case VarEnum.VT_R4: + variant.GetByRefDataRef() = (float)value; + break; + + case VarEnum.VT_R8: + variant.GetByRefDataRef() = (double)value; + break; + + case VarEnum.VT_DATE: + variant.GetByRefDataRef() = ((DateTime)value).ToOADate(); + break; + + case VarEnum.VT_UNKNOWN: + variant.GetByRefDataRef() = Marshal.GetIUnknownForObject(value); + break; + + case VarEnum.VT_DISPATCH: + variant.GetByRefDataRef() = Marshal.GetIDispatchForObject(value); + break; + + case VarEnum.VT_BSTR: + variant.GetByRefDataRef() = Marshal.StringToBSTR((string)value); + break; + + case VarEnum.VT_CY: + variant.GetByRefDataRef() = decimal.ToOACurrency((decimal)value); + break; + + case VarEnum.VT_DECIMAL: + variant.GetByRefDataRef() = (decimal)value; + break; + + case VarEnum.VT_VARIANT: + Marshal.GetNativeVariantForObject(value, variant.GetRawDataRef()); + break; + + default: + throw new ArgumentException(); + } + } + + /// + /// Get the managed object representing the Variant. + /// + /// + public static object? ToObject(this ref ComVariant variant) + { + return variant.VarType switch + { + VarEnum.VT_EMPTY => null, + VarEnum.VT_NULL => DBNull.Value, + VarEnum.VT_I1 => variant.As(), + VarEnum.VT_I2 => variant.As(), + VarEnum.VT_I4 => variant.As(), + VarEnum.VT_I8 => variant.As(), + VarEnum.VT_UI1 => variant.As(), + VarEnum.VT_UI2 => variant.As(), + VarEnum.VT_UI4 => variant.As(), + VarEnum.VT_UI8 => variant.As(), + VarEnum.VT_INT => variant.As(), + VarEnum.VT_UINT => variant.As(), + VarEnum.VT_BOOL => variant.As(), + VarEnum.VT_ERROR => variant.As(), + VarEnum.VT_R4 => variant.As(), + VarEnum.VT_R8 => variant.As(), + VarEnum.VT_DECIMAL => variant.As(), + VarEnum.VT_CY => decimal.FromOACurrency(variant.GetRawDataRef()), + VarEnum.VT_DATE => variant.As(), + VarEnum.VT_BSTR => Marshal.PtrToStringBSTR(variant.GetRawDataRef()), + VarEnum.VT_UNKNOWN => Marshal.GetObjectForIUnknown(variant.GetRawDataRef()), + VarEnum.VT_DISPATCH => Marshal.GetObjectForIUnknown(variant.GetRawDataRef()), + _ => GetObjectFromNativeVariant(ref variant), + }; + } + + private static unsafe object? GetObjectFromNativeVariant(ref ComVariant variant) + { + fixed (void* pVariant = &variant) + { + return Marshal.GetObjectForNativeVariant((nint)pVariant); + } + } + } +} diff --git a/src/libraries/Common/src/System/Runtime/InteropServices/ComEventsSink.cs b/src/libraries/Common/src/System/Runtime/InteropServices/ComEventsSink.cs index 3747e2f331b4b..5155bea123ce0 100644 --- a/src/libraries/Common/src/System/Runtime/InteropServices/ComEventsSink.cs +++ b/src/libraries/Common/src/System/Runtime/InteropServices/ComEventsSink.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.Runtime.InteropServices.Marshalling; using System.Runtime.Versioning; namespace System.Runtime.InteropServices @@ -120,18 +121,18 @@ void IDispatch.GetIDsOfNames(ref Guid iid, string[] names, int cNames, int lcid, private const VarEnum VT_TYPEMASK = (VarEnum)0x0fff; private const VarEnum VT_BYREF_TYPEMASK = VT_TYPEMASK | VarEnum.VT_BYREF; - private static unsafe ref Variant GetVariant(ref Variant pSrc) + private static unsafe ref ComVariant GetVariant(ref ComVariant pSrc) { - if (pSrc.VariantType == VT_BYREF_VARIANT) + if (pSrc.VarType == VT_BYREF_VARIANT) { // For VB6 compatibility reasons, if the VARIANT is a VT_BYREF | VT_VARIANT that // contains another VARIANT with VT_BYREF | VT_VARIANT, then we need to extract the // inner VARIANT and use it instead of the outer one. Note that if the inner VARIANT // is VT_BYREF | VT_VARIANT | VT_ARRAY, it will pass the below test too. - Span pByRefVariant = new Span(pSrc.AsByRefVariant.ToPointer(), 1); - if ((pByRefVariant[0].VariantType & VT_BYREF_TYPEMASK) == VT_BYREF_VARIANT) + ref ComVariant pByRefVariant = ref *(ComVariant*)(pSrc.GetRawDataRef().ToPointer()); + if ((pByRefVariant.VarType & VT_BYREF_TYPEMASK) == VT_BYREF_VARIANT) { - return ref pByRefVariant[0]; + return ref pByRefVariant; } } @@ -163,7 +164,7 @@ void IDispatch.GetIDsOfNames(ref Guid iid, string[] names, int cNames, int lcid, bool[] usedArgs = new bool[pDispParams.cArgs]; int totalCount = pDispParams.cNamedArgs + pDispParams.cArgs; - var vars = new Span(pDispParams.rgvarg.ToPointer(), totalCount); + var vars = new Span(pDispParams.rgvarg.ToPointer(), totalCount); var namedArgs = new Span(pDispParams.rgdispidNamedArgs.ToPointer(), totalCount); // copy the named args (positional) as specified @@ -172,12 +173,12 @@ void IDispatch.GetIDsOfNames(ref Guid iid, string[] names, int cNames, int lcid, for (i = 0; i < pDispParams.cNamedArgs; i++) { pos = namedArgs[i]; - ref Variant pvar = ref GetVariant(ref vars[i]); + ref ComVariant pvar = ref GetVariant(ref vars[i]); args[pos] = pvar.ToObject()!; usedArgs[pos] = true; int byrefIdx = InvalidIdx; - if (pvar.IsByRef) + if (pvar.VarType.HasFlag(VarEnum.VT_BYREF)) { byrefIdx = i; } @@ -195,11 +196,11 @@ void IDispatch.GetIDsOfNames(ref Guid iid, string[] names, int cNames, int lcid, pos++; } - ref Variant pvar = ref GetVariant(ref vars[pDispParams.cArgs - 1 - i]); + ref ComVariant pvar = ref GetVariant(ref vars[pDispParams.cArgs - 1 - i]); args[pos] = pvar.ToObject()!; int byrefIdx = InvalidIdx; - if (pvar.IsByRef) + if (pvar.VarType.HasFlag(VarEnum.VT_BYREF)) { byrefIdx = pDispParams.cArgs - 1 - i; } @@ -227,7 +228,7 @@ void IDispatch.GetIDsOfNames(ref Guid iid, string[] names, int cNames, int lcid, continue; } - ref Variant pvar = ref GetVariant(ref vars[idxToPos]); + ref ComVariant pvar = ref GetVariant(ref vars[idxToPos]); pvar.CopyFromIndirect(args[i]); } } diff --git a/src/libraries/Common/src/System/Runtime/InteropServices/Variant.cs b/src/libraries/Common/src/System/Runtime/InteropServices/Variant.cs deleted file mode 100644 index 2af1f942acee6..0000000000000 --- a/src/libraries/Common/src/System/Runtime/InteropServices/Variant.cs +++ /dev/null @@ -1,715 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Diagnostics; -using System.Runtime.Versioning; - -namespace System.Runtime.InteropServices -{ - /// - /// Variant is the basic COM type for late-binding. It can contain any other COM data type. - /// This type definition precisely matches the unmanaged data layout so that the struct can be passed - /// to and from COM calls. - /// - [StructLayout(LayoutKind.Explicit)] - [SupportedOSPlatform("windows")] - internal partial struct Variant - { -#if DEBUG - static Variant() - { - // Variant size is the size of 4 pointers (16 bytes) on a 32-bit processor, - // and 3 pointers (24 bytes) on a 64-bit processor. - int variantSize = Marshal.SizeOf(); - if (IntPtr.Size == 4) - { - Debug.Assert(variantSize == (4 * IntPtr.Size)); - } - else - { - Debug.Assert(IntPtr.Size == 8); - Debug.Assert(variantSize == (3 * IntPtr.Size)); - } - } -#endif - - // Most of the data types in the Variant are carried in _typeUnion - [FieldOffset(0)] private TypeUnion _typeUnion; - - // Decimal is the largest data type and it needs to use the space that is normally unused in TypeUnion._wReserved1, etc. - // Hence, it is declared to completely overlap with TypeUnion. A Decimal does not use the first two bytes, and so - // TypeUnion._vt can still be used to encode the type. - [FieldOffset(0)] private decimal _decimal; - - [StructLayout(LayoutKind.Sequential)] - private struct TypeUnion - { - public ushort _vt; - public ushort _wReserved1; - public ushort _wReserved2; - public ushort _wReserved3; - - public UnionTypes _unionTypes; - } - - [StructLayout(LayoutKind.Sequential)] - private struct Record - { - public IntPtr _record; - public IntPtr _recordInfo; - } - - [StructLayout(LayoutKind.Explicit)] - private struct UnionTypes - { - [FieldOffset(0)] public sbyte _i1; - [FieldOffset(0)] public short _i2; - [FieldOffset(0)] public int _i4; - [FieldOffset(0)] public long _i8; - [FieldOffset(0)] public byte _ui1; - [FieldOffset(0)] public ushort _ui2; - [FieldOffset(0)] public uint _ui4; - [FieldOffset(0)] public ulong _ui8; - [FieldOffset(0)] public int _int; - [FieldOffset(0)] public uint _uint; - [FieldOffset(0)] public short _bool; - [FieldOffset(0)] public int _error; - [FieldOffset(0)] public float _r4; - [FieldOffset(0)] public double _r8; - [FieldOffset(0)] public long _cy; - [FieldOffset(0)] public double _date; - [FieldOffset(0)] public IntPtr _bstr; - [FieldOffset(0)] public IntPtr _unknown; - [FieldOffset(0)] public IntPtr _dispatch; - [FieldOffset(0)] public IntPtr _pvarVal; - [FieldOffset(0)] public IntPtr _byref; - [FieldOffset(0)] public Record _record; - } - - /// - /// Primitive types are the basic COM types. It includes valuetypes like ints, but also reference types - /// like BStrs. It does not include composite types like arrays and user-defined COM types (IUnknown/IDispatch). - /// - public static bool IsPrimitiveType(VarEnum varEnum) - { - switch (varEnum) - { - case VarEnum.VT_I1: - case VarEnum.VT_I2: - case VarEnum.VT_I4: - case VarEnum.VT_I8: - case VarEnum.VT_UI1: - case VarEnum.VT_UI2: - case VarEnum.VT_UI4: - case VarEnum.VT_UI8: - case VarEnum.VT_INT: - case VarEnum.VT_UINT: - case VarEnum.VT_BOOL: - case VarEnum.VT_ERROR: - case VarEnum.VT_R4: - case VarEnum.VT_R8: - case VarEnum.VT_DECIMAL: - case VarEnum.VT_CY: - case VarEnum.VT_DATE: - case VarEnum.VT_BSTR: - return true; - } - - return false; - } - - public unsafe void CopyFromIndirect(object value) - { - VarEnum vt = (VarEnum)(((int)this.VariantType) & ~((int)VarEnum.VT_BYREF)); - - if (value == null) - { - if (vt == VarEnum.VT_DISPATCH || vt == VarEnum.VT_UNKNOWN || vt == VarEnum.VT_BSTR) - { - *(IntPtr*)this._typeUnion._unionTypes._byref = IntPtr.Zero; - } - return; - } - - if ((vt & VarEnum.VT_ARRAY) != 0) - { - Variant vArray; - Marshal.GetNativeVariantForObject(value, (IntPtr)(void*)&vArray); - *(IntPtr*)this._typeUnion._unionTypes._byref = vArray._typeUnion._unionTypes._byref; - return; - } - - switch (vt) - { - case VarEnum.VT_I1: - *(sbyte*)this._typeUnion._unionTypes._byref = (sbyte)value; - break; - - case VarEnum.VT_UI1: - *(byte*)this._typeUnion._unionTypes._byref = (byte)value; - break; - - case VarEnum.VT_I2: - *(short*)this._typeUnion._unionTypes._byref = (short)value; - break; - - case VarEnum.VT_UI2: - *(ushort*)this._typeUnion._unionTypes._byref = (ushort)value; - break; - - case VarEnum.VT_BOOL: - // VARIANT_TRUE = -1 - // VARIANT_FALSE = 0 - *(short*)this._typeUnion._unionTypes._byref = (bool)value ? (short)-1 : (short)0; - break; - - case VarEnum.VT_I4: - case VarEnum.VT_INT: - *(int*)this._typeUnion._unionTypes._byref = (int)value; - break; - - case VarEnum.VT_UI4: - case VarEnum.VT_UINT: - *(uint*)this._typeUnion._unionTypes._byref = (uint)value; - break; - - case VarEnum.VT_ERROR: - *(int*)this._typeUnion._unionTypes._byref = ((ErrorWrapper)value).ErrorCode; - break; - - case VarEnum.VT_I8: - *(long*)this._typeUnion._unionTypes._byref = (long)value; - break; - - case VarEnum.VT_UI8: - *(ulong*)this._typeUnion._unionTypes._byref = (ulong)value; - break; - - case VarEnum.VT_R4: - *(float*)this._typeUnion._unionTypes._byref = (float)value; - break; - - case VarEnum.VT_R8: - *(double*)this._typeUnion._unionTypes._byref = (double)value; - break; - - case VarEnum.VT_DATE: - *(double*)this._typeUnion._unionTypes._byref = ((DateTime)value).ToOADate(); - break; - - case VarEnum.VT_UNKNOWN: - *(IntPtr*)this._typeUnion._unionTypes._byref = Marshal.GetIUnknownForObject(value); - break; - - case VarEnum.VT_DISPATCH: - *(IntPtr*)this._typeUnion._unionTypes._byref = Marshal.GetIDispatchForObject(value); - break; - - case VarEnum.VT_BSTR: - *(IntPtr*)this._typeUnion._unionTypes._byref = Marshal.StringToBSTR((string)value); - break; - - case VarEnum.VT_CY: - *(long*)this._typeUnion._unionTypes._byref = decimal.ToOACurrency((decimal)value); - break; - - case VarEnum.VT_DECIMAL: - *(decimal*)this._typeUnion._unionTypes._byref = (decimal)value; - break; - - case VarEnum.VT_VARIANT: - Marshal.GetNativeVariantForObject(value, this._typeUnion._unionTypes._byref); - break; - - default: - throw new ArgumentException(); - } - } - - /// - /// Get the managed object representing the Variant. - /// - /// - public object? ToObject() - { - // Check the simple case upfront - if (IsEmpty) - { - return null; - } - - switch (VariantType) - { - case VarEnum.VT_NULL: - return DBNull.Value; - - case VarEnum.VT_I1: return AsI1; - case VarEnum.VT_I2: return AsI2; - case VarEnum.VT_I4: return AsI4; - case VarEnum.VT_I8: return AsI8; - case VarEnum.VT_UI1: return AsUi1; - case VarEnum.VT_UI2: return AsUi2; - case VarEnum.VT_UI4: return AsUi4; - case VarEnum.VT_UI8: return AsUi8; - case VarEnum.VT_INT: return AsInt; - case VarEnum.VT_UINT: return AsUint; - case VarEnum.VT_BOOL: return AsBool; - case VarEnum.VT_ERROR: return AsError; - case VarEnum.VT_R4: return AsR4; - case VarEnum.VT_R8: return AsR8; - case VarEnum.VT_DECIMAL: return AsDecimal; - case VarEnum.VT_CY: return AsCy; - case VarEnum.VT_DATE: return AsDate; - case VarEnum.VT_BSTR: return AsBstr; - case VarEnum.VT_UNKNOWN: return AsUnknown; - case VarEnum.VT_DISPATCH: return AsDispatch; - - default: - unsafe - { - fixed (void* pThis = &this) - { - return Marshal.GetObjectForNativeVariant((System.IntPtr)pThis); - } - } - } - } - - /// - /// Release any unmanaged memory associated with the Variant - /// - public void Clear() - { - // We do not need to call OLE32's VariantClear for primitive types or ByRefs - // to save ourselves the cost of interop transition. - // ByRef indicates the memory is not owned by the VARIANT itself while - // primitive types do not have any resources to free up. - // Hence, only safearrays, BSTRs, interfaces and user types are - // handled differently. - VarEnum vt = VariantType; - if ((vt & VarEnum.VT_BYREF) != 0) - { - VariantType = VarEnum.VT_EMPTY; - } - else if (((vt & VarEnum.VT_ARRAY) != 0) - || (vt == VarEnum.VT_BSTR) - || (vt == VarEnum.VT_UNKNOWN) - || (vt == VarEnum.VT_DISPATCH) - || (vt == VarEnum.VT_VARIANT) - || (vt == VarEnum.VT_RECORD)) - { - unsafe - { - fixed (void* pThis = &this) - { - Interop.OleAut32.VariantClear((IntPtr)pThis); - } - } - - Debug.Assert(IsEmpty); - } - else - { - VariantType = VarEnum.VT_EMPTY; - } - } - - public VarEnum VariantType - { - get => (VarEnum)_typeUnion._vt; - set => _typeUnion._vt = (ushort)value; - } - - public bool IsEmpty => _typeUnion._vt == ((ushort)VarEnum.VT_EMPTY); - - public bool IsByRef => (_typeUnion._vt & ((ushort)VarEnum.VT_BYREF)) != 0; - - public void SetAsNULL() - { - Debug.Assert(IsEmpty); - VariantType = VarEnum.VT_NULL; - } - - // VT_I1 - - public sbyte AsI1 - { - get - { - Debug.Assert(VariantType == VarEnum.VT_I1); - return _typeUnion._unionTypes._i1; - } - set - { - Debug.Assert(IsEmpty); - VariantType = VarEnum.VT_I1; - _typeUnion._unionTypes._i1 = value; - } - } - - // VT_I2 - - public short AsI2 - { - get - { - Debug.Assert(VariantType == VarEnum.VT_I2); - return _typeUnion._unionTypes._i2; - } - set - { - Debug.Assert(IsEmpty); - VariantType = VarEnum.VT_I2; - _typeUnion._unionTypes._i2 = value; - } - } - - // VT_I4 - - public int AsI4 - { - get - { - Debug.Assert(VariantType == VarEnum.VT_I4); - return _typeUnion._unionTypes._i4; - } - set - { - Debug.Assert(IsEmpty); - VariantType = VarEnum.VT_I4; - _typeUnion._unionTypes._i4 = value; - } - } - - // VT_I8 - - public long AsI8 - { - get - { - Debug.Assert(VariantType == VarEnum.VT_I8); - return _typeUnion._unionTypes._i8; - } - set - { - Debug.Assert(IsEmpty); - VariantType = VarEnum.VT_I8; - _typeUnion._unionTypes._i8 = value; - } - } - - // VT_UI1 - - public byte AsUi1 - { - get - { - Debug.Assert(VariantType == VarEnum.VT_UI1); - return _typeUnion._unionTypes._ui1; - } - set - { - Debug.Assert(IsEmpty); - VariantType = VarEnum.VT_UI1; - _typeUnion._unionTypes._ui1 = value; - } - } - - // VT_UI2 - - public ushort AsUi2 - { - get - { - Debug.Assert(VariantType == VarEnum.VT_UI2); - return _typeUnion._unionTypes._ui2; - } - set - { - Debug.Assert(IsEmpty); - VariantType = VarEnum.VT_UI2; - _typeUnion._unionTypes._ui2 = value; - } - } - - // VT_UI4 - - public uint AsUi4 - { - get - { - Debug.Assert(VariantType == VarEnum.VT_UI4); - return _typeUnion._unionTypes._ui4; - } - set - { - Debug.Assert(IsEmpty); - VariantType = VarEnum.VT_UI4; - _typeUnion._unionTypes._ui4 = value; - } - } - - // VT_UI8 - - public ulong AsUi8 - { - get - { - Debug.Assert(VariantType == VarEnum.VT_UI8); - return _typeUnion._unionTypes._ui8; - } - set - { - Debug.Assert(IsEmpty); - VariantType = VarEnum.VT_UI8; - _typeUnion._unionTypes._ui8 = value; - } - } - - // VT_INT - - public int AsInt - { - get - { - Debug.Assert(VariantType == VarEnum.VT_INT); - return _typeUnion._unionTypes._int; - } - set - { - Debug.Assert(IsEmpty); - VariantType = VarEnum.VT_INT; - _typeUnion._unionTypes._int = value; - } - } - - // VT_UINT - - public uint AsUint - { - get - { - Debug.Assert(VariantType == VarEnum.VT_UINT); - return _typeUnion._unionTypes._uint; - } - set - { - Debug.Assert(IsEmpty); - VariantType = VarEnum.VT_UINT; - _typeUnion._unionTypes._uint = value; - } - } - - // VT_BOOL - - public bool AsBool - { - get - { - Debug.Assert(VariantType == VarEnum.VT_BOOL); - return _typeUnion._unionTypes._bool != 0; - } - set - { - Debug.Assert(IsEmpty); - // VARIANT_TRUE = -1 - // VARIANT_FALSE = 0 - VariantType = VarEnum.VT_BOOL; - _typeUnion._unionTypes._bool = value ? (short)-1 : (short)0; - } - } - - // VT_ERROR - - public int AsError - { - get - { - Debug.Assert(VariantType == VarEnum.VT_ERROR); - return _typeUnion._unionTypes._error; - } - set - { - Debug.Assert(IsEmpty); - VariantType = VarEnum.VT_ERROR; - _typeUnion._unionTypes._error = value; - } - } - - // VT_R4 - - public float AsR4 - { - get - { - Debug.Assert(VariantType == VarEnum.VT_R4); - return _typeUnion._unionTypes._r4; - } - set - { - Debug.Assert(IsEmpty); - VariantType = VarEnum.VT_R4; - _typeUnion._unionTypes._r4 = value; - } - } - - // VT_R8 - - public double AsR8 - { - get - { - Debug.Assert(VariantType == VarEnum.VT_R8); - return _typeUnion._unionTypes._r8; - } - set - { - Debug.Assert(IsEmpty); - VariantType = VarEnum.VT_R8; - _typeUnion._unionTypes._r8 = value; - } - } - - // VT_DECIMAL - - public decimal AsDecimal - { - get - { - Debug.Assert(VariantType == VarEnum.VT_DECIMAL); - // The first byte of Decimal is unused, but usually set to 0 - Variant v = this; - v._typeUnion._vt = 0; - return v._decimal; - } - set - { - Debug.Assert(IsEmpty); - VariantType = VarEnum.VT_DECIMAL; - _decimal = value; - // _vt overlaps with _decimal, and should be set after setting _decimal - _typeUnion._vt = (ushort)VarEnum.VT_DECIMAL; - } - } - - // VT_CY - - public decimal AsCy - { - get - { - Debug.Assert(VariantType == VarEnum.VT_CY); - return decimal.FromOACurrency(_typeUnion._unionTypes._cy); - } - set - { - Debug.Assert(IsEmpty); - VariantType = VarEnum.VT_CY; - _typeUnion._unionTypes._cy = decimal.ToOACurrency(value); - } - } - - // VT_DATE - - public DateTime AsDate - { - get - { - Debug.Assert(VariantType == VarEnum.VT_DATE); - return DateTime.FromOADate(_typeUnion._unionTypes._date); - } - set - { - Debug.Assert(IsEmpty); - VariantType = VarEnum.VT_DATE; - _typeUnion._unionTypes._date = value.ToOADate(); - } - } - - // VT_BSTR - - public string? AsBstr - { - get - { - Debug.Assert(VariantType == VarEnum.VT_BSTR); - if (_typeUnion._unionTypes._bstr == IntPtr.Zero) - { - return null; - } - return (string)Marshal.PtrToStringBSTR(this._typeUnion._unionTypes._bstr); - } - set - { - Debug.Assert(IsEmpty); - VariantType = VarEnum.VT_BSTR; - this._typeUnion._unionTypes._bstr = Marshal.StringToBSTR(value); - } - } - - // VT_UNKNOWN - - public object? AsUnknown - { - get - { - Debug.Assert(VariantType == VarEnum.VT_UNKNOWN); - if (_typeUnion._unionTypes._unknown == IntPtr.Zero) - { - return null; - } - return Marshal.GetObjectForIUnknown(_typeUnion._unionTypes._unknown); - } - set - { - Debug.Assert(IsEmpty); - VariantType = VarEnum.VT_UNKNOWN; - if (value == null) - { - _typeUnion._unionTypes._unknown = IntPtr.Zero; - } - else - { - _typeUnion._unionTypes._unknown = Marshal.GetIUnknownForObject(value); - } - } - } - - // VT_DISPATCH - - public object? AsDispatch - { - get - { - Debug.Assert(VariantType == VarEnum.VT_DISPATCH); - if (_typeUnion._unionTypes._dispatch == IntPtr.Zero) - { - return null; - } - return Marshal.GetObjectForIUnknown(_typeUnion._unionTypes._dispatch); - } - set - { - Debug.Assert(IsEmpty); - VariantType = VarEnum.VT_DISPATCH; - if (value == null) - { - _typeUnion._unionTypes._dispatch = IntPtr.Zero; - } - else - { - _typeUnion._unionTypes._dispatch = Marshal.GetIDispatchForObject(value); - } - } - } - - public IntPtr AsByRefVariant - { - get - { - Debug.Assert(VariantType == (VarEnum.VT_BYREF | VarEnum.VT_VARIANT)); - return _typeUnion._unionTypes._pvarVal; - } - } - } -} diff --git a/src/libraries/Microsoft.CSharp/Microsoft.CSharp.sln b/src/libraries/Microsoft.CSharp/Microsoft.CSharp.sln index 7207dd4e74f6f..7c0e1c47b0f58 100644 --- a/src/libraries/Microsoft.CSharp/Microsoft.CSharp.sln +++ b/src/libraries/Microsoft.CSharp/Microsoft.CSharp.sln @@ -1,4 +1,8 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34117.57 +MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{A18337A4-46D6-470C-A995-CA70E5311F19}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CSharp", "ref\Microsoft.CSharp.csproj", "{BF947490-D7AE-46E1-B4E0-D8A6D1EA8E5A}" @@ -39,11 +43,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E4FC7A8F-502 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{9C11B257-64B7-4EC9-BF3E-4859FB66281D}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "tools\gen", "{D293C8E5-5C86-4096-9F9D-0129396A1AD7}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{D293C8E5-5C86-4096-9F9D-0129396A1AD7}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "tools\src", "{ABC2DBF6-FE78-44B1-86B8-D759660B5462}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{ABC2DBF6-FE78-44B1-86B8-D759660B5462}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "tools\ref", "{8C230199-AEBC-4299-A612-5025FC987A41}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{8C230199-AEBC-4299-A612-5025FC987A41}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{1725BEE8-1704-4D2D-BD98-CFEC326A5DEA}" EndProject @@ -123,26 +127,30 @@ Global EndGlobalSection GlobalSection(NestedProjects) = preSolution {A18337A4-46D6-470C-A995-CA70E5311F19} = {E6224881-0E5B-4FDC-99C4-DDE6E59F806B} - {7AEDFF97-79E2-441E-8B3F-5C8EC9C1E8FA} = {E6224881-0E5B-4FDC-99C4-DDE6E59F806B} {BF947490-D7AE-46E1-B4E0-D8A6D1EA8E5A} = {85A4D137-FEEC-4F3C-9358-F2BFFFF6D2DE} + {78073F44-8382-473D-8B24-90D54B57129E} = {E4FC7A8F-5024-4D51-9753-C2C61CF9DAD0} + {7AEDFF97-79E2-441E-8B3F-5C8EC9C1E8FA} = {E6224881-0E5B-4FDC-99C4-DDE6E59F806B} {629BA969-ADCA-47E9-9654-75B7411C5606} = {85A4D137-FEEC-4F3C-9358-F2BFFFF6D2DE} {B783B886-07DB-46B8-B02D-1C9259C767E9} = {85A4D137-FEEC-4F3C-9358-F2BFFFF6D2DE} {8E91F13C-8E06-431B-A4C9-0A9906B1DCD6} = {85A4D137-FEEC-4F3C-9358-F2BFFFF6D2DE} - {C89FC14C-795C-469E-A053-A2844C0B7AA8} = {85A4D137-FEEC-4F3C-9358-F2BFFFF6D2DE} - {78073F44-8382-473D-8B24-90D54B57129E} = {E4FC7A8F-5024-4D51-9753-C2C61CF9DAD0} {BB30502C-6FBE-467E-AE6B-380EC60BD666} = {9C11B257-64B7-4EC9-BF3E-4859FB66281D} {B78B9BD0-6D82-400A-A373-C42051D9C3D8} = {9C11B257-64B7-4EC9-BF3E-4859FB66281D} {7223E4B2-40ED-48FB-9BFA-07002AD674DB} = {9C11B257-64B7-4EC9-BF3E-4859FB66281D} + {C89FC14C-795C-469E-A053-A2844C0B7AA8} = {85A4D137-FEEC-4F3C-9358-F2BFFFF6D2DE} {780BF284-2765-4B96-A817-CE9AEB1BC979} = {D293C8E5-5C86-4096-9F9D-0129396A1AD7} {84957D3F-C9E3-4191-8BD1-D0492F5D0B69} = {D293C8E5-5C86-4096-9F9D-0129396A1AD7} - {D293C8E5-5C86-4096-9F9D-0129396A1AD7} = {1725BEE8-1704-4D2D-BD98-CFEC326A5DEA} {465840D4-5267-4DC2-A675-A32BE9584745} = {ABC2DBF6-FE78-44B1-86B8-D759660B5462} {DB79B0FC-557E-4FCE-871B-F53F790DBD60} = {ABC2DBF6-FE78-44B1-86B8-D759660B5462} - {ABC2DBF6-FE78-44B1-86B8-D759660B5462} = {1725BEE8-1704-4D2D-BD98-CFEC326A5DEA} {54EA706E-28CA-4CCF-82CC-6B211E683C2E} = {8C230199-AEBC-4299-A612-5025FC987A41} + {D293C8E5-5C86-4096-9F9D-0129396A1AD7} = {1725BEE8-1704-4D2D-BD98-CFEC326A5DEA} + {ABC2DBF6-FE78-44B1-86B8-D759660B5462} = {1725BEE8-1704-4D2D-BD98-CFEC326A5DEA} {8C230199-AEBC-4299-A612-5025FC987A41} = {1725BEE8-1704-4D2D-BD98-CFEC326A5DEA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A1ECF510-F5DB-4E7F-853E-DD3C0CE04C12} EndGlobalSection + GlobalSection(SharedMSBuildProjectFiles) = preSolution + ..\..\tools\illink\src\ILLink.Shared\ILLink.Shared.projitems*{84957d3f-c9e3-4191-8bd1-d0492f5d0b69}*SharedItemsImports = 5 + ..\..\tools\illink\src\ILLink.Shared\ILLink.Shared.projitems*{db79b0fc-557e-4fce-871b-f53f790dbd60}*SharedItemsImports = 5 + EndGlobalSection EndGlobal diff --git a/src/libraries/Microsoft.CSharp/src/Microsoft.CSharp.csproj b/src/libraries/Microsoft.CSharp/src/Microsoft.CSharp.csproj index 3be4e969da5a7..9388bfa98b91e 100644 --- a/src/libraries/Microsoft.CSharp/src/Microsoft.CSharp.csproj +++ b/src/libraries/Microsoft.CSharp/src/Microsoft.CSharp.csproj @@ -167,25 +167,19 @@ - - + + - - - - + + + + Common\System\Runtime\InteropServices\IDispatch.cs - - Common\System\Runtime\InteropServices\Variant.cs + + Common\System\Runtime\InteropServices\BuiltInVariantExtensions.cs @@ -234,7 +228,7 @@ - + diff --git a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/ComInvokeBinder.cs b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/ComInvokeBinder.cs index 9052ad6d7a0af..ff356ef08c96c 100644 --- a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/ComInvokeBinder.cs +++ b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/ComInvokeBinder.cs @@ -8,6 +8,7 @@ using System.Dynamic; using System.Linq.Expressions; using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; using ComTypes = System.Runtime.InteropServices.ComTypes; namespace Microsoft.CSharp.RuntimeBinder.ComInterop @@ -92,7 +93,7 @@ private ParameterExpression DispParamsVariable private ParameterExpression InvokeResultVariable { - get { return EnsureVariable(ref _invokeResult, typeof(Variant), "invokeResult"); } + get { return EnsureVariable(ref _invokeResult, typeof(ComVariant), "invokeResult"); } } private ParameterExpression ReturnValueVariable @@ -306,8 +307,8 @@ private Expression GenerateTryBlock() // Expression invokeResultObject = Expression.Call( - InvokeResultVariable, - typeof(Variant).GetMethod(nameof(Variant.ToObject))); + typeof(BuiltInInteropVariantExtensions).GetMethod(nameof(BuiltInInteropVariantExtensions.ToObject)), + InvokeResultVariable); VariantBuilder[] variants = _varEnumSelector.VariantBuilders; @@ -360,7 +361,7 @@ private Expression GenerateFinallyBlock() finallyStatements.Add( Expression.Call( InvokeResultVariable, - typeof(Variant).GetMethod(nameof(Variant.Clear)) + typeof(ComVariant).GetMethod(nameof(ComVariant.Dispose)) ) ); diff --git a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/ComRuntimeHelpers.cs b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/ComRuntimeHelpers.cs index 114b869124aff..d090f3300cdb2 100644 --- a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/ComRuntimeHelpers.cs +++ b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/ComRuntimeHelpers.cs @@ -8,6 +8,7 @@ using System.Reflection; using System.Reflection.Emit; using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; using System.Security; using ComTypes = System.Runtime.InteropServices.ComTypes; @@ -230,11 +231,11 @@ internal static class UnsafeMethods #region public members public static unsafe IntPtr ConvertInt32ByrefToPtr(ref int value) { return (IntPtr)System.Runtime.CompilerServices.Unsafe.AsPointer(ref value); } - public static unsafe IntPtr ConvertVariantByrefToPtr(ref Variant value) { return (IntPtr)System.Runtime.CompilerServices.Unsafe.AsPointer(ref value); } + public static unsafe IntPtr ConvertVariantByrefToPtr(ref ComVariant value) { return (IntPtr)System.Runtime.CompilerServices.Unsafe.AsPointer(ref value); } - internal static Variant GetVariantForObject(object obj) + internal static ComVariant GetVariantForObject(object obj) { - Variant variant = default; + ComVariant variant = default; if (obj == null) { return variant; @@ -243,7 +244,7 @@ internal static Variant GetVariantForObject(object obj) return variant; } - internal static void InitVariantForObject(object obj, ref Variant variant) + internal static void InitVariantForObject(object obj, ref ComVariant variant) { Debug.Assert(obj != null); @@ -252,7 +253,7 @@ internal static void InitVariantForObject(object obj, ref Variant variant) // Therefore we are going to test for IDispatch before defaulting to GetNativeVariantForObject. if (obj is IDispatch) { - variant.AsDispatch = obj; + variant = ComVariant.CreateRaw(VarEnum.VT_DISPATCH, obj is not null ? Marshal.GetIDispatchForObject(obj) : 0); return; } @@ -260,7 +261,7 @@ internal static void InitVariantForObject(object obj, ref Variant variant) } // This method is intended for use through reflection and should not be used directly - public static object GetObjectForVariant(Variant variant) + public static object GetObjectForVariant(ComVariant variant) { IntPtr ptr = UnsafeMethods.ConvertVariantByrefToPtr(ref variant); return Marshal.GetObjectForNativeVariant(ptr); @@ -287,18 +288,18 @@ public static void IUnknownReleaseNotZero(IntPtr interfacePointer) int memberDispId, ComTypes.INVOKEKIND flags, ref ComTypes.DISPPARAMS dispParams, - out Variant result, + out ComVariant result, out ExcepInfo excepInfo, out uint argErr) { Guid IID_NULL = default; fixed (ComTypes.DISPPARAMS* pDispParams = &dispParams) - fixed (Variant* pResult = &result) + fixed (ComVariant* pResult = &result) fixed (ExcepInfo* pExcepInfo = &excepInfo) fixed (uint* pArgErr = &argErr) { - var pfnIDispatchInvoke = (delegate* unmanaged) + var pfnIDispatchInvoke = (delegate* unmanaged) (*(*(void***)dispatchPointer + 6 /* IDispatch.Invoke slot */)); int hresult = pfnIDispatchInvoke(dispatchPointer, diff --git a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/DynamicVariantExtensions.cs b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/DynamicVariantExtensions.cs new file mode 100644 index 0000000000000..27647ed388f28 --- /dev/null +++ b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/DynamicVariantExtensions.cs @@ -0,0 +1,446 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Diagnostics; +using System.Globalization; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +using Microsoft.CSharp.RuntimeBinder.ComInterop; + +namespace Microsoft.CSharp.RuntimeBinder.ComInterop +{ + internal static class DynamicVariantExtensions + { + /// + /// Primitive types are the basic COM types. It includes valuetypes like ints, but also reference types + /// like BStrs. It does not include composite types like arrays and user-defined COM types (IUnknown/IDispatch). + /// + public static bool IsPrimitiveType(this VarEnum varEnum) + { + switch (varEnum) + { + case VarEnum.VT_I1: + case VarEnum.VT_I2: + case VarEnum.VT_I4: + case VarEnum.VT_I8: + case VarEnum.VT_UI1: + case VarEnum.VT_UI2: + case VarEnum.VT_UI4: + case VarEnum.VT_UI8: + case VarEnum.VT_INT: + case VarEnum.VT_UINT: + case VarEnum.VT_BOOL: + case VarEnum.VT_ERROR: + case VarEnum.VT_R4: + case VarEnum.VT_R8: + case VarEnum.VT_DECIMAL: + case VarEnum.VT_CY: + case VarEnum.VT_DATE: + case VarEnum.VT_BSTR: + return true; + } + + return false; + } + + public static void SetAsIConvertible(this ref ComVariant variant, IConvertible value) + { + Debug.Assert(variant.VarType == VarEnum.VT_EMPTY); // The setter can only be called once as VariantClear might be needed otherwise + + TypeCode tc = value.GetTypeCode(); + CultureInfo ci = CultureInfo.CurrentCulture; + + switch (tc) + { + case TypeCode.Empty: break; + case TypeCode.Object: variant = ComVariant.CreateRaw(VarEnum.VT_UNKNOWN, Marshal.GetIUnknownForObject(value)); break; + case TypeCode.DBNull: variant = ComVariant.Null; break; + case TypeCode.Boolean: variant = ComVariant.Create(value.ToBoolean(ci)); break; + case TypeCode.Char: variant = ComVariant.Create(value.ToChar(ci)); break; + case TypeCode.SByte: variant = ComVariant.Create(value.ToSByte(ci)); break; + case TypeCode.Byte: variant = ComVariant.Create(value.ToByte(ci)); break; + case TypeCode.Int16: variant = ComVariant.Create(value.ToInt16(ci)); break; + case TypeCode.UInt16: variant = ComVariant.Create(value.ToUInt16(ci)); break; + case TypeCode.Int32: variant = ComVariant.Create(value.ToInt32(ci)); break; + case TypeCode.UInt32: variant = ComVariant.Create(value.ToUInt32(ci)); break; + case TypeCode.Int64: variant = ComVariant.Create(value.ToInt64(ci)); break; + case TypeCode.UInt64: variant = ComVariant.Create(value.ToInt64(ci)); break; + case TypeCode.Single: variant = ComVariant.Create(value.ToSingle(ci)); break; + case TypeCode.Double: variant = ComVariant.Create(value.ToDouble(ci)); break; + case TypeCode.Decimal: variant = ComVariant.Create(value.ToDecimal(ci)); break; + case TypeCode.DateTime: variant = ComVariant.Create(value.ToDateTime(ci)); break; + case TypeCode.String: variant = ComVariant.Create(new BStrWrapper(value.ToString(ci))); break; + + default: + throw new NotSupportedException(); + } + } + // VT_I1 + + public static void SetAsByrefI1(ref this ComVariant variant, ref sbyte value) + { + variant.SetAsByref(ref value, VarEnum.VT_I1); + } + + // VT_I2 + + public static void SetAsByrefI2(ref this ComVariant variant, ref short value) + { + variant.SetAsByref(ref value, VarEnum.VT_I2); + } + + // VT_I4 + + public static void SetAsByrefI4(ref this ComVariant variant, ref int value) + { + variant.SetAsByref(ref value, VarEnum.VT_I4); + } + + // VT_I8 + + public static void SetAsByrefI8(ref this ComVariant variant, ref long value) + { + variant.SetAsByref(ref value, VarEnum.VT_I8); + } + + // VT_UI1 + + public static void SetAsByrefUi1(ref this ComVariant variant, ref byte value) + { + variant.SetAsByref(ref value, VarEnum.VT_UI1); + } + + // VT_UI2 + + public static void SetAsByrefUi2(ref this ComVariant variant, ref ushort value) + { + variant.SetAsByref(ref value, VarEnum.VT_UI2); + } + + // VT_UI4 + + public static void SetAsByrefUi4(ref this ComVariant variant, ref uint value) + { + variant.SetAsByref(ref value, VarEnum.VT_UI4); + } + + // VT_UI8 + + public static void SetAsByrefUi8(ref this ComVariant variant, ref ulong value) + { + variant.SetAsByref(ref value, VarEnum.VT_UI8); + } + + // VT_INT + + public static void SetAsByrefInt(ref this ComVariant variant, ref int value) + { + variant.SetAsByref(ref value, VarEnum.VT_INT); + } + + // VT_UINT + + public static void SetAsByrefUint(ref this ComVariant variant, ref uint value) + { + variant.SetAsByref(ref value, VarEnum.VT_UINT); + } + + // VT_BOOL + + public static void SetAsByrefBool(ref this ComVariant variant, ref short value) + { + variant.SetAsByref(ref value, VarEnum.VT_BOOL); + } + + // VT_ERROR + + public static void SetAsByrefError(ref this ComVariant variant, ref int value) + { + variant.SetAsByref(ref value, VarEnum.VT_ERROR); + } + + // VT_R4 + + public static void SetAsByrefR4(ref this ComVariant variant, ref float value) + { + variant.SetAsByref(ref value, VarEnum.VT_R4); + } + + // VT_R8 + + public static void SetAsByrefR8(ref this ComVariant variant, ref double value) + { + variant.SetAsByref(ref value, VarEnum.VT_R8); + } + + // VT_DECIMAL + + public static void SetAsByrefDecimal(ref this ComVariant variant, ref decimal value) + { + variant.SetAsByref(ref value, VarEnum.VT_DECIMAL); + } + + // VT_CY + + public static void SetAsByrefCy(ref this ComVariant variant, ref long value) + { + variant.SetAsByref(ref value, VarEnum.VT_CY); + } + + // VT_DATE + + public static void SetAsByrefDate(ref this ComVariant variant, ref double value) + { + variant.SetAsByref(ref value, VarEnum.VT_DATE); + } + + // VT_BSTR + + public static void SetAsByrefBstr(ref this ComVariant variant, ref IntPtr value) + { + variant.SetAsByref(ref value, VarEnum.VT_BSTR); + } + + // VT_UNKNOWN + + public static void SetAsByrefUnknown(ref this ComVariant variant, ref IntPtr value) + { + variant.SetAsByref(ref value, VarEnum.VT_UNKNOWN); + } + + // VT_DISPATCH + + public static void SetAsByrefDispatch(ref this ComVariant variant, ref IntPtr value) + { + variant.SetAsByref(ref value, VarEnum.VT_DISPATCH); + } + + private static unsafe void SetAsByref(ref this ComVariant variant, ref T value, VarEnum type) + { + Debug.Assert(variant.VarType == VarEnum.VT_EMPTY); // The setter can only be called once as VariantClear might be needed otherwise + variant = ComVariant.CreateRaw(type | VarEnum.VT_BYREF, (nint)Unsafe.AsPointer(ref value)); + } + + public static void SetAsByrefVariant(ref this ComVariant variant, ref ComVariant value) + { + variant.SetAsByref(ref value, VarEnum.VT_VARIANT); + } + + [StructLayout(LayoutKind.Sequential)] + private struct Record + { + public IntPtr _record; + public IntPtr _recordInfo; + } + + // constructs a ByRef variant to pass contents of another variant ByRef. + public static unsafe void SetAsByrefVariantIndirect(ref this ComVariant variant, ref ComVariant value) + { + Debug.Assert(variant.VarType == VarEnum.VT_EMPTY); // The setter can only be called once as VariantClear might be needed otherwise + Debug.Assert((value.VarType & VarEnum.VT_BYREF) == 0, "double indirection"); + + switch (value.VarType) + { + case VarEnum.VT_EMPTY: + case VarEnum.VT_NULL: + // these cannot combine with VT_BYREF. Should try passing as a variant reference + variant.SetAsByrefVariant(ref value); + return; + case VarEnum.VT_RECORD: + // VT_RECORD's are weird in that regardless of is the VT_BYREF flag is set or not + // they have the same internal representation. + variant = ComVariant.CreateRaw(value.VarType | VarEnum.VT_BYREF, value.GetRawDataRef()); + break; + case VarEnum.VT_DECIMAL: + // The DECIMAL value in an OLE Variant is stored at the start of the structure. + variant = ComVariant.CreateRaw(value.VarType | VarEnum.VT_BYREF, (nint)Unsafe.AsPointer(ref value)); + break; + default: + variant = ComVariant.CreateRaw(value.VarType | VarEnum.VT_BYREF, (nint)Unsafe.AsPointer(ref value.GetRawDataRef())); + break; + } + } + + internal static System.Reflection.MethodInfo GetByrefSetter(VarEnum varType) + { + switch (varType) + { + case VarEnum.VT_I1: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetAsByrefI1)); + case VarEnum.VT_I2: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetAsByrefI2)); + case VarEnum.VT_I4: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetAsByrefI4)); + case VarEnum.VT_I8: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetAsByrefI8)); + case VarEnum.VT_UI1: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetAsByrefUi1)); + case VarEnum.VT_UI2: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetAsByrefUi2)); + case VarEnum.VT_UI4: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetAsByrefUi4)); + case VarEnum.VT_UI8: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetAsByrefUi8)); + case VarEnum.VT_INT: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetAsByrefInt)); + case VarEnum.VT_UINT: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetAsByrefUint)); + case VarEnum.VT_BOOL: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetAsByrefBool)); + case VarEnum.VT_ERROR: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetAsByrefError)); + case VarEnum.VT_R4: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetAsByrefR4)); + case VarEnum.VT_R8: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetAsByrefR8)); + case VarEnum.VT_DECIMAL: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetAsByrefDecimal)); + case VarEnum.VT_CY: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetAsByrefCy)); + case VarEnum.VT_DATE: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetAsByrefDate)); + case VarEnum.VT_BSTR: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetAsByrefBstr)); + case VarEnum.VT_UNKNOWN: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetAsByrefUnknown)); + case VarEnum.VT_DISPATCH: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetAsByrefDispatch)); + + case VarEnum.VT_VARIANT: + return typeof(DynamicVariantExtensions).GetMethod(nameof(SetAsByrefVariant)); + case VarEnum.VT_RECORD: + case VarEnum.VT_ARRAY: + return typeof(DynamicVariantExtensions).GetMethod(nameof(SetAsByrefVariantIndirect)); + + default: + throw new NotSupportedException(); + } + } + + public static void SetI1(this ref ComVariant variant, sbyte value) + { + variant = ComVariant.Create(value); + } + + public static void SetUi1(this ref ComVariant variant, byte value) + { + variant = ComVariant.Create(value); + } + + public static void SetI2(this ref ComVariant variant, short value) + { + variant = ComVariant.Create(value); + } + + public static void SetUi2(this ref ComVariant variant, ushort value) + { + variant = ComVariant.Create(value); + } + + public static void SetI4(this ref ComVariant variant, int value) + { + variant = ComVariant.Create(value); + } + + public static void SetUi4(this ref ComVariant variant, uint value) + { + variant = ComVariant.Create(value); + } + + public static void SetI8(this ref ComVariant variant, long value) + { + variant = ComVariant.Create(value); + } + + public static void SetUi8(this ref ComVariant variant, ulong value) + { + variant = ComVariant.Create(value); + } + + public static void SetInt(this ref ComVariant variant, int value) + { + variant = ComVariant.CreateRaw(VarEnum.VT_INT, value); + } + + public static void SetUint(this ref ComVariant variant, uint value) + { + variant = ComVariant.CreateRaw(VarEnum.VT_UINT, value); + } + + public static void SetBool(this ref ComVariant variant, bool value) + { + variant = ComVariant.Create(value); + } + + public static void SetR4(this ref ComVariant variant, float value) + { + variant = ComVariant.Create(value); + } + + public static void SetR8(this ref ComVariant variant, double value) + { + variant = ComVariant.Create(value); + } + + public static void SetDecimal(this ref ComVariant variant, decimal value) + { + variant = ComVariant.Create(value); + } + + public static void SetDate(this ref ComVariant variant, DateTime value) + { + variant = ComVariant.Create(value); + } + + public static void SetBstr(this ref ComVariant variant, string value) + { + variant = ComVariant.Create(new BStrWrapper(value)); + } + + public static void SetUnknown(this ref ComVariant variant, object value) + { + variant = ComVariant.CreateRaw(VarEnum.VT_UNKNOWN, Marshal.GetIUnknownForObject(value)); + } + + public static void SetDispatch(this ref ComVariant variant, object value) + { + variant = ComVariant.CreateRaw(VarEnum.VT_DISPATCH, Marshal.GetIDispatchForObject(value)); + } + + public static void SetError(this ref ComVariant variant, int value) + { + variant = ComVariant.CreateRaw(VarEnum.VT_ERROR, value); + } + + public static void SetCy(this ref ComVariant variant, decimal value) + { + variant = ComVariant.CreateRaw(VarEnum.VT_CY, decimal.ToOACurrency(value)); + } + + public static unsafe void SetVariant(this ref ComVariant variant, object value) + { + Debug.Assert(variant.VarType == VarEnum.VT_EMPTY); // The setter can only be called once as VariantClear might be needed otherwise + if (value != null) + { + UnsafeMethods.InitVariantForObject(value, ref variant); + } + } + + internal static System.Reflection.MethodInfo GetSetter(VarEnum varType) + { + switch (varType) + { + case VarEnum.VT_I1: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetI1), System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + case VarEnum.VT_I2: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetI2), System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + case VarEnum.VT_I4: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetI4), System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + case VarEnum.VT_I8: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetI8), System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + case VarEnum.VT_UI1: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetUi1), System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + case VarEnum.VT_UI2: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetUi2), System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + case VarEnum.VT_UI4: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetUi4), System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + case VarEnum.VT_UI8: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetUi8), System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + case VarEnum.VT_INT: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetInt), System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + case VarEnum.VT_UINT: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetUint), System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + case VarEnum.VT_BOOL: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetBool), System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + case VarEnum.VT_ERROR: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetError), System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + case VarEnum.VT_R4: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetR4), System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + case VarEnum.VT_R8: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetR8), System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + case VarEnum.VT_DECIMAL: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetDecimal), System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + case VarEnum.VT_CY: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetCy), System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + case VarEnum.VT_DATE: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetDate), System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + case VarEnum.VT_BSTR: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetBstr), System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + case VarEnum.VT_UNKNOWN: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetUnknown), System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + case VarEnum.VT_DISPATCH: return typeof(DynamicVariantExtensions).GetMethod(nameof(SetDispatch), System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + + case VarEnum.VT_VARIANT: + case VarEnum.VT_RECORD: + case VarEnum.VT_ARRAY: + return typeof(DynamicVariantExtensions).GetMethod(nameof(SetVariant), System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); + + default: + throw new NotSupportedException(); + } + } + } +} diff --git a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/VarEnumSelector.cs b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/VarEnumSelector.cs index 85846d888f90e..6f69602277aba 100644 --- a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/VarEnumSelector.cs +++ b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/VarEnumSelector.cs @@ -46,7 +46,7 @@ internal VarEnumSelector(Type[] explicitArgTypes) /// /// Gets the managed type that an object needs to be converted to in order for it to be able - /// to be represented as a Variant. + /// to be represented as an ComVariant. /// /// In general, there is a many-to-many mapping between Type and VarEnum. However, this method /// returns a simple mapping that is needed for the current implementation. The reason for the @@ -65,7 +65,7 @@ internal static Type GetManagedMarshalType(VarEnum varEnum) return typeof(CurrencyWrapper); } - if (Variant.IsPrimitiveType(varEnum)) + if (varEnum.IsPrimitiveType()) { return s_comToManagedPrimitiveTypes[varEnum]; } @@ -375,7 +375,7 @@ private static VarEnum GetComType(ref Type argumentType) } /// - /// Get the COM Variant type that argument should be marshaled as for a call to COM + /// Get the ComVariant type that argument should be marshaled as for a call to COM /// [RequiresUnreferencedCode(Binder.TrimmerWarning)] private static VariantBuilder GetVariantBuilder(Type argumentType) @@ -447,7 +447,7 @@ private static ArgBuilder GetByValArgBuilder(Type elementType, ref VarEnum eleme return GetSimpleArgBuilder(elementType, elementVarEnum); } - // This helper can produce a builder for types that are directly supported by Variant. + // This helper can produce a builder for types that are directly supported by ComVariant or our extension methods. private static SimpleArgBuilder GetSimpleArgBuilder(Type elementType, VarEnum elementVarEnum) { SimpleArgBuilder argBuilder; diff --git a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/Variant.Extended.cs b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/Variant.Extended.cs deleted file mode 100644 index becef48a1466c..0000000000000 --- a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/Variant.Extended.cs +++ /dev/null @@ -1,319 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Diagnostics; -using System.Globalization; -using System.Runtime.CompilerServices; - -using Microsoft.CSharp.RuntimeBinder.ComInterop; - -namespace System.Runtime.InteropServices -{ - internal partial struct Variant - { - // VT_I1 - - public void SetAsByrefI1(ref sbyte value) - { - SetAsByref(ref value, VarEnum.VT_I1); - } - - // VT_I2 - - public void SetAsByrefI2(ref short value) - { - SetAsByref(ref value, VarEnum.VT_I2); - } - - // VT_I4 - - public void SetAsByrefI4(ref int value) - { - SetAsByref(ref value, VarEnum.VT_I4); - } - - // VT_I8 - - public void SetAsByrefI8(ref long value) - { - SetAsByref(ref value, VarEnum.VT_I8); - } - - // VT_UI1 - - public void SetAsByrefUi1(ref byte value) - { - SetAsByref(ref value, VarEnum.VT_UI1); - } - - // VT_UI2 - - public void SetAsByrefUi2(ref ushort value) - { - SetAsByref(ref value, VarEnum.VT_UI2); - } - - // VT_UI4 - - public void SetAsByrefUi4(ref uint value) - { - SetAsByref(ref value, VarEnum.VT_UI4); - } - - // VT_UI8 - - public void SetAsByrefUi8(ref ulong value) - { - SetAsByref(ref value, VarEnum.VT_UI8); - } - - // VT_INT - - public void SetAsByrefInt(ref int value) - { - SetAsByref(ref value, VarEnum.VT_INT); - } - - // VT_UINT - - public void SetAsByrefUint(ref uint value) - { - SetAsByref(ref value, VarEnum.VT_UINT); - } - - // VT_BOOL - - public void SetAsByrefBool(ref short value) - { - SetAsByref(ref value, VarEnum.VT_BOOL); - } - - // VT_ERROR - - public void SetAsByrefError(ref int value) - { - SetAsByref(ref value, VarEnum.VT_ERROR); - } - - // VT_R4 - - public void SetAsByrefR4(ref float value) - { - SetAsByref(ref value, VarEnum.VT_R4); - } - - // VT_R8 - - public void SetAsByrefR8(ref double value) - { - SetAsByref(ref value, VarEnum.VT_R8); - } - - // VT_DECIMAL - - public void SetAsByrefDecimal(ref decimal value) - { - SetAsByref(ref value, VarEnum.VT_DECIMAL); - } - - // VT_CY - - public void SetAsByrefCy(ref long value) - { - SetAsByref(ref value, VarEnum.VT_CY); - } - - // VT_DATE - - public void SetAsByrefDate(ref double value) - { - SetAsByref(ref value, VarEnum.VT_DATE); - } - - // VT_BSTR - - public void SetAsByrefBstr(ref IntPtr value) - { - SetAsByref(ref value, VarEnum.VT_BSTR); - } - - // VT_UNKNOWN - - public void SetAsByrefUnknown(ref IntPtr value) - { - SetAsByref(ref value, VarEnum.VT_UNKNOWN); - } - - // VT_DISPATCH - - public void SetAsByrefDispatch(ref IntPtr value) - { - SetAsByref(ref value, VarEnum.VT_DISPATCH); - } - - // VT_VARIANT - - public object AsVariant - { - get - { - return Marshal.GetObjectForNativeVariant(UnsafeMethods.ConvertVariantByrefToPtr(ref this)); - } - - set - { - Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise - if (value != null) - { - UnsafeMethods.InitVariantForObject(value, ref this); - } - } - } - - public void SetAsByrefVariant(ref Variant value) - { - SetAsByref(ref value, VarEnum.VT_VARIANT); - } - - // constructs a ByRef variant to pass contents of another variant ByRef. - public unsafe void SetAsByrefVariantIndirect(ref Variant value) - { - Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise - Debug.Assert((value.VariantType & VarEnum.VT_BYREF) == 0, "double indirection"); - - switch (value.VariantType) - { - case VarEnum.VT_EMPTY: - case VarEnum.VT_NULL: - // these cannot combine with VT_BYREF. Should try passing as a variant reference - SetAsByrefVariant(ref value); - return; - case VarEnum.VT_RECORD: - // VT_RECORD's are weird in that regardless of is the VT_BYREF flag is set or not - // they have the same internal representation. - _typeUnion._unionTypes._record = value._typeUnion._unionTypes._record; - break; - case VarEnum.VT_DECIMAL: - _typeUnion._unionTypes._byref = (IntPtr)Unsafe.AsPointer(ref value._decimal); - break; - default: - _typeUnion._unionTypes._byref = (IntPtr)Unsafe.AsPointer(ref value._typeUnion._unionTypes._byref); - break; - } - VariantType = (value.VariantType | VarEnum.VT_BYREF); - } - - private unsafe void SetAsByref(ref T value, VarEnum type) - { - Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise - VariantType = type | VarEnum.VT_BYREF; - _typeUnion._unionTypes._byref = (IntPtr)Unsafe.AsPointer(ref value); - } - - internal static System.Reflection.PropertyInfo GetAccessor(VarEnum varType) - { - switch (varType) - { - case VarEnum.VT_I1: return typeof(Variant).GetProperty(nameof(AsI1)); - case VarEnum.VT_I2: return typeof(Variant).GetProperty(nameof(AsI2)); - case VarEnum.VT_I4: return typeof(Variant).GetProperty(nameof(AsI4)); - case VarEnum.VT_I8: return typeof(Variant).GetProperty(nameof(AsI8)); - case VarEnum.VT_UI1: return typeof(Variant).GetProperty(nameof(AsUi1)); - case VarEnum.VT_UI2: return typeof(Variant).GetProperty(nameof(AsUi2)); - case VarEnum.VT_UI4: return typeof(Variant).GetProperty(nameof(AsUi4)); - case VarEnum.VT_UI8: return typeof(Variant).GetProperty(nameof(AsUi8)); - case VarEnum.VT_INT: return typeof(Variant).GetProperty(nameof(AsInt)); - case VarEnum.VT_UINT: return typeof(Variant).GetProperty(nameof(AsUint)); - case VarEnum.VT_BOOL: return typeof(Variant).GetProperty(nameof(AsBool)); - case VarEnum.VT_ERROR: return typeof(Variant).GetProperty(nameof(AsError)); - case VarEnum.VT_R4: return typeof(Variant).GetProperty(nameof(AsR4)); - case VarEnum.VT_R8: return typeof(Variant).GetProperty(nameof(AsR8)); - case VarEnum.VT_DECIMAL: return typeof(Variant).GetProperty(nameof(AsDecimal)); - case VarEnum.VT_CY: return typeof(Variant).GetProperty(nameof(AsCy)); - case VarEnum.VT_DATE: return typeof(Variant).GetProperty(nameof(AsDate)); - case VarEnum.VT_BSTR: return typeof(Variant).GetProperty(nameof(AsBstr)); - case VarEnum.VT_UNKNOWN: return typeof(Variant).GetProperty(nameof(AsUnknown)); - case VarEnum.VT_DISPATCH: return typeof(Variant).GetProperty(nameof(AsDispatch)); - - case VarEnum.VT_VARIANT: - case VarEnum.VT_RECORD: - case VarEnum.VT_ARRAY: - return typeof(Variant).GetProperty(nameof(AsVariant)); - - default: - throw new NotSupportedException(); - } - } - - internal static System.Reflection.MethodInfo GetByrefSetter(VarEnum varType) - { - switch (varType) - { - case VarEnum.VT_I1: return typeof(Variant).GetMethod(nameof(SetAsByrefI1)); - case VarEnum.VT_I2: return typeof(Variant).GetMethod(nameof(SetAsByrefI2)); - case VarEnum.VT_I4: return typeof(Variant).GetMethod(nameof(SetAsByrefI4)); - case VarEnum.VT_I8: return typeof(Variant).GetMethod(nameof(SetAsByrefI8)); - case VarEnum.VT_UI1: return typeof(Variant).GetMethod(nameof(SetAsByrefUi1)); - case VarEnum.VT_UI2: return typeof(Variant).GetMethod(nameof(SetAsByrefUi2)); - case VarEnum.VT_UI4: return typeof(Variant).GetMethod(nameof(SetAsByrefUi4)); - case VarEnum.VT_UI8: return typeof(Variant).GetMethod(nameof(SetAsByrefUi8)); - case VarEnum.VT_INT: return typeof(Variant).GetMethod(nameof(SetAsByrefInt)); - case VarEnum.VT_UINT: return typeof(Variant).GetMethod(nameof(SetAsByrefUint)); - case VarEnum.VT_BOOL: return typeof(Variant).GetMethod(nameof(SetAsByrefBool)); - case VarEnum.VT_ERROR: return typeof(Variant).GetMethod(nameof(SetAsByrefError)); - case VarEnum.VT_R4: return typeof(Variant).GetMethod(nameof(SetAsByrefR4)); - case VarEnum.VT_R8: return typeof(Variant).GetMethod(nameof(SetAsByrefR8)); - case VarEnum.VT_DECIMAL: return typeof(Variant).GetMethod(nameof(SetAsByrefDecimal)); - case VarEnum.VT_CY: return typeof(Variant).GetMethod(nameof(SetAsByrefCy)); - case VarEnum.VT_DATE: return typeof(Variant).GetMethod(nameof(SetAsByrefDate)); - case VarEnum.VT_BSTR: return typeof(Variant).GetMethod(nameof(SetAsByrefBstr)); - case VarEnum.VT_UNKNOWN: return typeof(Variant).GetMethod(nameof(SetAsByrefUnknown)); - case VarEnum.VT_DISPATCH: return typeof(Variant).GetMethod(nameof(SetAsByrefDispatch)); - - case VarEnum.VT_VARIANT: - return typeof(Variant).GetMethod(nameof(SetAsByrefVariant)); - case VarEnum.VT_RECORD: - case VarEnum.VT_ARRAY: - return typeof(Variant).GetMethod(nameof(SetAsByrefVariantIndirect)); - - default: - throw new NotSupportedException(); - } - } - - public override string ToString() => $"Variant ({VariantType})"; - - public void SetAsIConvertible(IConvertible value) - { - Debug.Assert(IsEmpty); // The setter can only be called once as VariantClear might be needed otherwise - - TypeCode tc = value.GetTypeCode(); - CultureInfo ci = CultureInfo.CurrentCulture; - - switch (tc) - { - case TypeCode.Empty: break; - case TypeCode.Object: AsUnknown = value; break; - case TypeCode.DBNull: SetAsNULL(); break; - case TypeCode.Boolean: AsBool = value.ToBoolean(ci); break; - case TypeCode.Char: AsUi2 = value.ToChar(ci); break; - case TypeCode.SByte: AsI1 = value.ToSByte(ci); break; - case TypeCode.Byte: AsUi1 = value.ToByte(ci); break; - case TypeCode.Int16: AsI2 = value.ToInt16(ci); break; - case TypeCode.UInt16: AsUi2 = value.ToUInt16(ci); break; - case TypeCode.Int32: AsI4 = value.ToInt32(ci); break; - case TypeCode.UInt32: AsUi4 = value.ToUInt32(ci); break; - case TypeCode.Int64: AsI8 = value.ToInt64(ci); break; - case TypeCode.UInt64: AsI8 = value.ToInt64(ci); break; - case TypeCode.Single: AsR4 = value.ToSingle(ci); break; - case TypeCode.Double: AsR8 = value.ToDouble(ci); break; - case TypeCode.Decimal: AsDecimal = value.ToDecimal(ci); break; - case TypeCode.DateTime: AsDate = value.ToDateTime(ci); break; - case TypeCode.String: AsBstr = value.ToString(ci); break; - - default: - throw new NotSupportedException(); - } - } - } -} diff --git a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/VariantArray.cs b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/VariantArray.cs index 37e34303feadf..559b9e92c01b1 100644 --- a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/VariantArray.cs +++ b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/VariantArray.cs @@ -10,31 +10,32 @@ using System.Reflection; using System.Reflection.Emit; using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; namespace Microsoft.CSharp.RuntimeBinder.ComInterop { [StructLayout(LayoutKind.Sequential)] internal struct VariantArray1 { - public Variant Element0; + public ComVariant Element0; } [StructLayout(LayoutKind.Sequential)] internal struct VariantArray2 { - public Variant Element0, Element1; + public ComVariant Element0, Element1; } [StructLayout(LayoutKind.Sequential)] internal struct VariantArray4 { - public Variant Element0, Element1, Element2, Element3; + public ComVariant Element0, Element1, Element2, Element3; } [StructLayout(LayoutKind.Sequential)] internal struct VariantArray8 { - public Variant Element0, Element1, Element2, Element3, Element4, Element5, Element6, Element7; + public ComVariant Element0, Element1, Element2, Element3, Element4, Element5, Element6, Element7; } // @@ -49,7 +50,6 @@ internal static class VariantArray // Don't need a dictionary for this, it will have very few elements // (guaranteed less than 28, in practice 0-2) private static readonly List s_generatedTypes = new List(0); - private static readonly string[] s_genericTName = new string[] { "T" }; [DynamicDependency(DynamicallyAccessedMemberTypes.PublicFields, typeof(VariantArray1))] [DynamicDependency(DynamicallyAccessedMemberTypes.PublicFields, typeof(VariantArray2))] @@ -62,8 +62,6 @@ internal static MemberExpression GetStructField(ParameterExpression variantArray return Expression.Field(variantArray, "Element" + field); } - [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2055:UnrecognizedReflectionPattern", - Justification = "MakeGenericType is called on a dynamically created type that doesn't contain trimming annotations.")] internal static Type GetStructType(int args) { Debug.Assert(args >= 0); @@ -91,7 +89,7 @@ internal static Type GetStructType(int args) } // Else generate a new type - Type type = CreateCustomType(size).MakeGenericType(new Type[] { typeof(Variant) }); + Type type = CreateCustomType(size); s_generatedTypes.Add(type); return type; } @@ -101,10 +99,9 @@ private static Type CreateCustomType(int size) { TypeAttributes attrs = TypeAttributes.NotPublic | TypeAttributes.SequentialLayout; TypeBuilder type = UnsafeMethods.DynamicModule.DefineType("VariantArray" + size, attrs, typeof(ValueType)); - GenericTypeParameterBuilder T = type.DefineGenericParameters(s_genericTName)[0]; for (int i = 0; i < size; i++) { - type.DefineField("Element" + i, T, FieldAttributes.Public); + type.DefineField("Element" + i, typeof(ComVariant), FieldAttributes.Public); } return type.CreateType(); } diff --git a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/VariantBuilder.cs b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/VariantBuilder.cs index 4fdb65bbd1aef..39bdcc24d9647 100644 --- a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/VariantBuilder.cs +++ b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/VariantBuilder.cs @@ -4,12 +4,14 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; +using System.Reflection; using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; namespace Microsoft.CSharp.RuntimeBinder.ComInterop { /// - /// VariantBuilder handles packaging of arguments into a Variant for a call to IDispatch.Invoke + /// VariantBuilder handles packaging of arguments into an ComVariant for a call to IDispatch.Invoke /// internal sealed class VariantBuilder { @@ -49,8 +51,8 @@ internal Expression InitializeArgumentVariant(MemberExpression variant, Expressi return Expression.Block( Expression.Assign(TempVariable, argExpr), Expression.Call( + DynamicVariantExtensions.GetByrefSetter(_targetComType & ~VarEnum.VT_BYREF), variant, - Variant.GetByrefSetter(_targetComType & ~VarEnum.VT_BYREF), TempVariable ) ); @@ -63,13 +65,13 @@ internal Expression InitializeArgumentVariant(MemberExpression variant, Expressi if (_argBuilder is ConvertibleArgBuilder) { return Expression.Call( + typeof(DynamicVariantExtensions).GetMethod(nameof(DynamicVariantExtensions.SetAsIConvertible)), variant, - typeof(Variant).GetMethod(nameof(Variant.SetAsIConvertible)), argument ); } - if (Variant.IsPrimitiveType(_targetComType) || + if (_targetComType.IsPrimitiveType() || (_targetComType == VarEnum.VT_DISPATCH) || (_targetComType == VarEnum.VT_UNKNOWN) || (_targetComType == VarEnum.VT_VARIANT) || @@ -77,13 +79,10 @@ internal Expression InitializeArgumentVariant(MemberExpression variant, Expressi (_targetComType == VarEnum.VT_ARRAY)) { // paramVariants._elementN.AsT = (cast)argN - return Expression.Assign( - Expression.Property( - variant, - Variant.GetAccessor(_targetComType) - ), - argument - ); + return Expression.Call(null, + DynamicVariantExtensions.GetSetter(_targetComType), + variant, + argument); } switch (_targetComType) @@ -92,8 +91,8 @@ internal Expression InitializeArgumentVariant(MemberExpression variant, Expressi return null; case VarEnum.VT_NULL: - // paramVariants._elementN.SetAsNull(); - return Expression.Call(variant, typeof(Variant).GetMethod(nameof(Variant.SetAsNULL))); + // paramVariants._elementN = ComVariant.Null; + return Expression.Assign(variant, Expression.Property(null, typeof(ComVariant).GetProperty(nameof(ComVariant.Null), BindingFlags.Public | BindingFlags.Static))); default: Debug.Assert(false, "Unexpected VarEnum"); @@ -131,7 +130,7 @@ internal Expression Clear() if (_argBuilder is VariantArgBuilder) { Debug.Assert(TempVariable != null); - return Expression.Call(TempVariable, typeof(Variant).GetMethod(nameof(Variant.Clear))); + return Expression.Call(TempVariable, typeof(ComVariant).GetMethod(nameof(ComVariant.Dispose))); } return null; } @@ -148,11 +147,11 @@ internal Expression Clear() case VarEnum.VT_ARRAY: case VarEnum.VT_RECORD: case VarEnum.VT_VARIANT: - // paramVariants._elementN.Clear() - return Expression.Call(_variant, typeof(Variant).GetMethod(nameof(Variant.Clear))); + // paramVariants._elementN.Dispose() + return Expression.Call(_variant, typeof(ComVariant).GetMethod(nameof(ComVariant.Dispose))); default: - Debug.Assert(Variant.IsPrimitiveType(_targetComType), "Unexpected VarEnum"); + Debug.Assert(_targetComType.IsPrimitiveType(), "Unexpected VarEnum"); return null; } } diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index b8f8a8980528c..540dc62f30918 100644 --- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -1,17 +1,17 @@  - @@ -376,7 +376,7 @@ One of the identified items was in an invalid format. - + Generic arguments after array spec or pointer type. @@ -1080,7 +1080,7 @@ Field '{0}' does not belong to the same class as the constructor. - + Field '{0}' does not have a valid type. @@ -1502,7 +1502,7 @@ Path cannot be the empty string or all whitespace. - Value of argument {0} does not match parameter type: {1} -> {2}. + Value of argument {0} does not match parameter type: {1} -> {2}. Parameter {0} does not have a valid type. @@ -3774,7 +3774,7 @@ "Property '{0}' does not have a setter. - "Value of property '{0}' does not match property type: '{1}' -> '{2}'. + "Value of property '{0}' does not match property type: '{1}' -> '{2}'. Cannot load hostpolicy library. AssemblyDependencyResolver is currently only supported if the runtime is hosted through hostpolicy library. @@ -4253,4 +4253,25 @@ SearchValues<string> supports only StringComparison.Ordinal and StringComparison.OrdinalIgnoreCase. - + + ComVariants containing SAFEARRAYs are not supported on this platform + + + Size of {0} should be the same size as the value specified by {1} + + + Variant type '{0}' is not one of the supported variant types for this operation: [{1}] + + + VT_DECIMAL is not supported in CreateRaw. Use the Create method. + + + VT_DECIMAL is not supported in GetRawDataRef. Use the As method. + + + VT_VARIANT is not supported in variants. + + + Unsupported type + + \ No newline at end of file diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index b27a43992e2ce..6998e54610c79 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -978,6 +978,7 @@ + @@ -2053,6 +2054,9 @@ Common\Interop\Windows\Ole32\Interop.CoTaskMemAlloc.cs + + Common\Interop\Windows\Ole32\Interop.PropVariantClear.cs + Common\Interop\Windows\Secur32\Interop.GetUserNameExW.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ComVariant.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ComVariant.cs new file mode 100644 index 0000000000000..95a102338e621 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ComVariant.cs @@ -0,0 +1,569 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +namespace System.Runtime.InteropServices.Marshalling +{ + /// + /// A type that represents an OLE VARIANT in managed code. + /// + [StructLayout(LayoutKind.Explicit)] + public struct ComVariant : IDisposable + { + // See definition in wtypes.h in the Windows SDK. + private const VarEnum VT_VERSIONED_STREAM = (VarEnum)73; + // VARIANT_BOOL constants. + internal const short VARIANT_TRUE = -1; + internal const short VARIANT_FALSE = 0; +#if DEBUG + static unsafe ComVariant() + { + // Variant size is the size of 4 pointers (16 bytes) on a 32-bit processor, + // and 3 pointers (24 bytes) on a 64-bit processor. + // See definition in oaidl.h in the Windows SDK. + int variantSize = sizeof(ComVariant); + if (IntPtr.Size == 4) + { + Debug.Assert(variantSize == (4 * IntPtr.Size)); + } + else + { + Debug.Assert(IntPtr.Size == 8); + Debug.Assert(variantSize == (3 * IntPtr.Size)); + } + } +#endif + + // Most of the data types in the Variant are carried in _typeUnion + [FieldOffset(0)] private TypeUnion _typeUnion; + + // Decimal is the largest data type and it needs to use the space that is normally unused in TypeUnion._wReserved1, etc. + // Hence, it is declared to completely overlap with TypeUnion. A Decimal does not use the first two bytes, and so + // TypeUnion._vt can still be used to encode the type. + [FieldOffset(0)] private decimal _decimal; + + [StructLayout(LayoutKind.Sequential)] + private struct TypeUnion + { + public ushort _vt; + public ushort _wReserved1; + public ushort _wReserved2; + public ushort _wReserved3; + + public UnionTypes _unionTypes; + } + + [StructLayout(LayoutKind.Sequential)] + private struct Record + { + public IntPtr _record; + public IntPtr _recordInfo; + } + + [StructLayout(LayoutKind.Sequential)] + private struct Blob + { + public int _size; + public IntPtr _data; + } + + [StructLayout(LayoutKind.Sequential)] + private unsafe struct Vector where T : unmanaged + { + public int _numElements; + public T* _data; + + public Span AsSpan() => new(_data, _numElements); + } + + [StructLayout(LayoutKind.Sequential)] + private struct VersionedStream + { + public Guid _version; + public IntPtr _stream; + } + + [StructLayout(LayoutKind.Sequential)] + private struct ClipboardData + { + public uint _size; + public int _format; + public IntPtr _data; + } + + [StructLayout(LayoutKind.Explicit)] + private unsafe struct UnionTypes + { + [FieldOffset(0)] public sbyte _i1; + [FieldOffset(0)] public short _i2; + [FieldOffset(0)] public int _i4; + [FieldOffset(0)] public long _i8; + [FieldOffset(0)] public byte _ui1; + [FieldOffset(0)] public ushort _ui2; + [FieldOffset(0)] public uint _ui4; + [FieldOffset(0)] public ulong _ui8; + [FieldOffset(0)] public int _int; + [FieldOffset(0)] public uint _uint; + [FieldOffset(0)] public short _bool; + [FieldOffset(0)] public int _error; + [FieldOffset(0)] public float _r4; + [FieldOffset(0)] public double _r8; + [FieldOffset(0)] public long _cy; + [FieldOffset(0)] public double _date; + [FieldOffset(0)] public IntPtr _bstr; + [FieldOffset(0)] public IntPtr _unknown; + [FieldOffset(0)] public IntPtr _dispatch; + [FieldOffset(0)] public IntPtr _pvarVal; + [FieldOffset(0)] public IntPtr _byref; + [FieldOffset(0)] public Record _record; + [FieldOffset(0)] public Blob _blob; + [FieldOffset(0)] public VersionedStream* _versionedStream; + [FieldOffset(0)] public ClipboardData* clipboardData; + } + + /// + /// Release resources owned by this instance. + /// + public unsafe void Dispose() + { +#if TARGET_WINDOWS + fixed (void* pThis = &this) + { + // We are using PropVariantClear instead of VariantClear + // as PropVariantClear covers more cases (like VT_BLOB, VT_STREAM, VT_CF, etc.) + // than VariantClear does. We intend for users to be able to use this ComVariant type for + // both VARIANT and PROPVARIANT scenarios, so we need to support all of the variant kinds that might be set. + Interop.Ole32.PropVariantClear((nint)pThis); + } +#else + // Re-implement the same clearing semantics as PropVariantClear manually for non-Windows platforms. + if (VarType == VarEnum.VT_BSTR) + { + Marshal.FreeBSTR(_typeUnion._unionTypes._bstr); + } + else if (VarType.HasFlag(VarEnum.VT_ARRAY)) + { + throw new PlatformNotSupportedException(SR.ComVariant_SafeArray_PlatformNotSupported); + } + else if (VarType == VarEnum.VT_UNKNOWN || VarType == VarEnum.VT_DISPATCH) + { + if (_typeUnion._unionTypes._unknown != IntPtr.Zero) + { + Marshal.Release(_typeUnion._unionTypes._unknown); + } + } + else if (VarType == VarEnum.VT_RECORD) + { + if (_typeUnion._unionTypes._record._recordInfo != IntPtr.Zero) + { + // Invoke RecordClear on the record info with the data. + if (_typeUnion._unionTypes._record._record != IntPtr.Zero) + { + Marshal.ThrowExceptionForHR(((delegate* unmanaged)(*(*(void***)_typeUnion._unionTypes._record._recordInfo + 4 /* IRecordInfo.RecordClear slot */)))(_typeUnion._unionTypes._record._recordInfo, _typeUnion._unionTypes._record._record)); + } + Marshal.Release(_typeUnion._unionTypes._record._recordInfo); + } + } + else if (VarType == VarEnum.VT_LPSTR || VarType == VarEnum.VT_LPWSTR || VarType == VarEnum.VT_CLSID) + { + Marshal.FreeCoTaskMem(_typeUnion._unionTypes._byref); + } + else if (VarType == VarEnum.VT_BLOB || VarType == VarEnum.VT_BLOB_OBJECT) + { + Marshal.FreeCoTaskMem(_typeUnion._unionTypes._blob._data); + } + else if (VarType == VarEnum.VT_STREAM || VarType == VarEnum.VT_STREAMED_OBJECT || VarType == VarEnum.VT_STORAGE || VarType == VarEnum.VT_STORED_OBJECT) + { + if (_typeUnion._unionTypes._unknown != IntPtr.Zero) + { + Marshal.Release(_typeUnion._unionTypes._unknown); + } + } + else if (VarType == VT_VERSIONED_STREAM) + { + VersionedStream* versionedStream = _typeUnion._unionTypes._versionedStream; + if (versionedStream != null && versionedStream->_stream != IntPtr.Zero) + { + Marshal.Release(versionedStream->_stream); + } + Marshal.FreeCoTaskMem((nint)versionedStream); + } + else if (VarType == VarEnum.VT_CF) + { + ClipboardData* clipboardData = _typeUnion._unionTypes.clipboardData; + if (clipboardData != null) + { + Marshal.FreeCoTaskMem(clipboardData->_data); + Marshal.FreeCoTaskMem((nint)clipboardData); + } + } + else if (VarType.HasFlag(VarEnum.VT_VECTOR)) + { + switch (VarType & ~VarEnum.VT_VECTOR) + { + case VarEnum.VT_BSTR: + foreach (var str in GetRawDataRef>().AsSpan()) + { + Marshal.FreeBSTR(str); + } + break; + case VarEnum.VT_LPSTR: + case VarEnum.VT_LPWSTR: + foreach (var str in GetRawDataRef>().AsSpan()) + { + Marshal.FreeCoTaskMem(str); + } + break; + case VarEnum.VT_CF: + foreach (var cf in GetRawDataRef>().AsSpan()) + { + Marshal.FreeCoTaskMem(cf._data); + } + break; + case VarEnum.VT_VARIANT: + foreach (var variant in GetRawDataRef>().AsSpan()) + { + variant.Dispose(); + } + break; + default: + break; + } + Marshal.FreeCoTaskMem((nint)GetRawDataRef>()._data); + } + + // Clear out this ComVariant instance. + this = default; +#endif + } + +#pragma warning disable CS0618 // We support the obsolete CurrencyWrapper type + /// + /// Create an instance from the specified value. + /// + /// The type of the specified value. + /// The value to wrap in an . + /// An that contains the provided value. + /// When does not directly correspond to a variant type. + public static ComVariant Create([DisallowNull] T value) + { + Unsafe.SkipInit(out ComVariant variant); + if (typeof(T) == typeof(DBNull)) + { + variant = Null; + } + else if (typeof(T) == typeof(short)) + { + variant.VarType = VarEnum.VT_I2; + variant._typeUnion._unionTypes._i2 = (short)(object)value; + } + else if (typeof(T) == typeof(int)) + { + variant.VarType = VarEnum.VT_I4; + variant._typeUnion._unionTypes._i4 = (int)(object)value; + } + else if (typeof(T) == typeof(float)) + { + variant.VarType = VarEnum.VT_R4; + variant._typeUnion._unionTypes._r4 = (float)(object)value; + } + else if (typeof(T) == typeof(double)) + { + variant.VarType = VarEnum.VT_R8; + variant._typeUnion._unionTypes._r8 = (double)(object)value; + } + else if (typeof(T) == typeof(CurrencyWrapper)) + { + variant.VarType = VarEnum.VT_CY; + variant._typeUnion._unionTypes._cy = decimal.ToOACurrency(((CurrencyWrapper)(object)value).WrappedObject); + } + else if (typeof(T) == typeof(DateTime)) + { + variant.VarType = VarEnum.VT_DATE; + variant._typeUnion._unionTypes._date = ((DateTime)(object)value).ToOADate(); + } + else if (typeof(T) == typeof(BStrWrapper)) + { + variant.VarType = VarEnum.VT_BSTR; + variant._typeUnion._unionTypes._bstr = Marshal.StringToBSTR(((BStrWrapper)(object)value).WrappedObject); + } + else if (typeof(T) == typeof(string)) + { + // We map string to VT_BSTR as that's the only valid option for a VARIANT. + // The rest of the "string" options are only supported in TYPEDESCs and PROPVARIANTs, + // which are different scenarios. + // Users who want to use the ComVariant type with VT_LPSTR or VT_LPWSTR can use CreateRaw + // to do so. + variant.VarType = VarEnum.VT_BSTR; + variant._typeUnion._unionTypes._bstr = Marshal.StringToBSTR((string)(object)value); + } + else if (typeof(T) == typeof(ErrorWrapper)) + { + variant.VarType = VarEnum.VT_ERROR; + variant._typeUnion._unionTypes._error = ((ErrorWrapper)(object)value).ErrorCode; + } + else if (typeof(T) == typeof(bool)) + { + // bool values in OLE VARIANTs are VARIANT_BOOL values. + variant.VarType = VarEnum.VT_BOOL; + variant._typeUnion._unionTypes._bool = ((bool)(object)value) ? VARIANT_TRUE : VARIANT_FALSE; + } + else if (typeof(T) == typeof(decimal)) + { + // Set the value first and then the type as the decimal storage + // overlaps with the type descriminator. + variant._decimal = (decimal)(object)value; + variant.VarType = VarEnum.VT_DECIMAL; + } + else if (typeof(T) == typeof(sbyte)) + { + variant.VarType = VarEnum.VT_I1; + variant._typeUnion._unionTypes._i1 = (sbyte)(object)value; + } + else if (typeof(T) == typeof(byte)) + { + variant.VarType = VarEnum.VT_UI1; + variant._typeUnion._unionTypes._ui1 = (byte)(object)value; + } + else if (typeof(T) == typeof(ushort)) + { + variant.VarType = VarEnum.VT_UI2; + variant._typeUnion._unionTypes._ui2 = (ushort)(object)value; + } + else if (typeof(T) == typeof(uint)) + { + variant.VarType = VarEnum.VT_UI4; + variant._typeUnion._unionTypes._ui4 = (uint)(object)value; + } + else if (typeof(T) == typeof(long)) + { + variant.VarType = VarEnum.VT_I8; + variant._typeUnion._unionTypes._i8 = (long)(object)value; + } + else if (typeof(T) == typeof(ulong)) + { + variant.VarType = VarEnum.VT_UI8; + variant._typeUnion._unionTypes._ui8 = (ulong)(object)value; + } + else + { + throw new ArgumentException(SR.UnsupportedType, nameof(T)); + } + // We do not support mapping nint or nuint to VT_INT and VT_UINT respectively + // as this does not match the MS-OAUT spec. + // We do not map VT_BYREF automatically, nor do we map any of the array types. + return variant; + } +#pragma warning restore CS0618 + + /// + /// Create a with the given type and provided value. + /// + /// The type of the value to store in the variant. + /// The type of the variant + /// The raw value to store in the variant without any processing + /// A variant that contains the provided value. + /// When the provided corresponds to a variant type that is not supported in VARIANTs or is + /// When the provided specifies the flag for SAFEARRAYs. + public static unsafe ComVariant CreateRaw(VarEnum vt, T rawValue) + where T : unmanaged + { + ArgumentOutOfRangeException.ThrowIfGreaterThan(Unsafe.SizeOf(), sizeof(UnionTypes), nameof(T)); + if (vt == VarEnum.VT_DECIMAL) + { + throw new ArgumentException(SR.ComVariant_VT_DECIMAL_NotSupported_CreateRaw, nameof(vt)); + } + if (vt == VarEnum.VT_VARIANT) + { + throw new ArgumentException(SR.ComVariant_VT_VARIANT_In_Variant, nameof(vt)); + } + if (vt.HasFlag(VarEnum.VT_ARRAY) && !OperatingSystem.IsWindows()) + { + throw new PlatformNotSupportedException(SR.ComVariant_SafeArray_PlatformNotSupported); + } + + Unsafe.SkipInit(out ComVariant value); + value.VarType = vt; + value.GetRawDataRef() = (vt, sizeof(T)) switch + { + (VarEnum.VT_I1 or VarEnum.VT_UI1, 1) => rawValue, + (VarEnum.VT_I2 or VarEnum.VT_UI2 or VarEnum.VT_BOOL, 2) => rawValue, + (VarEnum.VT_ERROR or VarEnum.VT_HRESULT or VarEnum.VT_I4 or VarEnum.VT_UI4 or VarEnum.VT_R4 or VarEnum.VT_INT or VarEnum.VT_UINT, 4) => rawValue, + (VarEnum.VT_I8 or VarEnum.VT_UI8 or VarEnum.VT_R8 or VarEnum.VT_DATE, 8) => rawValue, + (VarEnum.VT_UNKNOWN or VarEnum.VT_DISPATCH or VarEnum.VT_LPSTR or VarEnum.VT_BSTR or VarEnum.VT_LPWSTR or VarEnum.VT_SAFEARRAY + or VarEnum.VT_CLSID or VarEnum.VT_STREAM or VarEnum.VT_STREAMED_OBJECT or VarEnum.VT_STORAGE or VarEnum.VT_STORED_OBJECT or VarEnum.VT_CF or VT_VERSIONED_STREAM, _) when sizeof(T) == nint.Size => rawValue, + (VarEnum.VT_CY or VarEnum.VT_FILETIME, 8) => rawValue, + (VarEnum.VT_RECORD, _) when sizeof(T) == sizeof(Record) => rawValue, + _ when vt.HasFlag(VarEnum.VT_BYREF) && sizeof(T) == nint.Size => rawValue, + _ when vt.HasFlag(VarEnum.VT_VECTOR) && sizeof(T) == sizeof(Vector) => rawValue, + _ when vt.HasFlag(VarEnum.VT_ARRAY) && sizeof(T) == nint.Size => rawValue, + (VarEnum.VT_BLOB or VarEnum.VT_BLOB_OBJECT, _) when sizeof(T) == sizeof(Blob) => rawValue, + _ => throw new ArgumentException(SR.Format(SR.ComVariant_SizeMustMatchVariantSize, nameof(T), nameof(vt))) + }; + + return value; + } + + /// + /// A instance that represents a null value with type. + /// + public static ComVariant Null { get; } = new() { VarType = VarEnum.VT_NULL }; + + private readonly void ThrowIfNotVarType(params VarEnum[] requiredType) + { + if (Array.IndexOf(requiredType, VarType) == -1) + { + throw new InvalidOperationException(SR.Format(SR.ComVariant_TypeIsNotSupportedType, VarType, string.Join(", ", requiredType))); + } + } + +#pragma warning disable CS0618 // Type or member is obsolete + /// + /// Create a managed value based on the value in the instance. + /// + /// The managed type to create an instance of. + /// The managed value contained in this variant. + /// When does not match the of the . + public readonly T? As() + { + if (VarType == VarEnum.VT_EMPTY) + { + return default; + } + if (typeof(T) == typeof(DBNull)) + { + ThrowIfNotVarType(VarEnum.VT_NULL); + return (T)(object)DBNull.Value; + } + else if (typeof(T) == typeof(short)) + { + ThrowIfNotVarType(VarEnum.VT_I2); + return (T)(object)_typeUnion._unionTypes._i2; + } + else if (typeof(T) == typeof(int)) + { + ThrowIfNotVarType(VarEnum.VT_I4, VarEnum.VT_ERROR, VarEnum.VT_INT); + return (T)(object)_typeUnion._unionTypes._i4; + } + else if (typeof(T) == typeof(float)) + { + ThrowIfNotVarType(VarEnum.VT_R4); + return (T)(object)_typeUnion._unionTypes._r4; + } + else if (typeof(T) == typeof(double)) + { + ThrowIfNotVarType(VarEnum.VT_R8); + return (T)(object)_typeUnion._unionTypes._r8; + } + else if (typeof(T) == typeof(CurrencyWrapper)) + { + ThrowIfNotVarType(VarEnum.VT_CY); + return (T)(object)new CurrencyWrapper(decimal.FromOACurrency(_typeUnion._unionTypes._cy)); + } + else if (typeof(T) == typeof(DateTime)) + { + ThrowIfNotVarType(VarEnum.VT_DATE); + return (T)(object)DateTime.FromOADate(_typeUnion._unionTypes._date); + } + else if (typeof(T) == typeof(BStrWrapper)) + { + ThrowIfNotVarType(VarEnum.VT_BSTR); + return (T)(object)new BStrWrapper(Marshal.PtrToStringBSTR(_typeUnion._unionTypes._bstr)); + } + else if (typeof(T) == typeof(string)) + { + // To match the Create method, we will only support getting a string from an ComVariant + // when the ComVariant holds a BSTR. + ThrowIfNotVarType(VarEnum.VT_BSTR); + if (_typeUnion._unionTypes._bstr == IntPtr.Zero) + { + return default; + } + return (T)(object)Marshal.PtrToStringBSTR(_typeUnion._unionTypes._bstr); + } + else if (typeof(T) == typeof(ErrorWrapper)) + { + ThrowIfNotVarType(VarEnum.VT_ERROR); + return (T)(object)new ErrorWrapper(_typeUnion._unionTypes._error); + } + else if (typeof(T) == typeof(bool)) + { + // bool values in OLE VARIANTs are VARIANT_BOOL values. + ThrowIfNotVarType(VarEnum.VT_BOOL); + return (T)(object)(_typeUnion._unionTypes._bool != VARIANT_FALSE); + } + else if (typeof(T) == typeof(decimal)) + { + // Set the value first and then the type as the decimal storage + // overlaps with the type descriminator. + ThrowIfNotVarType(VarEnum.VT_DECIMAL); + // Create a second variant copy with the VarType set to VT_EMPTY. + // This will ensure that we don't leak the VT_DECMIAL flag into the decimal value itself. + ComVariant variantWithoutVarType = this; + variantWithoutVarType.VarType = VarEnum.VT_EMPTY; + return (T)(object)variantWithoutVarType._decimal; + } + else if (typeof(T) == typeof(sbyte)) + { + ThrowIfNotVarType(VarEnum.VT_I1); + return (T)(object)_typeUnion._unionTypes._i1; + } + else if (typeof(T) == typeof(byte)) + { + ThrowIfNotVarType(VarEnum.VT_UI1); + return (T)(object)_typeUnion._unionTypes._ui1; + } + else if (typeof(T) == typeof(ushort)) + { + ThrowIfNotVarType(VarEnum.VT_UI2); + return (T)(object)_typeUnion._unionTypes._ui2; + } + else if (typeof(T) == typeof(uint)) + { + ThrowIfNotVarType(VarEnum.VT_UI4, VarEnum.VT_UINT); + return (T)(object)_typeUnion._unionTypes._ui4; + } + else if (typeof(T) == typeof(long)) + { + ThrowIfNotVarType(VarEnum.VT_I8); + return (T)(object)_typeUnion._unionTypes._i8; + } + else if (typeof(T) == typeof(ulong)) + { + ThrowIfNotVarType(VarEnum.VT_UI8); + return (T)(object)_typeUnion._unionTypes._ui8; + } + throw new ArgumentException(SR.UnsupportedType, nameof(T)); + } +#pragma warning restore CS0618 // Type or member is obsolete + + /// + /// The type of the data stored in this . + /// + public VarEnum VarType + { + readonly get => (VarEnum)_typeUnion._vt; + private set => _typeUnion._vt = (ushort)value; + } + + /// + /// Get a reference to the storage location within this instance. + /// + /// The type of reference to return. + /// A reference to the storage location within this . + /// is or larger than the storage space in an . + [UnscopedRef] + public unsafe ref T GetRawDataRef() + where T : unmanaged + { + ArgumentOutOfRangeException.ThrowIfGreaterThan(Unsafe.SizeOf(), sizeof(UnionTypes), nameof(T)); + if (typeof(T) == typeof(decimal)) + { + throw new ArgumentException(SR.ComVariant_VT_DECIMAL_NotSupported_RawDataRef, nameof(T)); + } + return ref Unsafe.As(ref _typeUnion._unionTypes); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/System.Runtime.InteropServices.sln b/src/libraries/System.Runtime.InteropServices/System.Runtime.InteropServices.sln index e9534f4a25c81..56ccb89703b8e 100644 --- a/src/libraries/System.Runtime.InteropServices/System.Runtime.InteropServices.sln +++ b/src/libraries/System.Runtime.InteropServices/System.Runtime.InteropServices.sln @@ -1,4 +1,8 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34117.57 +MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.CoreLib", "..\..\coreclr\System.Private.CoreLib\System.Private.CoreLib.csproj", "{94B59BA0-491F-4B59-ADFF-A057EC3EC835}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}" @@ -73,16 +77,21 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{B1678CCD-95C EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{E1AEBD5D-AE4E-4F61-B9ED-AEF950B0CC33}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "tools\gen", "{8826C1E1-CEBD-49F8-9BC8-97FECE60F9B9}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{8826C1E1-CEBD-49F8-9BC8-97FECE60F9B9}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "tools\src", "{7B3C7C2F-58E0-4EE5-B904-9C978F40FD33}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{7B3C7C2F-58E0-4EE5-B904-9C978F40FD33}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "tools\ref", "{5114BD7E-8492-452A-8DAA-BF971D74A66D}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{5114BD7E-8492-452A-8DAA-BF971D74A66D}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{8FA3249B-3567-4C76-BA32-9488FC92994D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Checked|Any CPU = Checked|Any CPU + Checked|arm = Checked|arm + Checked|arm64 = Checked|arm64 + Checked|x64 = Checked|x64 + Checked|x86 = Checked|x86 Debug|Any CPU = Debug|Any CPU Debug|arm = Debug|arm Debug|arm64 = Debug|arm64 @@ -93,13 +102,18 @@ Global Release|arm64 = Release|arm64 Release|x64 = Release|x64 Release|x86 = Release|x86 - Checked|Any CPU = Checked|Any CPU - Checked|arm = Checked|arm - Checked|arm64 = Checked|arm64 - Checked|x64 = Checked|x64 - Checked|x86 = Checked|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|Any CPU.ActiveCfg = Checked|x64 + {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|Any CPU.Build.0 = Checked|x64 + {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|arm.ActiveCfg = Checked|arm + {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|arm.Build.0 = Checked|arm + {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|arm64.ActiveCfg = Checked|arm64 + {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|arm64.Build.0 = Checked|arm64 + {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|x64.ActiveCfg = Checked|x64 + {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|x64.Build.0 = Checked|x64 + {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|x86.ActiveCfg = Checked|x86 + {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|x86.Build.0 = Checked|x86 {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Debug|Any CPU.ActiveCfg = Debug|x64 {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Debug|Any CPU.Build.0 = Debug|x64 {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Debug|arm.ActiveCfg = Debug|arm @@ -120,16 +134,11 @@ Global {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Release|x64.Build.0 = Release|x64 {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Release|x86.ActiveCfg = Release|x86 {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Release|x86.Build.0 = Release|x86 - {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|Any CPU.ActiveCfg = Checked|x64 - {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|Any CPU.Build.0 = Checked|x64 - {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|arm.ActiveCfg = Checked|arm - {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|arm.Build.0 = Checked|arm - {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|arm64.ActiveCfg = Checked|arm64 - {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|arm64.Build.0 = Checked|arm64 - {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|x64.ActiveCfg = Checked|x64 - {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|x64.Build.0 = Checked|x64 - {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|x86.ActiveCfg = Checked|x86 - {94B59BA0-491F-4B59-ADFF-A057EC3EC835}.Checked|x86.Build.0 = Checked|x86 + {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Checked|arm.ActiveCfg = Debug|Any CPU + {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Checked|arm64.ActiveCfg = Debug|Any CPU + {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Checked|x64.ActiveCfg = Debug|Any CPU + {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Checked|x86.ActiveCfg = Debug|Any CPU {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Debug|Any CPU.Build.0 = Debug|Any CPU {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -146,11 +155,11 @@ Global {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Release|x64.Build.0 = Release|Any CPU {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Release|x86.ActiveCfg = Release|Any CPU {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Release|x86.Build.0 = Release|Any CPU - {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Checked|arm.ActiveCfg = Debug|Any CPU - {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Checked|arm64.ActiveCfg = Debug|Any CPU - {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Checked|x64.ActiveCfg = Debug|Any CPU - {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA}.Checked|x86.ActiveCfg = Debug|Any CPU + {0E0D5A1F-0212-4CEB-BADA-E1E3ABD395A0}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {0E0D5A1F-0212-4CEB-BADA-E1E3ABD395A0}.Checked|arm.ActiveCfg = Debug|Any CPU + {0E0D5A1F-0212-4CEB-BADA-E1E3ABD395A0}.Checked|arm64.ActiveCfg = Debug|Any CPU + {0E0D5A1F-0212-4CEB-BADA-E1E3ABD395A0}.Checked|x64.ActiveCfg = Debug|Any CPU + {0E0D5A1F-0212-4CEB-BADA-E1E3ABD395A0}.Checked|x86.ActiveCfg = Debug|Any CPU {0E0D5A1F-0212-4CEB-BADA-E1E3ABD395A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0E0D5A1F-0212-4CEB-BADA-E1E3ABD395A0}.Debug|Any CPU.Build.0 = Debug|Any CPU {0E0D5A1F-0212-4CEB-BADA-E1E3ABD395A0}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -167,11 +176,11 @@ Global {0E0D5A1F-0212-4CEB-BADA-E1E3ABD395A0}.Release|x64.Build.0 = Release|Any CPU {0E0D5A1F-0212-4CEB-BADA-E1E3ABD395A0}.Release|x86.ActiveCfg = Release|Any CPU {0E0D5A1F-0212-4CEB-BADA-E1E3ABD395A0}.Release|x86.Build.0 = Release|Any CPU - {0E0D5A1F-0212-4CEB-BADA-E1E3ABD395A0}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {0E0D5A1F-0212-4CEB-BADA-E1E3ABD395A0}.Checked|arm.ActiveCfg = Debug|Any CPU - {0E0D5A1F-0212-4CEB-BADA-E1E3ABD395A0}.Checked|arm64.ActiveCfg = Debug|Any CPU - {0E0D5A1F-0212-4CEB-BADA-E1E3ABD395A0}.Checked|x64.ActiveCfg = Debug|Any CPU - {0E0D5A1F-0212-4CEB-BADA-E1E3ABD395A0}.Checked|x86.ActiveCfg = Debug|Any CPU + {F552E4E4-20EE-484C-84F8-4FB3A3BD2E69}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {F552E4E4-20EE-484C-84F8-4FB3A3BD2E69}.Checked|arm.ActiveCfg = Debug|Any CPU + {F552E4E4-20EE-484C-84F8-4FB3A3BD2E69}.Checked|arm64.ActiveCfg = Debug|Any CPU + {F552E4E4-20EE-484C-84F8-4FB3A3BD2E69}.Checked|x64.ActiveCfg = Debug|Any CPU + {F552E4E4-20EE-484C-84F8-4FB3A3BD2E69}.Checked|x86.ActiveCfg = Debug|Any CPU {F552E4E4-20EE-484C-84F8-4FB3A3BD2E69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F552E4E4-20EE-484C-84F8-4FB3A3BD2E69}.Debug|Any CPU.Build.0 = Debug|Any CPU {F552E4E4-20EE-484C-84F8-4FB3A3BD2E69}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -188,11 +197,11 @@ Global {F552E4E4-20EE-484C-84F8-4FB3A3BD2E69}.Release|x64.Build.0 = Release|Any CPU {F552E4E4-20EE-484C-84F8-4FB3A3BD2E69}.Release|x86.ActiveCfg = Release|Any CPU {F552E4E4-20EE-484C-84F8-4FB3A3BD2E69}.Release|x86.Build.0 = Release|Any CPU - {F552E4E4-20EE-484C-84F8-4FB3A3BD2E69}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {F552E4E4-20EE-484C-84F8-4FB3A3BD2E69}.Checked|arm.ActiveCfg = Debug|Any CPU - {F552E4E4-20EE-484C-84F8-4FB3A3BD2E69}.Checked|arm64.ActiveCfg = Debug|Any CPU - {F552E4E4-20EE-484C-84F8-4FB3A3BD2E69}.Checked|x64.ActiveCfg = Debug|Any CPU - {F552E4E4-20EE-484C-84F8-4FB3A3BD2E69}.Checked|x86.ActiveCfg = Debug|Any CPU + {4859BEE3-34B7-48E7-83D4-1ADD8B8F3B3A}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {4859BEE3-34B7-48E7-83D4-1ADD8B8F3B3A}.Checked|arm.ActiveCfg = Debug|Any CPU + {4859BEE3-34B7-48E7-83D4-1ADD8B8F3B3A}.Checked|arm64.ActiveCfg = Debug|Any CPU + {4859BEE3-34B7-48E7-83D4-1ADD8B8F3B3A}.Checked|x64.ActiveCfg = Debug|Any CPU + {4859BEE3-34B7-48E7-83D4-1ADD8B8F3B3A}.Checked|x86.ActiveCfg = Debug|Any CPU {4859BEE3-34B7-48E7-83D4-1ADD8B8F3B3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4859BEE3-34B7-48E7-83D4-1ADD8B8F3B3A}.Debug|Any CPU.Build.0 = Debug|Any CPU {4859BEE3-34B7-48E7-83D4-1ADD8B8F3B3A}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -209,11 +218,11 @@ Global {4859BEE3-34B7-48E7-83D4-1ADD8B8F3B3A}.Release|x64.Build.0 = Release|Any CPU {4859BEE3-34B7-48E7-83D4-1ADD8B8F3B3A}.Release|x86.ActiveCfg = Release|Any CPU {4859BEE3-34B7-48E7-83D4-1ADD8B8F3B3A}.Release|x86.Build.0 = Release|Any CPU - {4859BEE3-34B7-48E7-83D4-1ADD8B8F3B3A}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {4859BEE3-34B7-48E7-83D4-1ADD8B8F3B3A}.Checked|arm.ActiveCfg = Debug|Any CPU - {4859BEE3-34B7-48E7-83D4-1ADD8B8F3B3A}.Checked|arm64.ActiveCfg = Debug|Any CPU - {4859BEE3-34B7-48E7-83D4-1ADD8B8F3B3A}.Checked|x64.ActiveCfg = Debug|Any CPU - {4859BEE3-34B7-48E7-83D4-1ADD8B8F3B3A}.Checked|x86.ActiveCfg = Debug|Any CPU + {C4B641C3-3317-4913-91DA-0DA3B64BABED}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {C4B641C3-3317-4913-91DA-0DA3B64BABED}.Checked|arm.ActiveCfg = Debug|Any CPU + {C4B641C3-3317-4913-91DA-0DA3B64BABED}.Checked|arm64.ActiveCfg = Debug|Any CPU + {C4B641C3-3317-4913-91DA-0DA3B64BABED}.Checked|x64.ActiveCfg = Debug|Any CPU + {C4B641C3-3317-4913-91DA-0DA3B64BABED}.Checked|x86.ActiveCfg = Debug|Any CPU {C4B641C3-3317-4913-91DA-0DA3B64BABED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C4B641C3-3317-4913-91DA-0DA3B64BABED}.Debug|Any CPU.Build.0 = Debug|Any CPU {C4B641C3-3317-4913-91DA-0DA3B64BABED}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -230,11 +239,11 @@ Global {C4B641C3-3317-4913-91DA-0DA3B64BABED}.Release|x64.Build.0 = Release|Any CPU {C4B641C3-3317-4913-91DA-0DA3B64BABED}.Release|x86.ActiveCfg = Release|Any CPU {C4B641C3-3317-4913-91DA-0DA3B64BABED}.Release|x86.Build.0 = Release|Any CPU - {C4B641C3-3317-4913-91DA-0DA3B64BABED}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {C4B641C3-3317-4913-91DA-0DA3B64BABED}.Checked|arm.ActiveCfg = Debug|Any CPU - {C4B641C3-3317-4913-91DA-0DA3B64BABED}.Checked|arm64.ActiveCfg = Debug|Any CPU - {C4B641C3-3317-4913-91DA-0DA3B64BABED}.Checked|x64.ActiveCfg = Debug|Any CPU - {C4B641C3-3317-4913-91DA-0DA3B64BABED}.Checked|x86.ActiveCfg = Debug|Any CPU + {3FB6F2AA-E763-4336-B927-18AB7AAF6C20}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {3FB6F2AA-E763-4336-B927-18AB7AAF6C20}.Checked|arm.ActiveCfg = Debug|Any CPU + {3FB6F2AA-E763-4336-B927-18AB7AAF6C20}.Checked|arm64.ActiveCfg = Debug|Any CPU + {3FB6F2AA-E763-4336-B927-18AB7AAF6C20}.Checked|x64.ActiveCfg = Debug|Any CPU + {3FB6F2AA-E763-4336-B927-18AB7AAF6C20}.Checked|x86.ActiveCfg = Debug|Any CPU {3FB6F2AA-E763-4336-B927-18AB7AAF6C20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3FB6F2AA-E763-4336-B927-18AB7AAF6C20}.Debug|Any CPU.Build.0 = Debug|Any CPU {3FB6F2AA-E763-4336-B927-18AB7AAF6C20}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -251,11 +260,11 @@ Global {3FB6F2AA-E763-4336-B927-18AB7AAF6C20}.Release|x64.Build.0 = Release|Any CPU {3FB6F2AA-E763-4336-B927-18AB7AAF6C20}.Release|x86.ActiveCfg = Release|Any CPU {3FB6F2AA-E763-4336-B927-18AB7AAF6C20}.Release|x86.Build.0 = Release|Any CPU - {3FB6F2AA-E763-4336-B927-18AB7AAF6C20}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {3FB6F2AA-E763-4336-B927-18AB7AAF6C20}.Checked|arm.ActiveCfg = Debug|Any CPU - {3FB6F2AA-E763-4336-B927-18AB7AAF6C20}.Checked|arm64.ActiveCfg = Debug|Any CPU - {3FB6F2AA-E763-4336-B927-18AB7AAF6C20}.Checked|x64.ActiveCfg = Debug|Any CPU - {3FB6F2AA-E763-4336-B927-18AB7AAF6C20}.Checked|x86.ActiveCfg = Debug|Any CPU + {716ED44B-37C8-4776-BE70-285952D2B30D}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {716ED44B-37C8-4776-BE70-285952D2B30D}.Checked|arm.ActiveCfg = Debug|Any CPU + {716ED44B-37C8-4776-BE70-285952D2B30D}.Checked|arm64.ActiveCfg = Debug|Any CPU + {716ED44B-37C8-4776-BE70-285952D2B30D}.Checked|x64.ActiveCfg = Debug|Any CPU + {716ED44B-37C8-4776-BE70-285952D2B30D}.Checked|x86.ActiveCfg = Debug|Any CPU {716ED44B-37C8-4776-BE70-285952D2B30D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {716ED44B-37C8-4776-BE70-285952D2B30D}.Debug|Any CPU.Build.0 = Debug|Any CPU {716ED44B-37C8-4776-BE70-285952D2B30D}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -272,11 +281,11 @@ Global {716ED44B-37C8-4776-BE70-285952D2B30D}.Release|x64.Build.0 = Release|Any CPU {716ED44B-37C8-4776-BE70-285952D2B30D}.Release|x86.ActiveCfg = Release|Any CPU {716ED44B-37C8-4776-BE70-285952D2B30D}.Release|x86.Build.0 = Release|Any CPU - {716ED44B-37C8-4776-BE70-285952D2B30D}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {716ED44B-37C8-4776-BE70-285952D2B30D}.Checked|arm.ActiveCfg = Debug|Any CPU - {716ED44B-37C8-4776-BE70-285952D2B30D}.Checked|arm64.ActiveCfg = Debug|Any CPU - {716ED44B-37C8-4776-BE70-285952D2B30D}.Checked|x64.ActiveCfg = Debug|Any CPU - {716ED44B-37C8-4776-BE70-285952D2B30D}.Checked|x86.ActiveCfg = Debug|Any CPU + {1B248B4C-7584-4C04-850A-A50EB592052C}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {1B248B4C-7584-4C04-850A-A50EB592052C}.Checked|arm.ActiveCfg = Debug|Any CPU + {1B248B4C-7584-4C04-850A-A50EB592052C}.Checked|arm64.ActiveCfg = Debug|Any CPU + {1B248B4C-7584-4C04-850A-A50EB592052C}.Checked|x64.ActiveCfg = Debug|Any CPU + {1B248B4C-7584-4C04-850A-A50EB592052C}.Checked|x86.ActiveCfg = Debug|Any CPU {1B248B4C-7584-4C04-850A-A50EB592052C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1B248B4C-7584-4C04-850A-A50EB592052C}.Debug|Any CPU.Build.0 = Debug|Any CPU {1B248B4C-7584-4C04-850A-A50EB592052C}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -293,11 +302,11 @@ Global {1B248B4C-7584-4C04-850A-A50EB592052C}.Release|x64.Build.0 = Release|Any CPU {1B248B4C-7584-4C04-850A-A50EB592052C}.Release|x86.ActiveCfg = Release|Any CPU {1B248B4C-7584-4C04-850A-A50EB592052C}.Release|x86.Build.0 = Release|Any CPU - {1B248B4C-7584-4C04-850A-A50EB592052C}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {1B248B4C-7584-4C04-850A-A50EB592052C}.Checked|arm.ActiveCfg = Debug|Any CPU - {1B248B4C-7584-4C04-850A-A50EB592052C}.Checked|arm64.ActiveCfg = Debug|Any CPU - {1B248B4C-7584-4C04-850A-A50EB592052C}.Checked|x64.ActiveCfg = Debug|Any CPU - {1B248B4C-7584-4C04-850A-A50EB592052C}.Checked|x86.ActiveCfg = Debug|Any CPU + {EF39CC5C-7A3B-40F2-82B6-C1C8BBC3F886}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {EF39CC5C-7A3B-40F2-82B6-C1C8BBC3F886}.Checked|arm.ActiveCfg = Debug|Any CPU + {EF39CC5C-7A3B-40F2-82B6-C1C8BBC3F886}.Checked|arm64.ActiveCfg = Debug|Any CPU + {EF39CC5C-7A3B-40F2-82B6-C1C8BBC3F886}.Checked|x64.ActiveCfg = Debug|Any CPU + {EF39CC5C-7A3B-40F2-82B6-C1C8BBC3F886}.Checked|x86.ActiveCfg = Debug|Any CPU {EF39CC5C-7A3B-40F2-82B6-C1C8BBC3F886}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EF39CC5C-7A3B-40F2-82B6-C1C8BBC3F886}.Debug|Any CPU.Build.0 = Debug|Any CPU {EF39CC5C-7A3B-40F2-82B6-C1C8BBC3F886}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -314,11 +323,11 @@ Global {EF39CC5C-7A3B-40F2-82B6-C1C8BBC3F886}.Release|x64.Build.0 = Release|Any CPU {EF39CC5C-7A3B-40F2-82B6-C1C8BBC3F886}.Release|x86.ActiveCfg = Release|Any CPU {EF39CC5C-7A3B-40F2-82B6-C1C8BBC3F886}.Release|x86.Build.0 = Release|Any CPU - {EF39CC5C-7A3B-40F2-82B6-C1C8BBC3F886}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {EF39CC5C-7A3B-40F2-82B6-C1C8BBC3F886}.Checked|arm.ActiveCfg = Debug|Any CPU - {EF39CC5C-7A3B-40F2-82B6-C1C8BBC3F886}.Checked|arm64.ActiveCfg = Debug|Any CPU - {EF39CC5C-7A3B-40F2-82B6-C1C8BBC3F886}.Checked|x64.ActiveCfg = Debug|Any CPU - {EF39CC5C-7A3B-40F2-82B6-C1C8BBC3F886}.Checked|x86.ActiveCfg = Debug|Any CPU + {C3EA0A28-A597-4946-9E08-EBBBFA94BFA5}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {C3EA0A28-A597-4946-9E08-EBBBFA94BFA5}.Checked|arm.ActiveCfg = Debug|Any CPU + {C3EA0A28-A597-4946-9E08-EBBBFA94BFA5}.Checked|arm64.ActiveCfg = Debug|Any CPU + {C3EA0A28-A597-4946-9E08-EBBBFA94BFA5}.Checked|x64.ActiveCfg = Debug|Any CPU + {C3EA0A28-A597-4946-9E08-EBBBFA94BFA5}.Checked|x86.ActiveCfg = Debug|Any CPU {C3EA0A28-A597-4946-9E08-EBBBFA94BFA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C3EA0A28-A597-4946-9E08-EBBBFA94BFA5}.Debug|Any CPU.Build.0 = Debug|Any CPU {C3EA0A28-A597-4946-9E08-EBBBFA94BFA5}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -335,11 +344,11 @@ Global {C3EA0A28-A597-4946-9E08-EBBBFA94BFA5}.Release|x64.Build.0 = Release|Any CPU {C3EA0A28-A597-4946-9E08-EBBBFA94BFA5}.Release|x86.ActiveCfg = Release|Any CPU {C3EA0A28-A597-4946-9E08-EBBBFA94BFA5}.Release|x86.Build.0 = Release|Any CPU - {C3EA0A28-A597-4946-9E08-EBBBFA94BFA5}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {C3EA0A28-A597-4946-9E08-EBBBFA94BFA5}.Checked|arm.ActiveCfg = Debug|Any CPU - {C3EA0A28-A597-4946-9E08-EBBBFA94BFA5}.Checked|arm64.ActiveCfg = Debug|Any CPU - {C3EA0A28-A597-4946-9E08-EBBBFA94BFA5}.Checked|x64.ActiveCfg = Debug|Any CPU - {C3EA0A28-A597-4946-9E08-EBBBFA94BFA5}.Checked|x86.ActiveCfg = Debug|Any CPU + {90CDAD9F-3ACC-43B0-9696-0C849FCD8C40}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {90CDAD9F-3ACC-43B0-9696-0C849FCD8C40}.Checked|arm.ActiveCfg = Debug|Any CPU + {90CDAD9F-3ACC-43B0-9696-0C849FCD8C40}.Checked|arm64.ActiveCfg = Debug|Any CPU + {90CDAD9F-3ACC-43B0-9696-0C849FCD8C40}.Checked|x64.ActiveCfg = Debug|Any CPU + {90CDAD9F-3ACC-43B0-9696-0C849FCD8C40}.Checked|x86.ActiveCfg = Debug|Any CPU {90CDAD9F-3ACC-43B0-9696-0C849FCD8C40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {90CDAD9F-3ACC-43B0-9696-0C849FCD8C40}.Debug|Any CPU.Build.0 = Debug|Any CPU {90CDAD9F-3ACC-43B0-9696-0C849FCD8C40}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -356,11 +365,11 @@ Global {90CDAD9F-3ACC-43B0-9696-0C849FCD8C40}.Release|x64.Build.0 = Release|Any CPU {90CDAD9F-3ACC-43B0-9696-0C849FCD8C40}.Release|x86.ActiveCfg = Release|Any CPU {90CDAD9F-3ACC-43B0-9696-0C849FCD8C40}.Release|x86.Build.0 = Release|Any CPU - {90CDAD9F-3ACC-43B0-9696-0C849FCD8C40}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {90CDAD9F-3ACC-43B0-9696-0C849FCD8C40}.Checked|arm.ActiveCfg = Debug|Any CPU - {90CDAD9F-3ACC-43B0-9696-0C849FCD8C40}.Checked|arm64.ActiveCfg = Debug|Any CPU - {90CDAD9F-3ACC-43B0-9696-0C849FCD8C40}.Checked|x64.ActiveCfg = Debug|Any CPU - {90CDAD9F-3ACC-43B0-9696-0C849FCD8C40}.Checked|x86.ActiveCfg = Debug|Any CPU + {768B77B0-EA45-469D-B39E-545EB72F5A43}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {768B77B0-EA45-469D-B39E-545EB72F5A43}.Checked|arm.ActiveCfg = Debug|Any CPU + {768B77B0-EA45-469D-B39E-545EB72F5A43}.Checked|arm64.ActiveCfg = Debug|Any CPU + {768B77B0-EA45-469D-B39E-545EB72F5A43}.Checked|x64.ActiveCfg = Debug|Any CPU + {768B77B0-EA45-469D-B39E-545EB72F5A43}.Checked|x86.ActiveCfg = Debug|Any CPU {768B77B0-EA45-469D-B39E-545EB72F5A43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {768B77B0-EA45-469D-B39E-545EB72F5A43}.Debug|Any CPU.Build.0 = Debug|Any CPU {768B77B0-EA45-469D-B39E-545EB72F5A43}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -377,11 +386,11 @@ Global {768B77B0-EA45-469D-B39E-545EB72F5A43}.Release|x64.Build.0 = Release|Any CPU {768B77B0-EA45-469D-B39E-545EB72F5A43}.Release|x86.ActiveCfg = Release|Any CPU {768B77B0-EA45-469D-B39E-545EB72F5A43}.Release|x86.Build.0 = Release|Any CPU - {768B77B0-EA45-469D-B39E-545EB72F5A43}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {768B77B0-EA45-469D-B39E-545EB72F5A43}.Checked|arm.ActiveCfg = Debug|Any CPU - {768B77B0-EA45-469D-B39E-545EB72F5A43}.Checked|arm64.ActiveCfg = Debug|Any CPU - {768B77B0-EA45-469D-B39E-545EB72F5A43}.Checked|x64.ActiveCfg = Debug|Any CPU - {768B77B0-EA45-469D-B39E-545EB72F5A43}.Checked|x86.ActiveCfg = Debug|Any CPU + {8671F164-F78C-44FA-93B7-A310F67890FE}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {8671F164-F78C-44FA-93B7-A310F67890FE}.Checked|arm.ActiveCfg = Debug|Any CPU + {8671F164-F78C-44FA-93B7-A310F67890FE}.Checked|arm64.ActiveCfg = Debug|Any CPU + {8671F164-F78C-44FA-93B7-A310F67890FE}.Checked|x64.ActiveCfg = Debug|Any CPU + {8671F164-F78C-44FA-93B7-A310F67890FE}.Checked|x86.ActiveCfg = Debug|Any CPU {8671F164-F78C-44FA-93B7-A310F67890FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8671F164-F78C-44FA-93B7-A310F67890FE}.Debug|Any CPU.Build.0 = Debug|Any CPU {8671F164-F78C-44FA-93B7-A310F67890FE}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -398,11 +407,11 @@ Global {8671F164-F78C-44FA-93B7-A310F67890FE}.Release|x64.Build.0 = Release|Any CPU {8671F164-F78C-44FA-93B7-A310F67890FE}.Release|x86.ActiveCfg = Release|Any CPU {8671F164-F78C-44FA-93B7-A310F67890FE}.Release|x86.Build.0 = Release|Any CPU - {8671F164-F78C-44FA-93B7-A310F67890FE}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {8671F164-F78C-44FA-93B7-A310F67890FE}.Checked|arm.ActiveCfg = Debug|Any CPU - {8671F164-F78C-44FA-93B7-A310F67890FE}.Checked|arm64.ActiveCfg = Debug|Any CPU - {8671F164-F78C-44FA-93B7-A310F67890FE}.Checked|x64.ActiveCfg = Debug|Any CPU - {8671F164-F78C-44FA-93B7-A310F67890FE}.Checked|x86.ActiveCfg = Debug|Any CPU + {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Checked|arm.ActiveCfg = Debug|Any CPU + {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Checked|arm64.ActiveCfg = Debug|Any CPU + {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Checked|x64.ActiveCfg = Debug|Any CPU + {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Checked|x86.ActiveCfg = Debug|Any CPU {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Debug|Any CPU.Build.0 = Debug|Any CPU {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -419,11 +428,11 @@ Global {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Release|x64.Build.0 = Release|Any CPU {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Release|x86.ActiveCfg = Release|Any CPU {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Release|x86.Build.0 = Release|Any CPU - {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Checked|arm.ActiveCfg = Debug|Any CPU - {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Checked|arm64.ActiveCfg = Debug|Any CPU - {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Checked|x64.ActiveCfg = Debug|Any CPU - {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1}.Checked|x86.ActiveCfg = Debug|Any CPU + {79F7BE0E-01AA-4AFB-B047-CF7C0B38F81E}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {79F7BE0E-01AA-4AFB-B047-CF7C0B38F81E}.Checked|arm.ActiveCfg = Debug|Any CPU + {79F7BE0E-01AA-4AFB-B047-CF7C0B38F81E}.Checked|arm64.ActiveCfg = Debug|Any CPU + {79F7BE0E-01AA-4AFB-B047-CF7C0B38F81E}.Checked|x64.ActiveCfg = Debug|Any CPU + {79F7BE0E-01AA-4AFB-B047-CF7C0B38F81E}.Checked|x86.ActiveCfg = Debug|Any CPU {79F7BE0E-01AA-4AFB-B047-CF7C0B38F81E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {79F7BE0E-01AA-4AFB-B047-CF7C0B38F81E}.Debug|Any CPU.Build.0 = Debug|Any CPU {79F7BE0E-01AA-4AFB-B047-CF7C0B38F81E}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -440,11 +449,11 @@ Global {79F7BE0E-01AA-4AFB-B047-CF7C0B38F81E}.Release|x64.Build.0 = Release|Any CPU {79F7BE0E-01AA-4AFB-B047-CF7C0B38F81E}.Release|x86.ActiveCfg = Release|Any CPU {79F7BE0E-01AA-4AFB-B047-CF7C0B38F81E}.Release|x86.Build.0 = Release|Any CPU - {79F7BE0E-01AA-4AFB-B047-CF7C0B38F81E}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {79F7BE0E-01AA-4AFB-B047-CF7C0B38F81E}.Checked|arm.ActiveCfg = Debug|Any CPU - {79F7BE0E-01AA-4AFB-B047-CF7C0B38F81E}.Checked|arm64.ActiveCfg = Debug|Any CPU - {79F7BE0E-01AA-4AFB-B047-CF7C0B38F81E}.Checked|x64.ActiveCfg = Debug|Any CPU - {79F7BE0E-01AA-4AFB-B047-CF7C0B38F81E}.Checked|x86.ActiveCfg = Debug|Any CPU + {3741C833-C364-4269-9B1D-D442055DA7CE}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {3741C833-C364-4269-9B1D-D442055DA7CE}.Checked|arm.ActiveCfg = Debug|Any CPU + {3741C833-C364-4269-9B1D-D442055DA7CE}.Checked|arm64.ActiveCfg = Debug|Any CPU + {3741C833-C364-4269-9B1D-D442055DA7CE}.Checked|x64.ActiveCfg = Debug|Any CPU + {3741C833-C364-4269-9B1D-D442055DA7CE}.Checked|x86.ActiveCfg = Debug|Any CPU {3741C833-C364-4269-9B1D-D442055DA7CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3741C833-C364-4269-9B1D-D442055DA7CE}.Debug|Any CPU.Build.0 = Debug|Any CPU {3741C833-C364-4269-9B1D-D442055DA7CE}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -461,11 +470,11 @@ Global {3741C833-C364-4269-9B1D-D442055DA7CE}.Release|x64.Build.0 = Release|Any CPU {3741C833-C364-4269-9B1D-D442055DA7CE}.Release|x86.ActiveCfg = Release|Any CPU {3741C833-C364-4269-9B1D-D442055DA7CE}.Release|x86.Build.0 = Release|Any CPU - {3741C833-C364-4269-9B1D-D442055DA7CE}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {3741C833-C364-4269-9B1D-D442055DA7CE}.Checked|arm.ActiveCfg = Debug|Any CPU - {3741C833-C364-4269-9B1D-D442055DA7CE}.Checked|arm64.ActiveCfg = Debug|Any CPU - {3741C833-C364-4269-9B1D-D442055DA7CE}.Checked|x64.ActiveCfg = Debug|Any CPU - {3741C833-C364-4269-9B1D-D442055DA7CE}.Checked|x86.ActiveCfg = Debug|Any CPU + {1D771995-D475-429B-AC31-2B1F618AA45F}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {1D771995-D475-429B-AC31-2B1F618AA45F}.Checked|arm.ActiveCfg = Debug|Any CPU + {1D771995-D475-429B-AC31-2B1F618AA45F}.Checked|arm64.ActiveCfg = Debug|Any CPU + {1D771995-D475-429B-AC31-2B1F618AA45F}.Checked|x64.ActiveCfg = Debug|Any CPU + {1D771995-D475-429B-AC31-2B1F618AA45F}.Checked|x86.ActiveCfg = Debug|Any CPU {1D771995-D475-429B-AC31-2B1F618AA45F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1D771995-D475-429B-AC31-2B1F618AA45F}.Debug|Any CPU.Build.0 = Debug|Any CPU {1D771995-D475-429B-AC31-2B1F618AA45F}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -482,11 +491,11 @@ Global {1D771995-D475-429B-AC31-2B1F618AA45F}.Release|x64.Build.0 = Release|Any CPU {1D771995-D475-429B-AC31-2B1F618AA45F}.Release|x86.ActiveCfg = Release|Any CPU {1D771995-D475-429B-AC31-2B1F618AA45F}.Release|x86.Build.0 = Release|Any CPU - {1D771995-D475-429B-AC31-2B1F618AA45F}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {1D771995-D475-429B-AC31-2B1F618AA45F}.Checked|arm.ActiveCfg = Debug|Any CPU - {1D771995-D475-429B-AC31-2B1F618AA45F}.Checked|arm64.ActiveCfg = Debug|Any CPU - {1D771995-D475-429B-AC31-2B1F618AA45F}.Checked|x64.ActiveCfg = Debug|Any CPU - {1D771995-D475-429B-AC31-2B1F618AA45F}.Checked|x86.ActiveCfg = Debug|Any CPU + {9C2C2B5C-5E75-4935-8A4A-DE3D3A5DBBC1}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {9C2C2B5C-5E75-4935-8A4A-DE3D3A5DBBC1}.Checked|arm.ActiveCfg = Debug|Any CPU + {9C2C2B5C-5E75-4935-8A4A-DE3D3A5DBBC1}.Checked|arm64.ActiveCfg = Debug|Any CPU + {9C2C2B5C-5E75-4935-8A4A-DE3D3A5DBBC1}.Checked|x64.ActiveCfg = Debug|Any CPU + {9C2C2B5C-5E75-4935-8A4A-DE3D3A5DBBC1}.Checked|x86.ActiveCfg = Debug|Any CPU {9C2C2B5C-5E75-4935-8A4A-DE3D3A5DBBC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9C2C2B5C-5E75-4935-8A4A-DE3D3A5DBBC1}.Debug|Any CPU.Build.0 = Debug|Any CPU {9C2C2B5C-5E75-4935-8A4A-DE3D3A5DBBC1}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -503,11 +512,11 @@ Global {9C2C2B5C-5E75-4935-8A4A-DE3D3A5DBBC1}.Release|x64.Build.0 = Release|Any CPU {9C2C2B5C-5E75-4935-8A4A-DE3D3A5DBBC1}.Release|x86.ActiveCfg = Release|Any CPU {9C2C2B5C-5E75-4935-8A4A-DE3D3A5DBBC1}.Release|x86.Build.0 = Release|Any CPU - {9C2C2B5C-5E75-4935-8A4A-DE3D3A5DBBC1}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {9C2C2B5C-5E75-4935-8A4A-DE3D3A5DBBC1}.Checked|arm.ActiveCfg = Debug|Any CPU - {9C2C2B5C-5E75-4935-8A4A-DE3D3A5DBBC1}.Checked|arm64.ActiveCfg = Debug|Any CPU - {9C2C2B5C-5E75-4935-8A4A-DE3D3A5DBBC1}.Checked|x64.ActiveCfg = Debug|Any CPU - {9C2C2B5C-5E75-4935-8A4A-DE3D3A5DBBC1}.Checked|x86.ActiveCfg = Debug|Any CPU + {EA8DBC12-60BC-433E-ABFF-A89DFA795283}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {EA8DBC12-60BC-433E-ABFF-A89DFA795283}.Checked|arm.ActiveCfg = Debug|Any CPU + {EA8DBC12-60BC-433E-ABFF-A89DFA795283}.Checked|arm64.ActiveCfg = Debug|Any CPU + {EA8DBC12-60BC-433E-ABFF-A89DFA795283}.Checked|x64.ActiveCfg = Debug|Any CPU + {EA8DBC12-60BC-433E-ABFF-A89DFA795283}.Checked|x86.ActiveCfg = Debug|Any CPU {EA8DBC12-60BC-433E-ABFF-A89DFA795283}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EA8DBC12-60BC-433E-ABFF-A89DFA795283}.Debug|Any CPU.Build.0 = Debug|Any CPU {EA8DBC12-60BC-433E-ABFF-A89DFA795283}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -524,11 +533,11 @@ Global {EA8DBC12-60BC-433E-ABFF-A89DFA795283}.Release|x64.Build.0 = Release|Any CPU {EA8DBC12-60BC-433E-ABFF-A89DFA795283}.Release|x86.ActiveCfg = Release|Any CPU {EA8DBC12-60BC-433E-ABFF-A89DFA795283}.Release|x86.Build.0 = Release|Any CPU - {EA8DBC12-60BC-433E-ABFF-A89DFA795283}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {EA8DBC12-60BC-433E-ABFF-A89DFA795283}.Checked|arm.ActiveCfg = Debug|Any CPU - {EA8DBC12-60BC-433E-ABFF-A89DFA795283}.Checked|arm64.ActiveCfg = Debug|Any CPU - {EA8DBC12-60BC-433E-ABFF-A89DFA795283}.Checked|x64.ActiveCfg = Debug|Any CPU - {EA8DBC12-60BC-433E-ABFF-A89DFA795283}.Checked|x86.ActiveCfg = Debug|Any CPU + {25D66424-2EAF-464D-8460-10C04EDEF3C3}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {25D66424-2EAF-464D-8460-10C04EDEF3C3}.Checked|arm.ActiveCfg = Debug|Any CPU + {25D66424-2EAF-464D-8460-10C04EDEF3C3}.Checked|arm64.ActiveCfg = Debug|Any CPU + {25D66424-2EAF-464D-8460-10C04EDEF3C3}.Checked|x64.ActiveCfg = Debug|Any CPU + {25D66424-2EAF-464D-8460-10C04EDEF3C3}.Checked|x86.ActiveCfg = Debug|Any CPU {25D66424-2EAF-464D-8460-10C04EDEF3C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {25D66424-2EAF-464D-8460-10C04EDEF3C3}.Debug|Any CPU.Build.0 = Debug|Any CPU {25D66424-2EAF-464D-8460-10C04EDEF3C3}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -545,11 +554,11 @@ Global {25D66424-2EAF-464D-8460-10C04EDEF3C3}.Release|x64.Build.0 = Release|Any CPU {25D66424-2EAF-464D-8460-10C04EDEF3C3}.Release|x86.ActiveCfg = Release|Any CPU {25D66424-2EAF-464D-8460-10C04EDEF3C3}.Release|x86.Build.0 = Release|Any CPU - {25D66424-2EAF-464D-8460-10C04EDEF3C3}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {25D66424-2EAF-464D-8460-10C04EDEF3C3}.Checked|arm.ActiveCfg = Debug|Any CPU - {25D66424-2EAF-464D-8460-10C04EDEF3C3}.Checked|arm64.ActiveCfg = Debug|Any CPU - {25D66424-2EAF-464D-8460-10C04EDEF3C3}.Checked|x64.ActiveCfg = Debug|Any CPU - {25D66424-2EAF-464D-8460-10C04EDEF3C3}.Checked|x86.ActiveCfg = Debug|Any CPU + {049B7FD4-ACEF-4BCD-A7A7-75C9BBEC4EBF}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {049B7FD4-ACEF-4BCD-A7A7-75C9BBEC4EBF}.Checked|arm.ActiveCfg = Debug|Any CPU + {049B7FD4-ACEF-4BCD-A7A7-75C9BBEC4EBF}.Checked|arm64.ActiveCfg = Debug|Any CPU + {049B7FD4-ACEF-4BCD-A7A7-75C9BBEC4EBF}.Checked|x64.ActiveCfg = Debug|Any CPU + {049B7FD4-ACEF-4BCD-A7A7-75C9BBEC4EBF}.Checked|x86.ActiveCfg = Debug|Any CPU {049B7FD4-ACEF-4BCD-A7A7-75C9BBEC4EBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {049B7FD4-ACEF-4BCD-A7A7-75C9BBEC4EBF}.Debug|Any CPU.Build.0 = Debug|Any CPU {049B7FD4-ACEF-4BCD-A7A7-75C9BBEC4EBF}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -566,11 +575,11 @@ Global {049B7FD4-ACEF-4BCD-A7A7-75C9BBEC4EBF}.Release|x64.Build.0 = Release|Any CPU {049B7FD4-ACEF-4BCD-A7A7-75C9BBEC4EBF}.Release|x86.ActiveCfg = Release|Any CPU {049B7FD4-ACEF-4BCD-A7A7-75C9BBEC4EBF}.Release|x86.Build.0 = Release|Any CPU - {049B7FD4-ACEF-4BCD-A7A7-75C9BBEC4EBF}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {049B7FD4-ACEF-4BCD-A7A7-75C9BBEC4EBF}.Checked|arm.ActiveCfg = Debug|Any CPU - {049B7FD4-ACEF-4BCD-A7A7-75C9BBEC4EBF}.Checked|arm64.ActiveCfg = Debug|Any CPU - {049B7FD4-ACEF-4BCD-A7A7-75C9BBEC4EBF}.Checked|x64.ActiveCfg = Debug|Any CPU - {049B7FD4-ACEF-4BCD-A7A7-75C9BBEC4EBF}.Checked|x86.ActiveCfg = Debug|Any CPU + {866D295E-424A-4747-9417-CD7746936138}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {866D295E-424A-4747-9417-CD7746936138}.Checked|arm.ActiveCfg = Debug|Any CPU + {866D295E-424A-4747-9417-CD7746936138}.Checked|arm64.ActiveCfg = Debug|Any CPU + {866D295E-424A-4747-9417-CD7746936138}.Checked|x64.ActiveCfg = Debug|Any CPU + {866D295E-424A-4747-9417-CD7746936138}.Checked|x86.ActiveCfg = Debug|Any CPU {866D295E-424A-4747-9417-CD7746936138}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {866D295E-424A-4747-9417-CD7746936138}.Debug|Any CPU.Build.0 = Debug|Any CPU {866D295E-424A-4747-9417-CD7746936138}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -587,11 +596,11 @@ Global {866D295E-424A-4747-9417-CD7746936138}.Release|x64.Build.0 = Release|Any CPU {866D295E-424A-4747-9417-CD7746936138}.Release|x86.ActiveCfg = Release|Any CPU {866D295E-424A-4747-9417-CD7746936138}.Release|x86.Build.0 = Release|Any CPU - {866D295E-424A-4747-9417-CD7746936138}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {866D295E-424A-4747-9417-CD7746936138}.Checked|arm.ActiveCfg = Debug|Any CPU - {866D295E-424A-4747-9417-CD7746936138}.Checked|arm64.ActiveCfg = Debug|Any CPU - {866D295E-424A-4747-9417-CD7746936138}.Checked|x64.ActiveCfg = Debug|Any CPU - {866D295E-424A-4747-9417-CD7746936138}.Checked|x86.ActiveCfg = Debug|Any CPU + {D3A329E3-0FEB-4136-9CB6-B38319B0FFA5}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {D3A329E3-0FEB-4136-9CB6-B38319B0FFA5}.Checked|arm.ActiveCfg = Debug|Any CPU + {D3A329E3-0FEB-4136-9CB6-B38319B0FFA5}.Checked|arm64.ActiveCfg = Debug|Any CPU + {D3A329E3-0FEB-4136-9CB6-B38319B0FFA5}.Checked|x64.ActiveCfg = Debug|Any CPU + {D3A329E3-0FEB-4136-9CB6-B38319B0FFA5}.Checked|x86.ActiveCfg = Debug|Any CPU {D3A329E3-0FEB-4136-9CB6-B38319B0FFA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D3A329E3-0FEB-4136-9CB6-B38319B0FFA5}.Debug|Any CPU.Build.0 = Debug|Any CPU {D3A329E3-0FEB-4136-9CB6-B38319B0FFA5}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -608,11 +617,11 @@ Global {D3A329E3-0FEB-4136-9CB6-B38319B0FFA5}.Release|x64.Build.0 = Release|Any CPU {D3A329E3-0FEB-4136-9CB6-B38319B0FFA5}.Release|x86.ActiveCfg = Release|Any CPU {D3A329E3-0FEB-4136-9CB6-B38319B0FFA5}.Release|x86.Build.0 = Release|Any CPU - {D3A329E3-0FEB-4136-9CB6-B38319B0FFA5}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {D3A329E3-0FEB-4136-9CB6-B38319B0FFA5}.Checked|arm.ActiveCfg = Debug|Any CPU - {D3A329E3-0FEB-4136-9CB6-B38319B0FFA5}.Checked|arm64.ActiveCfg = Debug|Any CPU - {D3A329E3-0FEB-4136-9CB6-B38319B0FFA5}.Checked|x64.ActiveCfg = Debug|Any CPU - {D3A329E3-0FEB-4136-9CB6-B38319B0FFA5}.Checked|x86.ActiveCfg = Debug|Any CPU + {0B5FD0C2-367D-4AD6-8001-80AD79B2441C}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {0B5FD0C2-367D-4AD6-8001-80AD79B2441C}.Checked|arm.ActiveCfg = Debug|Any CPU + {0B5FD0C2-367D-4AD6-8001-80AD79B2441C}.Checked|arm64.ActiveCfg = Debug|Any CPU + {0B5FD0C2-367D-4AD6-8001-80AD79B2441C}.Checked|x64.ActiveCfg = Debug|Any CPU + {0B5FD0C2-367D-4AD6-8001-80AD79B2441C}.Checked|x86.ActiveCfg = Debug|Any CPU {0B5FD0C2-367D-4AD6-8001-80AD79B2441C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0B5FD0C2-367D-4AD6-8001-80AD79B2441C}.Debug|Any CPU.Build.0 = Debug|Any CPU {0B5FD0C2-367D-4AD6-8001-80AD79B2441C}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -629,11 +638,11 @@ Global {0B5FD0C2-367D-4AD6-8001-80AD79B2441C}.Release|x64.Build.0 = Release|Any CPU {0B5FD0C2-367D-4AD6-8001-80AD79B2441C}.Release|x86.ActiveCfg = Release|Any CPU {0B5FD0C2-367D-4AD6-8001-80AD79B2441C}.Release|x86.Build.0 = Release|Any CPU - {0B5FD0C2-367D-4AD6-8001-80AD79B2441C}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {0B5FD0C2-367D-4AD6-8001-80AD79B2441C}.Checked|arm.ActiveCfg = Debug|Any CPU - {0B5FD0C2-367D-4AD6-8001-80AD79B2441C}.Checked|arm64.ActiveCfg = Debug|Any CPU - {0B5FD0C2-367D-4AD6-8001-80AD79B2441C}.Checked|x64.ActiveCfg = Debug|Any CPU - {0B5FD0C2-367D-4AD6-8001-80AD79B2441C}.Checked|x86.ActiveCfg = Debug|Any CPU + {C7DAC270-CC93-4C97-9A8D-6E724A10727D}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {C7DAC270-CC93-4C97-9A8D-6E724A10727D}.Checked|arm.ActiveCfg = Debug|Any CPU + {C7DAC270-CC93-4C97-9A8D-6E724A10727D}.Checked|arm64.ActiveCfg = Debug|Any CPU + {C7DAC270-CC93-4C97-9A8D-6E724A10727D}.Checked|x64.ActiveCfg = Debug|Any CPU + {C7DAC270-CC93-4C97-9A8D-6E724A10727D}.Checked|x86.ActiveCfg = Debug|Any CPU {C7DAC270-CC93-4C97-9A8D-6E724A10727D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C7DAC270-CC93-4C97-9A8D-6E724A10727D}.Debug|Any CPU.Build.0 = Debug|Any CPU {C7DAC270-CC93-4C97-9A8D-6E724A10727D}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -650,11 +659,11 @@ Global {C7DAC270-CC93-4C97-9A8D-6E724A10727D}.Release|x64.Build.0 = Release|Any CPU {C7DAC270-CC93-4C97-9A8D-6E724A10727D}.Release|x86.ActiveCfg = Release|Any CPU {C7DAC270-CC93-4C97-9A8D-6E724A10727D}.Release|x86.Build.0 = Release|Any CPU - {C7DAC270-CC93-4C97-9A8D-6E724A10727D}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {C7DAC270-CC93-4C97-9A8D-6E724A10727D}.Checked|arm.ActiveCfg = Debug|Any CPU - {C7DAC270-CC93-4C97-9A8D-6E724A10727D}.Checked|arm64.ActiveCfg = Debug|Any CPU - {C7DAC270-CC93-4C97-9A8D-6E724A10727D}.Checked|x64.ActiveCfg = Debug|Any CPU - {C7DAC270-CC93-4C97-9A8D-6E724A10727D}.Checked|x86.ActiveCfg = Debug|Any CPU + {C9B349C8-7B11-4DE4-A4BB-8D957A1D2A82}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {C9B349C8-7B11-4DE4-A4BB-8D957A1D2A82}.Checked|arm.ActiveCfg = Debug|Any CPU + {C9B349C8-7B11-4DE4-A4BB-8D957A1D2A82}.Checked|arm64.ActiveCfg = Debug|Any CPU + {C9B349C8-7B11-4DE4-A4BB-8D957A1D2A82}.Checked|x64.ActiveCfg = Debug|Any CPU + {C9B349C8-7B11-4DE4-A4BB-8D957A1D2A82}.Checked|x86.ActiveCfg = Debug|Any CPU {C9B349C8-7B11-4DE4-A4BB-8D957A1D2A82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C9B349C8-7B11-4DE4-A4BB-8D957A1D2A82}.Debug|Any CPU.Build.0 = Debug|Any CPU {C9B349C8-7B11-4DE4-A4BB-8D957A1D2A82}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -671,11 +680,11 @@ Global {C9B349C8-7B11-4DE4-A4BB-8D957A1D2A82}.Release|x64.Build.0 = Release|Any CPU {C9B349C8-7B11-4DE4-A4BB-8D957A1D2A82}.Release|x86.ActiveCfg = Release|Any CPU {C9B349C8-7B11-4DE4-A4BB-8D957A1D2A82}.Release|x86.Build.0 = Release|Any CPU - {C9B349C8-7B11-4DE4-A4BB-8D957A1D2A82}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {C9B349C8-7B11-4DE4-A4BB-8D957A1D2A82}.Checked|arm.ActiveCfg = Debug|Any CPU - {C9B349C8-7B11-4DE4-A4BB-8D957A1D2A82}.Checked|arm64.ActiveCfg = Debug|Any CPU - {C9B349C8-7B11-4DE4-A4BB-8D957A1D2A82}.Checked|x64.ActiveCfg = Debug|Any CPU - {C9B349C8-7B11-4DE4-A4BB-8D957A1D2A82}.Checked|x86.ActiveCfg = Debug|Any CPU + {5600CDE1-139F-461B-8DD9-86FCC499DCC2}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {5600CDE1-139F-461B-8DD9-86FCC499DCC2}.Checked|arm.ActiveCfg = Debug|Any CPU + {5600CDE1-139F-461B-8DD9-86FCC499DCC2}.Checked|arm64.ActiveCfg = Debug|Any CPU + {5600CDE1-139F-461B-8DD9-86FCC499DCC2}.Checked|x64.ActiveCfg = Debug|Any CPU + {5600CDE1-139F-461B-8DD9-86FCC499DCC2}.Checked|x86.ActiveCfg = Debug|Any CPU {5600CDE1-139F-461B-8DD9-86FCC499DCC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5600CDE1-139F-461B-8DD9-86FCC499DCC2}.Debug|Any CPU.Build.0 = Debug|Any CPU {5600CDE1-139F-461B-8DD9-86FCC499DCC2}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -692,11 +701,11 @@ Global {5600CDE1-139F-461B-8DD9-86FCC499DCC2}.Release|x64.Build.0 = Release|Any CPU {5600CDE1-139F-461B-8DD9-86FCC499DCC2}.Release|x86.ActiveCfg = Release|Any CPU {5600CDE1-139F-461B-8DD9-86FCC499DCC2}.Release|x86.Build.0 = Release|Any CPU - {5600CDE1-139F-461B-8DD9-86FCC499DCC2}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {5600CDE1-139F-461B-8DD9-86FCC499DCC2}.Checked|arm.ActiveCfg = Debug|Any CPU - {5600CDE1-139F-461B-8DD9-86FCC499DCC2}.Checked|arm64.ActiveCfg = Debug|Any CPU - {5600CDE1-139F-461B-8DD9-86FCC499DCC2}.Checked|x64.ActiveCfg = Debug|Any CPU - {5600CDE1-139F-461B-8DD9-86FCC499DCC2}.Checked|x86.ActiveCfg = Debug|Any CPU + {169B126B-48DF-425C-B902-D376A689D9FB}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {169B126B-48DF-425C-B902-D376A689D9FB}.Checked|arm.ActiveCfg = Debug|Any CPU + {169B126B-48DF-425C-B902-D376A689D9FB}.Checked|arm64.ActiveCfg = Debug|Any CPU + {169B126B-48DF-425C-B902-D376A689D9FB}.Checked|x64.ActiveCfg = Debug|Any CPU + {169B126B-48DF-425C-B902-D376A689D9FB}.Checked|x86.ActiveCfg = Debug|Any CPU {169B126B-48DF-425C-B902-D376A689D9FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {169B126B-48DF-425C-B902-D376A689D9FB}.Debug|Any CPU.Build.0 = Debug|Any CPU {169B126B-48DF-425C-B902-D376A689D9FB}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -713,11 +722,11 @@ Global {169B126B-48DF-425C-B902-D376A689D9FB}.Release|x64.Build.0 = Release|Any CPU {169B126B-48DF-425C-B902-D376A689D9FB}.Release|x86.ActiveCfg = Release|Any CPU {169B126B-48DF-425C-B902-D376A689D9FB}.Release|x86.Build.0 = Release|Any CPU - {169B126B-48DF-425C-B902-D376A689D9FB}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {169B126B-48DF-425C-B902-D376A689D9FB}.Checked|arm.ActiveCfg = Debug|Any CPU - {169B126B-48DF-425C-B902-D376A689D9FB}.Checked|arm64.ActiveCfg = Debug|Any CPU - {169B126B-48DF-425C-B902-D376A689D9FB}.Checked|x64.ActiveCfg = Debug|Any CPU - {169B126B-48DF-425C-B902-D376A689D9FB}.Checked|x86.ActiveCfg = Debug|Any CPU + {8EA17297-41EE-4CEE-AF61-F047D6F7A1AB}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {8EA17297-41EE-4CEE-AF61-F047D6F7A1AB}.Checked|arm.ActiveCfg = Debug|Any CPU + {8EA17297-41EE-4CEE-AF61-F047D6F7A1AB}.Checked|arm64.ActiveCfg = Debug|Any CPU + {8EA17297-41EE-4CEE-AF61-F047D6F7A1AB}.Checked|x64.ActiveCfg = Debug|Any CPU + {8EA17297-41EE-4CEE-AF61-F047D6F7A1AB}.Checked|x86.ActiveCfg = Debug|Any CPU {8EA17297-41EE-4CEE-AF61-F047D6F7A1AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8EA17297-41EE-4CEE-AF61-F047D6F7A1AB}.Debug|Any CPU.Build.0 = Debug|Any CPU {8EA17297-41EE-4CEE-AF61-F047D6F7A1AB}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -734,11 +743,11 @@ Global {8EA17297-41EE-4CEE-AF61-F047D6F7A1AB}.Release|x64.Build.0 = Release|Any CPU {8EA17297-41EE-4CEE-AF61-F047D6F7A1AB}.Release|x86.ActiveCfg = Release|Any CPU {8EA17297-41EE-4CEE-AF61-F047D6F7A1AB}.Release|x86.Build.0 = Release|Any CPU - {8EA17297-41EE-4CEE-AF61-F047D6F7A1AB}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {8EA17297-41EE-4CEE-AF61-F047D6F7A1AB}.Checked|arm.ActiveCfg = Debug|Any CPU - {8EA17297-41EE-4CEE-AF61-F047D6F7A1AB}.Checked|arm64.ActiveCfg = Debug|Any CPU - {8EA17297-41EE-4CEE-AF61-F047D6F7A1AB}.Checked|x64.ActiveCfg = Debug|Any CPU - {8EA17297-41EE-4CEE-AF61-F047D6F7A1AB}.Checked|x86.ActiveCfg = Debug|Any CPU + {1347FE73-506C-4C44-A469-979F6ADB78BE}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {1347FE73-506C-4C44-A469-979F6ADB78BE}.Checked|arm.ActiveCfg = Debug|Any CPU + {1347FE73-506C-4C44-A469-979F6ADB78BE}.Checked|arm64.ActiveCfg = Debug|Any CPU + {1347FE73-506C-4C44-A469-979F6ADB78BE}.Checked|x64.ActiveCfg = Debug|Any CPU + {1347FE73-506C-4C44-A469-979F6ADB78BE}.Checked|x86.ActiveCfg = Debug|Any CPU {1347FE73-506C-4C44-A469-979F6ADB78BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1347FE73-506C-4C44-A469-979F6ADB78BE}.Debug|Any CPU.Build.0 = Debug|Any CPU {1347FE73-506C-4C44-A469-979F6ADB78BE}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -755,11 +764,11 @@ Global {1347FE73-506C-4C44-A469-979F6ADB78BE}.Release|x64.Build.0 = Release|Any CPU {1347FE73-506C-4C44-A469-979F6ADB78BE}.Release|x86.ActiveCfg = Release|Any CPU {1347FE73-506C-4C44-A469-979F6ADB78BE}.Release|x86.Build.0 = Release|Any CPU - {1347FE73-506C-4C44-A469-979F6ADB78BE}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {1347FE73-506C-4C44-A469-979F6ADB78BE}.Checked|arm.ActiveCfg = Debug|Any CPU - {1347FE73-506C-4C44-A469-979F6ADB78BE}.Checked|arm64.ActiveCfg = Debug|Any CPU - {1347FE73-506C-4C44-A469-979F6ADB78BE}.Checked|x64.ActiveCfg = Debug|Any CPU - {1347FE73-506C-4C44-A469-979F6ADB78BE}.Checked|x86.ActiveCfg = Debug|Any CPU + {B36C9254-0C55-414E-8403-03B4F18D5F35}.Checked|Any CPU.ActiveCfg = Debug|Any CPU + {B36C9254-0C55-414E-8403-03B4F18D5F35}.Checked|arm.ActiveCfg = Debug|Any CPU + {B36C9254-0C55-414E-8403-03B4F18D5F35}.Checked|arm64.ActiveCfg = Debug|Any CPU + {B36C9254-0C55-414E-8403-03B4F18D5F35}.Checked|x64.ActiveCfg = Debug|Any CPU + {B36C9254-0C55-414E-8403-03B4F18D5F35}.Checked|x86.ActiveCfg = Debug|Any CPU {B36C9254-0C55-414E-8403-03B4F18D5F35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B36C9254-0C55-414E-8403-03B4F18D5F35}.Debug|Any CPU.Build.0 = Debug|Any CPU {B36C9254-0C55-414E-8403-03B4F18D5F35}.Debug|arm.ActiveCfg = Debug|Any CPU @@ -776,11 +785,6 @@ Global {B36C9254-0C55-414E-8403-03B4F18D5F35}.Release|x64.Build.0 = Release|Any CPU {B36C9254-0C55-414E-8403-03B4F18D5F35}.Release|x86.ActiveCfg = Release|Any CPU {B36C9254-0C55-414E-8403-03B4F18D5F35}.Release|x86.Build.0 = Release|Any CPU - {B36C9254-0C55-414E-8403-03B4F18D5F35}.Checked|Any CPU.ActiveCfg = Debug|Any CPU - {B36C9254-0C55-414E-8403-03B4F18D5F35}.Checked|arm.ActiveCfg = Debug|Any CPU - {B36C9254-0C55-414E-8403-03B4F18D5F35}.Checked|arm64.ActiveCfg = Debug|Any CPU - {B36C9254-0C55-414E-8403-03B4F18D5F35}.Checked|x64.ActiveCfg = Debug|Any CPU - {B36C9254-0C55-414E-8403-03B4F18D5F35}.Checked|x86.ActiveCfg = Debug|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -788,6 +792,19 @@ Global GlobalSection(NestedProjects) = preSolution {94B59BA0-491F-4B59-ADFF-A057EC3EC835} = {052823B7-A9E0-41DE-87D8-D1CAF407B41D} {1FF4CC8E-49C3-42A0-A6E0-2E5908455FBA} = {FB99AC59-1744-4F12-A4B0-0D54FCA048BF} + {0E0D5A1F-0212-4CEB-BADA-E1E3ABD395A0} = {D893B9AA-57C5-49E3-97B1-12CC62D84307} + {F552E4E4-20EE-484C-84F8-4FB3A3BD2E69} = {B1678CCD-95C8-4419-B9F9-14A03061BE4B} + {4859BEE3-34B7-48E7-83D4-1ADD8B8F3B3A} = {D893B9AA-57C5-49E3-97B1-12CC62D84307} + {C4B641C3-3317-4913-91DA-0DA3B64BABED} = {B1678CCD-95C8-4419-B9F9-14A03061BE4B} + {3FB6F2AA-E763-4336-B927-18AB7AAF6C20} = {D893B9AA-57C5-49E3-97B1-12CC62D84307} + {716ED44B-37C8-4776-BE70-285952D2B30D} = {B1678CCD-95C8-4419-B9F9-14A03061BE4B} + {1B248B4C-7584-4C04-850A-A50EB592052C} = {E1AEBD5D-AE4E-4F61-B9ED-AEF950B0CC33} + {EF39CC5C-7A3B-40F2-82B6-C1C8BBC3F886} = {D893B9AA-57C5-49E3-97B1-12CC62D84307} + {C3EA0A28-A597-4946-9E08-EBBBFA94BFA5} = {E1AEBD5D-AE4E-4F61-B9ED-AEF950B0CC33} + {90CDAD9F-3ACC-43B0-9696-0C849FCD8C40} = {E1AEBD5D-AE4E-4F61-B9ED-AEF950B0CC33} + {768B77B0-EA45-469D-B39E-545EB72F5A43} = {E1AEBD5D-AE4E-4F61-B9ED-AEF950B0CC33} + {8671F164-F78C-44FA-93B7-A310F67890FE} = {D893B9AA-57C5-49E3-97B1-12CC62D84307} + {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1} = {B1678CCD-95C8-4419-B9F9-14A03061BE4B} {79F7BE0E-01AA-4AFB-B047-CF7C0B38F81E} = {FB99AC59-1744-4F12-A4B0-0D54FCA048BF} {3741C833-C364-4269-9B1D-D442055DA7CE} = {FB99AC59-1744-4F12-A4B0-0D54FCA048BF} {1D771995-D475-429B-AC31-2B1F618AA45F} = {FB99AC59-1744-4F12-A4B0-0D54FCA048BF} @@ -797,32 +814,24 @@ Global {049B7FD4-ACEF-4BCD-A7A7-75C9BBEC4EBF} = {FB99AC59-1744-4F12-A4B0-0D54FCA048BF} {866D295E-424A-4747-9417-CD7746936138} = {FB99AC59-1744-4F12-A4B0-0D54FCA048BF} {D3A329E3-0FEB-4136-9CB6-B38319B0FFA5} = {FB99AC59-1744-4F12-A4B0-0D54FCA048BF} - {0E0D5A1F-0212-4CEB-BADA-E1E3ABD395A0} = {D893B9AA-57C5-49E3-97B1-12CC62D84307} - {4859BEE3-34B7-48E7-83D4-1ADD8B8F3B3A} = {D893B9AA-57C5-49E3-97B1-12CC62D84307} - {3FB6F2AA-E763-4336-B927-18AB7AAF6C20} = {D893B9AA-57C5-49E3-97B1-12CC62D84307} - {EF39CC5C-7A3B-40F2-82B6-C1C8BBC3F886} = {D893B9AA-57C5-49E3-97B1-12CC62D84307} - {8671F164-F78C-44FA-93B7-A310F67890FE} = {D893B9AA-57C5-49E3-97B1-12CC62D84307} {0B5FD0C2-367D-4AD6-8001-80AD79B2441C} = {D893B9AA-57C5-49E3-97B1-12CC62D84307} {C7DAC270-CC93-4C97-9A8D-6E724A10727D} = {D893B9AA-57C5-49E3-97B1-12CC62D84307} - {F552E4E4-20EE-484C-84F8-4FB3A3BD2E69} = {B1678CCD-95C8-4419-B9F9-14A03061BE4B} - {C4B641C3-3317-4913-91DA-0DA3B64BABED} = {B1678CCD-95C8-4419-B9F9-14A03061BE4B} - {716ED44B-37C8-4776-BE70-285952D2B30D} = {B1678CCD-95C8-4419-B9F9-14A03061BE4B} - {4FC33B9B-1BCF-4D16-B886-DCA8F2B823C1} = {B1678CCD-95C8-4419-B9F9-14A03061BE4B} {C9B349C8-7B11-4DE4-A4BB-8D957A1D2A82} = {B1678CCD-95C8-4419-B9F9-14A03061BE4B} - {1B248B4C-7584-4C04-850A-A50EB592052C} = {E1AEBD5D-AE4E-4F61-B9ED-AEF950B0CC33} - {C3EA0A28-A597-4946-9E08-EBBBFA94BFA5} = {E1AEBD5D-AE4E-4F61-B9ED-AEF950B0CC33} - {90CDAD9F-3ACC-43B0-9696-0C849FCD8C40} = {E1AEBD5D-AE4E-4F61-B9ED-AEF950B0CC33} - {768B77B0-EA45-469D-B39E-545EB72F5A43} = {E1AEBD5D-AE4E-4F61-B9ED-AEF950B0CC33} {5600CDE1-139F-461B-8DD9-86FCC499DCC2} = {8826C1E1-CEBD-49F8-9BC8-97FECE60F9B9} {169B126B-48DF-425C-B902-D376A689D9FB} = {8826C1E1-CEBD-49F8-9BC8-97FECE60F9B9} - {8826C1E1-CEBD-49F8-9BC8-97FECE60F9B9} = {8FA3249B-3567-4C76-BA32-9488FC92994D} {8EA17297-41EE-4CEE-AF61-F047D6F7A1AB} = {7B3C7C2F-58E0-4EE5-B904-9C978F40FD33} {1347FE73-506C-4C44-A469-979F6ADB78BE} = {7B3C7C2F-58E0-4EE5-B904-9C978F40FD33} - {7B3C7C2F-58E0-4EE5-B904-9C978F40FD33} = {8FA3249B-3567-4C76-BA32-9488FC92994D} {B36C9254-0C55-414E-8403-03B4F18D5F35} = {5114BD7E-8492-452A-8DAA-BF971D74A66D} + {8826C1E1-CEBD-49F8-9BC8-97FECE60F9B9} = {8FA3249B-3567-4C76-BA32-9488FC92994D} + {7B3C7C2F-58E0-4EE5-B904-9C978F40FD33} = {8FA3249B-3567-4C76-BA32-9488FC92994D} {5114BD7E-8492-452A-8DAA-BF971D74A66D} = {8FA3249B-3567-4C76-BA32-9488FC92994D} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {D4031401-FEB5-4CCF-91C1-38F5646B2BFD} EndGlobalSection + GlobalSection(SharedMSBuildProjectFiles) = preSolution + ..\..\tools\illink\src\ILLink.Shared\ILLink.Shared.projitems*{1347fe73-506c-4c44-a469-979f6adb78be}*SharedItemsImports = 5 + ..\..\tools\illink\src\ILLink.Shared\ILLink.Shared.projitems*{169b126b-48df-425c-b902-d376a689d9fb}*SharedItemsImports = 5 + ..\System.Private.CoreLib\src\System.Private.CoreLib.Shared.projitems*{94b59ba0-491f-4b59-adff-a057ec3ec835}*SharedItemsImports = 5 + EndGlobalSection EndGlobal diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGeneratorHelpers.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGeneratorHelpers.cs index c5fd203db2a0f..5bd5e1b893bc9 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGeneratorHelpers.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGeneratorHelpers.cs @@ -59,6 +59,7 @@ private static IMarshallingGeneratorFactory CreateGeneratorFactory(EnvironmentFl generatorFactory = new ComInterfaceDispatchMarshallerFactory(generatorFactory); generatorFactory = new ByValueContentsMarshalKindValidator(generatorFactory); + generatorFactory = new BreakingChangeDetector(generatorFactory); return generatorFactory; } diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VtableIndexStubGeneratorHelpers.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VtableIndexStubGeneratorHelpers.cs index 7d7c516f50998..7319a8540482c 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VtableIndexStubGeneratorHelpers.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VtableIndexStubGeneratorHelpers.cs @@ -55,6 +55,7 @@ private static IMarshallingGeneratorFactory CreateGeneratorFactory(EnvironmentFl generatorFactory = new ObjectUnwrapperMarshallerFactory(generatorFactory); generatorFactory = new ByValueContentsMarshalKindValidator(generatorFactory); + generatorFactory = new BreakingChangeDetector(generatorFactory); return generatorFactory; } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/Strings.resx b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/Strings.resx index bce2c5ae18804..c1b54b9dde9e9 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/Strings.resx +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/Strings.resx @@ -1,17 +1,17 @@  - @@ -907,4 +907,7 @@ The usage of 'LibraryImportAttribute' does not follow recommendations. {0} - + + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.cs.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.cs.xlf index 9f769d6c35c06..cb47ca8633ddb 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.cs.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.cs.xlf @@ -492,6 +492,11 @@ atributy [In] a [Out] + + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + + Events are not a concept in COM, so no interop code will be source generated for instance events on source-generated COM interfaces. Události nejsou konceptem COM, takže pro události instance na rozhraních COM generovaných zdrojem nebude vygenerován žádný kód spolupráce. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.de.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.de.xlf index a23a817897757..4c074a73b1d06 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.de.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.de.xlf @@ -492,6 +492,11 @@ [In]- und [Out]-Attribute + + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + + Events are not a concept in COM, so no interop code will be source generated for instance events on source-generated COM interfaces. Ereignisse sind kein Konzept in COM, daher wird kein Interopcode für Instanzereignisse auf von der Quelle generierten COM-Schnittstellen generiert. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.es.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.es.xlf index 7d4da3d239110..af7b114c148d8 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.es.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.es.xlf @@ -492,6 +492,11 @@ Atributos [In] y [Out] + + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + + Events are not a concept in COM, so no interop code will be source generated for instance events on source-generated COM interfaces. Los eventos no representan un concepto en COM, de modo que no se generará código de interoperabilidad para eventos de instancia en interfaces COM generadas en origen. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf index 467413d83f430..f6a5d7a2405fc 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.fr.xlf @@ -492,6 +492,11 @@ Attributs [In] et [Out] + + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + + Events are not a concept in COM, so no interop code will be source generated for instance events on source-generated COM interfaces. Les événements ne sont pas un concept dans COM. Par conséquent, aucun code d’interopérabilité n’est généré à la source pour les événements d’instance sur les interfaces COM générées par la source. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.it.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.it.xlf index 7af807ca8b6f6..583bd7d3b679a 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.it.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.it.xlf @@ -492,6 +492,11 @@ Attributi [In] e [Out] + + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + + Events are not a concept in COM, so no interop code will be source generated for instance events on source-generated COM interfaces. Gli eventi non sono concetti in COM quindi non verrà generato codice di interoperabilità per gli eventi dell’istanza nelle interfacce COM generate dall'origine. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ja.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ja.xlf index 900871e573895..922438e3b3b46 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ja.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ja.xlf @@ -492,6 +492,11 @@ 属性の[In]と[Out] + + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + + Events are not a concept in COM, so no interop code will be source generated for instance events on source-generated COM interfaces. イベントは COM の概念ではないため、ソース生成 COM インターフェイス上のインスタンス イベントに対して相互運用コードはソース生成されません。 diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf index c2061f1c47ed0..42a09317564ad 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ko.xlf @@ -492,6 +492,11 @@ [In] 및 [Out] 속성 + + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + + Events are not a concept in COM, so no interop code will be source generated for instance events on source-generated COM interfaces. 이벤트는 COM의 개념이 아니므로 소스 생성 COM 인터페이스의 인스턴스 이벤트에 대해 interop 코드가 생성되지 않습니다. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf index 4a5bed01000cb..a3b1860ab44e3 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pl.xlf @@ -492,6 +492,11 @@ Atrybuty [In] i [Out] + + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + + Events are not a concept in COM, so no interop code will be source generated for instance events on source-generated COM interfaces. Zdarzenia nie są koncepcją w modelu COM, więc żaden kod międzyoperacyjny nie będzie generowany dla zdarzeń wystąpień w interfejsach COM generowanych źródłowo. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf index a2dcb00fc8aa2..21f751b536107 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.pt-BR.xlf @@ -492,6 +492,11 @@ Atributos [In] e [Out] + + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + + Events are not a concept in COM, so no interop code will be source generated for instance events on source-generated COM interfaces. Os eventos não são um conceito em COM, portanto, nenhum código de interoperabilidade será gerado para eventos de instância em interfaces COM geradas pela origem. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ru.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ru.xlf index 9631d6c981aac..a9171f2bc3161 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ru.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.ru.xlf @@ -492,6 +492,11 @@ Атрибуты [In] и [Out] + + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + + Events are not a concept in COM, so no interop code will be source generated for instance events on source-generated COM interfaces. События не являются концепцией в COM, поэтому источник не будет генерировать код взаимодействия для событий экземпляра в COM-интерфейсах, создаваемых источником. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.tr.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.tr.xlf index 06f7c1279e14a..1cc5531a8683c 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.tr.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.tr.xlf @@ -492,6 +492,11 @@ [In] ve [Out] öznitelikleri + + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + + Events are not a concept in COM, so no interop code will be source generated for instance events on source-generated COM interfaces. Olaylar COM'da kavram olarak değerlendirilmez, bu nedenle kaynak tarafından oluşturulan COM arabirimleri üzerinde örnek olaylar için birlikte çalışma kodu oluşturulmaz. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hans.xlf index 9cf9ccbc906f5..8f895c4fec8b4 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hans.xlf @@ -492,6 +492,11 @@ [In] 和 [Out] 属性 + + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + + Events are not a concept in COM, so no interop code will be source generated for instance events on source-generated COM interfaces. 事件不是 COM 的概念,因此不会为源生成的 COM 接口上的实例事件生成互操作代码。 diff --git a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hant.xlf index 08a0d9ac8eb54..34074c682f507 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/System.Runtime.InteropServices/gen/Common/Resources/xlf/Strings.zh-Hant.xlf @@ -492,6 +492,11 @@ [In] 與 [Out] 屬性 + + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + Objects marshalled from VARIANTs as 'in' parameters in unmanaged-to-managed calls will not propagate back the updated result, even if the VARIANT is a VT_BYREF variant. Use a 'ref' parameter instead of an 'in' parameter to propagate the updated value back to the caller. + + Events are not a concept in COM, so no interop code will be source generated for instance events on source-generated COM interfaces. 事件不是 COM 中的概念,因此不會為來源產生的 COM 介面上的執行個體事件來源產生 Interop 程式碼。 diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGeneratorHelpers.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGeneratorHelpers.cs index 95ab175c46b51..49a5e8ac5edf5 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGeneratorHelpers.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGeneratorHelpers.cs @@ -110,6 +110,7 @@ public static IMarshallingGeneratorFactory CreateGeneratorFactory(TargetFramewor } generatorFactory = new ByValueContentsMarshalKindValidator(generatorFactory); + generatorFactory = new BreakingChangeDetector(generatorFactory); } return generatorFactory; diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/CustomMarshallingInfoHelper.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/CustomMarshallingInfoHelper.cs index e3dcb7a67ae4a..e98bc9ec3ddbd 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/CustomMarshallingInfoHelper.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/CustomMarshallingInfoHelper.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.DotnetRuntime.Extensions; namespace Microsoft.Interop { @@ -165,5 +166,27 @@ public static class CustomMarshallingInfoHelper return NoMarshallingInfo.Instance; } + + public static MarshallingInfo CreateMarshallingInfoByMarshallerTypeName( + Compilation compilation, + ITypeSymbol type, + string marshallerName) + { + INamedTypeSymbol? marshallerType = compilation.GetBestTypeByMetadataName(marshallerName); + if (marshallerType is null) + return new MissingSupportMarshallingInfo(); + + if (ManualTypeMarshallingHelper.HasEntryPointMarshallerAttribute(marshallerType)) + { + if (ManualTypeMarshallingHelper.TryGetValueMarshallersFromEntryType(marshallerType, type, compilation, out CustomTypeMarshallers? marshallers)) + { + return new NativeMarshallingAttributeInfo( + EntryPointType: ManagedTypeInfo.CreateTypeInfoForTypeSymbol(marshallerType), + Marshallers: marshallers.Value); + } + } + + return new MissingSupportMarshallingInfo(); + } } } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshalAsWithCustomMarshallersParser.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshalAsWithCustomMarshallersParser.cs index 496a767f3c01b..863520167a035 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshalAsWithCustomMarshallersParser.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshalAsWithCustomMarshallersParser.cs @@ -85,6 +85,11 @@ public MarshalAsWithCustomMarshallersParser(Compilation compilation, GeneratorDi return CreateStringMarshallingInfo(type, marshalAsInfo); } + if (type.SpecialType == SpecialType.System_Object && marshalAsInfo is MarshalAsScalarInfo(UnmanagedType.Struct, _)) + { + return CustomMarshallingInfoHelper.CreateMarshallingInfoByMarshallerTypeName(_compilation, type, TypeNames.ComVariantMarshaller); + } + return marshalAsInfo; } @@ -106,7 +111,7 @@ public MarshalAsWithCustomMarshallersParser(Compilation compilation, GeneratorDi return marshalAsInfo; } - return StringMarshallingInfoProvider.CreateStringMarshallingInfo(_compilation, type, marshallerName); + return CustomMarshallingInfoHelper.CreateMarshallingInfoByMarshallerTypeName(_compilation, type, marshallerName); } } } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/BreakingChangeDetector.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/BreakingChangeDetector.cs new file mode 100644 index 0000000000000..43f6e850d9a4b --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/BreakingChangeDetector.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.CodeAnalysis; + +namespace Microsoft.Interop +{ + /// + /// An that adds diagnostics to warn users about breaking changes in the interop generators, + /// whether from built-in to source-generated interop or between versions of interop source-generation. + /// + public sealed class BreakingChangeDetector(IMarshallingGeneratorFactory inner) : IMarshallingGeneratorFactory + { + public ResolvedGenerator Create(TypePositionInfo info, StubCodeContext context) + { + ResolvedGenerator gen = inner.Create(info, context); + if (!gen.ResolvedSuccessfully) + { + return gen; + } + + // Breaking change: [MarshalAs(UnmanagedType.Struct)] in object in unmanaged-to-managed scenarios will not respect VT_BYREF. + if (info is { RefKind: RefKind.In, MarshallingAttributeInfo: NativeMarshallingAttributeInfo(ManagedTypeInfo(_, TypeNames.ComVariantMarshaller), _) } + && context.Direction == MarshalDirection.UnmanagedToManaged) + { + gen = ResolvedGenerator.ResolvedWithDiagnostics( + gen.Generator, + gen.Diagnostics.Add( + new GeneratorDiagnostic.NotRecommended(info, context) + { + Details = SR.InVariantShouldBeRef + })); + } + + return gen; + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/StringMarshallingInfoProvider.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/StringMarshallingInfoProvider.cs index 12f69adfef136..ed96fe7cd8a74 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/StringMarshallingInfoProvider.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/StringMarshallingInfoProvider.cs @@ -59,35 +59,13 @@ public MarshallingInfo GetMarshallingInfo(ITypeSymbol type, int indirectionDepth // No marshalling info was computed, but a character encoding was provided. return _defaultMarshallingInfo.CharEncoding switch { - CharEncoding.Utf16 => CreateStringMarshallingInfo(_compilation, type, TypeNames.Utf16StringMarshaller), - CharEncoding.Utf8 => CreateStringMarshallingInfo(_compilation, type, TypeNames.Utf8StringMarshaller), + CharEncoding.Utf16 => CustomMarshallingInfoHelper.CreateMarshallingInfoByMarshallerTypeName(_compilation, type, TypeNames.Utf16StringMarshaller), + CharEncoding.Utf8 => CustomMarshallingInfoHelper.CreateMarshallingInfoByMarshallerTypeName(_compilation, type, TypeNames.Utf8StringMarshaller), _ => throw new InvalidOperationException() }; } return new MarshallingInfoStringSupport(_defaultMarshallingInfo.CharEncoding); } - - public static MarshallingInfo CreateStringMarshallingInfo( - Compilation compilation, - ITypeSymbol type, - string marshallerName) - { - INamedTypeSymbol? stringMarshaller = compilation.GetTypeByMetadataName(marshallerName); - if (stringMarshaller is null) - return new MissingSupportMarshallingInfo(); - - if (ManualTypeMarshallingHelper.HasEntryPointMarshallerAttribute(stringMarshaller)) - { - if (ManualTypeMarshallingHelper.TryGetValueMarshallersFromEntryType(stringMarshaller, type, compilation, out CustomTypeMarshallers? marshallers)) - { - return new NativeMarshallingAttributeInfo( - EntryPointType: ManagedTypeInfo.CreateTypeInfoForTypeSymbol(stringMarshaller), - Marshallers: marshallers.Value); - } - } - - return new MissingSupportMarshallingInfo(); - } } } diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs index 3eeb17588a086..818e9d0094941 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs @@ -311,5 +311,6 @@ public static string MarshalEx(InteropGenerationOptions options) public const string CallConvSuppressGCTransitionName = "System.Runtime.CompilerServices.CallConvSuppressGCTransition"; public const string CallConvMemberFunctionName = "System.Runtime.CompilerServices.CallConvMemberFunction"; public const string Nint = "nint"; + public const string ComVariantMarshaller = "System.Runtime.InteropServices.Marshalling.ComVariantMarshaller"; } } diff --git a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs index 59dfcf2713620..b973972873c91 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -460,6 +460,23 @@ public partial interface IUnmanagedVirtualMethodTableProvider { System.Runtime.InteropServices.Marshalling.VirtualMethodTableInfo GetVirtualMethodTableInfoForKey(System.Type type); } + [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(object), System.Runtime.InteropServices.Marshalling.MarshalMode.Default, typeof(System.Runtime.InteropServices.Marshalling.ComVariantMarshaller))] + [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(object), System.Runtime.InteropServices.Marshalling.MarshalMode.UnmanagedToManagedRef, typeof(System.Runtime.InteropServices.Marshalling.ComVariantMarshaller.RefPropagate))] + public static partial class ComVariantMarshaller + { + public static System.Runtime.InteropServices.Marshalling.ComVariant ConvertToUnmanaged(object? managed) { throw null; } + public static object? ConvertToManaged(System.Runtime.InteropServices.Marshalling.ComVariant unmanaged) { throw null; } + public static void Free(System.Runtime.InteropServices.Marshalling.ComVariant unmanaged) { } + + public struct RefPropagate + { + public void FromUnmanaged(System.Runtime.InteropServices.Marshalling.ComVariant unmanaged) { } + public void FromManaged(object? managed) { } + public System.Runtime.InteropServices.Marshalling.ComVariant ToUnmanaged() { throw null; } + public object? ToManaged() { throw null; } + public void Free() { } + } + } [System.CLSCompliantAttribute(false)] public partial class StrategyBasedComWrappers : System.Runtime.InteropServices.ComWrappers { @@ -2500,6 +2517,19 @@ public static unsafe class Utf16StringMarshaller public static void Free(ushort* unmanaged) { throw null; } public static ref readonly char GetPinnableReference(string? str) { throw null; } } + public struct ComVariant : System.IDisposable + { + private int _dummyPrimitive; + + public void Dispose() { } + public static System.Runtime.InteropServices.Marshalling.ComVariant Create([System.Diagnostics.CodeAnalysis.DisallowNullAttribute] T value) { throw null; } + public static System.Runtime.InteropServices.Marshalling.ComVariant CreateRaw(System.Runtime.InteropServices.VarEnum vt, T rawValue) where T : unmanaged { throw null; } + public static System.Runtime.InteropServices.Marshalling.ComVariant Null { get { throw null; } } + public readonly T? As() { throw null; } + public readonly System.Runtime.InteropServices.VarEnum VarType { get { throw null; } } + [System.Diagnostics.CodeAnalysis.UnscopedRefAttribute] + public ref T GetRawDataRef() where T : unmanaged { throw null; } + } } namespace System.Security { diff --git a/src/libraries/System.Runtime.InteropServices/src/Resources/Strings.resx b/src/libraries/System.Runtime.InteropServices/src/Resources/Strings.resx index 828dc3e2b9fe0..86f021792dd52 100644 --- a/src/libraries/System.Runtime.InteropServices/src/Resources/Strings.resx +++ b/src/libraries/System.Runtime.InteropServices/src/Resources/Strings.resx @@ -1,4 +1,64 @@ - + + + @@ -111,4 +171,10 @@ Specified file length was too large for the file system. - + + Type of managed object is not supported for marshalling as ComVariant. + + + Type of unmanaged variant is not supported for marshalling to a managed object. + + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/src/System.Runtime.InteropServices.csproj b/src/libraries/System.Runtime.InteropServices/src/System.Runtime.InteropServices.csproj index 393febd4cdcb7..1f5fd6a4de7e8 100644 --- a/src/libraries/System.Runtime.InteropServices/src/System.Runtime.InteropServices.csproj +++ b/src/libraries/System.Runtime.InteropServices/src/System.Runtime.InteropServices.csproj @@ -34,6 +34,7 @@ + diff --git a/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/ComVariantMarshaller.cs b/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/ComVariantMarshaller.cs new file mode 100644 index 0000000000000..9c2375d3a97fa --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/ComVariantMarshaller.cs @@ -0,0 +1,333 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using System.Threading.Tasks; + +namespace System.Runtime.InteropServices.Marshalling +{ + /// + /// Marshals an to an . + /// + /// + /// Supports the same types as as well as any types with applied. + /// + [CustomMarshaller(typeof(object), MarshalMode.Default, typeof(ComVariantMarshaller))] + [CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedRef, typeof(RefPropagate))] + public static partial class ComVariantMarshaller + { + // VARIANT_BOOL constants. + private const short VARIANT_TRUE = -1; + private const short VARIANT_FALSE = 0; + public static ComVariant ConvertToUnmanaged(object? managed) + { + if (managed is null) + { + return default; + } + +#pragma warning disable CS0618 // Type or member is obsolete + switch (managed) + { + case sbyte s: + return ComVariant.Create(s); + case byte b: + return ComVariant.Create(b); + case short s: + return ComVariant.Create(s); + case ushort s: + return ComVariant.Create(s); + case int i: + return ComVariant.Create(i); + case uint i: + return ComVariant.Create(i); + case long l: + return ComVariant.Create(l); + case ulong l: + return ComVariant.Create(l); + case float f: + return ComVariant.Create(f); + case double d: + return ComVariant.Create(d); + case decimal d: + return ComVariant.Create(d); + case bool b: + return ComVariant.Create(b); + case string s: + return ComVariant.Create(s); + case DateTime dt: + return ComVariant.Create(dt); + case ErrorWrapper errorWrapper: + return ComVariant.Create(errorWrapper); + case CurrencyWrapper currencyWrapper: + return ComVariant.Create(currencyWrapper); + case BStrWrapper bStrWrapper: + return ComVariant.Create(bStrWrapper); + case DBNull: + return ComVariant.Null; + } +#pragma warning restore CS0618 // Type or member is obsolete + + if (TryCreateOleVariantForInterfaceWrapper(managed, out ComVariant variant)) + { + return variant; + } + + throw new ArgumentException(SR.ComVariantMarshaller_ManagedTypeNotSupported, nameof(managed)); + } + +#pragma warning disable CA1416 // Validate platform compatibility + private static unsafe bool TryCreateOleVariantForInterfaceWrapper(object managed, out ComVariant variant) + { + if (managed is UnknownWrapper uw) + { + object? wrapped = uw.WrappedObject; + if (wrapped is null) + { + variant = default; + return true; + } + variant = ComVariant.CreateRaw(VarEnum.VT_UNKNOWN, StrategyBasedComWrappers.DefaultMarshallingInstance.GetOrCreateComInterfaceForObject(wrapped, CreateComInterfaceFlags.None)); + return true; + } + else if (managed is not null && StrategyBasedComWrappers.DefaultIUnknownInterfaceDetailsStrategy.GetComExposedTypeDetails(managed.GetType().TypeHandle) is not null) + { + variant = ComVariant.CreateRaw(VarEnum.VT_UNKNOWN, StrategyBasedComWrappers.DefaultMarshallingInstance.GetOrCreateComInterfaceForObject(managed, CreateComInterfaceFlags.None)); + return true; + } + variant = default; + return false; + } +#pragma warning restore CA1416 // Validate platform compatibility + + public static unsafe object? ConvertToManaged(ComVariant unmanaged) + { +#pragma warning disable CS0618 // Type or member is obsolete +#pragma warning disable CA1416 // Validate platform compatibility + switch (unmanaged.VarType) + { + case VarEnum.VT_EMPTY: + case VarEnum.VT_BYREF | VarEnum.VT_EMPTY: + return null; + case VarEnum.VT_NULL: + case VarEnum.VT_BYREF | VarEnum.VT_NULL: + return DBNull.Value; + case VarEnum.VT_I1: + return unmanaged.As(); + case VarEnum.VT_UI1: + return unmanaged.As(); + case VarEnum.VT_I2: + return unmanaged.As(); + case VarEnum.VT_UI2: + return unmanaged.As(); + case VarEnum.VT_INT: + case VarEnum.VT_I4: + return unmanaged.As(); + case VarEnum.VT_UINT: + case VarEnum.VT_UI4: + return unmanaged.As(); + case VarEnum.VT_I8: + return unmanaged.As(); + case VarEnum.VT_UI8: + return unmanaged.As(); + case VarEnum.VT_R4: + return unmanaged.As(); + case VarEnum.VT_R8: + return unmanaged.As(); + case VarEnum.VT_DECIMAL: + return unmanaged.As(); + case VarEnum.VT_BOOL: + return unmanaged.As(); + case VarEnum.VT_BSTR: + return unmanaged.As(); + case VarEnum.VT_DATE: + return unmanaged.As(); + case VarEnum.VT_ERROR: + return unmanaged.As(); + case VarEnum.VT_CY: + return unmanaged.As()!.WrappedObject; + case VarEnum.VT_UNKNOWN: + case VarEnum.VT_DISPATCH: + return StrategyBasedComWrappers.DefaultMarshallingInstance.GetOrCreateObjectForComInstance(unmanaged.GetRawDataRef(), CreateObjectFlags.Unwrap); + case VarEnum.VT_BYREF | VarEnum.VT_VARIANT: + return ConvertToManaged(*(ComVariant*)unmanaged.GetRawDataRef()); + case VarEnum.VT_BYREF | VarEnum.VT_I1: + return *(sbyte*)unmanaged.GetRawDataRef(); + case VarEnum.VT_BYREF | VarEnum.VT_UI1: + return *(byte*)unmanaged.GetRawDataRef(); + case VarEnum.VT_BYREF | VarEnum.VT_I2: + return *(short*)unmanaged.GetRawDataRef(); + case VarEnum.VT_BYREF | VarEnum.VT_UI2: + return *(ushort*)unmanaged.GetRawDataRef(); + case VarEnum.VT_BYREF | VarEnum.VT_I4: + return *(int*)unmanaged.GetRawDataRef(); + case VarEnum.VT_BYREF | VarEnum.VT_UI4: + return *(uint*)unmanaged.GetRawDataRef(); + case VarEnum.VT_BYREF | VarEnum.VT_I8: + return *(long*)unmanaged.GetRawDataRef(); + case VarEnum.VT_BYREF | VarEnum.VT_UI8: + return *(ulong*)unmanaged.GetRawDataRef(); + case VarEnum.VT_BYREF | VarEnum.VT_R4: + return *(float*)unmanaged.GetRawDataRef(); + case VarEnum.VT_BYREF | VarEnum.VT_R8: + return *(double*)unmanaged.GetRawDataRef(); + case VarEnum.VT_BYREF | VarEnum.VT_DECIMAL: + return *(decimal*)unmanaged.GetRawDataRef(); + case VarEnum.VT_BYREF | VarEnum.VT_BOOL: + return *(short*)unmanaged.GetRawDataRef() != VARIANT_FALSE; + case VarEnum.VT_BYREF | VarEnum.VT_BSTR: + return Marshal.PtrToStringBSTR(*(IntPtr*)unmanaged.GetRawDataRef()); + case VarEnum.VT_BYREF | VarEnum.VT_DATE: + return DateTime.FromOADate(*(double*)unmanaged.GetRawDataRef()); + case VarEnum.VT_BYREF | VarEnum.VT_ERROR: + return *(int*)unmanaged.GetRawDataRef(); + case VarEnum.VT_BYREF | VarEnum.VT_CY: + return decimal.FromOACurrency(*(long*)unmanaged.GetRawDataRef()); + case VarEnum.VT_BYREF | VarEnum.VT_UNKNOWN: + return StrategyBasedComWrappers.DefaultMarshallingInstance.GetOrCreateObjectForComInstance(*(nint*)unmanaged.GetRawDataRef(), CreateObjectFlags.Unwrap); + default: + throw new ArgumentException(SR.ComVariantMarshaller_UnmanagedTypeNotSupported, nameof(unmanaged)); + } +#pragma warning restore CA1416 // Validate platform compatibility +#pragma warning restore CS0618 // Type or member is obsolete + } + + public static void Free(ComVariant unmanaged) => unmanaged.Dispose(); + + /// + /// Marshals a to an , propagating the value of the back to the variant's + /// existing data storage if the variant has type. + /// + public struct RefPropagate + { + private ComVariant _unmanaged; + private object? _managed; + + /// + /// Initializes the marshaller with an unmanaged variant. + /// + /// The unmanaged value + public void FromUnmanaged(ComVariant unmanaged) => _unmanaged = unmanaged; + + /// + /// Initializes the marshaller with a managed object. + /// + /// The managed object. + public void FromManaged(object? managed) => _managed = managed; + + /// + /// Create an unmanaged based on the provided managed and unmanaged values. + /// + /// An instance representing the marshaller's current state. + /// When the managed value must be propagated back to the unmanaged variant, but the managed value type cannot be converted to the variant's type. + public unsafe ComVariant ToUnmanaged() + { + if (!_unmanaged.VarType.HasFlag(VarEnum.VT_BYREF)) + { + return ConvertToUnmanaged(_managed); + } + + if (_managed is null + && (_unmanaged.VarType & ~VarEnum.VT_BYREF) is + VarEnum.VT_BSTR + or VarEnum.VT_DISPATCH + or VarEnum.VT_UNKNOWN) + { + *(IntPtr*)_unmanaged.GetRawDataRef() = default; + return _unmanaged; + } + +#pragma warning disable CS0618 // Type or member is obsolete +#pragma warning disable CA1416 // Validate platform compatibility + switch ((_unmanaged.VarType & ~VarEnum.VT_BYREF, _managed)) + { + case (VarEnum.VT_VARIANT, _): + *(ComVariant*)_unmanaged.GetRawDataRef() = ConvertToUnmanaged(_managed); + break; + case (VarEnum.VT_I1 or VarEnum.VT_UI1, sbyte s): + *(sbyte*)_unmanaged.GetRawDataRef() = s; + break; + case (VarEnum.VT_I1 or VarEnum.VT_UI1, byte b): + *(byte*)_unmanaged.GetRawDataRef() = b; + break; + case (VarEnum.VT_I2 or VarEnum.VT_UI2, short s): + *(short*)_unmanaged.GetRawDataRef() = s; + break; + case (VarEnum.VT_I2 or VarEnum.VT_UI2, ushort u): + *(ushort*)_unmanaged.GetRawDataRef() = u; + break; + case (VarEnum.VT_I4 or VarEnum.VT_INT or VarEnum.VT_UI4 or VarEnum.VT_UINT or VarEnum.VT_ERROR, int i): + *(int*)_unmanaged.GetRawDataRef() = i; + break; + case (VarEnum.VT_I4 or VarEnum.VT_INT or VarEnum.VT_UI4 or VarEnum.VT_UINT or VarEnum.VT_ERROR, uint u): + *(uint*)_unmanaged.GetRawDataRef() = u; + break; + case (VarEnum.VT_I8 or VarEnum.VT_UI8, long l): + *(long*)_unmanaged.GetRawDataRef() = l; + break; + case (VarEnum.VT_I8 or VarEnum.VT_UI8, ulong ul): + *(ulong*)_unmanaged.GetRawDataRef() = ul; + break; + case (VarEnum.VT_R4, float f): + *(float*)_unmanaged.GetRawDataRef() = f; + break; + case (VarEnum.VT_R8, double d): + *(double*)_unmanaged.GetRawDataRef() = d; + break; + case (VarEnum.VT_DECIMAL, decimal d): + *(decimal*)_unmanaged.GetRawDataRef() = d; + break; + case (VarEnum.VT_BOOL, bool b): + *(short*)_unmanaged.GetRawDataRef() = b ? VARIANT_TRUE : VARIANT_FALSE; + break; + case (VarEnum.VT_BSTR, string str): + { + ref IntPtr bstrStorage = ref *(IntPtr*)_unmanaged.GetRawDataRef(); + Marshal.FreeBSTR(bstrStorage); + bstrStorage = Marshal.StringToBSTR(str); + break; + } + case (VarEnum.VT_BSTR, BStrWrapper str): + { + ref IntPtr bstrStorage = ref *(IntPtr*)_unmanaged.GetRawDataRef(); + Marshal.FreeBSTR(bstrStorage); + bstrStorage = Marshal.StringToBSTR(str.WrappedObject); + break; + } + case (VarEnum.VT_DATE, DateTime dt): + *(double*)_unmanaged.GetRawDataRef() = dt.ToOADate(); + break; + case (VarEnum.VT_ERROR, ErrorWrapper error): + *(int*)_unmanaged.GetRawDataRef() = error.ErrorCode; + break; + case (VarEnum.VT_CY, CurrencyWrapper cy): + *(long*)_unmanaged.GetRawDataRef() = decimal.ToOACurrency(cy.WrappedObject); + break; + case (VarEnum.VT_UNKNOWN, object unkObj): + *(IntPtr*)_unmanaged.GetRawDataRef() = StrategyBasedComWrappers.DefaultMarshallingInstance.GetOrCreateComInterfaceForObject(unkObj, CreateComInterfaceFlags.None); + break; + default: + throw new ArgumentException("Invalid combination of unmanaged variant type and managed object type.", nameof(_managed)); + } +#pragma warning restore CA1416 // Validate platform compatibility +#pragma warning restore CS0618 // Type or member is obsolete + + return _unmanaged; + } + + /// + /// Create the managed value based on the provided unmanaged value. + /// + /// The managed value corresponding to the VARIANT. + public object? ToManaged() => ConvertToManaged(_unmanaged); + + /// + /// Free all resources owned by the marshaller. + /// + public void Free() => _unmanaged.Dispose(); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CodeSnippets.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CodeSnippets.cs index 700797fcb3e88..12b59f274425a 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CodeSnippets.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CodeSnippets.cs @@ -301,6 +301,31 @@ partial interface INativeAPI """; public string BasicParametersAndModifiersNoImplicitThis() => BasicParametersAndModifiersNoImplicitThis(typeof(T).FullName!); + + public string MarshalAsParameterAndModifiers(string typeName, UnmanagedType unmanagedType) => + $$""" + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + [assembly:DisableRuntimeMarshalling] + + {{UnmanagedObjectUnwrapper(typeof(UnmanagedObjectUnwrapper.TestUnwrapper))}} + {{GeneratedComInterface()}} + partial interface INativeAPI + { + {{VirtualMethodIndex(0)}} + [return: {|#10:MarshalAs(UnmanagedType.{{unmanagedType}})|}] + {{typeName}} {|#0:Method|}( + [{|#11:MarshalAs(UnmanagedType.{{unmanagedType}})|}] {{typeName}} {|#1:value|}, + [{|#12:MarshalAs(UnmanagedType.{{unmanagedType}})|}] in {{typeName}} {|#2:inValue|}, + [{|#13:MarshalAs(UnmanagedType.{{unmanagedType}})|}] ref {{typeName}} {|#3:refValue|}, + [{|#14:MarshalAs(UnmanagedType.{{unmanagedType}})|}] out {{typeName}} {|#4:outValue|}); + } + + {{_attributeProvider.AdditionalUserRequiredInterfaces("INativeAPI")}} + """; + public string MarshalUsingCollectionCountInfoParametersAndModifiers() => MarshalUsingCollectionCountInfoParametersAndModifiers(typeof(T).ToString()); public string MarshalUsingCollectionCountInfoParametersAndModifiers(string collectionType) => $$""" using System.Runtime.CompilerServices; diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs index 331fa54117fb0..198e3370c04cd 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CompileFails.cs @@ -909,5 +909,24 @@ public async Task ValidateReturnTypeInfoDiagnostics(string id, string source, Di test.DisabledDiagnostics.Remove(GeneratorDiagnostics.Ids.NotRecommendedGeneratedComInterfaceUsage); await test.RunAsync(); } + + [Fact] + public async Task ByRefInVariant_ReportsNotRecommendedDiagnostic() + { + CodeSnippets codeSnippets = new CodeSnippets(GeneratorKind.ComInterfaceGeneratorManagedObjectWrapper); + + var test = new VerifyComInterfaceGenerator.Test(referenceAncillaryInterop: false) + { + TestCode = codeSnippets.MarshalAsParameterAndModifiers("object", System.Runtime.InteropServices.UnmanagedType.Struct), + TestBehaviors = TestBehaviors.SkipGeneratedSourcesCheck | TestBehaviors.SkipGeneratedCodeCheck, + }; + test.ExpectedDiagnostics.Add( + VerifyComInterfaceGenerator + .Diagnostic(GeneratorDiagnostics.GeneratedComInterfaceUsageDoesNotFollowBestPractices) + .WithLocation(2) + .WithArguments(SR.InVariantShouldBeRef)); + test.DisabledDiagnostics.Remove(GeneratorDiagnostics.Ids.NotRecommendedGeneratedComInterfaceUsage); + await test.RunAsync(); + } } } diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs index 3d20f2a8c7c68..bf04b97ffcded 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs @@ -339,6 +339,14 @@ public static IEnumerable ComInterfaceSnippetsToCompile() yield return new object[] { ID(), codeSnippets.ComInterfaceParameters }; } + public static IEnumerable ManagedToUnmanagedComInterfaceSnippetsToCompile() + { + CodeSnippets codeSnippets = new(GeneratorKind.ComInterfaceGeneratorComObjectWrapper); + + // MarshalAs + yield return new[] { ID(), codeSnippets.MarshalAsParameterAndModifiers("object", System.Runtime.InteropServices.UnmanagedType.Struct) }; + } + [Theory] [MemberData(nameof(CodeSnippetsToCompile), GeneratorKind.ComInterfaceGenerator)] [MemberData(nameof(CustomCollections), GeneratorKind.ComInterfaceGenerator)] @@ -346,6 +354,7 @@ public static IEnumerable ComInterfaceSnippetsToCompile() [MemberData(nameof(UnmanagedToManagedCodeSnippetsToCompile), GeneratorKind.ComInterfaceGeneratorManagedObjectWrapper)] [MemberData(nameof(CustomCollectionsManagedToUnmanaged), GeneratorKind.ComInterfaceGeneratorComObjectWrapper)] [MemberData(nameof(ComInterfaceSnippetsToCompile))] + [MemberData(nameof(ManagedToUnmanagedComInterfaceSnippetsToCompile))] public async Task ValidateComInterfaceSnippets(string id, string source) { _ = id; diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/VariantTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/VariantTests.cs new file mode 100644 index 0000000000000..2689327c2a1fe --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/VariantTests.cs @@ -0,0 +1,28 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace LibraryImportGenerator.IntegrationTests +{ + partial class NativeExportsNE + { + [LibraryImport(NativeExportsNE_Binary, EntryPoint = "get_variant_bstr_length")] + public static partial int GetVTBStrLength([MarshalAs(UnmanagedType.Struct)] in object obj); + } + + public class VariantTests + { + [Fact] + public void MarshalAsStruct_UsesVariantMarshaller() + { + Assert.Equal(3, NativeExportsNE.GetVTBStrLength("Foo")); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System.Runtime.InteropServices.Tests.csproj b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System.Runtime.InteropServices.Tests.csproj index 90173a66a48c6..31369aaca2a4a 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System.Runtime.InteropServices.Tests.csproj +++ b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System.Runtime.InteropServices.Tests.csproj @@ -30,6 +30,8 @@ + + diff --git a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/ComVariantMarshallerTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/ComVariantMarshallerTests.cs new file mode 100644 index 0000000000000..1e7e38610310e --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/ComVariantMarshallerTests.cs @@ -0,0 +1,295 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices.Marshalling; +using System.Runtime.InteropServices.Tests.Common; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace System.Runtime.InteropServices.Tests +{ + // NanoServer doesn't have any of the OLE Automation stack available, so we can't run these tests there. + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))] + public partial class ComVariantMarshallerTests + { + [Fact] + public void Null_Marshals_To_Empty() + { + Assert.Equal(VarEnum.VT_EMPTY, ComVariantMarshaller.ConvertToUnmanaged(null).VarType); + Assert.Null(ComVariantMarshaller.ConvertToManaged(default)); + } + + [Fact] + public void DBNull_Marshals_To_Null() + { + Assert.Equal(VarEnum.VT_NULL, ComVariantMarshaller.ConvertToUnmanaged(DBNull.Value).VarType); + Assert.Same(DBNull.Value, ComVariantMarshaller.ConvertToManaged(ComVariant.Null)); + } + + [Fact] + public void String_Marshals_To_BStr() + { + string value = "Hello"; + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(value); + Assert.Equal(VarEnum.VT_BSTR, variant.VarType); + Assert.Equal(value, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); + } + + [Fact] + public void BStrWrapper_Marshals_To_BStr() + { + string value = "Hello"; + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(new BStrWrapper(value)); + Assert.Equal(VarEnum.VT_BSTR, variant.VarType); + Assert.Equal(value, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); + } + + [Fact] + public void Int32_Marshals_To_I4() + { + int value = 42; + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(value); + Assert.Equal(VarEnum.VT_I4, variant.VarType); + Assert.Equal(value, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); + } + + [Fact] + public void UInt32_Marshals_To_UI4() + { + uint value = 42; + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(value); + Assert.Equal(VarEnum.VT_UI4, variant.VarType); + Assert.Equal(value, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); + } + + [Fact] + public void Int16_Marshals_To_I2() + { + short value = 42; + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(value); + Assert.Equal(VarEnum.VT_I2, variant.VarType); + Assert.Equal(value, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); + } + + [Fact] + public void UInt16_Marshals_To_UI2() + { + ushort value = 42; + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(value); + Assert.Equal(VarEnum.VT_UI2, variant.VarType); + Assert.Equal(value, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); + } + + [Fact] + public void Byte_Marshals_To_UI1() + { + byte value = 42; + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(value); + Assert.Equal(VarEnum.VT_UI1, variant.VarType); + Assert.Equal(value, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); + } + + [Fact] + public void SByte_Marshals_To_I1() + { + sbyte value = 42; + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(value); + Assert.Equal(VarEnum.VT_I1, variant.VarType); + Assert.Equal(value, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); + } + + [Fact] + public void Double_Marshals_To_R8() + { + double value = 42.0; + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(value); + Assert.Equal(VarEnum.VT_R8, variant.VarType); + Assert.Equal(value, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); + } + + [Fact] + public void Single_Marshals_To_R4() + { + float value = 42.0f; + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(value); + Assert.Equal(VarEnum.VT_R4, variant.VarType); + Assert.Equal(value, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); + } + + [InlineData(true)] + [InlineData(false)] + [Theory] + public void Boolean_Marshals_To_BOOL(bool value) + { + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(value); + Assert.Equal(VarEnum.VT_BOOL, variant.VarType); + Assert.Equal(value, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); + } + + [Fact] + public void ErrorWrapper_Maps_To_VT_ERROR() + { + ErrorWrapper errorWrapper = new ErrorWrapper(42); + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(errorWrapper); + Assert.Equal(VarEnum.VT_ERROR, variant.VarType); + Assert.Equal(errorWrapper.ErrorCode, Assert.IsType(ComVariantMarshaller.ConvertToManaged(variant))); + ComVariantMarshaller.Free(variant); + } + + [Fact] + public void VariantWrapper_Throws() + { + VariantWrapper wrapper = new VariantWrapper(42); + Assert.Throws("managed", () => ComVariantMarshaller.ConvertToUnmanaged(wrapper)); + } + + [Fact] + public void Decimal_Marshals_To_DECIMAL() + { + decimal value = 42.0m; + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(value); + Assert.Equal(VarEnum.VT_DECIMAL, variant.VarType); + Assert.Equal(value, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); + } + + [Fact] + public void Date_Marshals_To_DATE() + { + // OLE dates do not have time zones and do not support sub-millisecond precision. + // Select a date format that includes the maximum precision that OLE supports. + DateTime value = DateTime.Parse("2023-10-17T14:47:32.6390000"); + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(value); + Assert.Equal(VarEnum.VT_DATE, variant.VarType); + Assert.Equal(value, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); + } + +#pragma warning disable CS0618 // Type or member is obsolete + [Fact] + public void CurrentyWrapper_Marshals_To_CY() + { + decimal value = 42.0m; + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(new CurrencyWrapper(value)); + Assert.Equal(VarEnum.VT_CY, variant.VarType); + Assert.Equal(value, Assert.IsType(ComVariantMarshaller.ConvertToManaged(variant))); + ComVariantMarshaller.Free(variant); + } +#pragma warning restore CS0618 // Type or member is obsolete + + [GeneratedComInterface] + [Guid("ADD9E468-1503-48E5-AA18-B6B6BD1FF34A")] + internal partial interface IGeneratedComInterface + { + void Method(); + } + + [GeneratedComClass] + internal sealed partial class ComExposedType : IGeneratedComInterface + { + public void Method() { } + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/55742", TestRuntimes.Mono)] + public unsafe void GeneratedComInterfaceType_Marshals_To_UNKNOWN() + { + var obj = new ComExposedType(); + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(obj); + Assert.Equal(VarEnum.VT_UNKNOWN, variant.VarType); + // Validate that the correct object is wrapped. + Assert.True(ComWrappers.TryGetObject(variant.GetRawDataRef(), out object wrappedObj)); + Assert.Same(obj, wrappedObj); + // Validate that we use the same ComWrappers instance as ComInterfaceMarshaller. + Assert.Same(obj, ComInterfaceMarshaller.ConvertToManaged((void*)variant.GetRawDataRef())); + Assert.Same(obj, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/55742", TestRuntimes.Mono)] + public void UnknownWrapper_Of_GeneratedComInterfaceType_Marshals_To_UNKNOWN() + { + var obj = new ComExposedType(); + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(new UnknownWrapper(obj)); + Assert.Equal(VarEnum.VT_UNKNOWN, variant.VarType); + Assert.True(ComWrappers.TryGetObject(variant.GetRawDataRef(), out object wrappedObj)); + Assert.Same(obj, wrappedObj); + Assert.Same(obj, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); + } + + [Fact] + public void INT_Marshals_as_Int() + { + ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_INT, 42); + Assert.Equal(42, Assert.IsType(ComVariantMarshaller.ConvertToManaged(variant))); + } + + [Fact] + public void UINT_Marshals_as_UInt() + { + ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_UINT, 42u); + Assert.Equal(42u, Assert.IsType(ComVariantMarshaller.ConvertToManaged(variant))); + } + + [InlineData(VarEnum.VT_I1, (byte)42)] + [InlineData(VarEnum.VT_I1, (sbyte)42)] + [InlineData(VarEnum.VT_UI1, (byte)42)] + [InlineData(VarEnum.VT_UI1, (sbyte)42)] + [InlineData(VarEnum.VT_I2, (short)42)] + [InlineData(VarEnum.VT_I2, (ushort)42)] + [InlineData(VarEnum.VT_UI2, (short)42)] + [InlineData(VarEnum.VT_UI2, (ushort)42)] + [InlineData(VarEnum.VT_I4, 42)] + [InlineData(VarEnum.VT_I4, (uint)42)] + [InlineData(VarEnum.VT_UI4, 42)] + [InlineData(VarEnum.VT_UI4, (uint)42)] + [InlineData(VarEnum.VT_ERROR, (uint)42)] + [InlineData(VarEnum.VT_ERROR, 42)] + [InlineData(VarEnum.VT_I8, 42L)] + [InlineData(VarEnum.VT_I8, 42UL)] + [InlineData(VarEnum.VT_UI8, 42L)] + [InlineData(VarEnum.VT_UI8, 42UL)] + [InlineData(VarEnum.VT_R4, 42.0f)] + [InlineData(VarEnum.VT_R8, 42.0)] + [InlineData(VarEnum.VT_BOOL, true)] + [InlineData(VarEnum.VT_BOOL, false)] + [Theory] + public unsafe void ByRef_Primitives(VarEnum elementType, object valueToSet) + { + long storage = 0; + ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_BYREF | elementType, (nint)(&storage)); + // Set up the marshaller + ComVariantMarshaller.RefPropagate marshaller = default; + marshaller.FromUnmanaged(variant); + + // Marshal back the new value + marshaller.FromManaged(valueToSet); + + ComVariant updated = marshaller.ToUnmanaged(); + + // Make sure we didn't change the pointer. + Assert.Equal(variant.GetRawDataRef(), updated.GetRawDataRef()); + + // Validate that the new value of the variant is the same as the value we set. + // Go through IConvertible to handle the case of "same size, different signedness" (e.g. int and uint) + Assert.Equal(valueToSet, ((IConvertible)ComVariantMarshaller.ConvertToManaged(variant)).ToType(valueToSet.GetType(), null)); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/ComVariantTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/ComVariantTests.cs new file mode 100644 index 0000000000000..652b07c09c9fc --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/ComVariantTests.cs @@ -0,0 +1,493 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices.Marshalling; +using System.Runtime.InteropServices.Tests.Common; +using Xunit; + +namespace System.Runtime.InteropServices.Tests +{ + // NanoServer doesn't have any of the OLE Automation stack available, so we can't run these tests there. + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer))] + public class ComVariantTests + { + [Fact] + public void DefaultVariantIsEmpty() + { + Assert.Equal(VarEnum.VT_EMPTY, default(ComVariant).VarType); + } + + [Fact] + public void NullVariantIsNull() + { + Assert.Equal(VarEnum.VT_NULL, ComVariant.Null.VarType); + } + + [Fact] + public void Short() + { + ComVariant variant = ComVariant.Create(42); + Assert.Equal(VarEnum.VT_I2, variant.VarType); + Assert.Equal(42, variant.As()); + Assert.Equal(42, variant.GetRawDataRef()); + } + + [Fact] + public void Int4() + { + ComVariant variant = ComVariant.Create(42); + Assert.Equal(VarEnum.VT_I4, variant.VarType); + Assert.Equal(42, variant.As()); + Assert.Equal(42, variant.GetRawDataRef()); + } + + [Fact] + public void Float() + { + ComVariant variant = ComVariant.Create(42.0f); + Assert.Equal(VarEnum.VT_R4, variant.VarType); + Assert.Equal(42, variant.As()); + Assert.Equal(42, variant.GetRawDataRef()); + } + + [Fact] + public void Double() + { + ComVariant variant = ComVariant.Create(42.0); + Assert.Equal(VarEnum.VT_R8, variant.VarType); + Assert.Equal(42, variant.As()); + Assert.Equal(42, variant.GetRawDataRef()); + } + +#pragma warning disable CS0618 // Type or member is obsolete + [Fact] + public void Currency() + { + ComVariant variant = ComVariant.Create(new CurrencyWrapper(42.0m)); + Assert.Equal(VarEnum.VT_CY, variant.VarType); + Assert.Equal(42.0m, variant.As().WrappedObject); + Assert.Equal(decimal.ToOACurrency(42.0m), variant.GetRawDataRef()); + } +#pragma warning restore CS0618 // Type or member is obsolete + + [Fact] + public void Date() + { + ComVariant variant = ComVariant.Create(new DateTime(2020, 1, 1)); + Assert.Equal(VarEnum.VT_DATE, variant.VarType); + Assert.Equal(new DateTime(2020, 1, 1), variant.As()); + Assert.Equal(new DateTime(2020, 1, 1).ToOADate(), variant.GetRawDataRef()); + } + + [Fact] + public void BStrWrapper() + { + using ComVariant variant = ComVariant.Create(new BStrWrapper("Foo")); + Assert.Equal(VarEnum.VT_BSTR, variant.VarType); + Assert.Equal("Foo", variant.As().WrappedObject); + Assert.Equal("Foo", Marshal.PtrToStringBSTR(variant.GetRawDataRef())); + } + + [Fact] + public void BStr_String() + { + using ComVariant variant = ComVariant.Create("Foo"); + Assert.Equal(VarEnum.VT_BSTR, variant.VarType); + Assert.Equal("Foo", variant.As()); + Assert.Equal("Foo", Marshal.PtrToStringBSTR(variant.GetRawDataRef())); + } + + [Fact] + public void BStr_String_Null() + { + using ComVariant variant = ComVariant.Create(null); + Assert.Equal(VarEnum.VT_BSTR, variant.VarType); + Assert.Null(variant.As()); + Assert.Equal(IntPtr.Zero, variant.GetRawDataRef()); + } + +#if WINDOWS + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsBuiltInComEnabled))] + public void Dispatch_NotSupported() + { + DispatchWrapper wrapper = new(new IDispatchComObject()); + Assert.Throws("T", () => ComVariant.Create(wrapper)); + } +#endif + + [Fact] + public void Error() + { + ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_ERROR, 1); + Assert.Equal(VarEnum.VT_ERROR, variant.VarType); + Assert.Equal(1, variant.GetRawDataRef()); + Assert.Equal(1, variant.As().ErrorCode); + Assert.Equal(1, variant.As()); + } + + [Fact] + public void VariantBoolTrue() + { + ComVariant trueVariant = ComVariant.Create(true); + Assert.Equal(VarEnum.VT_BOOL, trueVariant.VarType); + Assert.True(trueVariant.As()); + Assert.Equal(-1, trueVariant.GetRawDataRef()); + } + + [Fact] + public void VariantBoolFalse() + { + ComVariant falseVariant = ComVariant.Create(false); + Assert.Equal(VarEnum.VT_BOOL, falseVariant.VarType); + Assert.False(falseVariant.As()); + Assert.Equal(0, falseVariant.GetRawDataRef()); + } + + [Fact] + public void VTVariantNotSupported() + { + Assert.Throws("vt", () => ComVariant.CreateRaw(VarEnum.VT_VARIANT, 1)); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsBuiltInComEnabled))] + public void Unknown_NotSupported() + { + UnknownWrapper wrapper = new(new TestObject()); + Assert.Throws("T", () => ComVariant.Create(wrapper)); + } + + [ComImport] + [Guid("9FBB5303-ED8B-448D-8174-571D03E1D947")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IUnknownInterface + { + } + + private sealed class TestObject : IUnknownInterface + { + } + + [Fact] + public void Decimal() + { + ComVariant variant = ComVariant.Create(42.0m); + Assert.Equal(VarEnum.VT_DECIMAL, variant.VarType); + Assert.Equal(42.0m, variant.As()); + Assert.ThrowsAny(() => variant.GetRawDataRef()); + } + + [Fact] + public void SByte() + { + ComVariant variant = ComVariant.Create(42); + Assert.Equal(VarEnum.VT_I1, variant.VarType); + Assert.Equal(42, variant.As()); + Assert.Equal(42, variant.GetRawDataRef()); + } + + [Fact] + public void Byte() + { + ComVariant variant = ComVariant.Create(42); + Assert.Equal(VarEnum.VT_UI1, variant.VarType); + Assert.Equal(42, variant.As()); + Assert.Equal(42, variant.GetRawDataRef()); + } + + [Fact] + public void UShort() + { + ComVariant variant = ComVariant.Create(42); + Assert.Equal(VarEnum.VT_UI2, variant.VarType); + Assert.Equal(42, variant.As()); + Assert.Equal(42, variant.GetRawDataRef()); + } + + [Fact] + public void UInt4() + { + ComVariant variant = ComVariant.Create(42); + Assert.Equal(VarEnum.VT_UI4, variant.VarType); + Assert.Equal(42u, variant.As()); + Assert.Equal(42u, variant.GetRawDataRef()); + } + + [Fact] + public void Long() + { + ComVariant variant = ComVariant.Create(42); + Assert.Equal(VarEnum.VT_I8, variant.VarType); + Assert.Equal(42, variant.As()); + Assert.Equal(42, variant.GetRawDataRef()); + } + + [Fact] + public void ULong() + { + ComVariant variant = ComVariant.Create(42); + Assert.Equal(VarEnum.VT_UI8, variant.VarType); + Assert.Equal(42ul, variant.As()); + Assert.Equal(42ul, variant.GetRawDataRef()); + } + + [Fact] + public void Int_Raw() + { + ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_INT, 42); + Assert.Equal(VarEnum.VT_INT, variant.VarType); + Assert.Equal(42, variant.As()); + Assert.Equal(42, variant.GetRawDataRef()); + } + + [Fact] + public void UInt() + { + ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_UINT, 42u); + Assert.Equal(VarEnum.VT_UINT, variant.VarType); + Assert.Equal(42u, variant.As()); + Assert.Equal(42u, variant.GetRawDataRef()); + } + + [StructLayout(LayoutKind.Sequential)] + private struct Record + { + private IntPtr _typeDesc; + private IntPtr _data; + } + + [Fact] + public void Record_Raw() + { + // We do not support record types in the opinionated Create method. + Assert.Throws("T", () => ComVariant.Create(new Record())); + // We support creating a record-based variant with the CreateRaw method. + ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_RECORD, new Record()); + Assert.Equal(VarEnum.VT_RECORD, variant.VarType); + Assert.Equal(default, variant.GetRawDataRef()); + } + + [Fact] + public void LPStr_Raw() + { + string str = "Foo"; + using ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_LPSTR, Marshal.StringToCoTaskMemAnsi(str)); + Assert.Equal(VarEnum.VT_LPSTR, variant.VarType); + Assert.Throws(variant.As); + Assert.Equal(str, Marshal.PtrToStringAnsi(variant.GetRawDataRef())); + } + + [Fact] + public void LPWStr_Raw() + { + string str = "Foo"; + using ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_LPWSTR, Marshal.StringToCoTaskMemUni(str)); + Assert.Equal(VarEnum.VT_LPWSTR, variant.VarType); + Assert.Throws(variant.As); + Assert.Equal(str, Marshal.PtrToStringUni(variant.GetRawDataRef())); + } + + [Fact] + public void FileTime_Raw() + { + long fileTime = DateTime.Now.ToFileTime(); + ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_FILETIME, fileTime); + Assert.Equal(VarEnum.VT_FILETIME, variant.VarType); + Assert.Throws(() => variant.As()); + Assert.Equal(fileTime, variant.GetRawDataRef()); + } + + [StructLayout(LayoutKind.Sequential)] + private struct Blob + { + public int Length; + public IntPtr Data; + } + + [Fact] + public void Blob_Raw() + { + Blob blob = new Blob { Length = 3, Data = Marshal.AllocCoTaskMem(25) }; + using ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_BLOB, blob); + Assert.Equal(VarEnum.VT_BLOB, variant.VarType); + Assert.Throws("T", () => variant.As()); + Assert.Equal(blob, variant.GetRawDataRef()); + } + + [Fact] + public void Stream_Raw() + { + IntPtr nativeStream = 42; + // Using a fake value so we aren't disposing the ComVariant instance. + ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_STREAM, nativeStream); + Assert.Equal(VarEnum.VT_STREAM, variant.VarType); + Assert.Equal(nativeStream, variant.GetRawDataRef()); + } + + [Fact] + public void Storage_Raw() + { + IntPtr nativeStorage = 42; + // Using a fake value so we aren't disposing the ComVariant instance. + ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_STORAGE, nativeStorage); + Assert.Equal(VarEnum.VT_STORAGE, variant.VarType); + Assert.Equal(nativeStorage, variant.GetRawDataRef()); + } + + [Fact] + public void StreamedObject_Raw() + { + IntPtr nativeStream = 42; + // Using a fake value so we aren't disposing the ComVariant instance. + ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_STREAMED_OBJECT, nativeStream); + Assert.Equal(VarEnum.VT_STREAMED_OBJECT, variant.VarType); + Assert.Equal(nativeStream, variant.GetRawDataRef()); + } + + [Fact] + public void StoredObject_Raw() + { + IntPtr nativeStorage = 42; + // Using a fake value so we aren't disposing the ComVariant instance. + ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_STORED_OBJECT, nativeStorage); + Assert.Equal(VarEnum.VT_STORED_OBJECT, variant.VarType); + Assert.Equal(nativeStorage, variant.GetRawDataRef()); + } + + [Fact] + public void VersionedStream_Raw() + { + IntPtr nativeStream = 42; + // Using a fake value so we aren't disposing the ComVariant instance. + ComVariant variant = ComVariant.CreateRaw((VarEnum)73, nativeStream); + Assert.Equal((VarEnum)73, variant.VarType); + Assert.Equal(nativeStream, variant.GetRawDataRef()); + } + + [Fact] + public void BlobObject_Raw() + { + Blob blob = new Blob { Length = 3, Data = Marshal.AllocCoTaskMem(10) }; + using ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_BLOB_OBJECT, blob); + Assert.Equal(VarEnum.VT_BLOB_OBJECT, variant.VarType); + Assert.Throws("T", () => variant.As()); + Assert.Equal(blob, variant.GetRawDataRef()); + } + + [StructLayout(LayoutKind.Sequential)] + private unsafe struct ClipboardData + { + public uint _size; + public int _format; + public IntPtr _data; + } + + [Fact] + public unsafe void ClipData_Raw() + { + // Construct a valid clipboard data structure + // so we can validate the Clear/Dispose logic. + IntPtr clipboardData = Marshal.AllocCoTaskMem(sizeof(ClipboardData)); + ((ClipboardData*)clipboardData)->_data = Marshal.AllocCoTaskMem(10); + ((ClipboardData*)clipboardData)->_size = 10; + ((ClipboardData*)clipboardData)->_format = 1; + + using ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_CF, clipboardData); + Assert.Equal(VarEnum.VT_CF, variant.VarType); + Assert.Equal(clipboardData, variant.GetRawDataRef()); + } + + [Fact] + public unsafe void Clsid_Raw() + { + // VT_CLSID is represented as a pointer to a GUID, not a GUID itself. + IntPtr pClsid = Marshal.AllocCoTaskMem(sizeof(Guid)); + *(Guid*)pClsid = Guid.NewGuid(); + using ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_CLSID, pClsid); + Assert.Equal(VarEnum.VT_CLSID, variant.VarType); + Assert.Equal(pClsid, variant.GetRawDataRef()); + } + + [StructLayout(LayoutKind.Sequential)] + private struct Vector + { + public int Length; + public IntPtr Data; + } + + [Fact] + public void Vector_Raw() + { + Vector vector = new Vector { Length = 3, Data = Marshal.AllocCoTaskMem(sizeof(int) * 3) }; + using ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_VECTOR | VarEnum.VT_I4, vector); + Assert.Equal(VarEnum.VT_VECTOR | VarEnum.VT_I4, variant.VarType); + Assert.Throws("T", () => variant.As()); + Assert.Equal(vector, variant.GetRawDataRef()); + } + + [Fact] + [PlatformSpecific(TestPlatforms.Windows)] + public void Array_Raw() + { + IntPtr safeArray = 42; + // Using a fake value so we aren't disposing the ComVariant instance. + ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_ARRAY | VarEnum.VT_I4, safeArray); + Assert.Equal(VarEnum.VT_ARRAY | VarEnum.VT_I4, variant.VarType); + Assert.Equal(safeArray, variant.GetRawDataRef()); + } + + [Fact] + [PlatformSpecific(~TestPlatforms.Windows)] + public void Array_Raw_NonWindows() + { + Assert.Throws(() => ComVariant.CreateRaw(VarEnum.VT_ARRAY | VarEnum.VT_I4, 0)); + } + + [Fact] + public void ByRef_Raw() + { + // byref VARIANTs don't own the memory they point to. + IntPtr byref = Marshal.AllocCoTaskMem(4); + using ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_BYREF | VarEnum.VT_I4, byref); + Assert.Equal(VarEnum.VT_BYREF | VarEnum.VT_I4, variant.VarType); + Assert.Equal(byref, variant.GetRawDataRef()); + Marshal.FreeCoTaskMem(byref); + } + + [InlineArray(5)] + private struct InvalidSize + { + private byte _b; + } + + // Test a variety of types to validate the size check. + [InlineData(VarEnum.VT_I1)] + [InlineData(VarEnum.VT_UI1)] + [InlineData(VarEnum.VT_I2)] + [InlineData(VarEnum.VT_UI2)] + [InlineData(VarEnum.VT_I4)] + [InlineData(VarEnum.VT_UI4)] + [InlineData(VarEnum.VT_I8)] + [InlineData(VarEnum.VT_UI8)] + [InlineData(VarEnum.VT_R4)] + [InlineData(VarEnum.VT_R8)] + [InlineData(VarEnum.VT_BOOL)] + [InlineData(VarEnum.VT_BLOB)] + [InlineData(VarEnum.VT_BYREF | VarEnum.VT_I4)] + [InlineData(VarEnum.VT_UNKNOWN)] + [Theory] + public void Raw_WrongSize(VarEnum vt) + { + // A 5-byte struct is never a valid size for a variant type. + Assert.Throws(() => ComVariant.CreateRaw(vt, new InvalidSize())); + } + + [InlineData(VarEnum.VT_INT)] + [InlineData(VarEnum.VT_UINT)] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))] + public void Raw_Int_WrongSize(VarEnum vt) + { + Assert.Throws(() => ComVariant.CreateRaw(vt, (nint)42)); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/Variant.cs b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/Variant.cs new file mode 100644 index 0000000000000..7ad1218f6f3ec --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/Variant.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +using System.Runtime.Versioning; +using System.Text; +using System.Threading.Tasks; + +namespace NativeExports +{ + public static unsafe class Variant + { + [UnmanagedCallersOnly(EntryPoint = "get_variant_bstr_length")] + public static int GetVTBStrLength([DNNE.C99Type("void*")] ComVariant* variant) + { + return variant->As().Length; + } + } +}