From 40d27a8af15d942e62924446f9e3c6a8f5509107 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Wed, 11 Oct 2023 17:24:07 -0700 Subject: [PATCH 01/20] Add initial implementation of OleVariant struct. --- .../System.Private.CoreLib.Shared.projitems | 6 +- .../InteropServices/Marshalling/OleVariant.cs | 361 ++++++++++++++++++ 2 files changed, 366 insertions(+), 1 deletion(-) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/OleVariant.cs 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 2b774a2f4fd550..21184e0e42b2ef 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 @@ -979,6 +979,7 @@ + @@ -2049,6 +2050,9 @@ Common\Interop\Windows\Ole32\Interop.CoTaskMemAlloc.cs + + Common\Interop\Windows\Ole32\Interop.PropVariantClear.cs + Common\Interop\Windows\Secur32\Interop.GetUserNameExW.cs @@ -2719,4 +2723,4 @@ - + \ No newline at end of file diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/OleVariant.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/OleVariant.cs new file mode 100644 index 00000000000000..df7f16cbe50c2b --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/OleVariant.cs @@ -0,0 +1,361 @@ +// 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 +{ + [StructLayout(LayoutKind.Explicit)] + public struct OleVariant : IDisposable + { +#if DEBUG + unsafe static OleVariant() + { + // 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 = sizeof(OleVariant); + 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 Currency _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; + } + + public unsafe void Dispose() + { +#if TARGET_WINDOWS + fixed (void* pThis = &this) + { + Interop.Ole32.PropVariantClear((nint)pThis); + } +#else + // TODO: Replicate the behavior of PropVariantClear on non-Windows platforms. + throw new NotImplementedException(); +#endif + } + +#pragma warning disable CS0618 // We support the obsolete *Wrapper types + public static OleVariant Create([DisallowNull] T value) + { + Unsafe.SkipInit(out OleVariant 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 = new Currency(((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(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) ? (short)-1 : (short)0; + } + 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("Unsupported type", 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 string to any VT_* type directly as there are multiple equally valid options. + // We do not map VT_BYREF automatically, nor do we map any of the array types. + return variant; + } +#pragma warning restore CS0618 + + public static unsafe OleVariant CreateRaw(VarEnum vt, T rawValue) + where T : unmanaged + { + ArgumentOutOfRangeException.ThrowIfGreaterThan(Unsafe.SizeOf(), sizeof(UnionTypes), nameof(T)); + if (vt == VarEnum.VT_DECIMAL) + { + throw new ArgumentException("VT_DECIMAL is not supported in CreateRaw. Use the Create method.", nameof(vt)); + } + if (vt == VarEnum.VT_VARIANT) + { + throw new ArgumentException("VT_VARIANT is not supported in variants.", nameof(vt)); + } + + Unsafe.SkipInit(out OleVariant 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, 4) => rawValue, + (VarEnum.VT_I8 or VarEnum.VT_UI8 or VarEnum.VT_R8 or VarEnum.VT_DATE, 8) => rawValue, + (VarEnum.VT_INT or VarEnum.VT_UINT or 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_CARRAY, _) 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) == nint.Size => rawValue, + _ when vt.HasFlag(VarEnum.VT_ARRAY) && sizeof(T) == nint.Size => rawValue, + (VarEnum.VT_CLSID, _) when sizeof(T) == sizeof(Guid) => rawValue, + _ => throw new ArgumentException("Size of T should be the same size as the value specified by vt") + }; + + return value; + } + + public static OleVariant Null { get; } = new() { VarType = VarEnum.VT_NULL }; + + private readonly void ThrowIfNotVarType(params VarEnum[] requiredType) + { + if (Array.IndexOf(requiredType, VarType) != -1) + { + throw new InvalidOperationException($"Variant type {VarType} cannot be cast to {requiredType}"); + } + } + +#pragma warning disable CS0618 // Type or member is obsolete + // This method will match the exact same semantics as Create with the same set of supported types. + 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); + 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(new decimal(_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(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 != 0); + } + 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. + OleVariant 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); + 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("Unsupported type", nameof(T)); + } +#pragma warning restore CS0618 // Type or member is obsolete + + public VarEnum VarType + { + readonly get => (VarEnum)_typeUnion._vt; + private set => _typeUnion._vt = (ushort)value; + } + + [UnscopedRef] + public unsafe ref T GetRawDataRef() + where T : unmanaged + { + ArgumentOutOfRangeException.ThrowIfGreaterThan(Unsafe.SizeOf(), sizeof(UnionTypes), nameof(T)); + return ref Unsafe.As(ref _typeUnion._unionTypes); + } + } +} From 2c574cd714275ee468ba055fd8e3e37d74a8736e Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 16 Oct 2023 13:20:00 -0700 Subject: [PATCH 02/20] Finish implementation of OleVariant, add unit tests, and use it in CoreLib and Microsoft.CSharp. Remove the prior internal Variant type that covered this scenario. --- .../System.Private.CoreLib.csproj | 4 +- .../EnumerableViewOfDispatch.cs | 5 +- .../Runtime/CompilerHelpers/InteropHelpers.cs | 5 +- .../src/System.Private.CoreLib.csproj | 4 +- .../Runtime/InteropServices/Marshal.Com.cs | 138 ++-- .../BuiltInVariantExtensions.cs | 178 +++++ .../Runtime/InteropServices/ComEventsSink.cs | 23 +- .../System/Runtime/InteropServices/Variant.cs | 715 ------------------ .../src/Microsoft.CSharp.csproj | 24 +- .../ComInterop/ComInvokeBinder.cs | 9 +- .../ComInterop/ComRuntimeHelpers.cs | 19 +- .../ComInterop/DynamicVariantExtensions.cs | 446 +++++++++++ .../ComInterop/VarEnumSelector.cs | 8 +- .../ComInterop/Variant.Extended.cs | 319 -------- .../RuntimeBinder/ComInterop/VariantArray.cs | 17 +- .../ComInterop/VariantBuilder.cs | 33 +- .../InteropServices/Marshalling/OleVariant.cs | 198 ++++- .../ref/System.Runtime.InteropServices.cs | 13 + ...ystem.Runtime.InteropServices.Tests.csproj | 1 + .../InteropServices/OleVariantTests.cs | 459 +++++++++++ 20 files changed, 1417 insertions(+), 1201 deletions(-) create mode 100644 src/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs delete mode 100644 src/libraries/Common/src/System/Runtime/InteropServices/Variant.cs create mode 100644 src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/DynamicVariantExtensions.cs delete mode 100644 src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/Variant.Extended.cs create mode 100644 src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/OleVariantTests.cs diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj index 20073739b2bbd0..818f666415430e 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 fa94eefcfb6a8d..0df8c60c312488 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; + OleVariant 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 faacce2ea5d14b..153f4c22d4e7aa 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(); + OleVariant* data = (OleVariant*)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 8f45dd1a4d5b92..737594d0a98f3f 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 @@ -257,8 +257,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 18828c7ad17f78..f3de62c3666de3 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; + OleVariant* data = (OleVariant*)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 = OleVariant.Create(value); break; case string value: - data->AsBstr = value; + *data = OleVariant.Create(new BStrWrapper(value)); break; case bool value: - data->AsBool = value; + *data = OleVariant.Create(value); break; case byte value: - data->AsUi1 = value; + *data = OleVariant.Create(value); break; case sbyte value: - data->AsI1 = value; + *data = OleVariant.Create(value); break; case short value: - data->AsI2 = value; + *data = OleVariant.Create(value); break; case ushort value: - data->AsUi2 = value; + *data = OleVariant.Create(value); break; case uint value: - data->AsUi4 = value; + *data = OleVariant.Create(value); break; case long value: - data->AsI8 = value; + *data = OleVariant.Create(value); break; case ulong value: - data->AsUi8 = value; + *data = OleVariant.Create(value); break; case float value: - data->AsR4 = value; + *data = OleVariant.Create(value); break; case double value: - data->AsR8 = value; + *data = OleVariant.Create(value); break; case DateTime value: - data->AsDate = value; + *data = OleVariant.Create(value); break; case decimal value: - data->AsDecimal = value; + *data = OleVariant.Create(value); break; case char value: - data->AsUi2 = value; + *data = OleVariant.Create(value); break; case BStrWrapper value: - data->AsBstr = value.WrappedObject; + *data = OleVariant.Create(value); break; #pragma warning disable 0618 // CurrencyWrapper is obsolete case CurrencyWrapper value: - data->AsCy = value.WrappedObject; + *data = OleVariant.Create(value); break; #pragma warning restore 0618 case UnknownWrapper value: - data->AsUnknown = value.WrappedObject; + *data = OleVariant.CreateRaw(VarEnum.VT_UNKNOWN, GetIUnknownForObject(value.WrappedObject)); break; case DispatchWrapper value: - data->AsDispatch = value.WrappedObject; + *data = OleVariant.CreateRaw(VarEnum.VT_DISPATCH, GetIDispatchForObject(value.WrappedObject)); break; case ErrorWrapper value: - data->AsError = value.ErrorCode; + *data = OleVariant.Create(value); break; case VariantWrapper value: throw new ArgumentException(); case DBNull value: - data->SetAsNULL(); + *data = OleVariant.Null; break; case Missing value: - data->AsError = DISP_E_PARAMNOTFOUND; + *data = OleVariant.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 = OleVariant.CreateRaw(VarEnum.VT_UNKNOWN, GetIUnknownForObject(value)); break; case TypeCode.DBNull: - data->SetAsNULL(); + *data = OleVariant.Null; break; case TypeCode.Boolean: - data->AsBool = value.ToBoolean(null); + *data = OleVariant.Create(value.ToBoolean(null)); break; case TypeCode.Char: - data->AsUi2 = value.ToChar(null); + *data = OleVariant.Create(value.ToChar(null)); break; case TypeCode.SByte: - data->AsI1 = value.ToSByte(null); + *data = OleVariant.Create(value.ToSByte(null)); break; case TypeCode.Byte: - data->AsUi1 = value.ToByte(null); + *data = OleVariant.Create(value.ToByte(null)); break; case TypeCode.Int16: - data->AsI2 = value.ToInt16(null); + *data = OleVariant.Create(value.ToInt16(null)); break; case TypeCode.UInt16: - data->AsUi2 = value.ToUInt16(null); + *data = OleVariant.Create(value.ToUInt16(null)); break; case TypeCode.Int32: - data->AsI4 = value.ToInt32(null); + *data = OleVariant.Create(value.ToInt32(null)); break; case TypeCode.UInt32: - data->AsUi4 = value.ToUInt32(null); + *data = OleVariant.Create(value.ToUInt32(null)); break; case TypeCode.Int64: - data->AsI8 = value.ToInt64(null); + *data = OleVariant.Create(value.ToInt64(null)); break; case TypeCode.UInt64: - data->AsUi8 = value.ToUInt64(null); + *data = OleVariant.Create(value.ToUInt64(null)); break; case TypeCode.Single: - data->AsR4 = value.ToSingle(null); + *data = OleVariant.Create(value.ToSingle(null)); break; case TypeCode.Double: - data->AsR8 = value.ToDouble(null); + *data = OleVariant.Create(value.ToDouble(null)); break; case TypeCode.Decimal: - data->AsDecimal = value.ToDecimal(null); + *data = OleVariant.Create(value.ToDecimal(null)); break; case TypeCode.DateTime: - data->AsDate = value.ToDateTime(null); + *data = OleVariant.Create(value.ToDateTime(null)); break; case TypeCode.String: - data->AsBstr = value.ToString(); + *data = OleVariant.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 = OleVariant.CreateRaw(VarEnum.VT_UNKNOWN, GetIDispatchForObject(obj)); break; } } @@ -303,38 +304,35 @@ public static object GetObjectForIUnknown(IntPtr pUnk) { ArgumentNullException.ThrowIfNull(pSrcNativeVariant); - Variant* data = (Variant*)pSrcNativeVariant; + OleVariant* data = (OleVariant*)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/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs b/src/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs new file mode 100644 index 00000000000000..bdd0a36ca8630b --- /dev/null +++ b/src/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs @@ -0,0 +1,178 @@ +// 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 + { + private static unsafe ref T GetByRefDataRef(this ref OleVariant 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 OleVariant 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) + { + OleVariant 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_TRUE = -1 + // VARIANT_FALSE = 0 + variant.GetByRefDataRef() = (bool)value ? (short)-1 : (short)0; + 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 OleVariant variant) + { + // Check the simple case upfront + if (variant.VarType == VarEnum.VT_EMPTY) + { + return null; + } + + switch (variant.VarType) + { + case VarEnum.VT_NULL: + return DBNull.Value; + + case VarEnum.VT_I1: return variant.As(); + case VarEnum.VT_I2: return variant.As(); + case VarEnum.VT_I4: return variant.As(); + case VarEnum.VT_I8: return variant.As(); + case VarEnum.VT_UI1: return variant.As(); + case VarEnum.VT_UI2: return variant.As(); + case VarEnum.VT_UI4: return variant.As(); + case VarEnum.VT_UI8: return variant.As(); + case VarEnum.VT_INT: return variant.As(); + case VarEnum.VT_UINT: return variant.As(); + case VarEnum.VT_BOOL: return variant.As() != -1; + case VarEnum.VT_ERROR: return variant.As(); + case VarEnum.VT_R4: return variant.As(); + case VarEnum.VT_R8: return variant.As(); + case VarEnum.VT_DECIMAL: return variant.As(); + case VarEnum.VT_CY: return decimal.FromOACurrency(variant.GetRawDataRef()); + case VarEnum.VT_DATE: return variant.As(); + case VarEnum.VT_BSTR: return Marshal.PtrToStringBSTR(variant.GetRawDataRef()); + case VarEnum.VT_UNKNOWN: return Marshal.GetObjectForIUnknown(variant.GetRawDataRef()); + case VarEnum.VT_DISPATCH: return Marshal.GetObjectForIUnknown(variant.GetRawDataRef()); + + default: + unsafe + { + fixed (void* pThis = &variant) + { + return Marshal.GetObjectForNativeVariant((nint)pThis); + } + } + } + } + } +} diff --git a/src/libraries/Common/src/System/Runtime/InteropServices/ComEventsSink.cs b/src/libraries/Common/src/System/Runtime/InteropServices/ComEventsSink.cs index 3747e2f331b4b4..de40f7cb44e62f 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 OleVariant GetVariant(ref OleVariant 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 OleVariant pByRefVariant = ref *(OleVariant*)(pSrc.GetRawDataRef().ToPointer()); + if ((pByRefVariant.VarType & VT_BYREF_TYPEMASK) == VT_BYREF_VARIANT) { - return ref pByRefVariant[0]; + return ref pByRefVariant; } } @@ -163,7 +164,7 @@ unsafe void IDispatch.Invoke( 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 @@ unsafe void IDispatch.Invoke( for (i = 0; i < pDispParams.cNamedArgs; i++) { pos = namedArgs[i]; - ref Variant pvar = ref GetVariant(ref vars[i]); + ref OleVariant 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 @@ unsafe void IDispatch.Invoke( pos++; } - ref Variant pvar = ref GetVariant(ref vars[pDispParams.cArgs - 1 - i]); + ref OleVariant 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 @@ unsafe void IDispatch.Invoke( continue; } - ref Variant pvar = ref GetVariant(ref vars[idxToPos]); + ref OleVariant 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 2af1f942acee68..00000000000000 --- 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/src/Microsoft.CSharp.csproj b/src/libraries/Microsoft.CSharp/src/Microsoft.CSharp.csproj index 3be4e969da5a7d..9388bfa98b91e7 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 9052ad6d7a0afb..c7fdf50c4e2315 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(OleVariant), "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(OleVariant).GetMethod(nameof(OleVariant.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 114b869124aff7..2558451d769d41 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 OleVariant value) { return (IntPtr)System.Runtime.CompilerServices.Unsafe.AsPointer(ref value); } - internal static Variant GetVariantForObject(object obj) + internal static OleVariant GetVariantForObject(object obj) { - Variant variant = default; + OleVariant 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 OleVariant 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 = OleVariant.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(OleVariant variant) { IntPtr ptr = UnsafeMethods.ConvertVariantByrefToPtr(ref variant); return Marshal.GetObjectForNativeVariant(ptr); @@ -287,18 +288,18 @@ public static unsafe int IDispatchInvoke( int memberDispId, ComTypes.INVOKEKIND flags, ref ComTypes.DISPPARAMS dispParams, - out Variant result, + out OleVariant result, out ExcepInfo excepInfo, out uint argErr) { Guid IID_NULL = default; fixed (ComTypes.DISPPARAMS* pDispParams = &dispParams) - fixed (Variant* pResult = &result) + fixed (OleVariant* 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 00000000000000..8d962caa403661 --- /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 OleVariant 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 = OleVariant.CreateRaw(VarEnum.VT_UNKNOWN, Marshal.GetIUnknownForObject(value)); break; + case TypeCode.DBNull: variant = OleVariant.Null; break; + case TypeCode.Boolean: variant = OleVariant.Create(value.ToBoolean(ci)); break; + case TypeCode.Char: variant = OleVariant.Create(value.ToChar(ci)); break; + case TypeCode.SByte: variant = OleVariant.Create(value.ToSByte(ci)); break; + case TypeCode.Byte: variant = OleVariant.Create(value.ToByte(ci)); break; + case TypeCode.Int16: variant = OleVariant.Create(value.ToInt16(ci)); break; + case TypeCode.UInt16: variant = OleVariant.Create(value.ToUInt16(ci)); break; + case TypeCode.Int32: variant = OleVariant.Create(value.ToInt32(ci)); break; + case TypeCode.UInt32: variant = OleVariant.Create(value.ToUInt32(ci)); break; + case TypeCode.Int64: variant = OleVariant.Create(value.ToInt64(ci)); break; + case TypeCode.UInt64: variant = OleVariant.Create(value.ToInt64(ci)); break; + case TypeCode.Single: variant = OleVariant.Create(value.ToSingle(ci)); break; + case TypeCode.Double: variant = OleVariant.Create(value.ToDouble(ci)); break; + case TypeCode.Decimal: variant = OleVariant.Create(value.ToDecimal(ci)); break; + case TypeCode.DateTime: variant = OleVariant.Create(value.ToDateTime(ci)); break; + case TypeCode.String: variant = OleVariant.Create(new BStrWrapper(value.ToString(ci))); break; + + default: + throw new NotSupportedException(); + } + } + // VT_I1 + + public static void SetAsByrefI1(ref this OleVariant variant, ref sbyte value) + { + variant.SetAsByref(ref value, VarEnum.VT_I1); + } + + // VT_I2 + + public static void SetAsByrefI2(ref this OleVariant variant, ref short value) + { + variant.SetAsByref(ref value, VarEnum.VT_I2); + } + + // VT_I4 + + public static void SetAsByrefI4(ref this OleVariant variant, ref int value) + { + variant.SetAsByref(ref value, VarEnum.VT_I4); + } + + // VT_I8 + + public static void SetAsByrefI8(ref this OleVariant variant, ref long value) + { + variant.SetAsByref(ref value, VarEnum.VT_I8); + } + + // VT_UI1 + + public static void SetAsByrefUi1(ref this OleVariant variant, ref byte value) + { + variant.SetAsByref(ref value, VarEnum.VT_UI1); + } + + // VT_UI2 + + public static void SetAsByrefUi2(ref this OleVariant variant, ref ushort value) + { + variant.SetAsByref(ref value, VarEnum.VT_UI2); + } + + // VT_UI4 + + public static void SetAsByrefUi4(ref this OleVariant variant, ref uint value) + { + variant.SetAsByref(ref value, VarEnum.VT_UI4); + } + + // VT_UI8 + + public static void SetAsByrefUi8(ref this OleVariant variant, ref ulong value) + { + variant.SetAsByref(ref value, VarEnum.VT_UI8); + } + + // VT_INT + + public static void SetAsByrefInt(ref this OleVariant variant, ref int value) + { + variant.SetAsByref(ref value, VarEnum.VT_INT); + } + + // VT_UINT + + public static void SetAsByrefUint(ref this OleVariant variant, ref uint value) + { + variant.SetAsByref(ref value, VarEnum.VT_UINT); + } + + // VT_BOOL + + public static void SetAsByrefBool(ref this OleVariant variant, ref short value) + { + variant.SetAsByref(ref value, VarEnum.VT_BOOL); + } + + // VT_ERROR + + public static void SetAsByrefError(ref this OleVariant variant, ref int value) + { + variant.SetAsByref(ref value, VarEnum.VT_ERROR); + } + + // VT_R4 + + public static void SetAsByrefR4(ref this OleVariant variant, ref float value) + { + variant.SetAsByref(ref value, VarEnum.VT_R4); + } + + // VT_R8 + + public static void SetAsByrefR8(ref this OleVariant variant, ref double value) + { + variant.SetAsByref(ref value, VarEnum.VT_R8); + } + + // VT_DECIMAL + + public static void SetAsByrefDecimal(ref this OleVariant variant, ref decimal value) + { + variant.SetAsByref(ref value, VarEnum.VT_DECIMAL); + } + + // VT_CY + + public static void SetAsByrefCy(ref this OleVariant variant, ref long value) + { + variant.SetAsByref(ref value, VarEnum.VT_CY); + } + + // VT_DATE + + public static void SetAsByrefDate(ref this OleVariant variant, ref double value) + { + variant.SetAsByref(ref value, VarEnum.VT_DATE); + } + + // VT_BSTR + + public static void SetAsByrefBstr(ref this OleVariant variant, ref IntPtr value) + { + variant.SetAsByref(ref value, VarEnum.VT_BSTR); + } + + // VT_UNKNOWN + + public static void SetAsByrefUnknown(ref this OleVariant variant, ref IntPtr value) + { + variant.SetAsByref(ref value, VarEnum.VT_UNKNOWN); + } + + // VT_DISPATCH + + public static void SetAsByrefDispatch(ref this OleVariant variant, ref IntPtr value) + { + variant.SetAsByref(ref value, VarEnum.VT_DISPATCH); + } + + private static unsafe void SetAsByref(ref this OleVariant 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 = OleVariant.CreateRaw(type | VarEnum.VT_BYREF, (nint)Unsafe.AsPointer(ref value)); + } + + public static void SetAsByrefVariant(ref this OleVariant variant, ref OleVariant 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(this OleVariant variant, ref OleVariant 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 = OleVariant.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 = OleVariant.CreateRaw(value.VarType | VarEnum.VT_BYREF, (nint)Unsafe.AsPointer(ref value)); + break; + default: + variant = OleVariant.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 OleVariant variant, sbyte value) + { + variant = OleVariant.Create(value); + } + + public static void SetUi1(this ref OleVariant variant, byte value) + { + variant = OleVariant.Create(value); + } + + public static void SetI2(this ref OleVariant variant, short value) + { + variant = OleVariant.Create(value); + } + + public static void SetUi2(this ref OleVariant variant, ushort value) + { + variant = OleVariant.Create(value); + } + + public static void SetI4(this ref OleVariant variant, int value) + { + variant = OleVariant.Create(value); + } + + public static void SetUi4(this ref OleVariant variant, uint value) + { + variant = OleVariant.Create(value); + } + + public static void SetI8(this ref OleVariant variant, long value) + { + variant = OleVariant.Create(value); + } + + public static void SetUi8(this ref OleVariant variant, ulong value) + { + variant = OleVariant.Create(value); + } + + public static void SetInt(this ref OleVariant variant, int value) + { + variant = OleVariant.CreateRaw(VarEnum.VT_INT, value); + } + + public static void SetUint(this ref OleVariant variant, uint value) + { + variant = OleVariant.CreateRaw(VarEnum.VT_UINT, value); + } + + public static void SetBool(this ref OleVariant variant, bool value) + { + variant = OleVariant.Create(value); + } + + public static void SetR4(this ref OleVariant variant, float value) + { + variant = OleVariant.Create(value); + } + + public static void SetR8(this ref OleVariant variant, double value) + { + variant = OleVariant.Create(value); + } + + public static void SetDecimal(this ref OleVariant variant, decimal value) + { + variant = OleVariant.Create(value); + } + + public static void SetDate(this ref OleVariant variant, DateTime value) + { + variant = OleVariant.Create(value); + } + + public static void SetBstr(this ref OleVariant variant, string value) + { + variant = OleVariant.Create(new BStrWrapper(value)); + } + + public static void SetUnknown(this ref OleVariant variant, object value) + { + variant = OleVariant.CreateRaw(VarEnum.VT_UNKNOWN, Marshal.GetIUnknownForObject(value)); + } + + public static void SetDispatch(this ref OleVariant variant, object value) + { + variant = OleVariant.CreateRaw(VarEnum.VT_DISPATCH, Marshal.GetIDispatchForObject(value)); + } + + public static void SetError(this ref OleVariant variant, int value) + { + variant = OleVariant.CreateRaw(VarEnum.VT_ERROR, value); + } + + public static void SetCy(this ref OleVariant variant, decimal value) + { + variant = OleVariant.CreateRaw(VarEnum.VT_CY, decimal.ToOACurrency(value)); + } + + public static unsafe void SetVariant(this ref OleVariant 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 85846d888f90ec..a0291e5642a6f6 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 OleVariant. /// /// 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 OleVariant 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 OleVariant 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 becef48a1466c2..00000000000000 --- 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 37e34303feadff..8d8b8d1f7d9f89 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 OleVariant Element0; } [StructLayout(LayoutKind.Sequential)] internal struct VariantArray2 { - public Variant Element0, Element1; + public OleVariant Element0, Element1; } [StructLayout(LayoutKind.Sequential)] internal struct VariantArray4 { - public Variant Element0, Element1, Element2, Element3; + public OleVariant Element0, Element1, Element2, Element3; } [StructLayout(LayoutKind.Sequential)] internal struct VariantArray8 { - public Variant Element0, Element1, Element2, Element3, Element4, Element5, Element6, Element7; + public OleVariant 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(OleVariant), 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 4fdb65bbd1aefb..ad8f359cebb83d 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 OleVariant 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 = OleVariant.Null; + return Expression.Assign(variant, Expression.Property(null, typeof(OleVariant).GetProperty(nameof(OleVariant.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(OleVariant).GetMethod(nameof(OleVariant.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(OleVariant).GetMethod(nameof(OleVariant.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/System/Runtime/InteropServices/Marshalling/OleVariant.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/OleVariant.cs index df7f16cbe50c2b..8a12686b2e3a22 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/OleVariant.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/OleVariant.cs @@ -9,8 +9,9 @@ namespace System.Runtime.InteropServices.Marshalling [StructLayout(LayoutKind.Explicit)] public struct OleVariant : IDisposable { + private const VarEnum VT_VERSIONED_STREAM = (VarEnum)73; #if DEBUG - unsafe static OleVariant() + static unsafe OleVariant() { // 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. @@ -53,8 +54,39 @@ private struct 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 unsafe struct VersionedStream + { + public Guid _version; + public IntPtr _stream; + } + + [StructLayout(LayoutKind.Sequential)] + private unsafe struct ClipboardData + { + public uint _size; + public int _format; + public IntPtr _data; + } + [StructLayout(LayoutKind.Explicit)] - private struct UnionTypes + private unsafe struct UnionTypes { [FieldOffset(0)] public sbyte _i1; [FieldOffset(0)] public short _i2; @@ -70,7 +102,7 @@ private struct UnionTypes [FieldOffset(0)] public int _error; [FieldOffset(0)] public float _r4; [FieldOffset(0)] public double _r8; - [FieldOffset(0)] public Currency _cy; + [FieldOffset(0)] public long _cy; [FieldOffset(0)] public double _date; [FieldOffset(0)] public IntPtr _bstr; [FieldOffset(0)] public IntPtr _unknown; @@ -78,6 +110,9 @@ private struct UnionTypes [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; } public unsafe void Dispose() @@ -88,12 +123,108 @@ public unsafe void Dispose() Interop.Ole32.PropVariantClear((nint)pThis); } #else - // TODO: Replicate the behavior of PropVariantClear on non-Windows platforms. - throw new NotImplementedException(); + // 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("OleVariants containing SAFEARRAYs are not supported on this platform"); + } + 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 == VT_STREAM || VarType == VT_STREAMED_OBJECT || VarType == VT_STORAGE || VarType == 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 != null) + { + Marshal.Release(versionedStream->_stream); + } + Marshal.FreeCoTaskMem((nint)versionedStream); + } + else if (VarType == 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.CoTaskMemFree((nint)GetRawDataRef>()._data); + } + + // Clear out this OleVariant instance. + this = default; #endif } -#pragma warning disable CS0618 // We support the obsolete *Wrapper types +#pragma warning disable CS0618 // We support the obsolete CurrencyWrapper type public static OleVariant Create([DisallowNull] T value) { Unsafe.SkipInit(out OleVariant variant); @@ -124,7 +255,7 @@ public static OleVariant Create([DisallowNull] T value) else if (typeof(T) == typeof(CurrencyWrapper)) { variant.VarType = VarEnum.VT_CY; - variant._typeUnion._unionTypes._cy = new Currency(((CurrencyWrapper)(object)value).WrappedObject); + variant._typeUnion._unionTypes._cy = decimal.ToOACurrency(((CurrencyWrapper)(object)value).WrappedObject); } else if (typeof(T) == typeof(DateTime)) { @@ -136,6 +267,16 @@ public static OleVariant Create([DisallowNull] T value) 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 OleVariant 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; @@ -145,7 +286,7 @@ public static OleVariant Create([DisallowNull] T value) { // bool values in OLE VARIANTs are VARIANT_BOOL values. variant.VarType = VarEnum.VT_BOOL; - variant._typeUnion._unionTypes._bool = ((bool)(object)value) ? (short)-1 : (short)0; + variant._typeUnion._unionTypes._bool = ((bool)(object)value) ? (short)0 : (short)-1; } else if (typeof(T) == typeof(decimal)) { @@ -190,7 +331,6 @@ public static OleVariant Create([DisallowNull] T value) } // 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 string to any VT_* type directly as there are multiple equally valid options. // We do not map VT_BYREF automatically, nor do we map any of the array types. return variant; } @@ -208,6 +348,10 @@ public static unsafe OleVariant CreateRaw(VarEnum vt, T rawValue) { throw new ArgumentException("VT_VARIANT is not supported in variants.", nameof(vt)); } + if (vt.HasFlag(VarEnum.VT_ARRAY) && !OperatingSystem.IsWindows()) + { + throw new PlatformNotSupportedException("OleVariants containing SAFEARRAYs are not supported on this platform"); + } Unsafe.SkipInit(out OleVariant value); value.VarType = vt; @@ -215,15 +359,16 @@ public static unsafe OleVariant CreateRaw(VarEnum vt, T rawValue) { (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, 4) => 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_INT or VarEnum.VT_UINT or 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_CARRAY, _) when sizeof(T) == nint.Size => rawValue, + (VarEnum.VT_INT or VarEnum.VT_UINT or 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) == 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_CLSID, _) when sizeof(T) == sizeof(Guid) => rawValue, + (VarEnum.VT_BLOB or VarEnum.VT_BLOB_OBJECT, _) when sizeof(T) == sizeof(Blob) => rawValue, _ => throw new ArgumentException("Size of T should be the same size as the value specified by vt") }; @@ -234,9 +379,9 @@ _ when vt.HasFlag(VarEnum.VT_ARRAY) && sizeof(T) == nint.Size => rawValue, private readonly void ThrowIfNotVarType(params VarEnum[] requiredType) { - if (Array.IndexOf(requiredType, VarType) != -1) + if (Array.IndexOf(requiredType, VarType) == -1) { - throw new InvalidOperationException($"Variant type {VarType} cannot be cast to {requiredType}"); + throw new InvalidOperationException($"Variant type {VarType} cannot be cast to any of the supported variant types: [{string.Join(", ", requiredType)}]"); } } @@ -260,7 +405,7 @@ public readonly T As() } else if (typeof(T) == typeof(int)) { - ThrowIfNotVarType(VarEnum.VT_I4); + ThrowIfNotVarType(VarEnum.VT_I4, VarEnum.VT_ERROR, VarEnum.VT_INT); return (T)(object)_typeUnion._unionTypes._i4; } else if (typeof(T) == typeof(float)) @@ -276,7 +421,7 @@ public readonly T As() else if (typeof(T) == typeof(CurrencyWrapper)) { ThrowIfNotVarType(VarEnum.VT_CY); - return (T)(object)new CurrencyWrapper(new decimal(_typeUnion._unionTypes._cy)); + return (T)(object)new CurrencyWrapper(decimal.FromOACurrency(_typeUnion._unionTypes._cy)); } else if (typeof(T) == typeof(DateTime)) { @@ -288,6 +433,17 @@ public readonly T As() 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 OleVariant + // when the OleVariant 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); @@ -297,7 +453,7 @@ public readonly T As() { // bool values in OLE VARIANTs are VARIANT_BOOL values. ThrowIfNotVarType(VarEnum.VT_BOOL); - return (T)(object)(_typeUnion._unionTypes._bool != 0); + return (T)(object)(_typeUnion._unionTypes._bool != -1); } else if (typeof(T) == typeof(decimal)) { @@ -327,7 +483,7 @@ public readonly T As() } else if (typeof(T) == typeof(uint)) { - ThrowIfNotVarType(VarEnum.VT_UI4); + ThrowIfNotVarType(VarEnum.VT_UI4, VarEnum.VT_UINT); return (T)(object)_typeUnion._unionTypes._ui4; } else if (typeof(T) == typeof(long)) @@ -355,6 +511,10 @@ public unsafe ref T GetRawDataRef() where T : unmanaged { ArgumentOutOfRangeException.ThrowIfGreaterThan(Unsafe.SizeOf(), sizeof(UnionTypes), nameof(T)); + if (typeof(T) == typeof(decimal)) + { + throw new ArgumentException("VT_DECIMAL is not supported in GetRawDataRef. Use the As method.", nameof(T)); + } return ref Unsafe.As(ref _typeUnion._unionTypes); } } 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 59dfcf2713620d..b33ec7e87889f1 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -2500,6 +2500,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 OleVariant : System.IDisposable + { + private int _dummyPrimitive; + + public void Dispose() { } + public static System.Runtime.InteropServices.Marshalling.OleVariant Create([System.Diagnostics.CodeAnalysis.DisallowNullAttribute] T value) { throw null; } + public static System.Runtime.InteropServices.Marshalling.OleVariant CreateRaw(System.Runtime.InteropServices.VarEnum vt, T rawValue) where T : unmanaged { throw null; } + public static System.Runtime.InteropServices.Marshalling.OleVariant 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/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 90173a66a48c68..16745068fe6862 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 @@ -152,6 +152,7 @@ + diff --git a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/OleVariantTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/OleVariantTests.cs new file mode 100644 index 00000000000000..414fafed420131 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/OleVariantTests.cs @@ -0,0 +1,459 @@ +// 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 +{ + public class OleVariantTests + { + [Fact] + public void DefaultVariantIsEmpty() + { + Assert.Equal(VarEnum.VT_EMPTY, default(OleVariant).VarType); + } + + [Fact] + public void NullVariantIsNull() + { + Assert.Equal(VarEnum.VT_NULL, OleVariant.Null.VarType); + } + + [Fact] + public void Short() + { + OleVariant variant = OleVariant.Create(42); + Assert.Equal(VarEnum.VT_I2, variant.VarType); + Assert.Equal(42, variant.As()); + Assert.Equal(42, variant.GetRawDataRef()); + } + + [Fact] + public void Int4() + { + OleVariant variant = OleVariant.Create(42); + Assert.Equal(VarEnum.VT_I4, variant.VarType); + Assert.Equal(42, variant.As()); + Assert.Equal(42, variant.GetRawDataRef()); + } + + [Fact] + public void Float() + { + OleVariant variant = OleVariant.Create(42.0f); + Assert.Equal(VarEnum.VT_R4, variant.VarType); + Assert.Equal(42, variant.As()); + Assert.Equal(42, variant.GetRawDataRef()); + } + + [Fact] + public void Double() + { + OleVariant variant = OleVariant.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() + { + OleVariant variant = OleVariant.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() + { + OleVariant variant = OleVariant.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 OleVariant variant = OleVariant.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 OleVariant variant = OleVariant.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 OleVariant variant = OleVariant.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", () => OleVariant.Create(wrapper)); + } +#endif + + [Fact] + public void Error() + { + OleVariant variant = OleVariant.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() + { + OleVariant trueVariant = OleVariant.Create(true); + Assert.Equal(VarEnum.VT_BOOL, trueVariant.VarType); + Assert.True(trueVariant.As()); + Assert.Equal(0, trueVariant.GetRawDataRef()); + } + + [Fact] + public void VariantBoolFalse() + { + OleVariant falseVariant = OleVariant.Create(false); + Assert.Equal(VarEnum.VT_BOOL, falseVariant.VarType); + Assert.False(falseVariant.As()); + Assert.Equal(-1, falseVariant.GetRawDataRef()); + } + + [Fact] + public void VTVariantNotSupported() + { + Assert.Throws("vt", () => OleVariant.CreateRaw(VarEnum.VT_VARIANT, 1)); + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsBuiltInComEnabled))] + public void Unknown_NotSupported() + { + UnknownWrapper wrapper = new(new TestObject()); + Assert.Throws("T", () => OleVariant.Create(wrapper)); + } + + [ComImport] + [Guid("9FBB5303-ED8B-448D-8174-571D03E1D947")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IUnknownInterface + { + } + + private sealed class TestObject : IUnknownInterface + { + } + + [Fact] + public void Decimal() + { + OleVariant variant = OleVariant.Create(42.0m); + Assert.Equal(VarEnum.VT_DECIMAL, variant.VarType); + Assert.Equal(42.0m, variant.As()); + Assert.Throws("T", () => variant.GetRawDataRef()); + } + + [Fact] + public void SByte() + { + OleVariant variant = OleVariant.Create(42); + Assert.Equal(VarEnum.VT_I1, variant.VarType); + Assert.Equal(42, variant.As()); + Assert.Equal(42, variant.GetRawDataRef()); + } + + [Fact] + public void Byte() + { + OleVariant variant = OleVariant.Create(42); + Assert.Equal(VarEnum.VT_UI1, variant.VarType); + Assert.Equal(42, variant.As()); + Assert.Equal(42, variant.GetRawDataRef()); + } + + [Fact] + public void UShort() + { + OleVariant variant = OleVariant.Create(42); + Assert.Equal(VarEnum.VT_UI2, variant.VarType); + Assert.Equal(42, variant.As()); + Assert.Equal(42, variant.GetRawDataRef()); + } + + [Fact] + public void UInt4() + { + OleVariant variant = OleVariant.Create(42); + Assert.Equal(VarEnum.VT_UI4, variant.VarType); + Assert.Equal(42u, variant.As()); + Assert.Equal(42u, variant.GetRawDataRef()); + } + + [Fact] + public void Long() + { + OleVariant variant = OleVariant.Create(42); + Assert.Equal(VarEnum.VT_I8, variant.VarType); + Assert.Equal(42, variant.As()); + Assert.Equal(42, variant.GetRawDataRef()); + } + + [Fact] + public void ULong() + { + OleVariant variant = OleVariant.Create(42); + Assert.Equal(VarEnum.VT_UI8, variant.VarType); + Assert.Equal(42ul, variant.As()); + Assert.Equal(42ul, variant.GetRawDataRef()); + } + + [Fact] + public void Int_Raw() + { + OleVariant variant = OleVariant.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() + { + OleVariant variant = OleVariant.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", () => OleVariant.Create(new Record())); + // We support creating a record-based variant with the CreateRaw method. + OleVariant variant = OleVariant.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 OleVariant variant = OleVariant.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 OleVariant variant = OleVariant.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 = 1039348523; + OleVariant variant = OleVariant.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 OleVariant variant = OleVariant.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 OleVariant instance. + OleVariant variant = OleVariant.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 OleVariant instance. + OleVariant variant = OleVariant.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 OleVariant instance. + OleVariant variant = OleVariant.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 OleVariant instance. + OleVariant variant = OleVariant.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 OleVariant instance. + OleVariant variant = OleVariant.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 OleVariant variant = OleVariant.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 OleVariant variant = OleVariant.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 OleVariant variant = OleVariant.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 OleVariant variant = OleVariant.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 OleVariant instance. + OleVariant variant = OleVariant.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(() => OleVariant.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 OleVariant variant = OleVariant.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); + } + } +} From 4ef3c25bb2fd43a679b9fc18096b7c07428cfd4c Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 17 Oct 2023 14:58:29 -0700 Subject: [PATCH 03/20] Implement OleVariantMarshaller. --- .../ref/System.Runtime.InteropServices.cs | 17 + .../src/System.Runtime.InteropServices.csproj | 1 + .../Marshalling/OleVariantMarshaller.cs | 300 ++++++++++++++++++ ...ystem.Runtime.InteropServices.Tests.csproj | 1 + .../OleVariantMarshallerTests.cs | 293 +++++++++++++++++ .../InteropServices/OleVariantTests.cs | 2 + 6 files changed, 614 insertions(+) create mode 100644 src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/OleVariantMarshaller.cs create mode 100644 src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/OleVariantMarshallerTests.cs 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 b33ec7e87889f1..cffd4062c066ce 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.OleVariantMarshaller))] + [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(object), System.Runtime.InteropServices.Marshalling.MarshalMode.UnmanagedToManagedRef, typeof(System.Runtime.InteropServices.Marshalling.OleVariantMarshaller.RefPropogate))] + public static partial class OleVariantMarshaller + { + public static System.Runtime.InteropServices.Marshalling.OleVariant ConvertToUnmanaged(object? managed) { throw null; } + public static object? ConvertToManaged(System.Runtime.InteropServices.Marshalling.OleVariant unmanaged) { throw null; } + public static void Free(System.Runtime.InteropServices.Marshalling.OleVariant unmanaged) { } + + public struct RefPropogate + { + public void FromUnmanaged(System.Runtime.InteropServices.Marshalling.OleVariant unmanaged) { } + public void FromManaged(object? managed) { } + public System.Runtime.InteropServices.Marshalling.OleVariant ToUnmanaged() { throw null; } + public object? ToManaged() { throw null; } + public void Free() { } + } + } [System.CLSCompliantAttribute(false)] public partial class StrategyBasedComWrappers : System.Runtime.InteropServices.ComWrappers { 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 393febd4cdcb7b..f35de7ed9aac5a 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/OleVariantMarshaller.cs b/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/OleVariantMarshaller.cs new file mode 100644 index 00000000000000..f7b0753a254301 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/OleVariantMarshaller.cs @@ -0,0 +1,300 @@ +// 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 +{ + [CustomMarshaller(typeof(object), MarshalMode.Default, typeof(OleVariantMarshaller))] + [CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedRef, typeof(RefPropogate))] + public static partial class OleVariantMarshaller + { + public static OleVariant ConvertToUnmanaged(object? managed) + { + if (managed is null) + { + return default; + } + +#pragma warning disable CS0618 // Type or member is obsolete + switch (managed) + { + case sbyte s: + return OleVariant.Create(s); + case byte b: + return OleVariant.Create(b); + case short s: + return OleVariant.Create(s); + case ushort s: + return OleVariant.Create(s); + case int i: + return OleVariant.Create(i); + case uint i: + return OleVariant.Create(i); + case long l: + return OleVariant.Create(l); + case ulong l: + return OleVariant.Create(l); + case float f: + return OleVariant.Create(f); + case double d: + return OleVariant.Create(d); + case decimal d: + return OleVariant.Create(d); + case bool b: + return OleVariant.Create(b); + case char c: + return OleVariant.Create((ushort)c); + case string s: + return OleVariant.Create(s); + case DateTime dt: + return OleVariant.Create(dt); + case ErrorWrapper errorWrapper: + return OleVariant.Create(errorWrapper); + case CurrencyWrapper currencyWrapper: + return OleVariant.Create(currencyWrapper); + case BStrWrapper bStrWrapper: + return OleVariant.Create(bStrWrapper); + case DBNull: + return OleVariant.Null; + } +#pragma warning restore CS0618 // Type or member is obsolete + + if (TryCreateOleVariantForInterfaceWrapper(managed, out OleVariant variant)) + { + return variant; + } + + throw new ArgumentException("Type of managed object is not supported for marshalling as OleVariant.", nameof(managed)); + } + +#pragma warning disable CA1416 // Validate platform compatibility + private static unsafe bool TryCreateOleVariantForInterfaceWrapper(object managed, out OleVariant variant) + { + if (managed is UnknownWrapper uw) + { + object? wrapped = uw.WrappedObject; + if (wrapped is null) + { + variant = default; + return true; + } + variant = OleVariant.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 = OleVariant.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(OleVariant 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(*(OleVariant*)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() != -1; + 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("Type of unmanaged variant is not supported for marshalling to a managed object.", nameof(unmanaged)); + } +#pragma warning restore CA1416 // Validate platform compatibility +#pragma warning restore CS0618 // Type or member is obsolete + } + + public static void Free(OleVariant unmanaged) => unmanaged.Dispose(); + + public struct RefPropogate + { + private OleVariant _unmanaged; + private object? _managed; + + public void FromUnmanaged(OleVariant unmanaged) => _unmanaged = unmanaged; + public void FromManaged(object? managed) => _managed = managed; + + public unsafe OleVariant 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, _): + *(OleVariant*)_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 ? (short)0 : (short)-1; + 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; + } + + public object? ToManaged() => ConvertToManaged(_unmanaged); + public void Free() => _unmanaged.Dispose(); + } + } +} 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 16745068fe6862..f738a9c75e33a9 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 @@ -152,6 +152,7 @@ + diff --git a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/OleVariantMarshallerTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/OleVariantMarshallerTests.cs new file mode 100644 index 00000000000000..4b70a81f259dbb --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/OleVariantMarshallerTests.cs @@ -0,0 +1,293 @@ +// 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 OleVariantMarshallerTests + { + [Fact] + public void Null_Marshals_To_Empty() + { + Assert.Equal(VarEnum.VT_EMPTY, OleVariantMarshaller.ConvertToUnmanaged(null).VarType); + Assert.Null(OleVariantMarshaller.ConvertToManaged(default)); + } + + [Fact] + public void DBNull_Marshals_To_Null() + { + Assert.Equal(VarEnum.VT_NULL, OleVariantMarshaller.ConvertToUnmanaged(DBNull.Value).VarType); + Assert.Same(DBNull.Value, OleVariantMarshaller.ConvertToManaged(OleVariant.Null)); + } + + [Fact] + public void String_Marshals_To_BStr() + { + string value = "Hello"; + OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(value); + Assert.Equal(VarEnum.VT_BSTR, variant.VarType); + Assert.Equal(value, OleVariantMarshaller.ConvertToManaged(variant)); + OleVariantMarshaller.Free(variant); + } + + [Fact] + public void BStrWrapper_Marshals_To_BStr() + { + string value = "Hello"; + OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(new BStrWrapper(value)); + Assert.Equal(VarEnum.VT_BSTR, variant.VarType); + Assert.Equal(value, OleVariantMarshaller.ConvertToManaged(variant)); + OleVariantMarshaller.Free(variant); + } + + [Fact] + public void Int32_Marshals_To_I4() + { + int value = 42; + OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(value); + Assert.Equal(VarEnum.VT_I4, variant.VarType); + Assert.Equal(value, OleVariantMarshaller.ConvertToManaged(variant)); + OleVariantMarshaller.Free(variant); + } + + [Fact] + public void UInt32_Marshals_To_UI4() + { + uint value = 42; + OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(value); + Assert.Equal(VarEnum.VT_UI4, variant.VarType); + Assert.Equal(value, OleVariantMarshaller.ConvertToManaged(variant)); + OleVariantMarshaller.Free(variant); + } + + [Fact] + public void Int16_Marshals_To_I2() + { + short value = 42; + OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(value); + Assert.Equal(VarEnum.VT_I2, variant.VarType); + Assert.Equal(value, OleVariantMarshaller.ConvertToManaged(variant)); + OleVariantMarshaller.Free(variant); + } + + [Fact] + public void UInt16_Marshals_To_UI2() + { + ushort value = 42; + OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(value); + Assert.Equal(VarEnum.VT_UI2, variant.VarType); + Assert.Equal(value, OleVariantMarshaller.ConvertToManaged(variant)); + OleVariantMarshaller.Free(variant); + } + + [Fact] + public void Byte_Marshals_To_UI1() + { + byte value = 42; + OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(value); + Assert.Equal(VarEnum.VT_UI1, variant.VarType); + Assert.Equal(value, OleVariantMarshaller.ConvertToManaged(variant)); + OleVariantMarshaller.Free(variant); + } + + [Fact] + public void SByte_Marshals_To_I1() + { + sbyte value = 42; + OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(value); + Assert.Equal(VarEnum.VT_I1, variant.VarType); + Assert.Equal(value, OleVariantMarshaller.ConvertToManaged(variant)); + OleVariantMarshaller.Free(variant); + } + + [Fact] + public void Double_Marshals_To_R8() + { + double value = 42.0; + OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(value); + Assert.Equal(VarEnum.VT_R8, variant.VarType); + Assert.Equal(value, OleVariantMarshaller.ConvertToManaged(variant)); + OleVariantMarshaller.Free(variant); + } + + [Fact] + public void Single_Marshals_To_R4() + { + float value = 42.0f; + OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(value); + Assert.Equal(VarEnum.VT_R4, variant.VarType); + Assert.Equal(value, OleVariantMarshaller.ConvertToManaged(variant)); + OleVariantMarshaller.Free(variant); + } + + [InlineData(true)] + [InlineData(false)] + [Theory] + public void Boolean_Marshals_To_BOOL(bool value) + { + OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(value); + Assert.Equal(VarEnum.VT_BOOL, variant.VarType); + Assert.Equal(value, OleVariantMarshaller.ConvertToManaged(variant)); + OleVariantMarshaller.Free(variant); + } + + [Fact] + public void ErrorWrapper_Maps_To_VT_ERROR() + { + ErrorWrapper errorWrapper = new ErrorWrapper(42); + OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(errorWrapper); + Assert.Equal(VarEnum.VT_ERROR, variant.VarType); + Assert.Equal(errorWrapper.ErrorCode, Assert.IsType(OleVariantMarshaller.ConvertToManaged(variant))); + OleVariantMarshaller.Free(variant); + } + + [Fact] + public void VariantWrapper_Throws() + { + VariantWrapper wrapper = new VariantWrapper(42); + Assert.Throws("managed", () => OleVariantMarshaller.ConvertToUnmanaged(wrapper)); + } + + [Fact] + public void Decimal_Marshals_To_DECIMAL() + { + decimal value = 42.0m; + OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(value); + Assert.Equal(VarEnum.VT_DECIMAL, variant.VarType); + Assert.Equal(value, OleVariantMarshaller.ConvertToManaged(variant)); + OleVariantMarshaller.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"); + OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(value); + Assert.Equal(VarEnum.VT_DATE, variant.VarType); + Assert.Equal(value, OleVariantMarshaller.ConvertToManaged(variant)); + OleVariantMarshaller.Free(variant); + } + +#pragma warning disable CS0618 // Type or member is obsolete + [Fact] + public void CurrentyWrapper_Marshals_To_CY() + { + decimal value = 42.0m; + OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(new CurrencyWrapper(value)); + Assert.Equal(VarEnum.VT_CY, variant.VarType); + Assert.Equal(value, Assert.IsType(OleVariantMarshaller.ConvertToManaged(variant))); + OleVariantMarshaller.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] + public unsafe void GeneratedComInterfaceType_Marshals_To_UNKNOWN() + { + var obj = new ComExposedType(); + OleVariant variant = OleVariantMarshaller.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, OleVariantMarshaller.ConvertToManaged(variant)); + OleVariantMarshaller.Free(variant); + } + + [Fact] + public void UnknownWrapper_Of_GeneratedComInterfaceType_Marshals_To_UNKNOWN() + { + var obj = new ComExposedType(); + OleVariant variant = OleVariantMarshaller.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, OleVariantMarshaller.ConvertToManaged(variant)); + OleVariantMarshaller.Free(variant); + } + + [Fact] + public void INT_Marshals_as_Int() + { + OleVariant variant = OleVariant.CreateRaw(VarEnum.VT_INT, 42); + Assert.Equal(42, Assert.IsType(OleVariantMarshaller.ConvertToManaged(variant))); + } + + [Fact] + public void UINT_Marshals_as_UInt() + { + OleVariant variant = OleVariant.CreateRaw(VarEnum.VT_UINT, 42u); + Assert.Equal(42u, Assert.IsType(OleVariantMarshaller.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; + OleVariant variant = OleVariant.CreateRaw(VarEnum.VT_BYREF | elementType, (nint)(&storage)); + // Set up the marshaller + OleVariantMarshaller.RefPropogate marshaller = default; + marshaller.FromUnmanaged(variant); + + // Marshal back the new value + marshaller.FromManaged(valueToSet); + + OleVariant 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)OleVariantMarshaller.ConvertToManaged(variant)).ToType(valueToSet.GetType(), null)); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/OleVariantTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/OleVariantTests.cs index 414fafed420131..9fd8607c44a3f7 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/OleVariantTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/OleVariantTests.cs @@ -12,6 +12,8 @@ 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 OleVariantTests { [Fact] From 099a1a3dbb5f86ec7be08bfacdf0fb5bd398da81 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 17 Oct 2023 16:21:25 -0700 Subject: [PATCH 04/20] Implement generator integration. Instead of special-casing support for "in object" to propagate back the value, we will instead require the user to specify "ref object" to get that behavior (and we'll notify the user of the breaking change with an info diagnostic). --- .../ComInterfaceGeneratorHelpers.cs | 1 + .../VtableIndexStubGeneratorHelpers.cs | 1 + .../gen/Common/Resources/Strings.resx | 59 ++++++++++--------- .../gen/Common/Resources/xlf/Strings.cs.xlf | 5 ++ .../gen/Common/Resources/xlf/Strings.de.xlf | 5 ++ .../gen/Common/Resources/xlf/Strings.es.xlf | 5 ++ .../gen/Common/Resources/xlf/Strings.fr.xlf | 5 ++ .../gen/Common/Resources/xlf/Strings.it.xlf | 5 ++ .../gen/Common/Resources/xlf/Strings.ja.xlf | 5 ++ .../gen/Common/Resources/xlf/Strings.ko.xlf | 5 ++ .../gen/Common/Resources/xlf/Strings.pl.xlf | 5 ++ .../Common/Resources/xlf/Strings.pt-BR.xlf | 5 ++ .../gen/Common/Resources/xlf/Strings.ru.xlf | 5 ++ .../gen/Common/Resources/xlf/Strings.tr.xlf | 5 ++ .../Common/Resources/xlf/Strings.zh-Hans.xlf | 5 ++ .../Common/Resources/xlf/Strings.zh-Hant.xlf | 5 ++ .../LibraryImportGeneratorHelpers.cs | 1 + .../CustomMarshallingInfoHelper.cs | 23 ++++++++ .../MarshalAsWithCustomMarshallersParser.cs | 7 ++- .../Marshalling/BreakingChangeDetector.cs | 41 +++++++++++++ .../StringMarshallingInfoProvider.cs | 26 +------- .../TypeNames.cs | 2 + .../CodeSnippets.cs | 25 ++++++++ .../CompileFails.cs | 19 ++++++ .../Compiles.cs | 9 +++ .../VariantTests.cs | 28 +++++++++ .../tests/TestAssets/NativeExports/Variant.cs | 23 ++++++++ 27 files changed, 277 insertions(+), 53 deletions(-) create mode 100644 src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Marshalling/BreakingChangeDetector.cs create mode 100644 src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/VariantTests.cs create mode 100644 src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/Variant.cs diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGeneratorHelpers.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGeneratorHelpers.cs index c5fd203db2a0f0..5bd5e1b893bc96 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 7d7c516f50998c..7319a8540482ce 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 bce2c5ae188043..c1b54b9dde9e90 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 9f769d6c35c061..cb47ca8633ddb9 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 a23a8178977575..4c074a73b1d06b 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 7d4da3d2391109..af7b114c148d88 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 467413d83f430d..f6a5d7a2405fcd 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 7af807ca8b6f60..583bd7d3b679a6 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 900871e5738958..922438e3b3b460 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 c2061f1c47ed04..42a09317564add 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 4a5bed01000cbb..a3b1860ab44e3a 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 a2dcb00fc8aa2c..21f751b5361071 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 9631d6c981aacd..a9171f2bc3161f 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 06f7c1279e14ac..1cc5531a8683c5 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 9cf9ccbc906f53..8f895c4fec8b42 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 08a0d9ac8eb548..34074c682f507c 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 367d704e3735a8..10ed18283049f0 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGeneratorHelpers.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGeneratorHelpers.cs @@ -57,6 +57,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 e3dcb7a67ae4a7..e98bc9ec3ddbd0 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 MarshallingInfo CreateNativeMarshallingInfoForNonSignatureElement( 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 17933bafb55afe..4519410e4e2d6f 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 @@ -92,6 +92,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.OleVariantMarshaller); + } + return marshalAsInfo; } @@ -113,7 +118,7 @@ private MarshallingInfo CreateStringMarshallingInfo( 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 00000000000000..e598a07bd7829e --- /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.OleVariantMarshaller), _) } + && 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 12f69adfef136b..ed96fe7cd8a74c 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 3eeb17588a0863..28f3eec7fd0ef9 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,7 @@ 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 OleVariantMarshaller = "System.Runtime.InteropServices.Marshalling.OleVariantMarshaller"; } } 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 700797fcb3e888..12b59f274425a6 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 331fa54117fb04..198e3370c04cd0 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 3d20f2a8c7c681..bf04b97ffcded6 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 00000000000000..e3a7c56fd213b5 --- /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.Tests +{ + partial class NativeExportsNE + { + [LibraryImport(nameof(NativeExportsNE), 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/TestAssets/NativeExports/Variant.cs b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/Variant.cs new file mode 100644 index 00000000000000..0085d27d3d9514 --- /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*")] OleVariant* variant) + { + return variant->As().Length; + } + } +} From b63a0b973024b4e98f1c64cfa71ecb4c16d3fb4f Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 17 Oct 2023 16:46:32 -0700 Subject: [PATCH 05/20] Add doc comments to new APIs --- .../InteropServices/Marshalling/OleVariant.cs | 41 ++++++++++++++++++- .../Marshalling/OleVariantMarshaller.cs | 32 +++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/OleVariant.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/OleVariant.cs index 8a12686b2e3a22..f6cedccc0cd618 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/OleVariant.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/OleVariant.cs @@ -6,6 +6,9 @@ namespace System.Runtime.InteropServices.Marshalling { + /// + /// A type that represents an OLE VARIANT in managed code. + /// [StructLayout(LayoutKind.Explicit)] public struct OleVariant : IDisposable { @@ -115,6 +118,9 @@ private unsafe struct UnionTypes [FieldOffset(0)] public ClipboardData* clipboardData; } + /// + /// Release resources owned by this instance. + /// public unsafe void Dispose() { #if TARGET_WINDOWS @@ -225,6 +231,13 @@ public unsafe void Dispose() } #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 OleVariant Create([DisallowNull] T value) { Unsafe.SkipInit(out OleVariant variant); @@ -336,6 +349,15 @@ public static OleVariant Create([DisallowNull] T value) } #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 OleVariant CreateRaw(VarEnum vt, T rawValue) where T : unmanaged { @@ -375,6 +397,9 @@ _ when vt.HasFlag(VarEnum.VT_ARRAY) && sizeof(T) == nint.Size => rawValue, return value; } + /// + /// A instance that represents a null value with type. + /// public static OleVariant Null { get; } = new() { VarType = VarEnum.VT_NULL }; private readonly void ThrowIfNotVarType(params VarEnum[] requiredType) @@ -386,7 +411,12 @@ private readonly void ThrowIfNotVarType(params VarEnum[] requiredType) } #pragma warning disable CS0618 // Type or member is obsolete - // This method will match the exact same semantics as Create with the same set of supported types. + /// + /// 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) @@ -500,12 +530,21 @@ public readonly T As() } #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 diff --git a/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/OleVariantMarshaller.cs b/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/OleVariantMarshaller.cs index f7b0753a254301..1188b8a9e5368a 100644 --- a/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/OleVariantMarshaller.cs +++ b/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/OleVariantMarshaller.cs @@ -9,6 +9,12 @@ 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(OleVariantMarshaller))] [CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedRef, typeof(RefPropogate))] public static partial class OleVariantMarshaller @@ -190,14 +196,32 @@ private static unsafe bool TryCreateOleVariantForInterfaceWrapper(object managed public static void Free(OleVariant 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 RefPropogate { private OleVariant _unmanaged; private object? _managed; + /// + /// Initializes the marshaller with an unmanaged variant. + /// + /// The unmanaged value public void FromUnmanaged(OleVariant 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 OleVariant ToUnmanaged() { if (!_unmanaged.VarType.HasFlag(VarEnum.VT_BYREF)) @@ -293,7 +317,15 @@ or VarEnum.VT_DISPATCH 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(); } } From 8472e6015ecd830506602f63965688d84324723b Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Wed, 18 Oct 2023 11:20:38 -0700 Subject: [PATCH 06/20] Fix xplat OleVariant.Dispose() --- .../System/Runtime/InteropServices/Marshalling/OleVariant.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/OleVariant.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/OleVariant.cs index f6cedccc0cd618..5b89f3a6ce742c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/OleVariant.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/OleVariant.cs @@ -152,7 +152,7 @@ public unsafe void Dispose() // 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.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); } @@ -165,7 +165,7 @@ public unsafe void Dispose() { Marshal.FreeCoTaskMem(_typeUnion._unionTypes._blob._data); } - else if (VarType == VT_STREAM || VarType == VT_STREAMED_OBJECT || VarType == VT_STORAGE || VarType == VT_STORED_OBJECT) + 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) { From 62d329ae370ed280cafff42fdf77346e578406fe Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Thu, 19 Oct 2023 12:03:11 -0700 Subject: [PATCH 07/20] Rename OleVariant to ComVariant --- .../EnumerableViewOfDispatch.cs | 2 +- .../src/System/Variant.cs | 2 +- .../Runtime/CompilerHelpers/InteropHelpers.cs | 2 +- .../Runtime/InteropServices/Marshal.Com.cs | 84 ++-- .../BuiltInVariantExtensions.cs | 8 +- .../Runtime/InteropServices/ComEventsSink.cs | 12 +- .../Microsoft.CSharp/Microsoft.CSharp.sln | 26 +- .../ComInterop/ComInvokeBinder.cs | 4 +- .../ComInterop/ComRuntimeHelpers.cs | 18 +- .../ComInterop/DynamicVariantExtensions.cs | 172 ++++---- .../ComInterop/VarEnumSelector.cs | 6 +- .../RuntimeBinder/ComInterop/VariantArray.cs | 10 +- .../ComInterop/VariantBuilder.cs | 10 +- .../System.Private.CoreLib.Shared.projitems | 2 +- .../{OleVariant.cs => ComVariant.cs} | 56 +-- .../System.Runtime.InteropServices.sln | 387 +++++++++--------- .../MarshalAsWithCustomMarshallersParser.cs | 2 +- .../Marshalling/BreakingChangeDetector.cs | 2 +- .../TypeNames.cs | 2 +- .../ref/System.Runtime.InteropServices.cs | 24 +- .../src/System.Runtime.InteropServices.csproj | 2 +- ...tMarshaller.cs => ComVariantMarshaller.cs} | 78 ++-- ...ystem.Runtime.InteropServices.Tests.csproj | 4 +- ...rTests.cs => ComVariantMarshallerTests.cs} | 130 +++--- ...{OleVariantTests.cs => ComVariantTests.cs} | 102 ++--- .../tests/TestAssets/NativeExports/Variant.cs | 2 +- 26 files changed, 583 insertions(+), 566 deletions(-) rename src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/{OleVariant.cs => ComVariant.cs} (94%) rename src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/{OleVariantMarshaller.cs => ComVariantMarshaller.cs} (87%) rename src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/{OleVariantMarshallerTests.cs => ComVariantMarshallerTests.cs} (67%) rename src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/{OleVariantTests.cs => ComVariantTests.cs} (81%) 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 0df8c60c312488..3c152d5a3a7d36 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 @@ -23,7 +23,7 @@ public EnumerableViewOfDispatch(object dispatch) public Collections.IEnumerator GetEnumerator() { - OleVariant result; + ComVariant result; unsafe { void* resultLocal = &result; diff --git a/src/coreclr/System.Private.CoreLib/src/System/Variant.cs b/src/coreclr/System.Private.CoreLib/src/System/Variant.cs index 0f55a7ef6a0224..2a53a3cbb8652d 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Variant.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Variant.cs @@ -34,7 +34,7 @@ internal struct Variant // What are the consequences of making this an enum? /////////////////////////////////////////////////////////////////////// // If you update this, update the corresponding stuff in OAVariantLib.cs, - // COMOAVariant.cpp (2 tables, forwards and reverse), and perhaps OleVariant.h + // COMOAVariant.cpp (2 tables, forwards and reverse), and perhaps ComVariant.h /////////////////////////////////////////////////////////////////////// internal const int CV_EMPTY = 0x0; internal const int CV_VOID = 0x1; 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 153f4c22d4e7aa..2beac031c78648 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 @@ -577,7 +577,7 @@ internal static unsafe void CleanupVariant(IntPtr pDstNativeVariant) { #if TARGET_WINDOWS #pragma warning disable CA1416 - OleVariant* data = (OleVariant*)pDstNativeVariant; + ComVariant* data = (ComVariant*)pDstNativeVariant; data->Dispose(); #pragma warning restore CA1416 #else 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 f3de62c3666de3..97694ca5d66756 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 @@ -122,7 +122,7 @@ public static unsafe void GetNativeVariantForObject(object? obj, IntPtr pDstNati { ArgumentNullException.ThrowIfNull(pDstNativeVariant); - OleVariant* data = (OleVariant*)pDstNativeVariant; + ComVariant* data = (ComVariant*)pDstNativeVariant; if (obj == null) { *data = default; @@ -133,75 +133,75 @@ public static unsafe void GetNativeVariantForObject(object? obj, IntPtr pDstNati { // Int and String most used types. case int value: - *data = OleVariant.Create(value); + *data = ComVariant.Create(value); break; case string value: - *data = OleVariant.Create(new BStrWrapper(value)); + *data = ComVariant.Create(new BStrWrapper(value)); break; case bool value: - *data = OleVariant.Create(value); + *data = ComVariant.Create(value); break; case byte value: - *data = OleVariant.Create(value); + *data = ComVariant.Create(value); break; case sbyte value: - *data = OleVariant.Create(value); + *data = ComVariant.Create(value); break; case short value: - *data = OleVariant.Create(value); + *data = ComVariant.Create(value); break; case ushort value: - *data = OleVariant.Create(value); + *data = ComVariant.Create(value); break; case uint value: - *data = OleVariant.Create(value); + *data = ComVariant.Create(value); break; case long value: - *data = OleVariant.Create(value); + *data = ComVariant.Create(value); break; case ulong value: - *data = OleVariant.Create(value); + *data = ComVariant.Create(value); break; case float value: - *data = OleVariant.Create(value); + *data = ComVariant.Create(value); break; case double value: - *data = OleVariant.Create(value); + *data = ComVariant.Create(value); break; case DateTime value: - *data = OleVariant.Create(value); + *data = ComVariant.Create(value); break; case decimal value: - *data = OleVariant.Create(value); + *data = ComVariant.Create(value); break; case char value: - *data = OleVariant.Create(value); + *data = ComVariant.Create(value); break; case BStrWrapper value: - *data = OleVariant.Create(value); + *data = ComVariant.Create(value); break; #pragma warning disable 0618 // CurrencyWrapper is obsolete case CurrencyWrapper value: - *data = OleVariant.Create(value); + *data = ComVariant.Create(value); break; #pragma warning restore 0618 case UnknownWrapper value: - *data = OleVariant.CreateRaw(VarEnum.VT_UNKNOWN, GetIUnknownForObject(value.WrappedObject)); + *data = ComVariant.CreateRaw(VarEnum.VT_UNKNOWN, GetIUnknownForObject(value.WrappedObject)); break; case DispatchWrapper value: - *data = OleVariant.CreateRaw(VarEnum.VT_DISPATCH, GetIDispatchForObject(value.WrappedObject)); + *data = ComVariant.CreateRaw(VarEnum.VT_DISPATCH, GetIDispatchForObject(value.WrappedObject)); break; case ErrorWrapper value: - *data = OleVariant.Create(value); + *data = ComVariant.Create(value); break; case VariantWrapper value: throw new ArgumentException(); case DBNull value: - *data = OleVariant.Null; + *data = ComVariant.Null; break; case Missing value: - *data = OleVariant.CreateRaw(VarEnum.VT_ERROR, DISP_E_PARAMNOTFOUND); + *data = ComVariant.CreateRaw(VarEnum.VT_ERROR, DISP_E_PARAMNOTFOUND); break; case IConvertible value: switch (value.GetTypeCode()) @@ -210,55 +210,55 @@ public static unsafe void GetNativeVariantForObject(object? obj, IntPtr pDstNati *data = default; break; case TypeCode.Object: - *data = OleVariant.CreateRaw(VarEnum.VT_UNKNOWN, GetIUnknownForObject(value)); + *data = ComVariant.CreateRaw(VarEnum.VT_UNKNOWN, GetIUnknownForObject(value)); break; case TypeCode.DBNull: - *data = OleVariant.Null; + *data = ComVariant.Null; break; case TypeCode.Boolean: - *data = OleVariant.Create(value.ToBoolean(null)); + *data = ComVariant.Create(value.ToBoolean(null)); break; case TypeCode.Char: - *data = OleVariant.Create(value.ToChar(null)); + *data = ComVariant.Create(value.ToChar(null)); break; case TypeCode.SByte: - *data = OleVariant.Create(value.ToSByte(null)); + *data = ComVariant.Create(value.ToSByte(null)); break; case TypeCode.Byte: - *data = OleVariant.Create(value.ToByte(null)); + *data = ComVariant.Create(value.ToByte(null)); break; case TypeCode.Int16: - *data = OleVariant.Create(value.ToInt16(null)); + *data = ComVariant.Create(value.ToInt16(null)); break; case TypeCode.UInt16: - *data = OleVariant.Create(value.ToUInt16(null)); + *data = ComVariant.Create(value.ToUInt16(null)); break; case TypeCode.Int32: - *data = OleVariant.Create(value.ToInt32(null)); + *data = ComVariant.Create(value.ToInt32(null)); break; case TypeCode.UInt32: - *data = OleVariant.Create(value.ToUInt32(null)); + *data = ComVariant.Create(value.ToUInt32(null)); break; case TypeCode.Int64: - *data = OleVariant.Create(value.ToInt64(null)); + *data = ComVariant.Create(value.ToInt64(null)); break; case TypeCode.UInt64: - *data = OleVariant.Create(value.ToUInt64(null)); + *data = ComVariant.Create(value.ToUInt64(null)); break; case TypeCode.Single: - *data = OleVariant.Create(value.ToSingle(null)); + *data = ComVariant.Create(value.ToSingle(null)); break; case TypeCode.Double: - *data = OleVariant.Create(value.ToDouble(null)); + *data = ComVariant.Create(value.ToDouble(null)); break; case TypeCode.Decimal: - *data = OleVariant.Create(value.ToDecimal(null)); + *data = ComVariant.Create(value.ToDecimal(null)); break; case TypeCode.DateTime: - *data = OleVariant.Create(value.ToDateTime(null)); + *data = ComVariant.Create(value.ToDateTime(null)); break; case TypeCode.String: - *data = OleVariant.Create(new BStrWrapper(value.ToString(null))); + *data = ComVariant.Create(new BStrWrapper(value.ToString(null))); break; default: throw new NotSupportedException(); @@ -274,7 +274,7 @@ public static unsafe void GetNativeVariantForObject(object? obj, IntPtr pDstNati case ValueType: throw new NotSupportedException("VT_RECORD"); default: - *data = OleVariant.CreateRaw(VarEnum.VT_UNKNOWN, GetIDispatchForObject(obj)); + *data = ComVariant.CreateRaw(VarEnum.VT_UNKNOWN, GetIDispatchForObject(obj)); break; } } @@ -304,7 +304,7 @@ public static object GetObjectForIUnknown(IntPtr pUnk) { ArgumentNullException.ThrowIfNull(pSrcNativeVariant); - OleVariant* data = (OleVariant*)pSrcNativeVariant; + ComVariant* data = (ComVariant*)pSrcNativeVariant; switch (data->VarType) { diff --git a/src/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs b/src/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs index bdd0a36ca8630b..dc5e020108362c 100644 --- a/src/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs +++ b/src/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs @@ -11,14 +11,14 @@ namespace System.Runtime.InteropServices [SupportedOSPlatform("windows")] internal static class BuiltInInteropVariantExtensions { - private static unsafe ref T GetByRefDataRef(this ref OleVariant variant) + 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 OleVariant variant, object value) + public static unsafe void CopyFromIndirect(this ref ComVariant variant, object value) { VarEnum vt = (VarEnum)(((int)variant.VarType) & ~((int)VarEnum.VT_BYREF)); @@ -33,7 +33,7 @@ public static unsafe void CopyFromIndirect(this ref OleVariant variant, object v if ((vt & VarEnum.VT_ARRAY) != 0) { - OleVariant vArray; + ComVariant vArray; Marshal.GetNativeVariantForObject(value, (IntPtr)(void*)&vArray); variant.GetRawDataRef() = vArray.GetRawDataRef(); return; @@ -130,7 +130,7 @@ public static unsafe void CopyFromIndirect(this ref OleVariant variant, object v /// Get the managed object representing the Variant. /// /// - public static object? ToObject(this ref OleVariant variant) + public static object? ToObject(this ref ComVariant variant) { // Check the simple case upfront if (variant.VarType == VarEnum.VT_EMPTY) diff --git a/src/libraries/Common/src/System/Runtime/InteropServices/ComEventsSink.cs b/src/libraries/Common/src/System/Runtime/InteropServices/ComEventsSink.cs index de40f7cb44e62f..5155bea123ce01 100644 --- a/src/libraries/Common/src/System/Runtime/InteropServices/ComEventsSink.cs +++ b/src/libraries/Common/src/System/Runtime/InteropServices/ComEventsSink.cs @@ -121,7 +121,7 @@ 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 OleVariant GetVariant(ref OleVariant pSrc) + private static unsafe ref ComVariant GetVariant(ref ComVariant pSrc) { if (pSrc.VarType == VT_BYREF_VARIANT) { @@ -129,7 +129,7 @@ private static unsafe ref OleVariant GetVariant(ref OleVariant pSrc) // 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. - ref OleVariant pByRefVariant = ref *(OleVariant*)(pSrc.GetRawDataRef().ToPointer()); + ref ComVariant pByRefVariant = ref *(ComVariant*)(pSrc.GetRawDataRef().ToPointer()); if ((pByRefVariant.VarType & VT_BYREF_TYPEMASK) == VT_BYREF_VARIANT) { return ref pByRefVariant; @@ -164,7 +164,7 @@ unsafe void IDispatch.Invoke( 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 @@ -173,7 +173,7 @@ unsafe void IDispatch.Invoke( for (i = 0; i < pDispParams.cNamedArgs; i++) { pos = namedArgs[i]; - ref OleVariant pvar = ref GetVariant(ref vars[i]); + ref ComVariant pvar = ref GetVariant(ref vars[i]); args[pos] = pvar.ToObject()!; usedArgs[pos] = true; @@ -196,7 +196,7 @@ unsafe void IDispatch.Invoke( pos++; } - ref OleVariant 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; @@ -228,7 +228,7 @@ unsafe void IDispatch.Invoke( continue; } - ref OleVariant pvar = ref GetVariant(ref vars[idxToPos]); + ref ComVariant pvar = ref GetVariant(ref vars[idxToPos]); pvar.CopyFromIndirect(args[i]); } } diff --git a/src/libraries/Microsoft.CSharp/Microsoft.CSharp.sln b/src/libraries/Microsoft.CSharp/Microsoft.CSharp.sln index 7207dd4e74f6f1..7c0e1c47b0f584 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/RuntimeBinder/ComInterop/ComInvokeBinder.cs b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/ComInvokeBinder.cs index c7fdf50c4e2315..ff356ef08c96c8 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 @@ -93,7 +93,7 @@ private ParameterExpression DispParamsVariable private ParameterExpression InvokeResultVariable { - get { return EnsureVariable(ref _invokeResult, typeof(OleVariant), "invokeResult"); } + get { return EnsureVariable(ref _invokeResult, typeof(ComVariant), "invokeResult"); } } private ParameterExpression ReturnValueVariable @@ -361,7 +361,7 @@ private Expression GenerateFinallyBlock() finallyStatements.Add( Expression.Call( InvokeResultVariable, - typeof(OleVariant).GetMethod(nameof(OleVariant.Dispose)) + 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 2558451d769d41..d090f3300cdb29 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 @@ -231,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 OleVariant 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 OleVariant GetVariantForObject(object obj) + internal static ComVariant GetVariantForObject(object obj) { - OleVariant variant = default; + ComVariant variant = default; if (obj == null) { return variant; @@ -244,7 +244,7 @@ internal static OleVariant GetVariantForObject(object obj) return variant; } - internal static void InitVariantForObject(object obj, ref OleVariant variant) + internal static void InitVariantForObject(object obj, ref ComVariant variant) { Debug.Assert(obj != null); @@ -253,7 +253,7 @@ internal static void InitVariantForObject(object obj, ref OleVariant variant) // Therefore we are going to test for IDispatch before defaulting to GetNativeVariantForObject. if (obj is IDispatch) { - variant = OleVariant.CreateRaw(VarEnum.VT_DISPATCH, obj is not null ? Marshal.GetIDispatchForObject(obj) : 0); + variant = ComVariant.CreateRaw(VarEnum.VT_DISPATCH, obj is not null ? Marshal.GetIDispatchForObject(obj) : 0); return; } @@ -261,7 +261,7 @@ internal static void InitVariantForObject(object obj, ref OleVariant variant) } // This method is intended for use through reflection and should not be used directly - public static object GetObjectForVariant(OleVariant variant) + public static object GetObjectForVariant(ComVariant variant) { IntPtr ptr = UnsafeMethods.ConvertVariantByrefToPtr(ref variant); return Marshal.GetObjectForNativeVariant(ptr); @@ -288,18 +288,18 @@ public static unsafe int IDispatchInvoke( int memberDispId, ComTypes.INVOKEKIND flags, ref ComTypes.DISPPARAMS dispParams, - out OleVariant result, + out ComVariant result, out ExcepInfo excepInfo, out uint argErr) { Guid IID_NULL = default; fixed (ComTypes.DISPPARAMS* pDispParams = &dispParams) - fixed (OleVariant* 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 index 8d962caa403661..c35eb5ef270e26 100644 --- a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/DynamicVariantExtensions.cs +++ b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/DynamicVariantExtensions.cs @@ -45,7 +45,7 @@ public static bool IsPrimitiveType(this VarEnum varEnum) return false; } - public static void SetAsIConvertible(this ref OleVariant variant, IConvertible value) + 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 @@ -55,23 +55,23 @@ public static void SetAsIConvertible(this ref OleVariant variant, IConvertible v switch (tc) { case TypeCode.Empty: break; - case TypeCode.Object: variant = OleVariant.CreateRaw(VarEnum.VT_UNKNOWN, Marshal.GetIUnknownForObject(value)); break; - case TypeCode.DBNull: variant = OleVariant.Null; break; - case TypeCode.Boolean: variant = OleVariant.Create(value.ToBoolean(ci)); break; - case TypeCode.Char: variant = OleVariant.Create(value.ToChar(ci)); break; - case TypeCode.SByte: variant = OleVariant.Create(value.ToSByte(ci)); break; - case TypeCode.Byte: variant = OleVariant.Create(value.ToByte(ci)); break; - case TypeCode.Int16: variant = OleVariant.Create(value.ToInt16(ci)); break; - case TypeCode.UInt16: variant = OleVariant.Create(value.ToUInt16(ci)); break; - case TypeCode.Int32: variant = OleVariant.Create(value.ToInt32(ci)); break; - case TypeCode.UInt32: variant = OleVariant.Create(value.ToUInt32(ci)); break; - case TypeCode.Int64: variant = OleVariant.Create(value.ToInt64(ci)); break; - case TypeCode.UInt64: variant = OleVariant.Create(value.ToInt64(ci)); break; - case TypeCode.Single: variant = OleVariant.Create(value.ToSingle(ci)); break; - case TypeCode.Double: variant = OleVariant.Create(value.ToDouble(ci)); break; - case TypeCode.Decimal: variant = OleVariant.Create(value.ToDecimal(ci)); break; - case TypeCode.DateTime: variant = OleVariant.Create(value.ToDateTime(ci)); break; - case TypeCode.String: variant = OleVariant.Create(new BStrWrapper(value.ToString(ci))); 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(); @@ -79,151 +79,151 @@ public static void SetAsIConvertible(this ref OleVariant variant, IConvertible v } // VT_I1 - public static void SetAsByrefI1(ref this OleVariant variant, ref sbyte value) + 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 OleVariant variant, ref short value) + 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 OleVariant variant, ref int value) + 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 OleVariant variant, ref long value) + 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 OleVariant variant, ref byte value) + 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 OleVariant variant, ref ushort value) + 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 OleVariant variant, ref uint value) + 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 OleVariant variant, ref ulong value) + 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 OleVariant variant, ref int value) + 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 OleVariant variant, ref uint value) + 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 OleVariant variant, ref short value) + 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 OleVariant variant, ref int value) + 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 OleVariant variant, ref float value) + 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 OleVariant variant, ref double value) + 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 OleVariant variant, ref decimal value) + 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 OleVariant variant, ref long value) + 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 OleVariant variant, ref double value) + 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 OleVariant variant, ref IntPtr value) + 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 OleVariant variant, ref IntPtr value) + 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 OleVariant variant, ref IntPtr value) + 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 OleVariant variant, ref T value, VarEnum type) + 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 = OleVariant.CreateRaw(type | VarEnum.VT_BYREF, (nint)Unsafe.AsPointer(ref value)); + variant = ComVariant.CreateRaw(type | VarEnum.VT_BYREF, (nint)Unsafe.AsPointer(ref value)); } - public static void SetAsByrefVariant(ref this OleVariant variant, ref OleVariant value) + public static void SetAsByrefVariant(ref this ComVariant variant, ref ComVariant value) { variant.SetAsByref(ref value, VarEnum.VT_VARIANT); } @@ -236,7 +236,7 @@ private struct Record } // constructs a ByRef variant to pass contents of another variant ByRef. - public static unsafe void SetAsByrefVariantIndirect(this OleVariant variant, ref OleVariant value) + public static unsafe void SetAsByrefVariantIndirect(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"); @@ -251,14 +251,14 @@ public static unsafe void SetAsByrefVariantIndirect(this OleVariant variant, ref 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 = OleVariant.CreateRaw(value.VarType | VarEnum.VT_BYREF, value.GetRawDataRef()); + 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 = OleVariant.CreateRaw(value.VarType | VarEnum.VT_BYREF, (nint)Unsafe.AsPointer(ref value)); + variant = ComVariant.CreateRaw(value.VarType | VarEnum.VT_BYREF, (nint)Unsafe.AsPointer(ref value)); break; default: - variant = OleVariant.CreateRaw(value.VarType | VarEnum.VT_BYREF, (nint)Unsafe.AsPointer(ref value.GetRawDataRef())); + variant = ComVariant.CreateRaw(value.VarType | VarEnum.VT_BYREF, (nint)Unsafe.AsPointer(ref value.GetRawDataRef())); break; } } @@ -299,107 +299,107 @@ internal static System.Reflection.MethodInfo GetByrefSetter(VarEnum varType) } } - public static void SetI1(this ref OleVariant variant, sbyte value) + public static void SetI1(this ref ComVariant variant, sbyte value) { - variant = OleVariant.Create(value); + variant = ComVariant.Create(value); } - public static void SetUi1(this ref OleVariant variant, byte value) + public static void SetUi1(this ref ComVariant variant, byte value) { - variant = OleVariant.Create(value); + variant = ComVariant.Create(value); } - public static void SetI2(this ref OleVariant variant, short value) + public static void SetI2(this ref ComVariant variant, short value) { - variant = OleVariant.Create(value); + variant = ComVariant.Create(value); } - public static void SetUi2(this ref OleVariant variant, ushort value) + public static void SetUi2(this ref ComVariant variant, ushort value) { - variant = OleVariant.Create(value); + variant = ComVariant.Create(value); } - public static void SetI4(this ref OleVariant variant, int value) + public static void SetI4(this ref ComVariant variant, int value) { - variant = OleVariant.Create(value); + variant = ComVariant.Create(value); } - public static void SetUi4(this ref OleVariant variant, uint value) + public static void SetUi4(this ref ComVariant variant, uint value) { - variant = OleVariant.Create(value); + variant = ComVariant.Create(value); } - public static void SetI8(this ref OleVariant variant, long value) + public static void SetI8(this ref ComVariant variant, long value) { - variant = OleVariant.Create(value); + variant = ComVariant.Create(value); } - public static void SetUi8(this ref OleVariant variant, ulong value) + public static void SetUi8(this ref ComVariant variant, ulong value) { - variant = OleVariant.Create(value); + variant = ComVariant.Create(value); } - public static void SetInt(this ref OleVariant variant, int value) + public static void SetInt(this ref ComVariant variant, int value) { - variant = OleVariant.CreateRaw(VarEnum.VT_INT, value); + variant = ComVariant.CreateRaw(VarEnum.VT_INT, value); } - public static void SetUint(this ref OleVariant variant, uint value) + public static void SetUint(this ref ComVariant variant, uint value) { - variant = OleVariant.CreateRaw(VarEnum.VT_UINT, value); + variant = ComVariant.CreateRaw(VarEnum.VT_UINT, value); } - public static void SetBool(this ref OleVariant variant, bool value) + public static void SetBool(this ref ComVariant variant, bool value) { - variant = OleVariant.Create(value); + variant = ComVariant.Create(value); } - public static void SetR4(this ref OleVariant variant, float value) + public static void SetR4(this ref ComVariant variant, float value) { - variant = OleVariant.Create(value); + variant = ComVariant.Create(value); } - public static void SetR8(this ref OleVariant variant, double value) + public static void SetR8(this ref ComVariant variant, double value) { - variant = OleVariant.Create(value); + variant = ComVariant.Create(value); } - public static void SetDecimal(this ref OleVariant variant, decimal value) + public static void SetDecimal(this ref ComVariant variant, decimal value) { - variant = OleVariant.Create(value); + variant = ComVariant.Create(value); } - public static void SetDate(this ref OleVariant variant, DateTime value) + public static void SetDate(this ref ComVariant variant, DateTime value) { - variant = OleVariant.Create(value); + variant = ComVariant.Create(value); } - public static void SetBstr(this ref OleVariant variant, string value) + public static void SetBstr(this ref ComVariant variant, string value) { - variant = OleVariant.Create(new BStrWrapper(value)); + variant = ComVariant.Create(new BStrWrapper(value)); } - public static void SetUnknown(this ref OleVariant variant, object value) + public static void SetUnknown(this ref ComVariant variant, object value) { - variant = OleVariant.CreateRaw(VarEnum.VT_UNKNOWN, Marshal.GetIUnknownForObject(value)); + variant = ComVariant.CreateRaw(VarEnum.VT_UNKNOWN, Marshal.GetIUnknownForObject(value)); } - public static void SetDispatch(this ref OleVariant variant, object value) + public static void SetDispatch(this ref ComVariant variant, object value) { - variant = OleVariant.CreateRaw(VarEnum.VT_DISPATCH, Marshal.GetIDispatchForObject(value)); + variant = ComVariant.CreateRaw(VarEnum.VT_DISPATCH, Marshal.GetIDispatchForObject(value)); } - public static void SetError(this ref OleVariant variant, int value) + public static void SetError(this ref ComVariant variant, int value) { - variant = OleVariant.CreateRaw(VarEnum.VT_ERROR, value); + variant = ComVariant.CreateRaw(VarEnum.VT_ERROR, value); } - public static void SetCy(this ref OleVariant variant, decimal value) + public static void SetCy(this ref ComVariant variant, decimal value) { - variant = OleVariant.CreateRaw(VarEnum.VT_CY, decimal.ToOACurrency(value)); + variant = ComVariant.CreateRaw(VarEnum.VT_CY, decimal.ToOACurrency(value)); } - public static unsafe void SetVariant(this ref OleVariant variant, object 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) 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 a0291e5642a6f6..6f69602277aba2 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 an OleVariant. + /// 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 @@ -375,7 +375,7 @@ private static VarEnum GetComType(ref Type argumentType) } /// - /// Get the OleVariant 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 OleVariant or our extension methods. + // 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/VariantArray.cs b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/VariantArray.cs index 8d8b8d1f7d9f89..559b9e92c01b1e 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 @@ -17,25 +17,25 @@ namespace Microsoft.CSharp.RuntimeBinder.ComInterop [StructLayout(LayoutKind.Sequential)] internal struct VariantArray1 { - public OleVariant Element0; + public ComVariant Element0; } [StructLayout(LayoutKind.Sequential)] internal struct VariantArray2 { - public OleVariant Element0, Element1; + public ComVariant Element0, Element1; } [StructLayout(LayoutKind.Sequential)] internal struct VariantArray4 { - public OleVariant Element0, Element1, Element2, Element3; + public ComVariant Element0, Element1, Element2, Element3; } [StructLayout(LayoutKind.Sequential)] internal struct VariantArray8 { - public OleVariant Element0, Element1, Element2, Element3, Element4, Element5, Element6, Element7; + public ComVariant Element0, Element1, Element2, Element3, Element4, Element5, Element6, Element7; } // @@ -101,7 +101,7 @@ private static Type CreateCustomType(int size) TypeBuilder type = UnsafeMethods.DynamicModule.DefineType("VariantArray" + size, attrs, typeof(ValueType)); for (int i = 0; i < size; i++) { - type.DefineField("Element" + i, typeof(OleVariant), 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 ad8f359cebb83d..39bdcc24d96478 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 @@ -11,7 +11,7 @@ namespace Microsoft.CSharp.RuntimeBinder.ComInterop { /// - /// VariantBuilder handles packaging of arguments into an OleVariant for a call to IDispatch.Invoke + /// VariantBuilder handles packaging of arguments into an ComVariant for a call to IDispatch.Invoke /// internal sealed class VariantBuilder { @@ -91,8 +91,8 @@ internal Expression InitializeArgumentVariant(MemberExpression variant, Expressi return null; case VarEnum.VT_NULL: - // paramVariants._elementN = OleVariant.Null; - return Expression.Assign(variant, Expression.Property(null, typeof(OleVariant).GetProperty(nameof(OleVariant.Null), BindingFlags.Public | BindingFlags.Static))); + // 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"); @@ -130,7 +130,7 @@ internal Expression Clear() if (_argBuilder is VariantArgBuilder) { Debug.Assert(TempVariable != null); - return Expression.Call(TempVariable, typeof(OleVariant).GetMethod(nameof(OleVariant.Dispose))); + return Expression.Call(TempVariable, typeof(ComVariant).GetMethod(nameof(ComVariant.Dispose))); } return null; } @@ -148,7 +148,7 @@ internal Expression Clear() case VarEnum.VT_RECORD: case VarEnum.VT_VARIANT: // paramVariants._elementN.Dispose() - return Expression.Call(_variant, typeof(OleVariant).GetMethod(nameof(OleVariant.Dispose))); + return Expression.Call(_variant, typeof(ComVariant).GetMethod(nameof(ComVariant.Dispose))); default: Debug.Assert(_targetComType.IsPrimitiveType(), "Unexpected VarEnum"); 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 21184e0e42b2ef..f29fb6a96f80ae 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 @@ -974,12 +974,12 @@ + - diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/OleVariant.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ComVariant.cs similarity index 94% rename from src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/OleVariant.cs rename to src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ComVariant.cs index f6cedccc0cd618..1c36165cbcf7d5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/OleVariant.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ComVariant.cs @@ -10,15 +10,15 @@ namespace System.Runtime.InteropServices.Marshalling /// A type that represents an OLE VARIANT in managed code. /// [StructLayout(LayoutKind.Explicit)] - public struct OleVariant : IDisposable + public struct ComVariant : IDisposable { private const VarEnum VT_VERSIONED_STREAM = (VarEnum)73; #if DEBUG - static unsafe OleVariant() + 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. - int variantSize = sizeof(OleVariant); + int variantSize = sizeof(ComVariant); if (IntPtr.Size == 4) { Debug.Assert(variantSize == (4 * IntPtr.Size)); @@ -119,7 +119,7 @@ private unsafe struct UnionTypes } /// - /// Release resources owned by this instance. + /// Release resources owned by this instance. /// public unsafe void Dispose() { @@ -136,7 +136,7 @@ public unsafe void Dispose() } else if (VarType.HasFlag(VarEnum.VT_ARRAY)) { - throw new PlatformNotSupportedException("OleVariants containing SAFEARRAYs are not supported on this platform"); + throw new PlatformNotSupportedException("ComVariants containing SAFEARRAYs are not supported on this platform"); } else if (VarType == VarEnum.VT_UNKNOWN || VarType == VarEnum.VT_DISPATCH) { @@ -214,7 +214,7 @@ public unsafe void Dispose() } break; case VarEnum.VT_VARIANT: - foreach (var variant in GetRawDataRef>().AsSpan()) + foreach (var variant in GetRawDataRef>().AsSpan()) { variant.Dispose(); } @@ -225,22 +225,22 @@ public unsafe void Dispose() Marshal.CoTaskMemFree((nint)GetRawDataRef>()._data); } - // Clear out this OleVariant instance. + // 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. + /// 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. + /// The value to wrap in an . + /// An that contains the provided value. /// When does not directly correspond to a variant type. - public static OleVariant Create([DisallowNull] T value) + public static ComVariant Create([DisallowNull] T value) { - Unsafe.SkipInit(out OleVariant variant); + Unsafe.SkipInit(out ComVariant variant); if (typeof(T) == typeof(DBNull)) { variant = Null; @@ -285,7 +285,7 @@ public static OleVariant Create([DisallowNull] T value) // 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 OleVariant type with VT_LPSTR or VT_LPWSTR can use CreateRaw + // 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); @@ -350,7 +350,7 @@ public static OleVariant Create([DisallowNull] T value) #pragma warning restore CS0618 /// - /// Create a with the given type and provided value. + /// Create a with the given type and provided value. /// /// The type of the value to store in the variant. /// The type of the variant @@ -358,7 +358,7 @@ public static OleVariant Create([DisallowNull] T value) /// 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 OleVariant CreateRaw(VarEnum vt, T rawValue) + public static unsafe ComVariant CreateRaw(VarEnum vt, T rawValue) where T : unmanaged { ArgumentOutOfRangeException.ThrowIfGreaterThan(Unsafe.SizeOf(), sizeof(UnionTypes), nameof(T)); @@ -372,10 +372,10 @@ public static unsafe OleVariant CreateRaw(VarEnum vt, T rawValue) } if (vt.HasFlag(VarEnum.VT_ARRAY) && !OperatingSystem.IsWindows()) { - throw new PlatformNotSupportedException("OleVariants containing SAFEARRAYs are not supported on this platform"); + throw new PlatformNotSupportedException("ComVariants containing SAFEARRAYs are not supported on this platform"); } - Unsafe.SkipInit(out OleVariant value); + Unsafe.SkipInit(out ComVariant value); value.VarType = vt; value.GetRawDataRef() = (vt, sizeof(T)) switch { @@ -398,9 +398,9 @@ _ when vt.HasFlag(VarEnum.VT_ARRAY) && sizeof(T) == nint.Size => rawValue, } /// - /// A instance that represents a null value with type. + /// A instance that represents a null value with type. /// - public static OleVariant Null { get; } = new() { VarType = VarEnum.VT_NULL }; + public static ComVariant Null { get; } = new() { VarType = VarEnum.VT_NULL }; private readonly void ThrowIfNotVarType(params VarEnum[] requiredType) { @@ -412,11 +412,11 @@ private readonly void ThrowIfNotVarType(params VarEnum[] requiredType) #pragma warning disable CS0618 // Type or member is obsolete /// - /// Create a managed value based on the value in the instance. + /// 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 . + /// When does not match the of the . public readonly T As() { if (VarType == VarEnum.VT_EMPTY) @@ -465,8 +465,8 @@ public readonly T As() } else if (typeof(T) == typeof(string)) { - // To match the Create method, we will only support getting a string from an OleVariant - // when the OleVariant holds a BSTR. + // 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) { @@ -492,7 +492,7 @@ public readonly T As() 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. - OleVariant variantWithoutVarType = this; + ComVariant variantWithoutVarType = this; variantWithoutVarType.VarType = VarEnum.VT_EMPTY; return (T)(object)variantWithoutVarType._decimal; } @@ -531,7 +531,7 @@ public readonly T As() #pragma warning restore CS0618 // Type or member is obsolete /// - /// The type of the data stored in this . + /// The type of the data stored in this . /// public VarEnum VarType { @@ -540,11 +540,11 @@ public VarEnum VarType } /// - /// Get a reference to the storage location within this instance. + /// 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 . + /// 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 diff --git a/src/libraries/System.Runtime.InteropServices/System.Runtime.InteropServices.sln b/src/libraries/System.Runtime.InteropServices/System.Runtime.InteropServices.sln index e9534f4a25c813..56ccb89703b8ef 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/Microsoft.Interop.SourceGeneration/MarshalAsWithCustomMarshallersParser.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MarshalAsWithCustomMarshallersParser.cs index 4519410e4e2d6f..2a77292ac02d3a 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 @@ -94,7 +94,7 @@ public MarshalAsWithCustomMarshallersParser(Compilation compilation, GeneratorDi if (type.SpecialType == SpecialType.System_Object && marshalAsInfo is MarshalAsScalarInfo(UnmanagedType.Struct, _)) { - return CustomMarshallingInfoHelper.CreateMarshallingInfoByMarshallerTypeName(_compilation, type, TypeNames.OleVariantMarshaller); + return CustomMarshallingInfoHelper.CreateMarshallingInfoByMarshallerTypeName(_compilation, type, TypeNames.ComVariantMarshaller); } return marshalAsInfo; 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 index e598a07bd7829e..43f6e850d9a4bf 100644 --- 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 @@ -23,7 +23,7 @@ public ResolvedGenerator Create(TypePositionInfo info, StubCodeContext context) } // 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.OleVariantMarshaller), _) } + if (info is { RefKind: RefKind.In, MarshallingAttributeInfo: NativeMarshallingAttributeInfo(ManagedTypeInfo(_, TypeNames.ComVariantMarshaller), _) } && context.Direction == MarshalDirection.UnmanagedToManaged) { gen = ResolvedGenerator.ResolvedWithDiagnostics( 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 28f3eec7fd0ef9..d712ab5416d942 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 @@ -312,6 +312,6 @@ public static string MarshalEx(InteropGenerationOptions options) public const string CallConvMemberFunctionName = "System.Runtime.CompilerServices.CallConvMemberFunction"; public const string Nint = "nint"; - public const string OleVariantMarshaller = "System.Runtime.InteropServices.Marshalling.OleVariantMarshaller"; + 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 cffd4062c066ce..dd80aa3dbf1b18 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -460,19 +460,19 @@ 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.OleVariantMarshaller))] - [System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute(typeof(object), System.Runtime.InteropServices.Marshalling.MarshalMode.UnmanagedToManagedRef, typeof(System.Runtime.InteropServices.Marshalling.OleVariantMarshaller.RefPropogate))] - public static partial class OleVariantMarshaller + [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.RefPropogate))] + public static partial class ComVariantMarshaller { - public static System.Runtime.InteropServices.Marshalling.OleVariant ConvertToUnmanaged(object? managed) { throw null; } - public static object? ConvertToManaged(System.Runtime.InteropServices.Marshalling.OleVariant unmanaged) { throw null; } - public static void Free(System.Runtime.InteropServices.Marshalling.OleVariant unmanaged) { } + 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 RefPropogate { - public void FromUnmanaged(System.Runtime.InteropServices.Marshalling.OleVariant unmanaged) { } + public void FromUnmanaged(System.Runtime.InteropServices.Marshalling.ComVariant unmanaged) { } public void FromManaged(object? managed) { } - public System.Runtime.InteropServices.Marshalling.OleVariant ToUnmanaged() { throw null; } + public System.Runtime.InteropServices.Marshalling.ComVariant ToUnmanaged() { throw null; } public object? ToManaged() { throw null; } public void Free() { } } @@ -2517,14 +2517,14 @@ 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 OleVariant : System.IDisposable + public struct ComVariant : System.IDisposable { private int _dummyPrimitive; public void Dispose() { } - public static System.Runtime.InteropServices.Marshalling.OleVariant Create([System.Diagnostics.CodeAnalysis.DisallowNullAttribute] T value) { throw null; } - public static System.Runtime.InteropServices.Marshalling.OleVariant CreateRaw(System.Runtime.InteropServices.VarEnum vt, T rawValue) where T : unmanaged { throw null; } - public static System.Runtime.InteropServices.Marshalling.OleVariant Null { get { throw null; } } + 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] 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 f35de7ed9aac5a..1f5fd6a4de7e81 100644 --- a/src/libraries/System.Runtime.InteropServices/src/System.Runtime.InteropServices.csproj +++ b/src/libraries/System.Runtime.InteropServices/src/System.Runtime.InteropServices.csproj @@ -34,7 +34,7 @@ - + diff --git a/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/OleVariantMarshaller.cs b/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/ComVariantMarshaller.cs similarity index 87% rename from src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/OleVariantMarshaller.cs rename to src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/ComVariantMarshaller.cs index 1188b8a9e5368a..3ab19b82b2c3fe 100644 --- a/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/OleVariantMarshaller.cs +++ b/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/ComVariantMarshaller.cs @@ -10,16 +10,16 @@ namespace System.Runtime.InteropServices.Marshalling { /// - /// Marshals an to an . + /// Marshals an to an . /// /// - /// Supports the same types as as well as any types with applied. + /// Supports the same types as as well as any types with applied. /// - [CustomMarshaller(typeof(object), MarshalMode.Default, typeof(OleVariantMarshaller))] + [CustomMarshaller(typeof(object), MarshalMode.Default, typeof(ComVariantMarshaller))] [CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedRef, typeof(RefPropogate))] - public static partial class OleVariantMarshaller + public static partial class ComVariantMarshaller { - public static OleVariant ConvertToUnmanaged(object? managed) + public static ComVariant ConvertToUnmanaged(object? managed) { if (managed is null) { @@ -30,56 +30,56 @@ public static OleVariant ConvertToUnmanaged(object? managed) switch (managed) { case sbyte s: - return OleVariant.Create(s); + return ComVariant.Create(s); case byte b: - return OleVariant.Create(b); + return ComVariant.Create(b); case short s: - return OleVariant.Create(s); + return ComVariant.Create(s); case ushort s: - return OleVariant.Create(s); + return ComVariant.Create(s); case int i: - return OleVariant.Create(i); + return ComVariant.Create(i); case uint i: - return OleVariant.Create(i); + return ComVariant.Create(i); case long l: - return OleVariant.Create(l); + return ComVariant.Create(l); case ulong l: - return OleVariant.Create(l); + return ComVariant.Create(l); case float f: - return OleVariant.Create(f); + return ComVariant.Create(f); case double d: - return OleVariant.Create(d); + return ComVariant.Create(d); case decimal d: - return OleVariant.Create(d); + return ComVariant.Create(d); case bool b: - return OleVariant.Create(b); + return ComVariant.Create(b); case char c: - return OleVariant.Create((ushort)c); + return ComVariant.Create((ushort)c); case string s: - return OleVariant.Create(s); + return ComVariant.Create(s); case DateTime dt: - return OleVariant.Create(dt); + return ComVariant.Create(dt); case ErrorWrapper errorWrapper: - return OleVariant.Create(errorWrapper); + return ComVariant.Create(errorWrapper); case CurrencyWrapper currencyWrapper: - return OleVariant.Create(currencyWrapper); + return ComVariant.Create(currencyWrapper); case BStrWrapper bStrWrapper: - return OleVariant.Create(bStrWrapper); + return ComVariant.Create(bStrWrapper); case DBNull: - return OleVariant.Null; + return ComVariant.Null; } #pragma warning restore CS0618 // Type or member is obsolete - if (TryCreateOleVariantForInterfaceWrapper(managed, out OleVariant variant)) + if (TryCreateOleVariantForInterfaceWrapper(managed, out ComVariant variant)) { return variant; } - throw new ArgumentException("Type of managed object is not supported for marshalling as OleVariant.", nameof(managed)); + throw new ArgumentException("Type of managed object is not supported for marshalling as ComVariant.", nameof(managed)); } #pragma warning disable CA1416 // Validate platform compatibility - private static unsafe bool TryCreateOleVariantForInterfaceWrapper(object managed, out OleVariant variant) + private static unsafe bool TryCreateOleVariantForInterfaceWrapper(object managed, out ComVariant variant) { if (managed is UnknownWrapper uw) { @@ -89,12 +89,12 @@ private static unsafe bool TryCreateOleVariantForInterfaceWrapper(object managed variant = default; return true; } - variant = OleVariant.CreateRaw(VarEnum.VT_UNKNOWN, StrategyBasedComWrappers.DefaultMarshallingInstance.GetOrCreateComInterfaceForObject(wrapped, CreateComInterfaceFlags.None)); + 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 = OleVariant.CreateRaw(VarEnum.VT_UNKNOWN, StrategyBasedComWrappers.DefaultMarshallingInstance.GetOrCreateComInterfaceForObject(managed, CreateComInterfaceFlags.None)); + variant = ComVariant.CreateRaw(VarEnum.VT_UNKNOWN, StrategyBasedComWrappers.DefaultMarshallingInstance.GetOrCreateComInterfaceForObject(managed, CreateComInterfaceFlags.None)); return true; } variant = default; @@ -102,7 +102,7 @@ private static unsafe bool TryCreateOleVariantForInterfaceWrapper(object managed } #pragma warning restore CA1416 // Validate platform compatibility - public static unsafe object? ConvertToManaged(OleVariant unmanaged) + public static unsafe object? ConvertToManaged(ComVariant unmanaged) { #pragma warning disable CS0618 // Type or member is obsolete #pragma warning disable CA1416 // Validate platform compatibility @@ -152,7 +152,7 @@ private static unsafe bool TryCreateOleVariantForInterfaceWrapper(object managed case VarEnum.VT_DISPATCH: return StrategyBasedComWrappers.DefaultMarshallingInstance.GetOrCreateObjectForComInstance(unmanaged.GetRawDataRef(), CreateObjectFlags.Unwrap); case VarEnum.VT_BYREF | VarEnum.VT_VARIANT: - return ConvertToManaged(*(OleVariant*)unmanaged.GetRawDataRef()); + return ConvertToManaged(*(ComVariant*)unmanaged.GetRawDataRef()); case VarEnum.VT_BYREF | VarEnum.VT_I1: return *(sbyte*)unmanaged.GetRawDataRef(); case VarEnum.VT_BYREF | VarEnum.VT_UI1: @@ -194,22 +194,22 @@ private static unsafe bool TryCreateOleVariantForInterfaceWrapper(object managed #pragma warning restore CS0618 // Type or member is obsolete } - public static void Free(OleVariant unmanaged) => unmanaged.Dispose(); + public static void Free(ComVariant unmanaged) => unmanaged.Dispose(); /// - /// Marshals a to an , propagating the value of the back to the variant's + /// Marshals a to an , propagating the value of the back to the variant's /// existing data storage if the variant has type. /// public struct RefPropogate { - private OleVariant _unmanaged; + private ComVariant _unmanaged; private object? _managed; /// /// Initializes the marshaller with an unmanaged variant. /// /// The unmanaged value - public void FromUnmanaged(OleVariant unmanaged) => _unmanaged = unmanaged; + public void FromUnmanaged(ComVariant unmanaged) => _unmanaged = unmanaged; /// /// Initializes the marshaller with a managed object. @@ -218,11 +218,11 @@ public struct RefPropogate public void FromManaged(object? managed) => _managed = managed; /// - /// Create an unmanaged based on the provided managed and unmanaged values. + /// Create an unmanaged based on the provided managed and unmanaged values. /// - /// An instance representing the marshaller's current state. + /// 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 OleVariant ToUnmanaged() + public unsafe ComVariant ToUnmanaged() { if (!_unmanaged.VarType.HasFlag(VarEnum.VT_BYREF)) { @@ -244,7 +244,7 @@ or VarEnum.VT_DISPATCH switch ((_unmanaged.VarType & ~VarEnum.VT_BYREF, _managed)) { case (VarEnum.VT_VARIANT, _): - *(OleVariant*)_unmanaged.GetRawDataRef() = ConvertToUnmanaged(_managed); + *(ComVariant*)_unmanaged.GetRawDataRef() = ConvertToUnmanaged(_managed); break; case (VarEnum.VT_I1 or VarEnum.VT_UI1, sbyte s): *(sbyte*)_unmanaged.GetRawDataRef() = s; 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 f738a9c75e33a9..31369aaca2a4a3 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 @@ + + @@ -152,8 +154,6 @@ - - diff --git a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/OleVariantMarshallerTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/ComVariantMarshallerTests.cs similarity index 67% rename from src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/OleVariantMarshallerTests.cs rename to src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/ComVariantMarshallerTests.cs index 4b70a81f259dbb..f3f7becc116690 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/OleVariantMarshallerTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/ComVariantMarshallerTests.cs @@ -14,120 +14,120 @@ 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 OleVariantMarshallerTests + public partial class ComVariantMarshallerTests { [Fact] public void Null_Marshals_To_Empty() { - Assert.Equal(VarEnum.VT_EMPTY, OleVariantMarshaller.ConvertToUnmanaged(null).VarType); - Assert.Null(OleVariantMarshaller.ConvertToManaged(default)); + 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, OleVariantMarshaller.ConvertToUnmanaged(DBNull.Value).VarType); - Assert.Same(DBNull.Value, OleVariantMarshaller.ConvertToManaged(OleVariant.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"; - OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(value); + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(value); Assert.Equal(VarEnum.VT_BSTR, variant.VarType); - Assert.Equal(value, OleVariantMarshaller.ConvertToManaged(variant)); - OleVariantMarshaller.Free(variant); + Assert.Equal(value, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); } [Fact] public void BStrWrapper_Marshals_To_BStr() { string value = "Hello"; - OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(new BStrWrapper(value)); + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(new BStrWrapper(value)); Assert.Equal(VarEnum.VT_BSTR, variant.VarType); - Assert.Equal(value, OleVariantMarshaller.ConvertToManaged(variant)); - OleVariantMarshaller.Free(variant); + Assert.Equal(value, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); } [Fact] public void Int32_Marshals_To_I4() { int value = 42; - OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(value); + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(value); Assert.Equal(VarEnum.VT_I4, variant.VarType); - Assert.Equal(value, OleVariantMarshaller.ConvertToManaged(variant)); - OleVariantMarshaller.Free(variant); + Assert.Equal(value, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); } [Fact] public void UInt32_Marshals_To_UI4() { uint value = 42; - OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(value); + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(value); Assert.Equal(VarEnum.VT_UI4, variant.VarType); - Assert.Equal(value, OleVariantMarshaller.ConvertToManaged(variant)); - OleVariantMarshaller.Free(variant); + Assert.Equal(value, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); } [Fact] public void Int16_Marshals_To_I2() { short value = 42; - OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(value); + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(value); Assert.Equal(VarEnum.VT_I2, variant.VarType); - Assert.Equal(value, OleVariantMarshaller.ConvertToManaged(variant)); - OleVariantMarshaller.Free(variant); + Assert.Equal(value, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); } [Fact] public void UInt16_Marshals_To_UI2() { ushort value = 42; - OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(value); + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(value); Assert.Equal(VarEnum.VT_UI2, variant.VarType); - Assert.Equal(value, OleVariantMarshaller.ConvertToManaged(variant)); - OleVariantMarshaller.Free(variant); + Assert.Equal(value, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); } [Fact] public void Byte_Marshals_To_UI1() { byte value = 42; - OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(value); + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(value); Assert.Equal(VarEnum.VT_UI1, variant.VarType); - Assert.Equal(value, OleVariantMarshaller.ConvertToManaged(variant)); - OleVariantMarshaller.Free(variant); + Assert.Equal(value, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); } [Fact] public void SByte_Marshals_To_I1() { sbyte value = 42; - OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(value); + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(value); Assert.Equal(VarEnum.VT_I1, variant.VarType); - Assert.Equal(value, OleVariantMarshaller.ConvertToManaged(variant)); - OleVariantMarshaller.Free(variant); + Assert.Equal(value, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); } [Fact] public void Double_Marshals_To_R8() { double value = 42.0; - OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(value); + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(value); Assert.Equal(VarEnum.VT_R8, variant.VarType); - Assert.Equal(value, OleVariantMarshaller.ConvertToManaged(variant)); - OleVariantMarshaller.Free(variant); + Assert.Equal(value, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); } [Fact] public void Single_Marshals_To_R4() { float value = 42.0f; - OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(value); + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(value); Assert.Equal(VarEnum.VT_R4, variant.VarType); - Assert.Equal(value, OleVariantMarshaller.ConvertToManaged(variant)); - OleVariantMarshaller.Free(variant); + Assert.Equal(value, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); } [InlineData(true)] @@ -135,37 +135,37 @@ public void Single_Marshals_To_R4() [Theory] public void Boolean_Marshals_To_BOOL(bool value) { - OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(value); + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(value); Assert.Equal(VarEnum.VT_BOOL, variant.VarType); - Assert.Equal(value, OleVariantMarshaller.ConvertToManaged(variant)); - OleVariantMarshaller.Free(variant); + Assert.Equal(value, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); } [Fact] public void ErrorWrapper_Maps_To_VT_ERROR() { ErrorWrapper errorWrapper = new ErrorWrapper(42); - OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(errorWrapper); + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(errorWrapper); Assert.Equal(VarEnum.VT_ERROR, variant.VarType); - Assert.Equal(errorWrapper.ErrorCode, Assert.IsType(OleVariantMarshaller.ConvertToManaged(variant))); - OleVariantMarshaller.Free(variant); + 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", () => OleVariantMarshaller.ConvertToUnmanaged(wrapper)); + Assert.Throws("managed", () => ComVariantMarshaller.ConvertToUnmanaged(wrapper)); } [Fact] public void Decimal_Marshals_To_DECIMAL() { decimal value = 42.0m; - OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(value); + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(value); Assert.Equal(VarEnum.VT_DECIMAL, variant.VarType); - Assert.Equal(value, OleVariantMarshaller.ConvertToManaged(variant)); - OleVariantMarshaller.Free(variant); + Assert.Equal(value, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); } [Fact] @@ -174,10 +174,10 @@ 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"); - OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(value); + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(value); Assert.Equal(VarEnum.VT_DATE, variant.VarType); - Assert.Equal(value, OleVariantMarshaller.ConvertToManaged(variant)); - OleVariantMarshaller.Free(variant); + Assert.Equal(value, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); } #pragma warning disable CS0618 // Type or member is obsolete @@ -185,10 +185,10 @@ public void Date_Marshals_To_DATE() public void CurrentyWrapper_Marshals_To_CY() { decimal value = 42.0m; - OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(new CurrencyWrapper(value)); + ComVariant variant = ComVariantMarshaller.ConvertToUnmanaged(new CurrencyWrapper(value)); Assert.Equal(VarEnum.VT_CY, variant.VarType); - Assert.Equal(value, Assert.IsType(OleVariantMarshaller.ConvertToManaged(variant))); - OleVariantMarshaller.Free(variant); + Assert.Equal(value, Assert.IsType(ComVariantMarshaller.ConvertToManaged(variant))); + ComVariantMarshaller.Free(variant); } #pragma warning restore CS0618 // Type or member is obsolete @@ -209,41 +209,41 @@ public void Method() { } public unsafe void GeneratedComInterfaceType_Marshals_To_UNKNOWN() { var obj = new ComExposedType(); - OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(obj); + 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, OleVariantMarshaller.ConvertToManaged(variant)); - OleVariantMarshaller.Free(variant); + Assert.Same(obj, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); } [Fact] public void UnknownWrapper_Of_GeneratedComInterfaceType_Marshals_To_UNKNOWN() { var obj = new ComExposedType(); - OleVariant variant = OleVariantMarshaller.ConvertToUnmanaged(new UnknownWrapper(obj)); + 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, OleVariantMarshaller.ConvertToManaged(variant)); - OleVariantMarshaller.Free(variant); + Assert.Same(obj, ComVariantMarshaller.ConvertToManaged(variant)); + ComVariantMarshaller.Free(variant); } [Fact] public void INT_Marshals_as_Int() { - OleVariant variant = OleVariant.CreateRaw(VarEnum.VT_INT, 42); - Assert.Equal(42, Assert.IsType(OleVariantMarshaller.ConvertToManaged(variant))); + ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_INT, 42); + Assert.Equal(42, Assert.IsType(ComVariantMarshaller.ConvertToManaged(variant))); } [Fact] public void UINT_Marshals_as_UInt() { - OleVariant variant = OleVariant.CreateRaw(VarEnum.VT_UINT, 42u); - Assert.Equal(42u, Assert.IsType(OleVariantMarshaller.ConvertToManaged(variant))); + ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_UINT, 42u); + Assert.Equal(42u, Assert.IsType(ComVariantMarshaller.ConvertToManaged(variant))); } [InlineData(VarEnum.VT_I1, (byte)42)] @@ -272,22 +272,22 @@ public void UINT_Marshals_as_UInt() public unsafe void ByRef_Primitives(VarEnum elementType, object valueToSet) { long storage = 0; - OleVariant variant = OleVariant.CreateRaw(VarEnum.VT_BYREF | elementType, (nint)(&storage)); + ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_BYREF | elementType, (nint)(&storage)); // Set up the marshaller - OleVariantMarshaller.RefPropogate marshaller = default; + ComVariantMarshaller.RefPropogate marshaller = default; marshaller.FromUnmanaged(variant); // Marshal back the new value marshaller.FromManaged(valueToSet); - OleVariant updated = marshaller.ToUnmanaged(); + 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)OleVariantMarshaller.ConvertToManaged(variant)).ToType(valueToSet.GetType(), null)); + 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/OleVariantTests.cs b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/ComVariantTests.cs similarity index 81% rename from src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/OleVariantTests.cs rename to src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/ComVariantTests.cs index 9fd8607c44a3f7..ea668b18c7957b 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/OleVariantTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/System.Runtime.InteropServices.UnitTests/System/Runtime/InteropServices/ComVariantTests.cs @@ -14,24 +14,24 @@ 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 OleVariantTests + public class ComVariantTests { [Fact] public void DefaultVariantIsEmpty() { - Assert.Equal(VarEnum.VT_EMPTY, default(OleVariant).VarType); + Assert.Equal(VarEnum.VT_EMPTY, default(ComVariant).VarType); } [Fact] public void NullVariantIsNull() { - Assert.Equal(VarEnum.VT_NULL, OleVariant.Null.VarType); + Assert.Equal(VarEnum.VT_NULL, ComVariant.Null.VarType); } [Fact] public void Short() { - OleVariant variant = OleVariant.Create(42); + ComVariant variant = ComVariant.Create(42); Assert.Equal(VarEnum.VT_I2, variant.VarType); Assert.Equal(42, variant.As()); Assert.Equal(42, variant.GetRawDataRef()); @@ -40,7 +40,7 @@ public void Short() [Fact] public void Int4() { - OleVariant variant = OleVariant.Create(42); + ComVariant variant = ComVariant.Create(42); Assert.Equal(VarEnum.VT_I4, variant.VarType); Assert.Equal(42, variant.As()); Assert.Equal(42, variant.GetRawDataRef()); @@ -49,7 +49,7 @@ public void Int4() [Fact] public void Float() { - OleVariant variant = OleVariant.Create(42.0f); + ComVariant variant = ComVariant.Create(42.0f); Assert.Equal(VarEnum.VT_R4, variant.VarType); Assert.Equal(42, variant.As()); Assert.Equal(42, variant.GetRawDataRef()); @@ -58,7 +58,7 @@ public void Float() [Fact] public void Double() { - OleVariant variant = OleVariant.Create(42.0); + ComVariant variant = ComVariant.Create(42.0); Assert.Equal(VarEnum.VT_R8, variant.VarType); Assert.Equal(42, variant.As()); Assert.Equal(42, variant.GetRawDataRef()); @@ -68,7 +68,7 @@ public void Double() [Fact] public void Currency() { - OleVariant variant = OleVariant.Create(new CurrencyWrapper(42.0m)); + 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()); @@ -78,7 +78,7 @@ public void Currency() [Fact] public void Date() { - OleVariant variant = OleVariant.Create(new DateTime(2020, 1, 1)); + 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()); @@ -87,7 +87,7 @@ public void Date() [Fact] public void BStrWrapper() { - using OleVariant variant = OleVariant.Create(new BStrWrapper("Foo")); + 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())); @@ -96,7 +96,7 @@ public void BStrWrapper() [Fact] public void BStr_String() { - using OleVariant variant = OleVariant.Create("Foo"); + 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())); @@ -105,7 +105,7 @@ public void BStr_String() [Fact] public void BStr_String_Null() { - using OleVariant variant = OleVariant.Create(null); + using ComVariant variant = ComVariant.Create(null); Assert.Equal(VarEnum.VT_BSTR, variant.VarType); Assert.Null(variant.As()); Assert.Equal(IntPtr.Zero, variant.GetRawDataRef()); @@ -116,14 +116,14 @@ public void BStr_String_Null() public void Dispatch_NotSupported() { DispatchWrapper wrapper = new(new IDispatchComObject()); - Assert.Throws("T", () => OleVariant.Create(wrapper)); + Assert.Throws("T", () => ComVariant.Create(wrapper)); } #endif [Fact] public void Error() { - OleVariant variant = OleVariant.CreateRaw(VarEnum.VT_ERROR, 1); + 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); @@ -133,7 +133,7 @@ public void Error() [Fact] public void VariantBoolTrue() { - OleVariant trueVariant = OleVariant.Create(true); + ComVariant trueVariant = ComVariant.Create(true); Assert.Equal(VarEnum.VT_BOOL, trueVariant.VarType); Assert.True(trueVariant.As()); Assert.Equal(0, trueVariant.GetRawDataRef()); @@ -142,7 +142,7 @@ public void VariantBoolTrue() [Fact] public void VariantBoolFalse() { - OleVariant falseVariant = OleVariant.Create(false); + ComVariant falseVariant = ComVariant.Create(false); Assert.Equal(VarEnum.VT_BOOL, falseVariant.VarType); Assert.False(falseVariant.As()); Assert.Equal(-1, falseVariant.GetRawDataRef()); @@ -151,14 +151,14 @@ public void VariantBoolFalse() [Fact] public void VTVariantNotSupported() { - Assert.Throws("vt", () => OleVariant.CreateRaw(VarEnum.VT_VARIANT, 1)); + 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", () => OleVariant.Create(wrapper)); + Assert.Throws("T", () => ComVariant.Create(wrapper)); } [ComImport] @@ -175,7 +175,7 @@ private sealed class TestObject : IUnknownInterface [Fact] public void Decimal() { - OleVariant variant = OleVariant.Create(42.0m); + ComVariant variant = ComVariant.Create(42.0m); Assert.Equal(VarEnum.VT_DECIMAL, variant.VarType); Assert.Equal(42.0m, variant.As()); Assert.Throws("T", () => variant.GetRawDataRef()); @@ -184,7 +184,7 @@ public void Decimal() [Fact] public void SByte() { - OleVariant variant = OleVariant.Create(42); + ComVariant variant = ComVariant.Create(42); Assert.Equal(VarEnum.VT_I1, variant.VarType); Assert.Equal(42, variant.As()); Assert.Equal(42, variant.GetRawDataRef()); @@ -193,7 +193,7 @@ public void SByte() [Fact] public void Byte() { - OleVariant variant = OleVariant.Create(42); + ComVariant variant = ComVariant.Create(42); Assert.Equal(VarEnum.VT_UI1, variant.VarType); Assert.Equal(42, variant.As()); Assert.Equal(42, variant.GetRawDataRef()); @@ -202,7 +202,7 @@ public void Byte() [Fact] public void UShort() { - OleVariant variant = OleVariant.Create(42); + ComVariant variant = ComVariant.Create(42); Assert.Equal(VarEnum.VT_UI2, variant.VarType); Assert.Equal(42, variant.As()); Assert.Equal(42, variant.GetRawDataRef()); @@ -211,7 +211,7 @@ public void UShort() [Fact] public void UInt4() { - OleVariant variant = OleVariant.Create(42); + ComVariant variant = ComVariant.Create(42); Assert.Equal(VarEnum.VT_UI4, variant.VarType); Assert.Equal(42u, variant.As()); Assert.Equal(42u, variant.GetRawDataRef()); @@ -220,7 +220,7 @@ public void UInt4() [Fact] public void Long() { - OleVariant variant = OleVariant.Create(42); + ComVariant variant = ComVariant.Create(42); Assert.Equal(VarEnum.VT_I8, variant.VarType); Assert.Equal(42, variant.As()); Assert.Equal(42, variant.GetRawDataRef()); @@ -229,7 +229,7 @@ public void Long() [Fact] public void ULong() { - OleVariant variant = OleVariant.Create(42); + ComVariant variant = ComVariant.Create(42); Assert.Equal(VarEnum.VT_UI8, variant.VarType); Assert.Equal(42ul, variant.As()); Assert.Equal(42ul, variant.GetRawDataRef()); @@ -238,7 +238,7 @@ public void ULong() [Fact] public void Int_Raw() { - OleVariant variant = OleVariant.CreateRaw(VarEnum.VT_INT, 42); + 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()); @@ -247,7 +247,7 @@ public void Int_Raw() [Fact] public void UInt() { - OleVariant variant = OleVariant.CreateRaw(VarEnum.VT_UINT, 42u); + 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()); @@ -264,9 +264,9 @@ private struct Record public void Record_Raw() { // We do not support record types in the opinionated Create method. - Assert.Throws("T", () => OleVariant.Create(new Record())); + Assert.Throws("T", () => ComVariant.Create(new Record())); // We support creating a record-based variant with the CreateRaw method. - OleVariant variant = OleVariant.CreateRaw(VarEnum.VT_RECORD, new Record()); + ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_RECORD, new Record()); Assert.Equal(VarEnum.VT_RECORD, variant.VarType); Assert.Equal(default, variant.GetRawDataRef()); } @@ -275,7 +275,7 @@ public void Record_Raw() public void LPStr_Raw() { string str = "Foo"; - using OleVariant variant = OleVariant.CreateRaw(VarEnum.VT_LPSTR, Marshal.StringToCoTaskMemAnsi(str)); + 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())); @@ -285,7 +285,7 @@ public void LPStr_Raw() public void LPWStr_Raw() { string str = "Foo"; - using OleVariant variant = OleVariant.CreateRaw(VarEnum.VT_LPWSTR, Marshal.StringToCoTaskMemUni(str)); + 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())); @@ -295,7 +295,7 @@ public void LPWStr_Raw() public void FileTime_Raw() { long fileTime = 1039348523; - OleVariant variant = OleVariant.CreateRaw(VarEnum.VT_FILETIME, fileTime); + ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_FILETIME, fileTime); Assert.Equal(VarEnum.VT_FILETIME, variant.VarType); Assert.Throws(() => variant.As()); Assert.Equal(fileTime, variant.GetRawDataRef()); @@ -312,7 +312,7 @@ private struct Blob public void Blob_Raw() { Blob blob = new Blob { Length = 3, Data = Marshal.AllocCoTaskMem(25) }; - using OleVariant variant = OleVariant.CreateRaw(VarEnum.VT_BLOB, blob); + 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()); @@ -322,8 +322,8 @@ public void Blob_Raw() public void Stream_Raw() { IntPtr nativeStream = 42; - // Using a fake value so we aren't disposing the OleVariant instance. - OleVariant variant = OleVariant.CreateRaw(VarEnum.VT_STREAM, nativeStream); + // 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()); } @@ -332,8 +332,8 @@ public void Stream_Raw() public void Storage_Raw() { IntPtr nativeStorage = 42; - // Using a fake value so we aren't disposing the OleVariant instance. - OleVariant variant = OleVariant.CreateRaw(VarEnum.VT_STORAGE, nativeStorage); + // 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()); } @@ -342,8 +342,8 @@ public void Storage_Raw() public void StreamedObject_Raw() { IntPtr nativeStream = 42; - // Using a fake value so we aren't disposing the OleVariant instance. - OleVariant variant = OleVariant.CreateRaw(VarEnum.VT_STREAMED_OBJECT, nativeStream); + // 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()); } @@ -352,8 +352,8 @@ public void StreamedObject_Raw() public void StoredObject_Raw() { IntPtr nativeStorage = 42; - // Using a fake value so we aren't disposing the OleVariant instance. - OleVariant variant = OleVariant.CreateRaw(VarEnum.VT_STORED_OBJECT, nativeStorage); + // 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()); } @@ -362,8 +362,8 @@ public void StoredObject_Raw() public void VersionedStream_Raw() { IntPtr nativeStream = 42; - // Using a fake value so we aren't disposing the OleVariant instance. - OleVariant variant = OleVariant.CreateRaw((VarEnum)73, nativeStream); + // 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()); } @@ -372,7 +372,7 @@ public void VersionedStream_Raw() public void BlobObject_Raw() { Blob blob = new Blob { Length = 3, Data = Marshal.AllocCoTaskMem(10) }; - using OleVariant variant = OleVariant.CreateRaw(VarEnum.VT_BLOB_OBJECT, blob); + 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()); @@ -396,7 +396,7 @@ public unsafe void ClipData_Raw() ((ClipboardData*)clipboardData)->_size = 10; ((ClipboardData*)clipboardData)->_format = 1; - using OleVariant variant = OleVariant.CreateRaw(VarEnum.VT_CF, clipboardData); + using ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_CF, clipboardData); Assert.Equal(VarEnum.VT_CF, variant.VarType); Assert.Equal(clipboardData, variant.GetRawDataRef()); } @@ -407,7 +407,7 @@ 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 OleVariant variant = OleVariant.CreateRaw(VarEnum.VT_CLSID, pClsid); + using ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_CLSID, pClsid); Assert.Equal(VarEnum.VT_CLSID, variant.VarType); Assert.Equal(pClsid, variant.GetRawDataRef()); } @@ -423,7 +423,7 @@ private struct Vector public void Vector_Raw() { Vector vector = new Vector { Length = 3, Data = Marshal.AllocCoTaskMem(sizeof(int) * 3) }; - using OleVariant variant = OleVariant.CreateRaw(VarEnum.VT_VECTOR | VarEnum.VT_I4, vector); + 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()); @@ -434,8 +434,8 @@ public void Vector_Raw() public void Array_Raw() { IntPtr safeArray = 42; - // Using a fake value so we aren't disposing the OleVariant instance. - OleVariant variant = OleVariant.CreateRaw(VarEnum.VT_ARRAY | VarEnum.VT_I4, safeArray); + // 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()); } @@ -444,7 +444,7 @@ public void Array_Raw() [PlatformSpecific(~TestPlatforms.Windows)] public void Array_Raw_NonWindows() { - Assert.Throws(() => OleVariant.CreateRaw(VarEnum.VT_ARRAY | VarEnum.VT_I4, 0)); + Assert.Throws(() => ComVariant.CreateRaw(VarEnum.VT_ARRAY | VarEnum.VT_I4, 0)); } [Fact] @@ -452,7 +452,7 @@ public void ByRef_Raw() { // byref VARIANTs don't own the memory they point to. IntPtr byref = Marshal.AllocCoTaskMem(4); - using OleVariant variant = OleVariant.CreateRaw(VarEnum.VT_BYREF | VarEnum.VT_I4, byref); + 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); diff --git a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/Variant.cs b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/Variant.cs index 0085d27d3d9514..7ad1218f6f3ecc 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/Variant.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/Variant.cs @@ -15,7 +15,7 @@ namespace NativeExports public static unsafe class Variant { [UnmanagedCallersOnly(EntryPoint = "get_variant_bstr_length")] - public static int GetVTBStrLength([DNNE.C99Type("void*")] OleVariant* variant) + public static int GetVTBStrLength([DNNE.C99Type("void*")] ComVariant* variant) { return variant->As().Length; } From c7ee9062df2ed746a5b6f0324acc4518c38a34e1 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Thu, 19 Oct 2023 15:38:36 -0700 Subject: [PATCH 08/20] PR feedback --- .../src/Resources/Strings.resx | 85 ++++++++++++------- .../InteropServices/Marshalling/ComVariant.cs | 39 +++++---- .../TypeNames.cs | 1 - .../ref/System.Runtime.InteropServices.cs | 6 +- .../src/Resources/Strings.resx | 70 ++++++++++++++- .../Marshalling/ComVariantMarshaller.cs | 10 +-- .../ComVariantMarshallerTests.cs | 2 +- 7 files changed, 153 insertions(+), 60 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index e1cc39aeaf4aa5..6300780e9aeb26 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. @@ -3777,7 +3777,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. @@ -4256,4 +4256,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/Runtime/InteropServices/Marshalling/ComVariant.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ComVariant.cs index f58e4f1fd4b106..b0dbddf2c47b8f 100644 --- 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 @@ -12,12 +12,14 @@ namespace System.Runtime.InteropServices.Marshalling [StructLayout(LayoutKind.Explicit)] public struct ComVariant : IDisposable { + // See definition in wtypes.h in the Windows SDK. private const VarEnum VT_VERSIONED_STREAM = (VarEnum)73; #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) { @@ -74,14 +76,14 @@ private unsafe struct Vector where T : unmanaged } [StructLayout(LayoutKind.Sequential)] - private unsafe struct VersionedStream + private struct VersionedStream { public Guid _version; public IntPtr _stream; } [StructLayout(LayoutKind.Sequential)] - private unsafe struct ClipboardData + private struct ClipboardData { public uint _size; public int _format; @@ -126,6 +128,10 @@ 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 @@ -136,7 +142,7 @@ public unsafe void Dispose() } else if (VarType.HasFlag(VarEnum.VT_ARRAY)) { - throw new PlatformNotSupportedException("ComVariants containing SAFEARRAYs are not supported on this platform"); + throw new PlatformNotSupportedException(SR.ComVariant_SafeArray_PlatformNotSupported); } else if (VarType == VarEnum.VT_UNKNOWN || VarType == VarEnum.VT_DISPATCH) { @@ -240,7 +246,8 @@ public unsafe void Dispose() /// When does not directly correspond to a variant type. public static ComVariant Create([DisallowNull] T value) { - Unsafe.SkipInit(out ComVariant variant); + ComVariant variant; + Unsafe.SkipInit(out variant); if (typeof(T) == typeof(DBNull)) { variant = Null; @@ -340,7 +347,7 @@ public static ComVariant Create([DisallowNull] T value) } else { - throw new ArgumentException("Unsupported type", nameof(T)); + 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. @@ -364,15 +371,15 @@ public static unsafe ComVariant CreateRaw(VarEnum vt, T rawValue) ArgumentOutOfRangeException.ThrowIfGreaterThan(Unsafe.SizeOf(), sizeof(UnionTypes), nameof(T)); if (vt == VarEnum.VT_DECIMAL) { - throw new ArgumentException("VT_DECIMAL is not supported in CreateRaw. Use the Create method.", nameof(vt)); + throw new ArgumentException(SR.ComVariant_VT_DECIMAL_NotSupported_CreateRaw, nameof(vt)); } if (vt == VarEnum.VT_VARIANT) { - throw new ArgumentException("VT_VARIANT is not supported in variants.", nameof(vt)); + throw new ArgumentException(SR.ComVariant_VT_VARIANT_In_Variant, nameof(vt)); } if (vt.HasFlag(VarEnum.VT_ARRAY) && !OperatingSystem.IsWindows()) { - throw new PlatformNotSupportedException("ComVariants containing SAFEARRAYs are not supported on this platform"); + throw new PlatformNotSupportedException(SR.ComVariant_SafeArray_PlatformNotSupported); } Unsafe.SkipInit(out ComVariant value); @@ -383,7 +390,7 @@ public static unsafe ComVariant CreateRaw(VarEnum vt, T 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_INT or VarEnum.VT_UINT or VarEnum.VT_UNKNOWN or VarEnum.VT_DISPATCH or VarEnum.VT_LPSTR or VarEnum.VT_BSTR or VarEnum.VT_LPWSTR or VarEnum.VT_SAFEARRAY + (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, @@ -391,7 +398,7 @@ _ 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("Size of T should be the same size as the value specified by vt") + _ => throw new ArgumentException(SR.Format(SR.ComVariant_SizeMustMatchVariantSize, nameof(T), nameof(vt))) }; return value; @@ -406,7 +413,7 @@ private readonly void ThrowIfNotVarType(params VarEnum[] requiredType) { if (Array.IndexOf(requiredType, VarType) == -1) { - throw new InvalidOperationException($"Variant type {VarType} cannot be cast to any of the supported variant types: [{string.Join(", ", requiredType)}]"); + throw new InvalidOperationException(SR.Format(SR.ComVariant_TypeIsNotSupportedType, VarType, string.Join(", ", requiredType))); } } @@ -417,11 +424,11 @@ private readonly void ThrowIfNotVarType(params VarEnum[] requiredType) /// 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() + public readonly T? As() { if (VarType == VarEnum.VT_EMPTY) { - return default!; + return default; } if (typeof(T) == typeof(DBNull)) { @@ -470,7 +477,7 @@ public readonly T As() ThrowIfNotVarType(VarEnum.VT_BSTR); if (_typeUnion._unionTypes._bstr == IntPtr.Zero) { - return default!; + return default; } return (T)(object)Marshal.PtrToStringBSTR(_typeUnion._unionTypes._bstr); } @@ -526,7 +533,7 @@ public readonly T As() ThrowIfNotVarType(VarEnum.VT_UI8); return (T)(object)_typeUnion._unionTypes._ui8; } - throw new ArgumentException("Unsupported type", nameof(T)); + throw new ArgumentException(SR.UnsupportedType, nameof(T)); } #pragma warning restore CS0618 // Type or member is obsolete @@ -552,7 +559,7 @@ public unsafe ref T GetRawDataRef() ArgumentOutOfRangeException.ThrowIfGreaterThan(Unsafe.SizeOf(), sizeof(UnionTypes), nameof(T)); if (typeof(T) == typeof(decimal)) { - throw new ArgumentException("VT_DECIMAL is not supported in GetRawDataRef. Use the As method.", nameof(T)); + 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/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs index d712ab5416d942..818e9d00949415 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,7 +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 dd80aa3dbf1b18..b973972873c91e 100644 --- a/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs +++ b/src/libraries/System.Runtime.InteropServices/ref/System.Runtime.InteropServices.cs @@ -461,14 +461,14 @@ 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.RefPropogate))] + [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 RefPropogate + public struct RefPropagate { public void FromUnmanaged(System.Runtime.InteropServices.Marshalling.ComVariant unmanaged) { } public void FromManaged(object? managed) { } @@ -2525,7 +2525,7 @@ 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 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; } diff --git a/src/libraries/System.Runtime.InteropServices/src/Resources/Strings.resx b/src/libraries/System.Runtime.InteropServices/src/Resources/Strings.resx index 828dc3e2b9fe01..86f021792dd52b 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/Marshalling/ComVariantMarshaller.cs b/src/libraries/System.Runtime.InteropServices/src/System/Runtime/InteropServices/Marshalling/ComVariantMarshaller.cs index 3ab19b82b2c3fe..d18d58bc8762f8 100644 --- 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 @@ -16,7 +16,7 @@ namespace System.Runtime.InteropServices.Marshalling /// 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(RefPropogate))] + [CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedRef, typeof(RefPropagate))] public static partial class ComVariantMarshaller { public static ComVariant ConvertToUnmanaged(object? managed) @@ -75,7 +75,7 @@ public static ComVariant ConvertToUnmanaged(object? managed) return variant; } - throw new ArgumentException("Type of managed object is not supported for marshalling as ComVariant.", nameof(managed)); + throw new ArgumentException(SR.ComVariantMarshaller_ManagedTypeNotSupported, nameof(managed)); } #pragma warning disable CA1416 // Validate platform compatibility @@ -147,7 +147,7 @@ private static unsafe bool TryCreateOleVariantForInterfaceWrapper(object managed case VarEnum.VT_ERROR: return unmanaged.As(); case VarEnum.VT_CY: - return unmanaged.As().WrappedObject; + return unmanaged.As()!.WrappedObject; case VarEnum.VT_UNKNOWN: case VarEnum.VT_DISPATCH: return StrategyBasedComWrappers.DefaultMarshallingInstance.GetOrCreateObjectForComInstance(unmanaged.GetRawDataRef(), CreateObjectFlags.Unwrap); @@ -188,7 +188,7 @@ private static unsafe bool TryCreateOleVariantForInterfaceWrapper(object managed case VarEnum.VT_BYREF | VarEnum.VT_UNKNOWN: return StrategyBasedComWrappers.DefaultMarshallingInstance.GetOrCreateObjectForComInstance(*(nint*)unmanaged.GetRawDataRef(), CreateObjectFlags.Unwrap); default: - throw new ArgumentException("Type of unmanaged variant is not supported for marshalling to a managed object.", nameof(unmanaged)); + throw new ArgumentException(SR.ComVariantMarshaller_UnmanagedTypeNotSupported, nameof(unmanaged)); } #pragma warning restore CA1416 // Validate platform compatibility #pragma warning restore CS0618 // Type or member is obsolete @@ -200,7 +200,7 @@ private static unsafe bool TryCreateOleVariantForInterfaceWrapper(object managed /// Marshals a to an , propagating the value of the back to the variant's /// existing data storage if the variant has type. /// - public struct RefPropogate + public struct RefPropagate { private ComVariant _unmanaged; private object? _managed; 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 index f3f7becc116690..032247951e3705 100644 --- 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 @@ -274,7 +274,7 @@ 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.RefPropogate marshaller = default; + ComVariantMarshaller.RefPropagate marshaller = default; marshaller.FromUnmanaged(variant); // Marshal back the new value From ba5cbfc259362fc6d534fbaa7c947017f37b13b3 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Thu, 19 Oct 2023 17:11:55 -0700 Subject: [PATCH 09/20] Add some negative tests for CreateRaw --- .../InteropServices/ComVariantTests.cs | 42 ++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) 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 index ea668b18c7957b..eeeb27bb69f0d8 100644 --- 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 @@ -1,13 +1,9 @@ // 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.CompilerServices; 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 @@ -457,5 +453,41 @@ public void ByRef_Raw() 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)); + } } } From 70277791360982bbb17dccb57832a67384cff059 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Thu, 19 Oct 2023 17:14:26 -0700 Subject: [PATCH 10/20] Re-inline the variable decl. --- .../System/Runtime/InteropServices/Marshalling/ComVariant.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 index b0dbddf2c47b8f..81f642961d1f03 100644 --- 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 @@ -246,8 +246,7 @@ public unsafe void Dispose() /// When does not directly correspond to a variant type. public static ComVariant Create([DisallowNull] T value) { - ComVariant variant; - Unsafe.SkipInit(out variant); + Unsafe.SkipInit(out ComVariant variant); if (typeof(T) == typeof(DBNull)) { variant = Null; From e378fc62738d6f6c311d08a890df6337cbab05bf Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 20 Oct 2023 11:40:42 -0700 Subject: [PATCH 11/20] PR feedback --- .../src/System/Variant.cs | 2 +- .../BuiltInVariantExtensions.cs | 67 +++++++++---------- .../Marshalling/ComVariantMarshaller.cs | 2 - .../InteropServices/ComVariantTests.cs | 2 +- 4 files changed, 32 insertions(+), 41 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Variant.cs b/src/coreclr/System.Private.CoreLib/src/System/Variant.cs index 2a53a3cbb8652d..0f55a7ef6a0224 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Variant.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Variant.cs @@ -34,7 +34,7 @@ internal struct Variant // What are the consequences of making this an enum? /////////////////////////////////////////////////////////////////////// // If you update this, update the corresponding stuff in OAVariantLib.cs, - // COMOAVariant.cpp (2 tables, forwards and reverse), and perhaps ComVariant.h + // COMOAVariant.cpp (2 tables, forwards and reverse), and perhaps OleVariant.h /////////////////////////////////////////////////////////////////////// internal const int CV_EMPTY = 0x0; internal const int CV_VOID = 0x1; diff --git a/src/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs b/src/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs index dc5e020108362c..8ca831ea66f760 100644 --- a/src/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs +++ b/src/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs @@ -132,46 +132,39 @@ public static unsafe void CopyFromIndirect(this ref ComVariant variant, object v /// public static object? ToObject(this ref ComVariant variant) { - // Check the simple case upfront - if (variant.VarType == VarEnum.VT_EMPTY) + return variant.VarType switch { - return null; - } + 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() != -1, + 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), + }; + } - switch (variant.VarType) + private static unsafe object? GetObjectFromNativeVariant(ref ComVariant variant) + { + fixed (void* pVariant = &variant) { - case VarEnum.VT_NULL: - return DBNull.Value; - - case VarEnum.VT_I1: return variant.As(); - case VarEnum.VT_I2: return variant.As(); - case VarEnum.VT_I4: return variant.As(); - case VarEnum.VT_I8: return variant.As(); - case VarEnum.VT_UI1: return variant.As(); - case VarEnum.VT_UI2: return variant.As(); - case VarEnum.VT_UI4: return variant.As(); - case VarEnum.VT_UI8: return variant.As(); - case VarEnum.VT_INT: return variant.As(); - case VarEnum.VT_UINT: return variant.As(); - case VarEnum.VT_BOOL: return variant.As() != -1; - case VarEnum.VT_ERROR: return variant.As(); - case VarEnum.VT_R4: return variant.As(); - case VarEnum.VT_R8: return variant.As(); - case VarEnum.VT_DECIMAL: return variant.As(); - case VarEnum.VT_CY: return decimal.FromOACurrency(variant.GetRawDataRef()); - case VarEnum.VT_DATE: return variant.As(); - case VarEnum.VT_BSTR: return Marshal.PtrToStringBSTR(variant.GetRawDataRef()); - case VarEnum.VT_UNKNOWN: return Marshal.GetObjectForIUnknown(variant.GetRawDataRef()); - case VarEnum.VT_DISPATCH: return Marshal.GetObjectForIUnknown(variant.GetRawDataRef()); - - default: - unsafe - { - fixed (void* pThis = &variant) - { - return Marshal.GetObjectForNativeVariant((nint)pThis); - } - } + return Marshal.GetObjectForNativeVariant((nint)pVariant); } } } 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 index d18d58bc8762f8..94c75afa7ccc5a 100644 --- 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 @@ -53,8 +53,6 @@ public static ComVariant ConvertToUnmanaged(object? managed) return ComVariant.Create(d); case bool b: return ComVariant.Create(b); - case char c: - return ComVariant.Create((ushort)c); case string s: return ComVariant.Create(s); case DateTime dt: 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 index eeeb27bb69f0d8..fa9f33548258a5 100644 --- 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 @@ -290,7 +290,7 @@ public void LPWStr_Raw() [Fact] public void FileTime_Raw() { - long fileTime = 1039348523; + long fileTime = DateTime.Now.ToFileTime(); ComVariant variant = ComVariant.CreateRaw(VarEnum.VT_FILETIME, fileTime); Assert.Equal(VarEnum.VT_FILETIME, variant.VarType); Assert.Throws(() => variant.As()); From b62287040f58cca9e1e99128034562b6791a80bd Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 20 Oct 2023 11:41:45 -0700 Subject: [PATCH 12/20] Fix non-Windows build. --- .../Runtime/InteropServices/Marshalling/ComVariant.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 index 81f642961d1f03..784627663542a3 100644 --- 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 @@ -181,13 +181,13 @@ public unsafe void Dispose() else if (VarType == VT_VERSIONED_STREAM) { VersionedStream* versionedStream = _typeUnion._unionTypes._versionedStream; - if (versionedStream != null && versionedStream->_stream != null) + if (versionedStream != null && versionedStream->_stream != IntPtr.Zero) { Marshal.Release(versionedStream->_stream); } Marshal.FreeCoTaskMem((nint)versionedStream); } - else if (VarType == VT_CF) + else if (VarType == VarEnum.VT_CF) { ClipboardData* clipboardData = _typeUnion._unionTypes.clipboardData; if (clipboardData != null) @@ -228,7 +228,7 @@ public unsafe void Dispose() default: break; } - Marshal.CoTaskMemFree((nint)GetRawDataRef>()._data); + Marshal.FreeCoTaskMem((nint)GetRawDataRef>()._data); } // Clear out this ComVariant instance. From 15f4a9ba3e20a4e496200718366a837040ea6cff Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 23 Oct 2023 16:27:56 -0700 Subject: [PATCH 13/20] Abstract out VARIANT_TRUE and VARIANT_FALSE to constants and fix the code paths that they were inverted on. Fix integration test. --- .../Runtime/InteropServices/BuiltInVariantExtensions.cs | 6 ++---- .../Runtime/InteropServices/Marshalling/ComVariant.cs | 7 +++++-- .../InteropServices/Marshalling/ComVariantMarshaller.cs | 7 +++++-- .../tests/LibraryImportGenerator.Tests/VariantTests.cs | 4 ++-- .../System/Runtime/InteropServices/ComVariantTests.cs | 4 ++-- 5 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs b/src/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs index 8ca831ea66f760..5b8e363212c5fd 100644 --- a/src/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs +++ b/src/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs @@ -58,9 +58,7 @@ public static unsafe void CopyFromIndirect(this ref ComVariant variant, object v break; case VarEnum.VT_BOOL: - // VARIANT_TRUE = -1 - // VARIANT_FALSE = 0 - variant.GetByRefDataRef() = (bool)value ? (short)-1 : (short)0; + variant.GetByRefDataRef() = (bool)value ? ComVariant.VARIANT_TRUE : ComVariant.VARIANT_FALSE; break; case VarEnum.VT_I4: @@ -146,7 +144,7 @@ public static unsafe void CopyFromIndirect(this ref ComVariant variant, object v VarEnum.VT_UI8 => variant.As(), VarEnum.VT_INT => variant.As(), VarEnum.VT_UINT => variant.As(), - VarEnum.VT_BOOL => variant.As() != -1, + VarEnum.VT_BOOL => variant.As() != ComVariant.VARIANT_FALSE, VarEnum.VT_ERROR => variant.As(), VarEnum.VT_R4 => variant.As(), VarEnum.VT_R8 => variant.As(), 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 index 784627663542a3..95a102338e6211 100644 --- 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 @@ -14,6 +14,9 @@ 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() { @@ -305,7 +308,7 @@ public static ComVariant Create([DisallowNull] T value) { // bool values in OLE VARIANTs are VARIANT_BOOL values. variant.VarType = VarEnum.VT_BOOL; - variant._typeUnion._unionTypes._bool = ((bool)(object)value) ? (short)0 : (short)-1; + variant._typeUnion._unionTypes._bool = ((bool)(object)value) ? VARIANT_TRUE : VARIANT_FALSE; } else if (typeof(T) == typeof(decimal)) { @@ -489,7 +492,7 @@ private readonly void ThrowIfNotVarType(params VarEnum[] requiredType) { // bool values in OLE VARIANTs are VARIANT_BOOL values. ThrowIfNotVarType(VarEnum.VT_BOOL); - return (T)(object)(_typeUnion._unionTypes._bool != -1); + return (T)(object)(_typeUnion._unionTypes._bool != VARIANT_FALSE); } else if (typeof(T) == typeof(decimal)) { 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 index 94c75afa7ccc5a..9c2375d3a97fa6 100644 --- 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 @@ -19,6 +19,9 @@ namespace System.Runtime.InteropServices.Marshalling [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) @@ -174,7 +177,7 @@ private static unsafe bool TryCreateOleVariantForInterfaceWrapper(object managed case VarEnum.VT_BYREF | VarEnum.VT_DECIMAL: return *(decimal*)unmanaged.GetRawDataRef(); case VarEnum.VT_BYREF | VarEnum.VT_BOOL: - return *(short*)unmanaged.GetRawDataRef() != -1; + 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: @@ -278,7 +281,7 @@ or VarEnum.VT_DISPATCH *(decimal*)_unmanaged.GetRawDataRef() = d; break; case (VarEnum.VT_BOOL, bool b): - *(short*)_unmanaged.GetRawDataRef() = b ? (short)0 : (short)-1; + *(short*)_unmanaged.GetRawDataRef() = b ? VARIANT_TRUE : VARIANT_FALSE; break; case (VarEnum.VT_BSTR, string str): { diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/VariantTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/VariantTests.cs index e3a7c56fd213b5..2689327c2a1fef 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/VariantTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/VariantTests.cs @@ -9,11 +9,11 @@ using System.Threading.Tasks; using Xunit; -namespace LibraryImportGenerator.Tests +namespace LibraryImportGenerator.IntegrationTests { partial class NativeExportsNE { - [LibraryImport(nameof(NativeExportsNE), EntryPoint = "get_variant_bstr_length")] + [LibraryImport(NativeExportsNE_Binary, EntryPoint = "get_variant_bstr_length")] public static partial int GetVTBStrLength([MarshalAs(UnmanagedType.Struct)] in object obj); } 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 index fa9f33548258a5..781d3e6ef06137 100644 --- 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 @@ -132,7 +132,7 @@ public void VariantBoolTrue() ComVariant trueVariant = ComVariant.Create(true); Assert.Equal(VarEnum.VT_BOOL, trueVariant.VarType); Assert.True(trueVariant.As()); - Assert.Equal(0, trueVariant.GetRawDataRef()); + Assert.Equal(-1, trueVariant.GetRawDataRef()); } [Fact] @@ -141,7 +141,7 @@ public void VariantBoolFalse() ComVariant falseVariant = ComVariant.Create(false); Assert.Equal(VarEnum.VT_BOOL, falseVariant.VarType); Assert.False(falseVariant.As()); - Assert.Equal(-1, falseVariant.GetRawDataRef()); + Assert.Equal(0, falseVariant.GetRawDataRef()); } [Fact] From 1d8c472ee46ba651f8e8df6b16ebb7f64869acf1 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 24 Oct 2023 10:48:40 -0700 Subject: [PATCH 14/20] Fix build failure --- .../Runtime/InteropServices/BuiltInVariantExtensions.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs b/src/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs index 5b8e363212c5fd..a352788e4ede9a 100644 --- a/src/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs +++ b/src/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs @@ -11,6 +11,9 @@ 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 { @@ -58,7 +61,7 @@ public static unsafe void CopyFromIndirect(this ref ComVariant variant, object v break; case VarEnum.VT_BOOL: - variant.GetByRefDataRef() = (bool)value ? ComVariant.VARIANT_TRUE : ComVariant.VARIANT_FALSE; + variant.GetByRefDataRef() = (bool)value ? VARIANT_TRUE : VARIANT_FALSE; break; case VarEnum.VT_I4: @@ -144,7 +147,7 @@ public static unsafe void CopyFromIndirect(this ref ComVariant variant, object v VarEnum.VT_UI8 => variant.As(), VarEnum.VT_INT => variant.As(), VarEnum.VT_UINT => variant.As(), - VarEnum.VT_BOOL => variant.As() != ComVariant.VARIANT_FALSE, + VarEnum.VT_BOOL => variant.As() != VARIANT_FALSE, VarEnum.VT_ERROR => variant.As(), VarEnum.VT_R4 => variant.As(), VarEnum.VT_R8 => variant.As(), From 1d3a54b5da6e36fc7eaa77679e537b2fc44e9bf7 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 24 Oct 2023 13:30:00 -0700 Subject: [PATCH 15/20] Skip ComWrappers in Variant tests on Mono. --- .../System/Runtime/InteropServices/ComVariantMarshallerTests.cs | 2 ++ 1 file changed, 2 insertions(+) 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 index 032247951e3705..1e7e38610310e4 100644 --- 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 @@ -206,6 +206,7 @@ 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(); @@ -221,6 +222,7 @@ public unsafe void GeneratedComInterfaceType_Marshals_To_UNKNOWN() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/55742", TestRuntimes.Mono)] public void UnknownWrapper_Of_GeneratedComInterfaceType_Marshals_To_UNKNOWN() { var obj = new ComExposedType(); From 3cbf99565c9fb77e00b5cec73119f8ef22525564 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 24 Oct 2023 13:31:02 -0700 Subject: [PATCH 16/20] Fix VT_BOOL handling in BuiltInVariantExtensions. --- .../System/Runtime/InteropServices/BuiltInVariantExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs b/src/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs index a352788e4ede9a..777a1c03b0a7a2 100644 --- a/src/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs +++ b/src/libraries/Common/src/System/Runtime/InteropServices/BuiltInVariantExtensions.cs @@ -147,7 +147,7 @@ public static unsafe void CopyFromIndirect(this ref ComVariant variant, object v VarEnum.VT_UI8 => variant.As(), VarEnum.VT_INT => variant.As(), VarEnum.VT_UINT => variant.As(), - VarEnum.VT_BOOL => variant.As() != VARIANT_FALSE, + VarEnum.VT_BOOL => variant.As(), VarEnum.VT_ERROR => variant.As(), VarEnum.VT_R4 => variant.As(), VarEnum.VT_R8 => variant.As(), From 07228afcfcd7d2be70266e5d494dd59b0b21afb7 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 24 Oct 2023 15:17:07 -0700 Subject: [PATCH 17/20] Allow a subtype of ArgumentException to be thrown in the Decimal case (ArgumentOutOfRange on 32-bit platforms) --- .../System/Runtime/InteropServices/ComVariantTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 781d3e6ef06137..7d5d0a64abde76 100644 --- 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 @@ -174,7 +174,7 @@ public void Decimal() ComVariant variant = ComVariant.Create(42.0m); Assert.Equal(VarEnum.VT_DECIMAL, variant.VarType); Assert.Equal(42.0m, variant.As()); - Assert.Throws("T", () => variant.GetRawDataRef()); + Assert.ThrowsAny("T", () => variant.GetRawDataRef()); } [Fact] From 896da6cdb39715888551168f6c5e0943e18905a7 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 24 Oct 2023 15:21:30 -0700 Subject: [PATCH 18/20] Use ComVariant type in NativeAOT's known types --- src/coreclr/tools/Common/TypeSystem/Interop/InteropTypes.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Interop/InteropTypes.cs b/src/coreclr/tools/Common/TypeSystem/Interop/InteropTypes.cs index 3beeb5f187a89e..7fdd0f06596209 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) From c13cd7244d4df9b67f58218208a2ec5c686681f0 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 24 Oct 2023 16:48:18 -0700 Subject: [PATCH 19/20] Make mutating extension method take ComVariant by ref. --- .../CSharp/RuntimeBinder/ComInterop/DynamicVariantExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index c35eb5ef270e26..27647ed388f28e 100644 --- a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/DynamicVariantExtensions.cs +++ b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop/DynamicVariantExtensions.cs @@ -236,7 +236,7 @@ private struct Record } // constructs a ByRef variant to pass contents of another variant ByRef. - public static unsafe void SetAsByrefVariantIndirect(this ComVariant variant, ref ComVariant value) + 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"); From bf95eea728022f953bc022733ebe7c83d4484c06 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Wed, 25 Oct 2023 11:58:03 -0700 Subject: [PATCH 20/20] Don't pass "T" for ThrowsAny --- .../System/Runtime/InteropServices/ComVariantTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 7d5d0a64abde76..652b07c09c9fc0 100644 --- 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 @@ -174,7 +174,7 @@ public void Decimal() ComVariant variant = ComVariant.Create(42.0m); Assert.Equal(VarEnum.VT_DECIMAL, variant.VarType); Assert.Equal(42.0m, variant.As()); - Assert.ThrowsAny("T", () => variant.GetRawDataRef()); + Assert.ThrowsAny(() => variant.GetRawDataRef()); } [Fact]