From c1a9f26efa4fcf2e3fdcd8557da19d358f51eb00 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Wed, 28 Aug 2024 10:40:27 +0800 Subject: [PATCH] Cleanup VARIANT marshalling and convert to managed (#102498) * Handle simple cases of MarshalComVariantForOleVariant * Pseudo code for MarshalOleVariantForComVariant * Complete and setup managed call for MarshalObjectForOleVariant * Setup MarshalHelperConvertObjectToVariant except record * Setup MarshalHelperCastVariant * Cleanup Variant struct and FCall * Handle record case * Cleanup VariantOleToCom/VariantComToOle routines * Remove VariantData definition at unmanaged side * Eliminate a dead branch for ref * Remove CVTypes in native * Share GetComIPFromObjectRef * Add tests for managed to native side * Add test for native to managed side * Add test for byref returning to BYREF * Fix BYREF handling * Fix array marshalling * Fix record marshalling * Fix VT_VARIANT case * Cleanup and fix IUnknown case * Add more test for VT_UNKNOWN * Cleanup for VT_VARIANT * Cleanup SR and comment * Fix contract in GetTypeHandleForVarType * Move VariantChangeTypeEx to coreclr * Add unmanaged fast path for (U)Int64 * Make ComVariant immutable * Add GCPROTECT in ConvertSystemColorToOleColor * Fix variant init * Fix BYREF|EMPTY * Initialize ComVariant * Move GCPROTECT to the QCall * Pass UnknownWrapper through SetFieldsObject * Apply suggestions from code review Co-authored-by: Aaron Robinson * Suggestions at native side * Rename ComIP * Add comments for ConvertWrappedObject * Try convert to RECORD for all cases * Dispose Variant on failure * Update formatting * Fix NO_MAPPING definition --------- Co-authored-by: Aaron Robinson --- .../System.Private.CoreLib.csproj | 3 + .../src/Microsoft/Win32/OAVariantLib.cs | 11 +- .../src/System/Variant.cs | 671 +++++---- .../classlibnative/bcltype/variant.cpp | 287 +--- src/coreclr/classlibnative/bcltype/variant.h | 21 +- src/coreclr/dlls/mscorrc/mscorrc.rc | 5 - src/coreclr/dlls/mscorrc/resource.h | 3 - src/coreclr/vm/corelib.h | 12 +- src/coreclr/vm/dispparammarshaler.cpp | 4 +- src/coreclr/vm/ecalllist.h | 10 - src/coreclr/vm/ilmarshalers.cpp | 8 +- src/coreclr/vm/interoputil.h | 2 - src/coreclr/vm/metasig.h | 8 +- src/coreclr/vm/olevariant.cpp | 1196 +++-------------- src/coreclr/vm/olevariant.h | 379 +----- src/coreclr/vm/qcallentrypoints.cpp | 1 + src/libraries/Common/src/System/HResults.cs | 1 + .../src/Resources/Strings.resx | 15 + .../System.Private.CoreLib.Shared.projitems | 3 - .../InteropServices/Marshalling/ComVariant.cs | 6 +- .../COM/NETClients/MiscTypes/Program.cs | 137 ++ .../Interop/COM/NETServer/MiscTypesTesting.cs | 18 +- .../COM/NativeClients/MiscTypes/MiscTypes.cpp | 230 ++++ .../COM/NativeServer/MiscTypesTesting.h | 5 + .../COM/ServerContracts/Server.Contracts.cs | 2 + .../COM/ServerContracts/Server.Contracts.h | 4 + 26 files changed, 941 insertions(+), 2101 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj index 8cdcb03995b5f..4ffdcd15afb5f 100644 --- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -285,6 +285,9 @@ Common\Interop\Windows\OleAut32\Interop.VariantClear.cs + + Common\Interop\Windows\OleAut32\Interop.VariantChangeTypeEx.cs + diff --git a/src/coreclr/System.Private.CoreLib/src/Microsoft/Win32/OAVariantLib.cs b/src/coreclr/System.Private.CoreLib/src/Microsoft/Win32/OAVariantLib.cs index a51ec6f0132e4..81c480c4d951d 100644 --- a/src/coreclr/System.Private.CoreLib/src/Microsoft/Win32/OAVariantLib.cs +++ b/src/coreclr/System.Private.CoreLib/src/Microsoft/Win32/OAVariantLib.cs @@ -151,19 +151,10 @@ private static ComVariant ToOAVariant(object input) null => default, Missing => throw new NotSupportedException(SR.NotSupported_ChangeType), DBNull => ComVariant.Null, - _ => GetComIPFromObjectRef(input) // Convert the object to an IDispatch/IUnknown pointer. + _ => Variant.GetIUnknownOrIDispatchFromObject(input) // Convert the object to an IDispatch/IUnknown pointer. }; } - private static ComVariant GetComIPFromObjectRef(object? obj) - { - IntPtr pUnk = GetIUnknownOrIDispatchForObject(ObjectHandleOnStack.Create(ref obj), out bool isIDispatch); - return ComVariant.CreateRaw(isIDispatch ? VarEnum.VT_DISPATCH : VarEnum.VT_UNKNOWN, pUnk); - } - - [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "MarshalNative_GetIUnknownOrIDispatchForObject")] - private static partial IntPtr GetIUnknownOrIDispatchForObject(ObjectHandleOnStack o, [MarshalAs(UnmanagedType.Bool)] out bool isIDispatch); - private static object? FromOAVariant(ComVariant input) => input.VarType switch { diff --git a/src/coreclr/System.Private.CoreLib/src/System/Variant.cs b/src/coreclr/System.Private.CoreLib/src/System/Variant.cs index 1ee6acc5be1c4..35052c0f9feb8 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Variant.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Variant.cs @@ -1,75 +1,20 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -/*============================================================ -** -** -** -** Purpose: The CLR implementation of Variant. -** -** -===========================================================*/ - using System.Diagnostics; using System.Globalization; +using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +#pragma warning disable CA1416 // COM interop is only supported on Windows namespace System { - internal partial struct Variant + // Contains code for built-in marshalling of OLE VARIANT. + internal static partial class Variant { - // Do Not change the order of these fields. - // They are mapped to the native VariantData * data structure. - private object? _objref; - private long _data; - private int _flags; - - // The following bits have been taken up as follows - // bits 0-15 - Type code - // bit 16 - Array - // bits 19-23 - Enums - // bits 24-31 - Optional VT code (for roundtrip VT preservation) - - // What are the consequences of making this an enum? - /////////////////////////////////////////////////////////////////////// - // If you update this, update the corresponding stuff in OAVariantLib.cs, - // OAVariant.cpp (2 tables, forwards and reverse), and perhaps OleVariant.h - /////////////////////////////////////////////////////////////////////// - internal const int CV_EMPTY = 0x0; - internal const int CV_VOID = 0x1; - internal const int CV_BOOLEAN = 0x2; - internal const int CV_CHAR = 0x3; - internal const int CV_I1 = 0x4; - internal const int CV_U1 = 0x5; - internal const int CV_I2 = 0x6; - internal const int CV_U2 = 0x7; - internal const int CV_I4 = 0x8; - internal const int CV_U4 = 0x9; - internal const int CV_I8 = 0xa; - internal const int CV_U8 = 0xb; - internal const int CV_R4 = 0xc; - internal const int CV_R8 = 0xd; - internal const int CV_STRING = 0xe; - internal const int CV_PTR = 0xf; - internal const int CV_DATETIME = 0x10; - internal const int CV_TIMESPAN = 0x11; - internal const int CV_OBJECT = 0x12; - internal const int CV_DECIMAL = 0x13; - internal const int CV_ENUM = 0x15; - internal const int CV_MISSING = 0x16; - internal const int CV_NULL = 0x17; - internal const int CV_LAST = 0x18; - - internal const int TypeCodeBitMask = 0xffff; - internal const int VTBitMask = unchecked((int)0xff000000); - internal const int VTBitShift = 24; - internal const int ArrayBitMask = 0x10000; - - internal static Variant Empty => default; - internal static Variant Missing => new Variant(CV_MISSING, Type.Missing, 0); - internal static Variant DBNull => new Variant(CV_NULL, System.DBNull.Value, 0); - internal static bool IsSystemDrawingColor(Type type) => type.FullName == "System.Drawing.Color"; // Matches the behavior of IsTypeRefOrDef [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "Variant_ConvertSystemColorToOleColor")] @@ -78,323 +23,346 @@ internal partial struct Variant [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "Variant_ConvertOleColorToSystemColor")] internal static partial void ConvertOleColorToSystemColor(ObjectHandleOnStack objret, uint value, IntPtr pMT); - // - // Native Methods - // - [MethodImpl(MethodImplOptions.InternalCall)] - internal extern void SetFieldsObject(object val); - - // - // Constructors - // - - internal Variant(int flags, object or, long data) - { - _flags = flags; - _objref = or; - _data = data; - } + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "Variant_ConvertValueTypeToRecord")] + private static partial void ConvertValueTypeToRecord(ObjectHandleOnStack obj, out ComVariant pOle); - public Variant(bool val) + internal static ComVariant GetIUnknownOrIDispatchFromObject(object? obj) { - _objref = null; - _flags = CV_BOOLEAN; - _data = (val) ? bool.True : bool.False; + IntPtr pUnk = GetIUnknownOrIDispatchForObject(ObjectHandleOnStack.Create(ref obj), out bool isIDispatch); + return ComVariant.CreateRaw(isIDispatch ? VarEnum.VT_DISPATCH : VarEnum.VT_UNKNOWN, pUnk); } - public Variant(sbyte val) - { - _objref = null; - _flags = CV_I1; - _data = val; - } + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "MarshalNative_GetIUnknownOrIDispatchForObject")] + private static partial IntPtr GetIUnknownOrIDispatchForObject(ObjectHandleOnStack o, [MarshalAs(UnmanagedType.Bool)] out bool isIDispatch); - public Variant(byte val) + private static object? GetObjectFromIUnknown(IntPtr pUnk) { - _objref = null; - _flags = CV_U1; - _data = val; + return pUnk == IntPtr.Zero ? null : Marshal.GetObjectForIUnknown(pUnk); } - public Variant(short val) + private static unsafe object? ConvertWrappedObject(object? wrapped) { - _objref = null; - _flags = CV_I2; - _data = val; - } + // Historically, for UnknownWrapper and DispatchWrapper, the wrapped object is passed + // into Variant.SetFieldsObject, and the result set in objRef field is used for + // IUnknown/IDispatch marshalling. Here the behavior is simulated. - public Variant(ushort val) - { - _objref = null; - _flags = CV_U2; - _data = val; - } + if (wrapped is ValueType) + { + // Enums are stored with underlying value in number bits, and type in objRef field. + if (wrapped is Enum) + return wrapped.GetType(); - public Variant(char val) - { - _objref = null; - _flags = CV_CHAR; - _data = val; - } + // Primitive types (ELEMENT_TYPE_BOOLEAN through ELEMENT_TYPE_STRING, IntPtr/UIntPtr + // not included) don't have objRef set and become null. + if (wrapped is IntPtr or UIntPtr) + return wrapped; - public Variant(int val) - { - _objref = null; - _flags = CV_I4; - _data = val; - } + if (wrapped.GetType().IsPrimitive) + return null; - public Variant(uint val) - { - _objref = null; - _flags = CV_U4; - _data = val; - } + // System.Drawing.Color is converted to UInt32. + if (IsSystemDrawingColor(wrapped.GetType())) + return null; - public Variant(long val) - { - _objref = null; - _flags = CV_I8; - _data = val; - } + // DateTime, TimeSpan and Currency are stored with corresponding types with + // objectRef unset. + if (wrapped is DateTime or TimeSpan or Currency) + return null; - public Variant(ulong val) - { - _objref = null; - _flags = CV_U8; - _data = (long)val; - } - - public Variant(float val) - { - _objref = null; - _flags = CV_R4; - _data = BitConverter.SingleToUInt32Bits(val); - } - - public Variant(double val) - { - _objref = null; - _flags = CV_R8; - _data = BitConverter.DoubleToInt64Bits(val); - } - - public Variant(DateTime val) - { - _objref = null; - _flags = CV_DATETIME; - _data = val.Ticks; - } + // Other value types are boxed as-is. + return wrapped; + } + else + { + // Empty is stored with null objRef. + // DBNull and Missing are stored with corresponding types, with objRef also set. + if (wrapped is Empty) + return null; - public Variant(decimal val) - { - _objref = (object)val; - _flags = CV_DECIMAL; - _data = 0; + return wrapped; + } } - public Variant(object? obj) + // Helper code for marshaling managed objects to VARIANT's + internal static void MarshalHelperConvertObjectToVariant(object? o, out ComVariant pOle) { - _data = 0; + // Cases handled at native side: string, bool, primitives including (U)IntPtr excluding U(Int)64, array - VarEnum vt = VarEnum.VT_EMPTY; - - if (obj is DateTime) + switch (o) { - _objref = null; - _flags = CV_DATETIME; - _data = ((DateTime)obj).Ticks; - return; - } + case null: + pOle = default; + break; - if (obj is string) - { - _flags = CV_STRING; - _objref = obj; - return; - } + case IConvertible ic when ic.GetTypeCode() != TypeCode.Object: + { + IFormatProvider provider = CultureInfo.InvariantCulture; + pOle = ic.GetTypeCode() switch + { + TypeCode.Empty => default, + TypeCode.DBNull => ComVariant.Create(DBNull.Value), + TypeCode.Boolean => ComVariant.Create(ic.ToBoolean(provider)), + TypeCode.Char => ComVariant.Create((ushort)ic.ToChar(provider)), + TypeCode.SByte => ComVariant.Create(ic.ToSByte(provider)), + TypeCode.Byte => ComVariant.Create(ic.ToByte(provider)), + TypeCode.Int16 => ComVariant.Create(ic.ToInt16(provider)), + TypeCode.UInt16 => ComVariant.Create(ic.ToUInt16(provider)), + TypeCode.Int32 => ComVariant.Create(ic.ToInt32(provider)), + TypeCode.UInt32 => ComVariant.Create(ic.ToUInt32(provider)), + TypeCode.Int64 => ComVariant.Create(ic.ToInt64(provider)), + TypeCode.UInt64 => ComVariant.Create(ic.ToUInt64(provider)), + TypeCode.Single => ComVariant.Create(ic.ToSingle(provider)), + TypeCode.Double => ComVariant.Create(ic.ToDouble(provider)), + TypeCode.Decimal => ComVariant.Create(ic.ToDecimal(provider)), + TypeCode.DateTime => ComVariant.Create(ic.ToDateTime(provider)), + TypeCode.String => ComVariant.Create(ic.ToString(provider)), + _ => throw new NotSupportedException(SR.Format(SR.NotSupported_UnknownTypeCode, ic.GetTypeCode())), + }; + break; + } - if (obj == null) - { - this = Empty; - return; - } - if (obj == System.DBNull.Value) - { - this = DBNull; - return; - } - if (obj == Type.Missing) - { - this = Missing; - return; - } + case Missing: + pOle = ComVariant.CreateRaw(VarEnum.VT_ERROR, HResults.DISP_E_PARAMNOTFOUND); + break; - if (obj is Array) - { - _flags = CV_OBJECT | ArrayBitMask; - _objref = obj; - return; - } + // Array handled by native side - // Compiler appeasement - _flags = CV_EMPTY; - _objref = null; + case UnknownWrapper wrapper: + { + object? wrapped = ConvertWrappedObject(wrapper.WrappedObject); + pOle = ComVariant.CreateRaw(VarEnum.VT_UNKNOWN, + wrapped is null ? IntPtr.Zero : Marshal.GetIUnknownForObject(wrapped)); + break; + } + case DispatchWrapper wrapper: + { + object? wrapped = ConvertWrappedObject(wrapper.WrappedObject); + pOle = ComVariant.CreateRaw(VarEnum.VT_DISPATCH, + wrapped is null ? IntPtr.Zero : Marshal.GetIDispatchForObject(wrapped)); + break; + } - // Check to see if the object passed in is a wrapper object. - if (obj is UnknownWrapper) - { - vt = VarEnum.VT_UNKNOWN; - obj = ((UnknownWrapper)obj).WrappedObject; - } - else if (obj is DispatchWrapper) - { - vt = VarEnum.VT_DISPATCH; - Debug.Assert(OperatingSystem.IsWindows()); - obj = ((DispatchWrapper)obj).WrappedObject; - } - else if (obj is ErrorWrapper) - { - vt = VarEnum.VT_ERROR; - obj = (object)(((ErrorWrapper)obj).ErrorCode); - Debug.Assert(obj != null); - } + case ErrorWrapper wrapper: + pOle = ComVariant.Create(wrapper); + break; #pragma warning disable 0618 // CurrencyWrapper is obsolete - else if (obj is CurrencyWrapper) - { - vt = VarEnum.VT_CY; - obj = (object)(((CurrencyWrapper)obj).WrappedObject); - Debug.Assert(obj != null); - } + case CurrencyWrapper wrapper: + pOle = ComVariant.Create(wrapper); + break; #pragma warning restore 0618 - else if (obj is BStrWrapper) - { - vt = VarEnum.VT_BSTR; - obj = (object?)(((BStrWrapper)obj).WrappedObject); - } - - if (obj != null) - { - SetFieldsObject(obj); + case BStrWrapper wrapper: + pOle = ComVariant.Create(wrapper); + break; + + case Empty: + pOle = default; + break; + case DBNull: + pOle = ComVariant.Create(DBNull.Value); + break; + + case { } when IsSystemDrawingColor(o.GetType()): + // System.Drawing.Color is converted to UInt32 + pOle = ComVariant.Create(ConvertSystemColorToOleColor(ObjectHandleOnStack.Create(ref o))); + break; + + // DateTime, decimal handled by IConvertible case + + case TimeSpan: + throw new ArgumentException(SR.ComVariant_UnsupportedSignature); + case Currency c: + pOle = ComVariant.CreateRaw(VarEnum.VT_CY, c.m_value); + break; + + // Enums handled by IConvertible case + + case ValueType: + ConvertValueTypeToRecord(ObjectHandleOnStack.Create(ref o), out pOle); + break; + + // SafeHandle's or CriticalHandle's cannot be stored in VARIANT's. + case SafeHandle: + throw new ArgumentException(SR.ComVariant_SafeHandle_In_Variant); + case CriticalHandle: + throw new ArgumentException(SR.ComVariant_CriticalHandle_In_Variant); + + // VariantWrappers cannot be stored in VARIANT's. + case VariantWrapper: + throw new ArgumentException(SR.ComVariant_VariantWrapper_In_Variant); + + default: + // We are dealing with a normal object (not a wrapper) so we will + // leave the VT as VT_DISPATCH for now and we will determine the actual + // VT when we convert the object to a COM IP. + pOle = GetIUnknownOrIDispatchFromObject(o); + break; } - - // If the object passed in is one of the wrappers then set the VARIANT type. - if (vt != VarEnum.VT_EMPTY) - _flags |= ((int)vt << VTBitShift); } - // This is a family-only accessor for the CVType. - // This is never to be exposed externally. - internal int CVType => _flags & TypeCodeBitMask; - - public object? ToObject() => - CVType switch - { - CV_EMPTY => null, - CV_BOOLEAN => (int)_data != 0, - CV_I1 => (sbyte)_data, - CV_U1 => (byte)_data, - CV_CHAR => (char)_data, - CV_I2 => (short)_data, - CV_U2 => (ushort)_data, - CV_I4 => (int)_data, - CV_U4 => (uint)_data, - CV_I8 => _data, - CV_U8 => (ulong)_data, - CV_R4 => BitConverter.UInt32BitsToSingle((uint)_data), - CV_R8 => BitConverter.Int64BitsToDouble(_data), - CV_DATETIME => new DateTime(_data), - CV_TIMESPAN => new TimeSpan(_data), - CV_ENUM => BoxEnum(), - CV_MISSING => Type.Missing, - CV_NULL => System.DBNull.Value, - _ => _objref, // CV_DECIMAL, CV_STRING, CV_OBJECT - }; - - // This routine will return an boxed enum. - [MethodImpl(MethodImplOptions.InternalCall)] - private extern object BoxEnum(); - - // Helper code for marshaling managed objects to VARIANT's (we use - // managed variants as an intermediate type. - internal static void MarshalHelperConvertObjectToVariant(object o, ref Variant v) + // Helper code for marshaling VARIANTS to managed objects + internal static unsafe object? MarshalHelperConvertVariantToObject(ref readonly ComVariant pOle) { - if (o == null) - { - v = Empty; - } - else if (o is IConvertible ic) - { - IFormatProvider provider = CultureInfo.InvariantCulture; - v = ic.GetTypeCode() switch - { - TypeCode.Empty => Empty, - TypeCode.Object => new Variant((object)o), - TypeCode.DBNull => DBNull, - TypeCode.Boolean => new Variant(ic.ToBoolean(provider)), - TypeCode.Char => new Variant(ic.ToChar(provider)), - TypeCode.SByte => new Variant(ic.ToSByte(provider)), - TypeCode.Byte => new Variant(ic.ToByte(provider)), - TypeCode.Int16 => new Variant(ic.ToInt16(provider)), - TypeCode.UInt16 => new Variant(ic.ToUInt16(provider)), - TypeCode.Int32 => new Variant(ic.ToInt32(provider)), - TypeCode.UInt32 => new Variant(ic.ToUInt32(provider)), - TypeCode.Int64 => new Variant(ic.ToInt64(provider)), - TypeCode.UInt64 => new Variant(ic.ToUInt64(provider)), - TypeCode.Single => new Variant(ic.ToSingle(provider)), - TypeCode.Double => new Variant(ic.ToDouble(provider)), - TypeCode.Decimal => new Variant(ic.ToDecimal(provider)), - TypeCode.DateTime => new Variant(ic.ToDateTime(provider)), - TypeCode.String => new Variant(ic.ToString(provider)), - _ => throw new NotSupportedException(SR.Format(SR.NotSupported_UnknownTypeCode, ic.GetTypeCode())), - }; - } - else + // Invalid and common types are handled at native side + Debug.Assert((pOle.VarType & VarEnum.VT_ARRAY) == 0, "Array should be handled at native side."); + Debug.Assert((pOle.VarType & ~VarEnum.VT_BYREF) != VarEnum.VT_RECORD, "Records should be handled at native side."); + + switch (pOle.VarType) { - // This path should eventually go away. But until - // the work is done to have all of our wrapper types implement - // IConvertible, this is a cheapo way to get the work done. - v = new Variant(o); + case VarEnum.VT_I4: + case VarEnum.VT_INT: + return pOle.As(); + case VarEnum.VT_BYREF | VarEnum.VT_I4: + case VarEnum.VT_BYREF | VarEnum.VT_INT: + return *(int*)pOle.GetRawDataRef(); + + case VarEnum.VT_UI4: + case VarEnum.VT_UINT: + return pOle.As(); + case VarEnum.VT_BYREF | VarEnum.VT_UI4: + case VarEnum.VT_BYREF | VarEnum.VT_UINT: + return *(uint*)pOle.GetRawDataRef(); + + case VarEnum.VT_I1: + return pOle.As(); + case VarEnum.VT_BYREF | VarEnum.VT_I1: + return *(sbyte*)pOle.GetRawDataRef(); + + case VarEnum.VT_UI1: + return pOle.As(); + case VarEnum.VT_BYREF | VarEnum.VT_UI1: + return *(byte*)pOle.GetRawDataRef(); + + case VarEnum.VT_I2: + return pOle.As(); + case VarEnum.VT_BYREF | VarEnum.VT_I2: + return *(short*)pOle.GetRawDataRef(); + + case VarEnum.VT_UI2: + return pOle.As(); + case VarEnum.VT_BYREF | VarEnum.VT_UI2: + return *(ushort*)pOle.GetRawDataRef(); + + case VarEnum.VT_I8: + return pOle.As(); + case VarEnum.VT_BYREF | VarEnum.VT_I8: + return *(long*)pOle.GetRawDataRef(); + + case VarEnum.VT_UI8: + return pOle.As(); + case VarEnum.VT_BYREF | VarEnum.VT_UI8: + return *(ulong*)pOle.GetRawDataRef(); + + case VarEnum.VT_R4: + return pOle.As(); + case VarEnum.VT_BYREF | VarEnum.VT_R4: + return *(float*)pOle.GetRawDataRef(); + + case VarEnum.VT_R8: + return pOle.As(); + case VarEnum.VT_BYREF | VarEnum.VT_R8: + return *(double*)pOle.GetRawDataRef(); + + case VarEnum.VT_BOOL: + return pOle.As(); + case VarEnum.VT_BYREF | VarEnum.VT_BOOL: + // VARIANT_BOOL is 2 bytes + return *(short*)pOle.GetRawDataRef() != 0; + + case VarEnum.VT_BSTR: + return pOle.As(); + + case VarEnum.VT_BYREF | VarEnum.VT_BSTR: + IntPtr bstr = *(IntPtr*)pOle.GetRawDataRef(); + return bstr == IntPtr.Zero ? null : Marshal.PtrToStringBSTR(bstr); + + case VarEnum.VT_EMPTY: + return null; + + case VarEnum.VT_BYREF | VarEnum.VT_EMPTY: +#if TARGET_64BIT + return (ulong)pOle.GetRawDataRef(); +#else + return (uint)pOle.GetRawDataRef(); +#endif + + case VarEnum.VT_NULL: + case VarEnum.VT_BYREF | VarEnum.VT_NULL: + return DBNull.Value; + + case VarEnum.VT_DATE: + return pOle.As(); + case VarEnum.VT_BYREF | VarEnum.VT_DATE: + return DateTime.FromOADate(*(double*)pOle.GetRawDataRef()); + + case VarEnum.VT_DECIMAL: + return pOle.As(); + case VarEnum.VT_BYREF | VarEnum.VT_DECIMAL: + return *(decimal*)pOle.GetRawDataRef(); + + case VarEnum.VT_CY: + return decimal.FromOACurrency(pOle.GetRawDataRef()); + case VarEnum.VT_BYREF | VarEnum.VT_CY: + return decimal.FromOACurrency(*(long*)pOle.GetRawDataRef()); + + case VarEnum.VT_UNKNOWN: + case VarEnum.VT_DISPATCH: + return GetObjectFromIUnknown(pOle.GetRawDataRef()); + case VarEnum.VT_BYREF | VarEnum.VT_UNKNOWN: + case VarEnum.VT_BYREF | VarEnum.VT_DISPATCH: + return GetObjectFromIUnknown(*(IntPtr*)pOle.GetRawDataRef()); + + case VarEnum.VT_ERROR: + int error = pOle.GetRawDataRef(); + return error == HResults.DISP_E_PARAMNOTFOUND ? Missing.Value : error; + case VarEnum.VT_BYREF | VarEnum.VT_ERROR: + int refError = *(int*)pOle.GetRawDataRef(); + return refError == HResults.DISP_E_PARAMNOTFOUND ? Missing.Value : refError; + + case VarEnum.VT_VOID: + case VarEnum.VT_BYREF | VarEnum.VT_VOID: + return null; // CV_VOID + + default: + throw new ArgumentException(SR.ComVariant_UnsupportedType); } } - // Helper code for marshaling VARIANTS to managed objects (we use - // managed variants as an intermediate type. - internal static object? MarshalHelperConvertVariantToObject(ref Variant v) - { - return v.ToObject(); - } - // Helper code: on the back propagation path where a VT_BYREF VARIANT* // is marshaled to a "ref Object", we use this helper to force the // updated object back to the original type. - internal static void MarshalHelperCastVariant(object pValue, int vt, ref Variant v) + internal static void MarshalHelperCastVariant(object pValue, int vt, out ComVariant v) { + Debug.Assert((VarEnum)vt != VarEnum.VT_VARIANT, "Should be handled at native side."); + if (pValue is not IConvertible iv) { - switch (vt) + switch ((VarEnum)vt) { - case 9: /*VT_DISPATCH*/ + case VarEnum.VT_DISPATCH: Debug.Assert(OperatingSystem.IsWindows()); - v = new Variant(new DispatchWrapper(pValue)); + v = ComVariant.CreateRaw(VarEnum.VT_DISPATCH, + pValue is null ? IntPtr.Zero : Marshal.GetIDispatchForObject(pValue)); break; - case 12: /*VT_VARIANT*/ - v = new Variant(pValue); + case VarEnum.VT_UNKNOWN: + v = ComVariant.CreateRaw(VarEnum.VT_UNKNOWN, + pValue is null ? IntPtr.Zero : Marshal.GetIUnknownForObject(pValue)); break; - case 13: /*VT_UNKNOWN*/ - v = new Variant(new UnknownWrapper(pValue)); - break; - - case 36: /*VT_RECORD*/ - v = new Variant(pValue); + case VarEnum.VT_RECORD: + MarshalHelperConvertObjectToVariant(pValue, out v); + if (v.VarType != VarEnum.VT_RECORD) + { + // v can hold disposable content like BSTR + v.Dispose(); + throw new InvalidCastException(SR.InvalidCast_CannotCoerceByRefVariant); + } break; - case 8: /*VT_BSTR*/ + case VarEnum.VT_BSTR: /*VT_BSTR*/ if (pValue == null) { - v = new Variant(null) { _flags = CV_STRING }; + v = ComVariant.CreateRaw(VarEnum.VT_BSTR, IntPtr.Zero); break; } goto default; @@ -406,36 +374,31 @@ internal static void MarshalHelperCastVariant(object pValue, int vt, ref Variant else { IFormatProvider provider = CultureInfo.InvariantCulture; - v = vt switch + v = (VarEnum)vt switch { - 0 => /*VT_EMPTY*/ Empty, - 1 => /*VT_NULL*/ DBNull, - 2 => /*VT_I2*/ new Variant(iv.ToInt16(provider)), - 3 => /*VT_I4*/ new Variant(iv.ToInt32(provider)), - 4 => /*VT_R4*/ new Variant(iv.ToSingle(provider)), - 5 => /*VT_R8*/ new Variant(iv.ToDouble(provider)), -#pragma warning disable 0618 // CurrencyWrapper is obsolete - 6 => /*VT_CY*/ new Variant(new CurrencyWrapper(iv.ToDecimal(provider))), -#pragma warning restore 0618 - 7 => /*VT_DATE*/ new Variant(iv.ToDateTime(provider)), - 8 => /*VT_BSTR*/ new Variant(iv.ToString(provider)), -#pragma warning disable CA1416 // Validate platform compatibility - 9 => /*VT_DISPATCH*/ new Variant(new DispatchWrapper((object)iv)), -#pragma warning restore CA1416 - 10 => /*VT_ERROR*/ new Variant(new ErrorWrapper(iv.ToInt32(provider))), - 11 => /*VT_BOOL*/ new Variant(iv.ToBoolean(provider)), - 12 => /*VT_VARIANT*/ new Variant((object)iv), - 13 => /*VT_UNKNOWN*/ new Variant(new UnknownWrapper((object)iv)), - 14 => /*VT_DECIMAL*/ new Variant(iv.ToDecimal(provider)), + VarEnum.VT_EMPTY => default, + VarEnum.VT_NULL => ComVariant.Create(DBNull.Value), + VarEnum.VT_I2 => ComVariant.Create(iv.ToInt16(provider)), + VarEnum.VT_I4 => ComVariant.Create(iv.ToInt32(provider)), + VarEnum.VT_R4 => ComVariant.Create(iv.ToSingle(provider)), + VarEnum.VT_R8 => ComVariant.Create(iv.ToDouble(provider)), + VarEnum.VT_CY => ComVariant.CreateRaw(VarEnum.VT_CY, decimal.ToOACurrency(iv.ToDecimal(provider))), + VarEnum.VT_DATE => ComVariant.Create(iv.ToDateTime(provider)), + VarEnum.VT_BSTR => ComVariant.Create(iv.ToString(provider)), + VarEnum.VT_DISPATCH => ComVariant.CreateRaw(VarEnum.VT_DISPATCH, Marshal.GetIDispatchForObject(iv)), + VarEnum.VT_ERROR => ComVariant.CreateRaw(VarEnum.VT_ERROR, iv.ToInt32(provider)), + VarEnum.VT_BOOL => ComVariant.Create(iv.ToBoolean(provider)), + VarEnum.VT_UNKNOWN => ComVariant.CreateRaw(VarEnum.VT_UNKNOWN, Marshal.GetIUnknownForObject(iv)), + VarEnum.VT_DECIMAL => ComVariant.Create(iv.ToDecimal(provider)), // 15 => : /*unused*/ NOT SUPPORTED - 16 => /*VT_I1*/ new Variant(iv.ToSByte(provider)), - 17 => /*VT_UI1*/ new Variant(iv.ToByte(provider)), - 18 => /*VT_UI2*/ new Variant(iv.ToUInt16(provider)), - 19 => /*VT_UI4*/ new Variant(iv.ToUInt32(provider)), - 20 => /*VT_I8*/ new Variant(iv.ToInt64(provider)), - 21 => /*VT_UI8*/ new Variant(iv.ToUInt64(provider)), - 22 => /*VT_INT*/ new Variant(iv.ToInt32(provider)), - 23 => /*VT_UINT*/ new Variant(iv.ToUInt32(provider)), + VarEnum.VT_I1 => ComVariant.Create(iv.ToSByte(provider)), + VarEnum.VT_UI1 => ComVariant.Create(iv.ToByte(provider)), + VarEnum.VT_UI2 => ComVariant.Create(iv.ToUInt16(provider)), + VarEnum.VT_UI4 => ComVariant.Create(iv.ToUInt32(provider)), + VarEnum.VT_I8 => ComVariant.Create(iv.ToInt64(provider)), + VarEnum.VT_UI8 => ComVariant.Create(iv.ToUInt64(provider)), + VarEnum.VT_INT => ComVariant.Create(iv.ToInt32(provider)), + VarEnum.VT_UINT => ComVariant.Create(iv.ToUInt32(provider)), _ => throw new InvalidCastException(SR.InvalidCast_CannotCoerceByRefVariant), }; } diff --git a/src/coreclr/classlibnative/bcltype/variant.cpp b/src/coreclr/classlibnative/bcltype/variant.cpp index 1a3cf7e75bb44..74baf2b62087c 100644 --- a/src/coreclr/classlibnative/bcltype/variant.cpp +++ b/src/coreclr/classlibnative/bcltype/variant.cpp @@ -15,277 +15,8 @@ #ifdef FEATURE_COMINTEROP #include "object.h" -#include "excep.h" -#include "frames.h" #include "vars.hpp" #include "variant.h" -#include "string.h" - -#include "field.h" - -// The following values are used to represent underlying -// type of the Enum.. -#define EnumI1 0x100000 -#define EnumU1 0x200000 -#define EnumI2 0x300000 -#define EnumU2 0x400000 -#define EnumI4 0x500000 -#define EnumU4 0x600000 -#define EnumI8 0x700000 -#define EnumU8 0x800000 -#define EnumMask 0xF00000 - - -/*===============================SetFieldsObject================================ -** -==============================================================================*/ -FCIMPL2(void, COMVariant::SetFieldsObject, VariantData* var, Object* vVal) -{ - CONTRACTL - { - FCALL_CHECK; - PRECONDITION(CheckPointer(var)); - PRECONDITION(CheckPointer(vVal)); - } - CONTRACTL_END; - - OBJECTREF val = ObjectToOBJECTREF(vVal); - - HELPER_METHOD_FRAME_BEGIN_1(val); - GCPROTECT_BEGININTERIOR(var) - - CVTypes cvt = CV_EMPTY; - TypeHandle typeHandle; - - MethodTable *valMT = val->GetMethodTable(); - - //If this isn't a value class, we should just skip out because we're not going - //to do anything special with it. - if (!valMT->IsValueType()) - { - var->SetObjRef(val); - typeHandle = TypeHandle(valMT); - - if (typeHandle==GetTypeHandleForCVType(CV_MISSING)) - { - var->SetType(CV_MISSING); - } - else if (typeHandle==GetTypeHandleForCVType(CV_NULL)) - { - var->SetType(CV_NULL); - } - else if (typeHandle==GetTypeHandleForCVType(CV_EMPTY)) - { - var->SetType(CV_EMPTY); - var->SetObjRef(NULL); - } - else - { - var->SetType(CV_OBJECT); - } - } - else if (IsTypeRefOrDef(g_ColorClassName, valMT->GetModule(), valMT->GetCl())) - { - // System.Drawing.Color is converted to UInt32 - var->SetDataAsUInt32(ConvertSystemColorToOleColor(&val)); - var->SetType(CV_U4); - } - else - { - //If this is a primitive type, we need to unbox it, get the value and create a variant - //with just those values. - void *UnboxData = val->UnBox(); - - ClearObjectReference(var->GetObjRefPtr()); - typeHandle = TypeHandle(valMT); - CorElementType cet = typeHandle.GetSignatureCorElementType(); - - if (cet>=ELEMENT_TYPE_BOOLEAN && cet<=ELEMENT_TYPE_STRING) - { - cvt = (CVTypes)cet; - } - else - { - cvt = GetCVTypeFromClass(valMT); - } - var->SetType(cvt); - - - //copy all of the data. - // Copies must be done based on the exact number of bytes to copy. - // We don't want to read garbage from other blocks of memory. - //CV_I8 --> CV_R8, CV_DATETIME, CV_TIMESPAN, & CV_CURRENCY are all of the 8 byte quantities - //If we don't find one of those ranges, we've found a value class - //of which we don't have inherent knowledge, so just slam that into an - //ObjectRef. - if (cvt>=CV_BOOLEAN && cvt<=CV_U1 && cvt != CV_CHAR) - { - var->SetDataAsInt64(*((UINT8 *)UnboxData)); - } - else if (cvt==CV_CHAR || cvt>=CV_I2 && cvt<=CV_U2) - { - var->SetDataAsInt64(*((UINT16 *)UnboxData)); - } - else if (cvt>=CV_I4 && cvt<=CV_U4 || cvt==CV_R4) - { - var->SetDataAsInt64(*((UINT32 *)UnboxData)); - } - else if ((cvt>=CV_I8 && cvt<=CV_R8) || (cvt==CV_DATETIME) || (cvt==CV_TIMESPAN) || (cvt==CV_CURRENCY)) - { - var->SetDataAsInt64(*((INT64 *)UnboxData)); - } - else if (cvt==CV_EMPTY || cvt==CV_NULL || cvt==CV_MISSING) - { - var->SetType(cvt); - } - else if (cvt==CV_ENUM) - { - var->SetDataAsInt64(*((INT32 *)UnboxData)); - var->SetObjRef(typeHandle.GetManagedClassObject()); - var->SetType(GetEnumFlags(typeHandle)); - } - else - { - // Decimals and other boxed value classes get handled here. - var->SetObjRef(val); - } - } - - GCPROTECT_END(); - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - - -FCIMPL1(Object*, COMVariant::BoxEnum, VariantData* var) -{ - CONTRACTL - { - FCALL_CHECK; - PRECONDITION(CheckPointer(var)); - PRECONDITION(var->GetObjRef() != NULL); - } - CONTRACTL_END; - - OBJECTREF retO = NULL; - - HELPER_METHOD_FRAME_BEGIN_RET_1(retO); - -#ifdef _DEBUG - CVTypes vType = (CVTypes) var->GetType(); -#endif - - _ASSERTE(vType == CV_ENUM); - - MethodTable* mt = ((REFLECTCLASSBASEREF) var->GetObjRef())->GetType().GetMethodTable(); - _ASSERTE(mt); - - retO = mt->Box(var->GetData()); - - HELPER_METHOD_FRAME_END(); - return OBJECTREFToObject(retO); -} -FCIMPLEND - - -/*===============================GetTypeFromClass=============================== -**Action: Takes an MethodTable * and returns the associated CVType. -**Arguments: MethodTable * -- a pointer to the class for which we want the CVType. -**Returns: The CVType associated with the MethodTable or CV_OBJECT if this can't be -** determined. -**Exceptions: None -==============================================================================*/ - -CVTypes COMVariant::GetCVTypeFromClass(TypeHandle th) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - if (th.IsNull()) - return CV_EMPTY; - - //We'll start looking from Variant. Empty and Void are handled below. - for (int i=CV_EMPTY; i check this approximation - we may be losing exact type information - ApproxFieldDescIterator fdIterator(th.GetMethodTable(), ApproxFieldDescIterator::INSTANCE_FIELDS); - FieldDesc* p = fdIterator.Next(); - if (NULL == p) - { - _ASSERTE(!"NULL FieldDesc returned"); - return 0; - } - -#ifdef _DEBUG - WORD fldCnt = th.GetMethodTable()->GetNumInstanceFields(); -#endif - - _ASSERTE(fldCnt == 1); - - CorElementType cet = p[0].GetFieldType(); - switch (cet) - { - case ELEMENT_TYPE_I1: - return (CV_ENUM | EnumI1); - - case ELEMENT_TYPE_U1: - return (CV_ENUM | EnumU1); - - case ELEMENT_TYPE_I2: - return (CV_ENUM | EnumI2); - - case ELEMENT_TYPE_U2: - return (CV_ENUM | EnumU2); - - IN_TARGET_32BIT(case ELEMENT_TYPE_I:) - case ELEMENT_TYPE_I4: - return (CV_ENUM | EnumI4); - - IN_TARGET_32BIT(case ELEMENT_TYPE_U:) - case ELEMENT_TYPE_U4: - return (CV_ENUM | EnumU4); - - IN_TARGET_64BIT(case ELEMENT_TYPE_I:) - case ELEMENT_TYPE_I8: - return (CV_ENUM | EnumI8); - - IN_TARGET_64BIT(case ELEMENT_TYPE_U:) - case ELEMENT_TYPE_U8: - return (CV_ENUM | EnumU8); - - default: - _ASSERTE(!"UNknown Type"); - return 0; - } -} extern "C" uint32_t QCALLTYPE Variant_ConvertSystemColorToOleColor(QCall::ObjectHandleOnStack obj) { @@ -297,7 +28,10 @@ extern "C" uint32_t QCALLTYPE Variant_ConvertSystemColorToOleColor(QCall::Object GCX_COOP(); OBJECTREF srcObj = obj.Get(); + + GCPROTECT_BEGIN(srcObj); ret = ConvertSystemColorToOleColor(&srcObj); + GCPROTECT_END(); END_QCALL; @@ -318,4 +52,19 @@ extern "C" void QCALLTYPE Variant_ConvertOleColorToSystemColor(QCall::ObjectHand END_QCALL; } +extern "C" void QCALLTYPE Variant_ConvertValueTypeToRecord(QCall::ObjectHandleOnStack obj, VARIANT * pOle) +{ + QCALL_CONTRACT; + + BEGIN_QCALL; + GCX_COOP(); + + OBJECTREF objRef = obj.Get(); + GCPROTECT_BEGIN(objRef); + V_VT(pOle) = VT_RECORD; + OleVariant::ConvertValueClassToVariant(&objRef, pOle); + GCPROTECT_END(); + + END_QCALL; +} #endif // FEATURE_COMINTEROP diff --git a/src/coreclr/classlibnative/bcltype/variant.h b/src/coreclr/classlibnative/bcltype/variant.h index 12c5a3d36d53d..597cf76d72088 100644 --- a/src/coreclr/classlibnative/bcltype/variant.h +++ b/src/coreclr/classlibnative/bcltype/variant.h @@ -18,30 +18,11 @@ #endif // FEATURE_COMINTEROP #include -#include "fcall.h" #include "olevariant.h" -class COMVariant -{ - friend class OleVariant; - -public: - // - // Helper Routines - // - - static FCDECL2(void, SetFieldsObject, VariantData* vThisRef, Object* vVal); - static FCDECL1(Object*, BoxEnum, VariantData* var); - -private: - // GetCVTypeFromClass - // This method will return the CVTypes from the Variant instance - static CVTypes GetCVTypeFromClass(TypeHandle th); - static int GetEnumFlags(TypeHandle th); -}; - extern "C" uint32_t QCALLTYPE Variant_ConvertSystemColorToOleColor(QCall::ObjectHandleOnStack obj); extern "C" void QCALLTYPE Variant_ConvertOleColorToSystemColor(QCall::ObjectHandleOnStack objRet, uint32_t oleColor, MethodTable* pMT); +extern "C" void QCALLTYPE Variant_ConvertValueTypeToRecord(QCall::ObjectHandleOnStack obj, VARIANT* pOle); #endif // _VARIANT_H_ diff --git a/src/coreclr/dlls/mscorrc/mscorrc.rc b/src/coreclr/dlls/mscorrc/mscorrc.rc index e29b2c75f16ac..aef92ce036054 100644 --- a/src/coreclr/dlls/mscorrc/mscorrc.rc +++ b/src/coreclr/dlls/mscorrc/mscorrc.rc @@ -487,11 +487,6 @@ BEGIN IDS_EE_CLASS_TO_VARIANT_TLB_NOT_REG "Type '%1' cannot be marshalled to a Variant. Type library is not registered." IDS_EE_CANNOT_MAP_TO_MANAGED_VC "The specified record cannot be mapped to a managed value class." - IDS_EE_SH_IN_VARIANT_NOT_SUPPORTED "SafeHandle derived types cannot be stored in Variants." - - IDS_EE_CH_IN_VARIANT_NOT_SUPPORTED "CriticalHandle derived types cannot be stored in Variants." - - IDS_EE_VAR_WRAP_IN_VAR_NOT_SUPPORTED "VariantWrappers cannot be stored in Variants." IDS_EE_RECORD_NON_SUPPORTED_FIELDS "The structure contains fields that are not supported in unmanaged records." IDS_CLASSLOAD_NSTRUCT_NEGATIVE_OFFSET "Could not load type '%1' from assembly '%2' because field '%3' was given a negative offset." diff --git a/src/coreclr/dlls/mscorrc/resource.h b/src/coreclr/dlls/mscorrc/resource.h index 7e9c3e9cc3fec..6962fdfec89b5 100644 --- a/src/coreclr/dlls/mscorrc/resource.h +++ b/src/coreclr/dlls/mscorrc/resource.h @@ -261,10 +261,8 @@ #define IDS_EE_BADMARSHAL_SAFEHANDLE 0x1a3d #define IDS_EE_BADMARSHAL_ABSTRACTRETSAFEHANDLE 0x1a44 -#define IDS_EE_SH_IN_VARIANT_NOT_SUPPORTED 0x1a47 #define IDS_EE_BADMARSHAL_SYSARRAY 0x1a48 -#define IDS_EE_VAR_WRAP_IN_VAR_NOT_SUPPORTED 0x1a49 #define IDS_EE_RECORD_NON_SUPPORTED_FIELDS 0x1a4a #define IDS_CLASSLOAD_TYPEWRONGNUMGENERICARGS 0x1a4b @@ -282,7 +280,6 @@ #define IDS_EE_BADMARSHAL_INT128_RESTRICTION 0x1a66 #define IDS_EE_BADMARSHAL_ABSTRACTRETCRITICALHANDLE 0x1a6a -#define IDS_EE_CH_IN_VARIANT_NOT_SUPPORTED 0x1a6b #define IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_IMPLICIT_OVERRIDE 0x1a6f #define IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_IMPLICIT_IMPLEMENTATION 0x1a70 diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 671ae48e7ee7c..4cffd124370fe 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -371,14 +371,10 @@ DEFINE_CLASS(GUID, System, Guid) BEGIN_ILLINK_FEATURE_SWITCH(System.Runtime.InteropServices.BuiltInComInterop.IsSupported, true, true) #ifdef FEATURE_COMINTEROP DEFINE_CLASS(VARIANT, System, Variant) -DEFINE_METHOD(VARIANT, CONVERT_OBJECT_TO_VARIANT,MarshalHelperConvertObjectToVariant,SM_Obj_RefVariant_RetVoid) -DEFINE_METHOD(VARIANT, CAST_VARIANT, MarshalHelperCastVariant, SM_Obj_Int_RefVariant_RetVoid) -DEFINE_METHOD(VARIANT, CONVERT_VARIANT_TO_OBJECT,MarshalHelperConvertVariantToObject,SM_RefVariant_RetObject) - -DEFINE_CLASS_U(System, Variant, VariantData) -DEFINE_FIELD_U(_objref, VariantData, m_objref) -DEFINE_FIELD_U(_data, VariantData, m_data) -DEFINE_FIELD_U(_flags, VariantData, m_flags) +DEFINE_METHOD(VARIANT, CONVERT_OBJECT_TO_VARIANT,MarshalHelperConvertObjectToVariant,SM_Obj_RefComVariant_RetVoid) +DEFINE_METHOD(VARIANT, CAST_VARIANT, MarshalHelperCastVariant, SM_Obj_Int_RefComVariant_RetVoid) +DEFINE_METHOD(VARIANT, CONVERT_VARIANT_TO_OBJECT,MarshalHelperConvertVariantToObject,SM_RefComVariant_RetObject) + #endif // FEATURE_COMINTEROP END_ILLINK_FEATURE_SWITCH() diff --git a/src/coreclr/vm/dispparammarshaler.cpp b/src/coreclr/vm/dispparammarshaler.cpp index 9286bd1ec39fa..ee05c624a1cc1 100644 --- a/src/coreclr/vm/dispparammarshaler.cpp +++ b/src/coreclr/vm/dispparammarshaler.cpp @@ -354,7 +354,7 @@ void DispParamArrayMarshaler::MarshalManagedToNativeRef(OBJECTREF *pSrcObj, VARI } // Copy the converted variant back into the byref variant. - OleVariant::InsertContentsIntoByrefVariant(&vtmp, pRefVar); + OleVariant::InsertContentsIntoByRefVariant(&vtmp, pRefVar); } void DispParamRecordMarshaler::MarshalNativeToManaged(VARIANT *pSrcVar, OBJECTREF *pDestObj) @@ -649,7 +649,7 @@ void DispParamCustomMarshaler::MarshalManagedToNativeRef(OBJECTREF *pSrcObj, VAR } // Copy the converted variant back into the byref variant. - OleVariant::InsertContentsIntoByrefVariant(&vtmp, pRefVar); + OleVariant::InsertContentsIntoByRefVariant(&vtmp, pRefVar); } void DispParamCustomMarshaler::CleanUpManaged(OBJECTREF *pObj) diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index 9cadd51c06ae4..7dc5e664dfd42 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -333,13 +333,6 @@ FCFuncStart(gWaitHandleFuncs) FCFuncElement("SignalAndWaitNative", WaitHandleNative::CorSignalAndWaitOneNative) FCFuncEnd() -#ifdef FEATURE_COMINTEROP -FCFuncStart(gVariantFuncs) - FCFuncElement("SetFieldsObject", COMVariant::SetFieldsObject) - FCFuncElement("BoxEnum", COMVariant::BoxEnum) -FCFuncEnd() -#endif // FEATURE_COMINTEROP - FCFuncStart(gCastHelpers) FCFuncElement("IsInstanceOfAny_NoCacheLookup", ::IsInstanceOfAny_NoCacheLookup) FCFuncElement("ChkCastAny_NoCacheLookup", ::ChkCastAny_NoCacheLookup) @@ -523,9 +516,6 @@ FCClassElement("Thread", "System.Threading", gThreadFuncs) FCClassElement("ThreadPool", "System.Threading", gThreadPoolFuncs) FCClassElement("Type", "System", gSystem_Type) FCClassElement("TypedReference", "System", gTypedReferenceFuncs) -#ifdef FEATURE_COMINTEROP -FCClassElement("Variant", "System", gVariantFuncs) -#endif FCClassElement("WaitHandle", "System.Threading", gWaitHandleFuncs) #undef FCFuncElement diff --git a/src/coreclr/vm/ilmarshalers.cpp b/src/coreclr/vm/ilmarshalers.cpp index 6d38d94a46004..d528fa10e1642 100644 --- a/src/coreclr/vm/ilmarshalers.cpp +++ b/src/coreclr/vm/ilmarshalers.cpp @@ -4344,7 +4344,7 @@ extern "C" void QCALLTYPE MngdNativeArrayMarshaler_ConvertContentsToNative(MngdN if ( (!ClrSafeInt::multiply(cElements, OleVariant::GetElementSizeForVarType(pThis->m_vt, pThis->m_pElementMT), cElements)) || cElements > MAX_SIZE_FOR_INTEROP) COMPlusThrow(kArgumentException, IDS_EE_STRUCTARRAYTOOLARGE); - _ASSERTE(!GetTypeHandleForCVType(OleVariant::GetCVTypeForVarType(pThis->m_vt)).GetMethodTable()->ContainsGCPointers()); + _ASSERTE(!OleVariant::GetTypeHandleForVarType(pThis->m_vt).GetMethodTable()->ContainsGCPointers()); memcpyNoGCRefs(*pNativeHome, arrayRef->GetDataPtr(), cElements); } else @@ -4413,7 +4413,7 @@ extern "C" void QCALLTYPE MngdNativeArrayMarshaler_ConvertContentsToManaged(Mngd COMPlusThrow(kArgumentException, IDS_EE_STRUCTARRAYTOOLARGE); // If we are copying variants, strings, etc, we need to use write barrier - _ASSERTE(!GetTypeHandleForCVType(OleVariant::GetCVTypeForVarType(pThis->m_vt)).GetMethodTable()->ContainsGCPointers()); + _ASSERTE(!OleVariant::GetTypeHandleForVarType(pThis->m_vt).GetMethodTable()->ContainsGCPointers()); memcpyNoGCRefs(arrayRef->GetDataPtr(), *pNativeHome, cElements); } else @@ -4528,7 +4528,7 @@ extern "C" void QCALLTYPE MngdFixedArrayMarshaler_ConvertContentsToNative(MngdFi SIZE_T cElements = arrayRef->GetNumComponents(); if (pMarshaler == NULL || pMarshaler->ComToOleArray == NULL) { - _ASSERTE(!GetTypeHandleForCVType(OleVariant::GetCVTypeForVarType(pThis->m_vt)).GetMethodTable()->ContainsGCPointers()); + _ASSERTE(!OleVariant::GetTypeHandleForVarType(pThis->m_vt).GetMethodTable()->ContainsGCPointers()); memcpyNoGCRefs(pNativeHome, arrayRef->GetDataPtr(), nativeSize); } else @@ -4602,7 +4602,7 @@ extern "C" void QCALLTYPE MngdFixedArrayMarshaler_ConvertContentsToManaged(MngdF if (pMarshaler == NULL || pMarshaler->OleToComArray == NULL) { // If we are copying variants, strings, etc, we need to use write barrier - _ASSERTE(!GetTypeHandleForCVType(OleVariant::GetCVTypeForVarType(pThis->m_vt)).GetMethodTable()->ContainsGCPointers()); + _ASSERTE(!OleVariant::GetTypeHandleForVarType(pThis->m_vt).GetMethodTable()->ContainsGCPointers()); memcpyNoGCRefs(arrayRef->GetDataPtr(), pNativeHome, nativeSize); } else diff --git a/src/coreclr/vm/interoputil.h b/src/coreclr/vm/interoputil.h index 3bc78c1e1ff0f..b3666f385a55b 100644 --- a/src/coreclr/vm/interoputil.h +++ b/src/coreclr/vm/interoputil.h @@ -8,8 +8,6 @@ #include "debugmacros.h" #include "interopconverter.h" -struct VariantData; - // Out of memory helper. #define IfNullThrow(EXPR) \ do {if ((EXPR) == 0) {ThrowOutOfMemory();} } while (0) diff --git a/src/coreclr/vm/metasig.h b/src/coreclr/vm/metasig.h index 19cc399478a19..eaa50c2f8421c 100644 --- a/src/coreclr/vm/metasig.h +++ b/src/coreclr/vm/metasig.h @@ -31,8 +31,6 @@ // r -- Ref -- a byref // Ret -- indicates function return type // -// Var -- Variant -// // b -- Byte -- (unsigned) byte // u -- Char -- character (2 byte unsigned unicode) // d -- Dbl -- double @@ -363,9 +361,9 @@ DEFINE_METASIG(SM(Obj_Bool_RetArrByte, j F, a(b))) DEFINE_METASIG(SM(Obj_Obj_RefArrByte_RetArrByte, j j r(a(b)), a(b))) #ifdef FEATURE_COMINTEROP -DEFINE_METASIG_T(SM(Obj_Int_RefVariant_RetVoid, j i r(g(VARIANT)), v)) -DEFINE_METASIG_T(SM(Obj_RefVariant_RetVoid, j r(g(VARIANT)), v)) -DEFINE_METASIG_T(SM(RefVariant_RetObject, r(g(VARIANT)), j)) +DEFINE_METASIG_T(SM(Obj_Int_RefComVariant_RetVoid, j i r(g(COMVARIANT)), v)) +DEFINE_METASIG_T(SM(Obj_RefComVariant_RetVoid, j r(g(COMVARIANT)), v)) +DEFINE_METASIG_T(SM(RefComVariant_RetObject, r(g(COMVARIANT)), j)) DEFINE_METASIG_T(IM(RuntimeTypeHandle_RefBool_RefIntPtr_RetVoid, g(RT_TYPE_HANDLE) r(F) r(I), v)) #endif diff --git a/src/coreclr/vm/olevariant.cpp b/src/coreclr/vm/olevariant.cpp index 5f7913b07b720..ab42391080e03 100644 --- a/src/coreclr/vm/olevariant.cpp +++ b/src/coreclr/vm/olevariant.cpp @@ -24,68 +24,12 @@ #define NO_MAPPING ((BYTE) -1) -#define GCPROTECT_BEGIN_VARIANTDATA(/*VARIANTDATA*/vd) do { \ - GCFrame __gcframe(vd.GetObjRefPtr(), 1, FALSE); \ - /* work around unreachable code warning */ \ - if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT); - - -#define GCPROTECT_END_VARIANTDATA() \ - DEBUG_ASSURE_NO_RETURN_END(GCPROTECT); } \ - } while(0) - - -//Mapping from CVType to type handle. Used for conversion between the two internally. -const BinderClassID CVTypeToBinderClassID[] = -{ - CLASS__EMPTY, //CV_EMPTY - CLASS__VOID, //CV_VOID, Changing this to object messes up signature resolution very badly. - CLASS__BOOLEAN, //CV_BOOLEAN - CLASS__CHAR, //CV_CHAR - CLASS__SBYTE, //CV_I1 - CLASS__BYTE, //CV_U1 - CLASS__INT16, //CV_I2 - CLASS__UINT16, //CV_U2 - CLASS__INT32, //CV_I4 - CLASS__UINT32, //CV_UI4 - CLASS__INT64, //CV_I8 - CLASS__UINT64, //CV_UI8 - CLASS__SINGLE, //CV_R4 - CLASS__DOUBLE, //CV_R8 - CLASS__STRING, //CV_STRING - CLASS__VOID, //CV_PTR...We treat this as void - CLASS__DATE_TIME, //CV_DATETIME - CLASS__TIMESPAN, //CV_TIMESPAN - CLASS__OBJECT, //CV_OBJECT - CLASS__DECIMAL, //CV_DECIMAL - CLASS__CURRENCY, //CV_CURRENCY - CLASS__OBJECT, //ENUM...We treat this as OBJECT - CLASS__MISSING, //CV_MISSING - CLASS__NULL, //CV_NULL - CLASS__NIL, //CV_LAST -}; - -// Use this very carefully. There is not a direct mapping between -// CorElementType and CVTypes for a bunch of things. In this case -// we return CV_LAST. You need to check this at the call site. -CVTypes CorElementTypeToCVTypes(CorElementType type) -{ - LIMITED_METHOD_CONTRACT; - - if (type <= ELEMENT_TYPE_STRING) - return (CVTypes) type; - - if (type == ELEMENT_TYPE_CLASS || type == ELEMENT_TYPE_OBJECT) - return (CVTypes) ELEMENT_TYPE_CLASS; - - return CV_LAST; -} /* ------------------------------------------------------------------------- * * Mapping routines * ------------------------------------------------------------------------- */ -VARTYPE OleVariant::GetVarTypeForCVType(CVTypes type) +VARTYPE GetVarTypeForCorElementType(CorElementType type) { CONTRACTL { @@ -97,33 +41,24 @@ VARTYPE OleVariant::GetVarTypeForCVType(CVTypes type) static const BYTE map[] = { - VT_EMPTY, // CV_EMPTY - VT_VOID, // CV_VOID - VT_BOOL, // CV_BOOLEAN - VT_UI2, // CV_CHAR - VT_I1, // CV_I1 - VT_UI1, // CV_U1 - VT_I2, // CV_I2 - VT_UI2, // CV_U2 - VT_I4, // CV_I4 - VT_UI4, // CV_U4 - VT_I8, // CV_I8 - VT_UI8, // CV_U8 - VT_R4, // CV_R4 - VT_R8, // CV_R8 - VT_BSTR, // CV_STRING - NO_MAPPING, // CV_PTR - VT_DATE, // CV_DATETIME - NO_MAPPING, // CV_TIMESPAN - VT_DISPATCH, // CV_OBJECT - VT_DECIMAL, // CV_DECIMAL - VT_CY, // CV_CURRENCY - VT_I4, // CV_ENUM - VT_ERROR, // CV_MISSING - VT_NULL // CV_NULL + VT_EMPTY, // ELEMENT_TYPE_END + VT_VOID, // ELEMENT_TYPE_VOID + VT_BOOL, // ELEMENT_TYPE_BOOLEAN + VT_UI2, // ELEMENT_TYPE_CHAR + VT_I1, // ELEMENT_TYPE_I1 + VT_UI1, // ELEMENT_TYPE_U1 + VT_I2, // ELEMENT_TYPE_I2 + VT_UI2, // ELEMENT_TYPE_U2 + VT_I4, // ELEMENT_TYPE_I4 + VT_UI4, // ELEMENT_TYPE_U4 + VT_I8, // ELEMENT_TYPE_I8 + VT_UI8, // ELEMENT_TYPE_U8 + VT_R4, // ELEMENT_TYPE_R4 + VT_R8, // ELEMENT_TYPE_R8 + VT_BSTR, // ELEMENT_TYPE_STRING }; - _ASSERTE(type < (CVTypes) (sizeof(map) / sizeof(map[0]))); + _ASSERTE(type < (CorElementType) (sizeof(map) / sizeof(map[0]))); VARTYPE vt = VARTYPE(map[type]); @@ -134,48 +69,48 @@ VARTYPE OleVariant::GetVarTypeForCVType(CVTypes type) } // -// GetCVTypeForVarType returns the COM+ variant type for a given +// GetTypeHandleForVarType returns the TypeHandle for a given // VARTYPE. This is called by the marshaller in the context of // a function call. // -CVTypes OleVariant::GetCVTypeForVarType(VARTYPE vt) +TypeHandle OleVariant::GetTypeHandleForVarType(VARTYPE vt) { CONTRACTL { THROWS; - GC_NOTRIGGER; + GC_TRIGGERS; MODE_ANY; } CONTRACTL_END; static const BYTE map[] = { - CV_EMPTY, // VT_EMPTY - CV_NULL, // VT_NULL - CV_I2, // VT_I2 - CV_I4, // VT_I4 - CV_R4, // VT_R4 - CV_R8, // VT_R8 - CV_DECIMAL, // VT_CY - CV_DATETIME, // VT_DATE - CV_STRING, // VT_BSTR - CV_OBJECT, // VT_DISPATCH - CV_I4, // VT_ERROR - CV_BOOLEAN, // VT_BOOL + CLASS__EMPTY, // VT_EMPTY + CLASS__NULL, // VT_NULL + CLASS__INT16, // VT_I2 + CLASS__INT32, // VT_I4 + CLASS__SINGLE, // VT_R4 + CLASS__DOUBLE, // VT_R8 + CLASS__DECIMAL, // VT_CY + CLASS__DATE_TIME, // VT_DATE + CLASS__STRING, // VT_BSTR + CLASS__OBJECT, // VT_DISPATCH + CLASS__INT32, // VT_ERROR + CLASS__BOOLEAN, // VT_BOOL NO_MAPPING, // VT_VARIANT - CV_OBJECT, // VT_UNKNOWN - CV_DECIMAL, // VT_DECIMAL + CLASS__OBJECT, // VT_UNKNOWN + CLASS__DECIMAL, // VT_DECIMAL NO_MAPPING, // unused - CV_I1, // VT_I1 - CV_U1, // VT_UI1 - CV_U2, // VT_UI2 - CV_U4, // VT_UI4 - CV_I8, // VT_I8 - CV_U8, // VT_UI8 - CV_I4, // VT_INT - CV_U4, // VT_UINT - CV_VOID, // VT_VOID + CLASS__SBYTE, // VT_I1 + CLASS__BYTE, // VT_UI1 + CLASS__UINT16, // VT_UI2 + CLASS__UINT32, // VT_UI4 + CLASS__INT64, // VT_I8 + CLASS__UINT64, // VT_UI8 + CLASS__INT32, // VT_INT + CLASS__UINT32, // VT_UINT + CLASS__VOID, // VT_VOID NO_MAPPING, // VT_HRESULT NO_MAPPING, // VT_PTR NO_MAPPING, // VT_SAFEARRAY @@ -187,102 +122,25 @@ CVTypes OleVariant::GetCVTypeForVarType(VARTYPE vt) NO_MAPPING, // unused NO_MAPPING, // unused NO_MAPPING, // unused - CV_OBJECT, // VT_RECORD + CLASS__OBJECT, // VT_RECORD }; - CVTypes type = CV_LAST; + BinderClassID type = CLASS__NIL; // Validate the arguments. _ASSERTE((vt & VT_BYREF) == 0); - // Array's map to CV_OBJECT. + // Array's map to object. if (vt & VT_ARRAY) - return CV_OBJECT; + return TypeHandle(CoreLibBinder::GetClass(CLASS__OBJECT)); // This is prety much a workaround because you cannot cast a CorElementType into a CVTYPE - if (vt > VT_RECORD || (BYTE)(type = (CVTypes) map[vt]) == NO_MAPPING) + if (vt > VT_RECORD || (type = (BinderClassID) map[vt]) == NO_MAPPING) COMPlusThrow(kArgumentException, IDS_EE_COM_UNSUPPORTED_TYPE); - return type; + return TypeHandle(CoreLibBinder::GetClass(type)); } // CVTypes OleVariant::GetCVTypeForVarType() -#ifdef FEATURE_COMINTEROP - -// GetVarTypeForComVariant retusn the VARTYPE for the contents -// of a COM+ variant. -// -VARTYPE OleVariant::GetVarTypeForComVariant(VariantData *pComVariant) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } - CONTRACTL_END; - - CVTypes type = pComVariant->GetType(); - VARTYPE vt; - - vt = pComVariant->GetVT(); - if (vt != VT_EMPTY) - { - // This variant was originally unmarshaled from unmanaged, and had the original VT recorded in it. - // We'll always use that over inference. - return vt; - } - - if (type == CV_OBJECT) - { - OBJECTREF obj = pComVariant->GetObjRef(); - - // Null objects will be converted to VT_DISPATCH variants with a null - // IDispatch pointer. - if (obj == NULL) - return VT_DISPATCH; - - // Retrieve the object's method table. - MethodTable *pMT = obj->GetMethodTable(); - - // Handle the value class case. - if (pMT->IsValueType()) - return VT_RECORD; - - // Handle the array case. - if (pMT->IsArray()) - { - vt = GetElementVarTypeForArrayRef((BASEARRAYREF)obj); - if (vt == VT_ARRAY) - vt = VT_VARIANT; - - return vt | VT_ARRAY; - } - -#ifdef FEATURE_COMINTEROP - // SafeHandle's or CriticalHandle's cannot be stored in VARIANT's. - if (pMT->CanCastToClass(CoreLibBinder::GetClass(CLASS__SAFE_HANDLE))) - COMPlusThrow(kArgumentException, IDS_EE_SH_IN_VARIANT_NOT_SUPPORTED); - if (pMT->CanCastToClass(CoreLibBinder::GetClass(CLASS__CRITICAL_HANDLE))) - COMPlusThrow(kArgumentException, IDS_EE_CH_IN_VARIANT_NOT_SUPPORTED); - - // VariantWrappers cannot be stored in VARIANT's. - if (CoreLibBinder::IsClass(pMT, CLASS__VARIANT_WRAPPER)) - COMPlusThrow(kArgumentException, IDS_EE_VAR_WRAP_IN_VAR_NOT_SUPPORTED); - - // We are dealing with a normal object (not a wrapper) so we will - // leave the VT as VT_DISPATCH for now and we will determine the actual - // VT when we convert the object to a COM IP. - return VT_DISPATCH; -#else // FEATURE_COMINTEROP - return VT_UNKNOWN; -#endif // FEATURE_COMINTEROP - } - - return GetVarTypeForCVType(type); -} - -#endif // FEATURE_COMINTEROP - VARTYPE OleVariant::GetVarTypeForTypeHandle(TypeHandle type) { CONTRACTL @@ -296,7 +154,7 @@ VARTYPE OleVariant::GetVarTypeForTypeHandle(TypeHandle type) // Handle primitive types. CorElementType elemType = type.GetSignatureCorElementType(); if (elemType <= ELEMENT_TYPE_R8) - return GetVarTypeForCVType(CorElementTypeToCVTypes(elemType)); + return GetVarTypeForCorElementType(elemType); // Types incompatible with interop. if (type.IsTypeDesc()) @@ -350,7 +208,7 @@ VARTYPE OleVariant::GetVarTypeForTypeHandle(TypeHandle type) #endif // FEATURE_COMINTEROP if (pMT->IsEnum()) - return GetVarTypeForCVType((CVTypes)type.GetInternalCorElementType()); + return GetVarTypeForCorElementType(type.GetInternalCorElementType()); if (pMT->IsValueType()) return VT_RECORD; @@ -868,26 +726,14 @@ const OleVariant::Marshaler *OleVariant::GetMarshalerForVarType(VARTYPE vt, BOOL } CONTRACT_END; -#ifdef FEATURE_COMINTEROP - -#define RETURN_MARSHALER(OleToCom, ComToOle, OleRefToCom, ArrayOleToCom, ArrayComToOle, ClearArray) \ - { static const Marshaler marshaler = { OleToCom, ComToOle, OleRefToCom, ArrayOleToCom, ArrayComToOle, ClearArray }; RETURN &marshaler; } - -#else // FEATURE_COMINTEROP - -#define RETURN_MARSHALER(OleToCom, ComToOle, OleRefToCom, ArrayOleToCom, ArrayComToOle, ClearArray) \ +#define RETURN_MARSHALER(ArrayOleToCom, ArrayComToOle, ClearArray) \ { static const Marshaler marshaler = { ArrayOleToCom, ArrayComToOle, ClearArray }; RETURN &marshaler; } -#endif // FEATURE_COMINTEROP - #ifdef FEATURE_COMINTEROP if (vt & VT_ARRAY) { VariantArray: RETURN_MARSHALER( - MarshalArrayVariantOleToCom, - MarshalArrayVariantComToOle, - MarshalArrayVariantOleRefToCom, NULL, NULL, ClearVariantArray @@ -899,9 +745,6 @@ const OleVariant::Marshaler *OleVariant::GetMarshalerForVarType(VARTYPE vt, BOOL { case VT_BOOL: RETURN_MARSHALER( - MarshalBoolVariantOleToCom, - NULL, - NULL, MarshalBoolArrayOleToCom, MarshalBoolArrayComToOle, NULL @@ -909,28 +752,14 @@ const OleVariant::Marshaler *OleVariant::GetMarshalerForVarType(VARTYPE vt, BOOL case VT_DATE: RETURN_MARSHALER( - MarshalDateVariantOleToCom, - MarshalDateVariantComToOle, - MarshalDateVariantOleRefToCom, MarshalDateArrayOleToCom, MarshalDateArrayComToOle, NULL ); - case VT_DECIMAL: - RETURN_MARSHALER( - MarshalDecimalVariantOleToCom, - MarshalDecimalVariantComToOle, - MarshalDecimalVariantOleRefToCom, - NULL, NULL, NULL - ); - #ifdef FEATURE_COMINTEROP case VT_CY: RETURN_MARSHALER( - MarshalCurrencyVariantOleToCom, - MarshalCurrencyVariantComToOle, - MarshalCurrencyVariantOleRefToCom, MarshalCurrencyArrayOleToCom, MarshalCurrencyArrayComToOle, NULL @@ -938,9 +767,6 @@ const OleVariant::Marshaler *OleVariant::GetMarshalerForVarType(VARTYPE vt, BOOL case VT_BSTR: RETURN_MARSHALER( - MarshalBSTRVariantOleToCom, - MarshalBSTRVariantComToOle, - NULL, MarshalBSTRArrayOleToCom, MarshalBSTRArrayComToOle, ClearBSTRArray @@ -948,9 +774,6 @@ const OleVariant::Marshaler *OleVariant::GetMarshalerForVarType(VARTYPE vt, BOOL case VT_UNKNOWN: RETURN_MARSHALER( - MarshalInterfaceVariantOleToCom, - MarshalInterfaceVariantComToOle, - MarshalInterfaceVariantOleRefToCom, MarshalInterfaceArrayOleToCom, MarshalIUnknownArrayComToOle, ClearInterfaceArray @@ -958,9 +781,6 @@ const OleVariant::Marshaler *OleVariant::GetMarshalerForVarType(VARTYPE vt, BOOL case VT_DISPATCH: RETURN_MARSHALER( - MarshalInterfaceVariantOleToCom, - MarshalInterfaceVariantComToOle, - MarshalInterfaceVariantOleRefToCom, MarshalInterfaceArrayOleToCom, MarshalIDispatchArrayComToOle, ClearInterfaceArray @@ -971,24 +791,15 @@ const OleVariant::Marshaler *OleVariant::GetMarshalerForVarType(VARTYPE vt, BOOL case VT_VARIANT: RETURN_MARSHALER( - NULL, NULL, NULL, MarshalVariantArrayOleToCom, MarshalVariantArrayComToOle, ClearVariantArray ); - case VT_ERROR: - RETURN_MARSHALER( - MarshalErrorVariantOleToCom, - MarshalErrorVariantComToOle, - MarshalErrorVariantOleRefToCom, - NULL, NULL, NULL - ); #endif // FEATURE_COMINTEROP case VTHACK_NONBLITTABLERECORD: RETURN_MARSHALER( - NULL, NULL, NULL, MarshalNonBlittableRecordArrayOleToCom, MarshalNonBlittableRecordArrayComToOle, ClearNonBlittableRecordArray @@ -999,9 +810,6 @@ const OleVariant::Marshaler *OleVariant::GetMarshalerForVarType(VARTYPE vt, BOOL case VTHACK_WINBOOL: RETURN_MARSHALER( - MarshalWinBoolVariantOleToCom, - MarshalWinBoolVariantComToOle, - MarshalWinBoolVariantOleRefToCom, MarshalWinBoolArrayOleToCom, MarshalWinBoolArrayComToOle, NULL @@ -1009,9 +817,6 @@ const OleVariant::Marshaler *OleVariant::GetMarshalerForVarType(VARTYPE vt, BOOL case VTHACK_CBOOL: RETURN_MARSHALER( - MarshalCBoolVariantOleToCom, - MarshalCBoolVariantComToOle, - MarshalCBoolVariantOleRefToCom, MarshalCBoolArrayOleToCom, MarshalCBoolArrayComToOle, NULL @@ -1019,9 +824,6 @@ const OleVariant::Marshaler *OleVariant::GetMarshalerForVarType(VARTYPE vt, BOOL case VTHACK_ANSICHAR: RETURN_MARSHALER( - MarshalAnsiCharVariantOleToCom, - MarshalAnsiCharVariantComToOle, - MarshalAnsiCharVariantOleRefToCom, MarshalAnsiCharArrayOleToCom, MarshalAnsiCharArrayComToOle, NULL @@ -1029,7 +831,6 @@ const OleVariant::Marshaler *OleVariant::GetMarshalerForVarType(VARTYPE vt, BOOL case VT_LPSTR: RETURN_MARSHALER( - NULL, NULL, NULL, MarshalLPSTRArrayOleToCom, MarshalLPSTRRArrayComToOle, ClearLPSTRArray @@ -1037,7 +838,6 @@ const OleVariant::Marshaler *OleVariant::GetMarshalerForVarType(VARTYPE vt, BOOL case VT_LPWSTR: RETURN_MARSHALER( - NULL, NULL, NULL, MarshalLPWSTRArrayOleToCom, MarshalLPWSTRRArrayComToOle, ClearLPWSTRArray @@ -1046,16 +846,12 @@ const OleVariant::Marshaler *OleVariant::GetMarshalerForVarType(VARTYPE vt, BOOL case VT_RECORD: #ifdef FEATURE_COMINTEROP RETURN_MARSHALER( - MarshalRecordVariantOleToCom, - MarshalRecordVariantComToOle, - MarshalRecordVariantOleRefToCom, MarshalRecordArrayOleToCom, MarshalRecordArrayComToOle, ClearRecordArray ); #else RETURN_MARSHALER( - NULL, NULL, NULL, MarshalRecordArrayOleToCom, MarshalRecordArrayComToOle, ClearRecordArray @@ -1081,79 +877,6 @@ const OleVariant::Marshaler *OleVariant::GetMarshalerForVarType(VARTYPE vt, BOOL #ifdef FEATURE_COMINTEROP -/*==================================NewVariant================================== -**N.B.: This method does a GC Allocation. Any method calling it is required to -** GC_PROTECT the OBJECTREF. -** -**Actions: Allocates a new Variant and fills it with the appropriate data. -**Returns: A new Variant with all of the appropriate fields filled out. -**Exceptions: OutOfMemoryError if v can't be allocated. -==============================================================================*/ -void VariantData::NewVariant(VariantData * const& dest, const CVTypes type, INT64 data - DEBUG_ARG(BOOL bDestIsInterior)) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - // Don't pass an object in for Empty. - PRECONDITION(CheckPointer(dest)); - PRECONDITION((bDestIsInterior && IsProtectedByGCFrame ((OBJECTREF *) &dest)) - || (!bDestIsInterior && IsProtectedByGCFrame (dest->GetObjRefPtr ()))); - PRECONDITION((type == CV_EMPTY) || (type == CV_NULL) || (type == CV_U4) || (type == CV_U8)); - } - CONTRACTL_END; - - //If both arguments are null or both are specified, we're in an illegal situation. Bail. - //If all three are null, we're creating an empty variant - if ( (type != CV_EMPTY) && (type != CV_NULL) && (type != CV_U4) && (type != CV_U8) ) - { - COMPlusThrow(kArgumentException); - } - - //Fill in the data. - dest->SetType(type); - - switch (type) - { - case CV_U4: - dest->SetObjRef(NULL); - dest->SetDataAsUInt32((UINT32)data); - break; - - case CV_U8: - dest->SetObjRef(NULL); - dest->SetDataAsInt64(data); - break; - - case CV_NULL: - { - FieldDesc * pFD = CoreLibBinder::GetField(FIELD__NULL__VALUE); - _ASSERTE(pFD); - - pFD->CheckRunClassInitThrowing(); - - OBJECTREF obj = pFD->GetStaticOBJECTREF(); - _ASSERTE(obj!=NULL); - - dest->SetObjRef(obj); - dest->SetDataAsInt64(0); - break; - } - - case CV_EMPTY: - { - dest->SetObjRef(NULL); - break; - } - - default: - // Did you add any new CVTypes? - COMPlusThrow(kNotSupportedException, W("Arg_InvalidOleVariantTypeException")); - } -} - void SafeVariantClear(VARIANT* pVar) { CONTRACTL @@ -1226,26 +949,6 @@ class RecordVariantHolder : public Wrapper, Reco * Boolean marshaling routines * ------------------------------------------------------------------------- */ -#ifdef FEATURE_COMINTEROP - -void OleVariant::MarshalBoolVariantOleToCom(VARIANT *pOleVariant, - VariantData *pComVariant) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(CheckPointer(pComVariant)); - PRECONDITION(CheckPointer(pOleVariant)); - } - CONTRACTL_END; - - *(INT64*)pComVariant->GetData() = V_BOOL(pOleVariant) ? 1 : 0; -} - -#endif // FEATURE_COMINTEROP - void OleVariant::MarshalBoolArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray, MethodTable *pInterfaceMT, PCODE pManagedMarshalerCode) { @@ -1311,32 +1014,6 @@ void OleVariant::MarshalBoolArrayComToOle(BASEARRAYREF *pComArray, void *oleArra * WinBoolean marshaling routines * ------------------------------------------------------------------------- */ -#ifdef FEATURE_COMINTEROP -void OleVariant::MarshalWinBoolVariantOleToCom(VARIANT *pOleVariant, - VariantData *pComVariant) -{ - LIMITED_METHOD_CONTRACT; - - _ASSERTE(!"Not supposed to get here."); -} - -void OleVariant::MarshalWinBoolVariantComToOle(VariantData *pComVariant, - VARIANT *pOleVariant) -{ - LIMITED_METHOD_CONTRACT; - - _ASSERTE(!"Not supposed to get here."); -} - -void OleVariant::MarshalWinBoolVariantOleRefToCom(VARIANT *pOleVariant, - VariantData *pComVariant) -{ - LIMITED_METHOD_CONTRACT; - - _ASSERTE(!"Not supposed to get here."); -} -#endif // FEATURE_COMINTEROP - void OleVariant::MarshalWinBoolArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray, MethodTable *pInterfaceMT, PCODE pManagedMarshalerCode) { @@ -1402,29 +1079,6 @@ void OleVariant::MarshalWinBoolArrayComToOle(BASEARRAYREF *pComArray, void *oleA * CBool marshaling routines * ------------------------------------------------------------------------- */ -#ifdef FEATURE_COMINTEROP -void OleVariant::MarshalCBoolVariantOleToCom(VARIANT* pOleVariant, VariantData* pComVariant) -{ - LIMITED_METHOD_CONTRACT; - - _ASSERTE(!"Not supposed to get here."); -} - -void OleVariant::MarshalCBoolVariantComToOle(VariantData* pComVariant, VARIANT* pOleVariant) -{ - LIMITED_METHOD_CONTRACT; - - _ASSERTE(!"Not supposed to get here."); -} - -void OleVariant::MarshalCBoolVariantOleRefToCom(VARIANT* pOleVariant, VariantData* pComVariant) -{ - LIMITED_METHOD_CONTRACT; - - _ASSERTE(!"Not supposed to get here."); -} -#endif // FEATURE_COMINTEROP - void OleVariant::MarshalCBoolArrayOleToCom(void* oleArray, BASEARRAYREF* pComArray, MethodTable* pInterfaceMT, PCODE pManagedMarshalerCode) { @@ -1496,32 +1150,6 @@ void OleVariant::MarshalCBoolArrayComToOle(BASEARRAYREF* pComArray, void* oleArr * Ansi char marshaling routines * ------------------------------------------------------------------------- */ -#ifdef FEATURE_COMINTEROP -void OleVariant::MarshalAnsiCharVariantOleToCom(VARIANT *pOleVariant, - VariantData *pComVariant) -{ - LIMITED_METHOD_CONTRACT; - - _ASSERTE(!"Not supposed to get here."); -} - -void OleVariant::MarshalAnsiCharVariantComToOle(VariantData *pComVariant, - VARIANT *pOleVariant) -{ - LIMITED_METHOD_CONTRACT; - - _ASSERTE(!"Not supposed to get here."); -} - -void OleVariant::MarshalAnsiCharVariantOleRefToCom(VARIANT *pOleVariant, - VariantData *pComVariant) -{ - LIMITED_METHOD_CONTRACT; - - _ASSERTE(!"Not supposed to get here."); -} -#endif // FEATURE_COMINTEROP - void OleVariant::MarshalAnsiCharArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray, MethodTable *pInterfaceMT, PCODE pManagedMarshalerCode) { @@ -1593,118 +1221,6 @@ void OleVariant::MarshalAnsiCharArrayComToOle(BASEARRAYREF *pComArray, void *ole * ------------------------------------------------------------------------- */ #ifdef FEATURE_COMINTEROP -void OleVariant::MarshalInterfaceVariantOleToCom(VARIANT *pOleVariant, - VariantData *pComVariant) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(CheckPointer(pOleVariant)); - PRECONDITION(CheckPointer(pComVariant)); - } - CONTRACTL_END; - - IUnknown *unk = V_UNKNOWN(pOleVariant); - - OBJECTREF obj = NULL; - if (unk != NULL) - { - GCPROTECT_BEGIN(obj); - GetObjectRefFromComIP(&obj, V_UNKNOWN(pOleVariant)); - GCPROTECT_END(); - } - - pComVariant->SetObjRef(obj); -} - -void OleVariant::MarshalInterfaceVariantComToOle(VariantData *pComVariant, - VARIANT *pOleVariant) - -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(CheckPointer(pOleVariant)); - PRECONDITION(CheckPointer(pComVariant)); - } - CONTRACTL_END; - - OBJECTREF *obj = pComVariant->GetObjRefPtr(); - VARTYPE vt = pComVariant->GetVT(); - - ASSERT_PROTECTED(obj); - - if (*obj == NULL) - { - // If there is no VT set in the managed variant, then default to VT_UNKNOWN. - if (vt == VT_EMPTY) - vt = VT_UNKNOWN; - - V_UNKNOWN(pOleVariant) = NULL; - V_VT(pOleVariant) = vt; - } - else - { -#ifdef FEATURE_COMINTEROP - ComIpType FetchedIpType = ComIpType_None; - ComIpType ReqIpType; - - if (vt != VT_EMPTY) - { - // We are dealing with an UnknownWrapper or DispatchWrapper. - // In this case, we need to respect the VT. - _ASSERTE(vt == VT_DISPATCH || vt == VT_UNKNOWN); - ReqIpType = vt == VT_DISPATCH ? ComIpType_Dispatch : ComIpType_Unknown; - } - else - { - // We are dealing with a normal object so we can give either - // IDispatch or IUnknown out depending on what it supports. - ReqIpType = ComIpType_Both; - } - - IUnknown *unk = GetComIPFromObjectRef(obj, ReqIpType, &FetchedIpType); - BOOL ItfIsDispatch = FetchedIpType == ComIpType_Dispatch; - - V_UNKNOWN(pOleVariant) = unk; - V_VT(pOleVariant) = static_cast(ItfIsDispatch ? VT_DISPATCH : VT_UNKNOWN); -#else // FEATURE_COMINTEROP - V_UNKNOWN(pOleVariant) = GetComIPFromObjectRef(obj); - V_VT(pOleVariant) = VT_UNKNOWN; -#endif // FEATURE_COMINTEROP - } -} - -void OleVariant::MarshalInterfaceVariantOleRefToCom(VARIANT *pOleVariant, - VariantData *pComVariant) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(CheckPointer(pOleVariant)); - PRECONDITION(CheckPointer(pComVariant)); - } - CONTRACTL_END; - - IUnknown *unk = V_UNKNOWN(pOleVariant); - - OBJECTREF obj = NULL; - if (unk != NULL) - { - GCPROTECT_BEGIN(obj); - GetObjectRefFromComIP(&obj, *V_UNKNOWNREF(pOleVariant)); - GCPROTECT_END(); - } - - pComVariant->SetObjRef(obj); -} - void OleVariant::MarshalInterfaceArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray, MethodTable *pElementMT, PCODE pManagedMarshalerCode) { @@ -1815,55 +1331,6 @@ void OleVariant::ClearInterfaceArray(void *oleArray, SIZE_T cElements, MethodTab * BSTR marshaling routines * ------------------------------------------------------------------------- */ -void OleVariant::MarshalBSTRVariantOleToCom(VARIANT *pOleVariant, - VariantData *pComVariant) -{ - CONTRACTL - { - WRAPPER(THROWS); - WRAPPER(GC_TRIGGERS); - MODE_COOPERATIVE; - INJECT_FAULT(COMPlusThrowOM()); - PRECONDITION(CheckPointer(pOleVariant)); - PRECONDITION(CheckPointer(pComVariant)); - } - CONTRACTL_END; - - BSTR bstr = V_BSTR(pOleVariant); - - STRINGREF stringObj = NULL; - GCPROTECT_BEGIN(stringObj) - { - ConvertBSTRToString(bstr, &stringObj); - pComVariant->SetObjRef((OBJECTREF) stringObj); - } - GCPROTECT_END(); - - pComVariant->SetObjRef((OBJECTREF) stringObj); -} - -void OleVariant::MarshalBSTRVariantComToOle(VariantData *pComVariant, - VARIANT *pOleVariant) -{ - CONTRACTL - { - THROWS; - WRAPPER(GC_TRIGGERS); - MODE_COOPERATIVE; - INJECT_FAULT(COMPlusThrowOM()); - PRECONDITION(CheckPointer(pOleVariant)); - PRECONDITION(CheckPointer(pComVariant)); - } - CONTRACTL_END; - - STRINGREF stringObj = (STRINGREF) pComVariant->GetObjRef(); - GCPROTECT_BEGIN(stringObj) - { - V_BSTR(pOleVariant) = ConvertStringToBSTR(&stringObj); - } - GCPROTECT_END(); -} - void OleVariant::MarshalBSTRArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray, MethodTable *pInterfaceMT, PCODE pManagedMarshalerCode) { @@ -2374,38 +1841,12 @@ void OleVariant::ClearLPSTRArray(void *oleArray, SIZE_T cElements, MethodTable * if (lpstr != NULL) CoTaskMemFree(lpstr); - } -} - -/* ------------------------------------------------------------------------- * - * Date marshaling routines - * ------------------------------------------------------------------------- */ - -#ifdef FEATURE_COMINTEROP -void OleVariant::MarshalDateVariantOleToCom(VARIANT *pOleVariant, - VariantData *pComVariant) -{ - WRAPPER_NO_CONTRACT; - - *(INT64*)pComVariant->GetData() = COMDateTime::DoubleDateToTicks(V_DATE(pOleVariant)); -} - -void OleVariant::MarshalDateVariantComToOle(VariantData *pComVariant, - VARIANT *pOleVariant) -{ - WRAPPER_NO_CONTRACT; - - V_DATE(pOleVariant) = COMDateTime::TicksToDoubleDate(*(INT64*)pComVariant->GetData()); -} - -void OleVariant::MarshalDateVariantOleRefToCom(VARIANT *pOleVariant, - VariantData *pComVariant) -{ - WRAPPER_NO_CONTRACT; - - *(INT64*)pComVariant->GetData() = COMDateTime::DoubleDateToTicks(*V_DATEREF(pOleVariant)); + } } -#endif // FEATURE_COMINTEROP + +/* ------------------------------------------------------------------------- * + * Date marshaling routines + * ------------------------------------------------------------------------- */ void OleVariant::MarshalDateArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray, MethodTable *pInterfaceMT, PCODE pManagedMarshalerCode) @@ -2469,87 +1910,13 @@ void OleVariant::MarshalDateArrayComToOle(BASEARRAYREF *pComArray, void *oleArra *pOle++ = COMDateTime::TicksToDoubleDate(*pCom++); } -/* ------------------------------------------------------------------------- * - * Decimal marshaling routines - * ------------------------------------------------------------------------- */ - -#ifdef FEATURE_COMINTEROP - -void OleVariant::MarshalDecimalVariantOleToCom(VARIANT *pOleVariant, - VariantData *pComVariant) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - INJECT_FAULT(COMPlusThrowOM()); - PRECONDITION(CheckPointer(pOleVariant)); - PRECONDITION(CheckPointer(pComVariant)); - } - CONTRACTL_END; - - OBJECTREF pDecimalRef = AllocateObject(CoreLibBinder::GetClass(CLASS__DECIMAL)); - - DECIMAL* pDecimal = (DECIMAL *) pDecimalRef->UnBox(); - *pDecimal = V_DECIMAL(pOleVariant); - // Mashaling uses the reserved value to store the variant type, so clear it out when marshaling back - pDecimal->wReserved = 0; - - pComVariant->SetObjRef(pDecimalRef); -} - -void OleVariant::MarshalDecimalVariantComToOle(VariantData *pComVariant, - VARIANT *pOleVariant) -{ - CONTRACTL - { - WRAPPER(THROWS); - WRAPPER(GC_TRIGGERS); - MODE_COOPERATIVE; - PRECONDITION(CheckPointer(pOleVariant)); - PRECONDITION(CheckPointer(pComVariant)); - } - CONTRACTL_END; - - VARTYPE vt = V_VT(pOleVariant); - _ASSERTE(vt == VT_DECIMAL); - V_DECIMAL(pOleVariant) = * (DECIMAL*) pComVariant->GetObjRef()->UnBox(); - V_VT(pOleVariant) = vt; -} - -void OleVariant::MarshalDecimalVariantOleRefToCom(VARIANT *pOleVariant, - VariantData *pComVariant ) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - INJECT_FAULT(COMPlusThrowOM()); - PRECONDITION(CheckPointer(pOleVariant)); - PRECONDITION(CheckPointer(pComVariant)); - } - CONTRACTL_END; - - OBJECTREF pDecimalRef = AllocateObject(CoreLibBinder::GetClass(CLASS__DECIMAL)); - - DECIMAL* pDecimal = (DECIMAL *) pDecimalRef->UnBox(); - *pDecimal = *V_DECIMALREF(pOleVariant); - // Mashaling uses the reserved value to store the variant type, so clear it out when marshaling back - pDecimal->wReserved = 0; - - pComVariant->SetObjRef(pDecimalRef); -} -#endif // FEATURE_COMINTEROP - /* ------------------------------------------------------------------------- * * Record marshaling routines * ------------------------------------------------------------------------- */ #ifdef FEATURE_COMINTEROP -void OleVariant::MarshalRecordVariantOleToCom(VARIANT *pOleVariant, - VariantData *pComVariant) +void OleVariant::MarshalRecordVariantOleToObject(const VARIANT *pOleVariant, + OBJECTREF * const & pObj) { CONTRACTL { @@ -2558,7 +1925,8 @@ void OleVariant::MarshalRecordVariantOleToCom(VARIANT *pOleVariant, MODE_COOPERATIVE; INJECT_FAULT(COMPlusThrowOM()); PRECONDITION(CheckPointer(pOleVariant)); - PRECONDITION(CheckPointer(pComVariant)); + PRECONDITION(CheckPointer(pObj)); + PRECONDITION(*pObj == NULL || (IsProtectedByGCFrame (pObj))); } CONTRACTL_END; @@ -2570,7 +1938,7 @@ void OleVariant::MarshalRecordVariantOleToCom(VARIANT *pOleVariant, LPVOID pvRecord = V_RECORD(pOleVariant); if (pvRecord == NULL) { - pComVariant->SetObjRef(NULL); + SetObjectReference(pObj, NULL); return; } @@ -2595,42 +1963,10 @@ void OleVariant::MarshalRecordVariantOleToCom(VARIANT *pOleVariant, // boxed value class and copy the contents of the record into it. BoxedValueClass = AllocateObject(pValueClass); memcpyNoGCRefs(BoxedValueClass->GetData(), (BYTE*)pvRecord, pValueClass->GetNativeSize()); - pComVariant->SetObjRef(BoxedValueClass); - } - GCPROTECT_END(); -} - -void OleVariant::MarshalRecordVariantComToOle(VariantData *pComVariant, - VARIANT *pOleVariant) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(CheckPointer(pOleVariant)); - PRECONDITION(CheckPointer(pComVariant)); - } - CONTRACTL_END; - - OBJECTREF BoxedValueClass = pComVariant->GetObjRef(); - GCPROTECT_BEGIN(BoxedValueClass) - { - _ASSERTE(BoxedValueClass != NULL); - ConvertValueClassToVariant(&BoxedValueClass, pOleVariant); + SetObjectReference(pObj, BoxedValueClass); } GCPROTECT_END(); } - -void OleVariant::MarshalRecordVariantOleRefToCom(VARIANT *pOleVariant, - VariantData *pComVariant) -{ - WRAPPER_NO_CONTRACT; - - // The representation of a VT_RECORD and a VT_BYREF | VT_RECORD VARIANT are - // the same so we can simply forward the call to the non byref API. - MarshalRecordVariantOleToCom(pOleVariant, pComVariant); -} #endif // FEATURE_COMINTEROP void OleVariant::MarshalRecordArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray, @@ -2778,6 +2114,11 @@ void OleVariant::MarshalOleVariantForObject(OBJECTREF * const & pObj, VARIANT *p V_I1(pOle) = *(CHAR*)( (*pObj)->GetData() ); V_VT(pOle) = VT_I1; } + else if (pMT == CoreLibBinder::GetElementType(ELEMENT_TYPE_I8)) + { + V_I8(pOle) = *(INT64*)( (*pObj)->GetData() ); + V_VT(pOle) = VT_I8; + } else if (pMT == CoreLibBinder::GetElementType(ELEMENT_TYPE_U4)) { V_UI4(pOle) = *(ULONG*)( (*pObj)->GetData() ); @@ -2793,6 +2134,11 @@ void OleVariant::MarshalOleVariantForObject(OBJECTREF * const & pObj, VARIANT *p V_UI1(pOle) = *(BYTE*)( (*pObj)->GetData() ); V_VT(pOle) = VT_UI1; } + else if (pMT == CoreLibBinder::GetElementType(ELEMENT_TYPE_U8)) + { + V_UI8(pOle) = *(UINT64*)( (*pObj)->GetData() ); + V_VT(pOle) = VT_UI8; + } else if (pMT == CoreLibBinder::GetElementType(ELEMENT_TYPE_R4)) { V_R4(pOle) = *(FLOAT*)( (*pObj)->GetData() ); @@ -2820,22 +2166,7 @@ void OleVariant::MarshalOleVariantForObject(OBJECTREF * const & pObj, VARIANT *p } else { - MethodDescCallSite convertObjectToVariant(METHOD__VARIANT__CONVERT_OBJECT_TO_VARIANT); - - VariantData managedVariant; - FillMemory(&managedVariant, sizeof(managedVariant), 0); - GCPROTECT_BEGIN_VARIANTDATA(managedVariant) - { - ARG_SLOT args[] = { - ObjToArgSlot(*pObj), - PtrToArgSlot(&managedVariant), - }; - - convertObjectToVariant.Call(args); - - OleVariant::MarshalOleVariantForComVariant(&managedVariant, pOle); - } - GCPROTECT_END_VARIANTDATA(); + OleVariant::MarshalOleVariantForObjectUncommon(pObj, pOle); } } } @@ -2872,49 +2203,19 @@ void OleVariant::MarshalOleRefVariantForObject(OBJECTREF *pObj, VARIANT *pOle) // MarshalOleRefVariantForObjectNoCast has checked that the variant is not an array // so we can use the marshal cast helper to coerce the object to the proper type. - VariantData vd; - FillMemory(&vd, sizeof(vd), 0); + VARIANT vtmp; + VariantInit(&vtmp); VARTYPE vt = V_VT(pOle) & ~VT_BYREF; - GCPROTECT_BEGIN_VARIANTDATA(vd); - { - ARG_SLOT args[3]; - args[0] = ObjToArgSlot(*pObj); - args[1] = (ARG_SLOT)vt; - args[2] = PtrToArgSlot(&vd); - castVariant.Call(args); - VARIANT vtmp; - VariantInit(&vtmp); - OleVariant::MarshalOleVariantForComVariant(&vd, &vtmp); - - // If the variant types are still not the same then call VariantChangeType to - // try and coerse them. - if (V_VT(&vtmp) != vt) - { - VARIANT vtmp2; - memset(&vtmp2, 0, sizeof(VARIANT)); - - // The type of the variant has changed so attempt to change - // the type back. - hr = SafeVariantChangeType(&vtmp2, &vtmp, 0, vt); - if (FAILED(hr)) - { - if (hr == DISP_E_TYPEMISMATCH) - COMPlusThrow(kInvalidCastException, IDS_EE_CANNOT_COERCE_BYREF_VARIANT); - else - COMPlusThrowHR(hr); - } + ARG_SLOT args[3]; + args[0] = ObjToArgSlot(*pObj); + args[1] = (ARG_SLOT)vt; + args[2] = PtrToArgSlot(&vtmp); + castVariant.Call(args); - // Copy the converted variant back into the original variant and clear the temp. - InsertContentsIntoByrefVariant(&vtmp2, pOle); - SafeVariantClear(&vtmp); - } - else - { - InsertContentsIntoByrefVariant(&vtmp, pOle); - } - } - GCPROTECT_END_VARIANTDATA(); + // Managed implementation of CastVariant should either return correct type or throw. + _ASSERTE(V_VT(&vtmp) == vt); + InsertContentsIntoByRefVariant(&vtmp, pOle); } } } @@ -2959,6 +2260,13 @@ HRESULT OleVariant::MarshalCommonOleRefVariantForObject(OBJECTREF *pObj, VARIANT *(V_I1REF(pOle)) = *(CHAR*)( (*pObj)->GetData() ); } + else if ( (V_VT(pOle) == (VT_BYREF | VT_I8) || V_VT(pOle) == (VT_BYREF | VT_UI8)) && (pMT == CoreLibBinder::GetElementType(ELEMENT_TYPE_I8) || pMT == CoreLibBinder::GetElementType(ELEMENT_TYPE_U8)) ) + { + // deallocation of old value optimized away since there's nothing to + // deallocate for this vartype. + + *(V_I8REF(pOle)) = *(INT64*)( (*pObj)->GetData() ); + } else if ( V_VT(pOle) == (VT_BYREF | VT_R4) && pMT == CoreLibBinder::GetElementType(ELEMENT_TYPE_R4) ) { // deallocation of old value optimized away since there's nothing to @@ -3018,7 +2326,7 @@ HRESULT OleVariant::MarshalCommonOleRefVariantForObject(OBJECTREF *pObj, VARIANT // Since variants can contain any VARTYPE we simply convert the object to // a variant and stuff it back into the byref variant. MarshalOleVariantForObject(pObj, &vtmp); - InsertContentsIntoByrefVariant(&vtmp, pOle); + InsertContentsIntoByRefVariant(&vtmp, pOle); } else if (vt & VT_ARRAY) { @@ -3031,7 +2339,7 @@ HRESULT OleVariant::MarshalCommonOleRefVariantForObject(OBJECTREF *pObj, VARIANT hr = DISP_E_TYPEMISMATCH; goto Exit; } - InsertContentsIntoByrefVariant(&vtmp, pOle); + InsertContentsIntoByRefVariant(&vtmp, pOle); } else if ( (*pObj) == NULL && (vt == VT_BSTR || @@ -3047,7 +2355,7 @@ HRESULT OleVariant::MarshalCommonOleRefVariantForObject(OBJECTREF *pObj, VARIANT // conversion will return a VT_EMPTY which isn't what we want. V_VT(&vtmp) = vt; V_UNKNOWN(&vtmp) = NULL; - InsertContentsIntoByrefVariant(&vtmp, pOle); + InsertContentsIntoByRefVariant(&vtmp, pOle); } else { @@ -3160,6 +2468,30 @@ void OleVariant::MarshalObjectForOleVariant(const VARIANT * pOle, OBJECTREF * co AllocateObject(CoreLibBinder::GetElementType(ELEMENT_TYPE_U1)) ); *(BYTE*)((*pObj)->GetData()) = *(V_UI1REF(pOle)); break; + + case VT_I8: + SetObjectReference( pObj, + AllocateObject(CoreLibBinder::GetElementType(ELEMENT_TYPE_I8)) ); + *(INT64*)((*pObj)->GetData()) = V_I8(pOle); + break; + + case VT_BYREF|VT_I8: + SetObjectReference( pObj, + AllocateObject(CoreLibBinder::GetElementType(ELEMENT_TYPE_I8)) ); + *(INT64*)((*pObj)->GetData()) = *(V_I8REF(pOle)); + break; + + case VT_UI8: + SetObjectReference( pObj, + AllocateObject(CoreLibBinder::GetElementType(ELEMENT_TYPE_U8)) ); + *(UINT64*)((*pObj)->GetData()) = V_UI8(pOle); + break; + + case VT_BYREF|VT_UI8: + SetObjectReference( pObj, + AllocateObject(CoreLibBinder::GetElementType(ELEMENT_TYPE_U8)) ); + *(UINT64*)((*pObj)->GetData()) = *(V_UI8REF(pOle)); + break; case VT_R4: SetObjectReference( pObj, @@ -3206,20 +2538,7 @@ void OleVariant::MarshalObjectForOleVariant(const VARIANT * pOle, OBJECTREF * co break; default: - { - MethodDescCallSite convertVariantToObject(METHOD__VARIANT__CONVERT_VARIANT_TO_OBJECT); - - VariantData managedVariant; - FillMemory(&managedVariant, sizeof(managedVariant), 0); - GCPROTECT_BEGIN_VARIANTDATA(managedVariant) - { - OleVariant::MarshalComVariantForOleVariant((VARIANT*)pOle, &managedVariant); - ARG_SLOT args[] = { PtrToArgSlot(&managedVariant) }; - SetObjectReference( pObj, - convertVariantToObject.Call_RetOBJECTREF(args) ); - } - GCPROTECT_END_VARIANTDATA(); - } + MarshalObjectForOleVariantUncommon(pOle, pObj); } RETURN; } @@ -3303,7 +2622,7 @@ void OleVariant::ExtractContentsFromByrefVariant(VARIANT *pByrefVar, VARIANT *pD RETURN; } -void OleVariant::InsertContentsIntoByrefVariant(VARIANT *pSrcVar, VARIANT *pByrefVar) +void OleVariant::InsertContentsIntoByRefVariant(VARIANT *pSrcVar, VARIANT *pByrefVar) { CONTRACT_VOID { @@ -3434,7 +2753,7 @@ void OleVariant::CreateByrefVariantForVariant(VARIANT *pSrcVar, VARIANT *pByrefV // the COM variant. // -void OleVariant::MarshalComVariantForOleVariant(VARIANT *pOle, VariantData *pCom) +void OleVariant::MarshalObjectForOleVariantUncommon(const VARIANT *pOle, OBJECTREF * const & pObj) { CONTRACTL { @@ -3442,7 +2761,8 @@ void OleVariant::MarshalComVariantForOleVariant(VARIANT *pOle, VariantData *pCom GC_TRIGGERS; MODE_COOPERATIVE; PRECONDITION(CheckPointer(pOle)); - PRECONDITION(CheckPointer(pCom)); + PRECONDITION(CheckPointer(pObj)); + PRECONDITION(*pObj == NULL || (IsProtectedByGCFrame (pObj))); } CONTRACTL_END; @@ -3467,54 +2787,24 @@ void OleVariant::MarshalComVariantForOleVariant(VARIANT *pOle, VariantData *pCom COMPlusThrow(kInvalidOleVariantTypeException, IDS_EE_INVALID_OLE_VARIANT); } - CVTypes cvt = GetCVTypeForVarType(vt); - const Marshaler *marshal = GetMarshalerForVarType(vt, TRUE); - - pCom->SetType(cvt); - pCom->SetVT(vt); // store away VT for return trip. - if (marshal == NULL || (byref - ? marshal->OleRefToComVariant == NULL - : marshal->OleToComVariant == NULL)) + if ((vt & VT_ARRAY)) { - if (cvt==CV_EMPTY) - { - if (V_ISBYREF(pOle)) - { - // Must set ObjectRef field of Variant to a specific instance. -#ifdef HOST_64BIT - VariantData::NewVariant(pCom, CV_U8, (INT64)(size_t)V_BYREF(pOle)); -#else // HOST_64BIT - VariantData::NewVariant(pCom, CV_U4, (INT32)(size_t)V_BYREF(pOle)); -#endif // HOST_64BIT - } - else - { - VariantData::NewVariant(pCom, cvt, NULL); - } - } - else if (cvt==CV_NULL) - { - VariantData::NewVariant(pCom, cvt, NULL); - } + if (byref) + MarshalArrayVariantOleRefToObject(pOle, pObj); else - { - pCom->SetObjRef(NULL); - if (byref) - { - INT64 data = 0; - CopyMemory(&data, V_R8REF(pOle), GetElementSizeForVarType(vt, NULL)); - pCom->SetData(&data); - } - else - pCom->SetData(&V_R8(pOle)); - } + MarshalArrayVariantOleToObject(pOle, pObj); + } + else if (vt == VT_RECORD) + { + // The representation of a VT_RECORD and a VT_BYREF | VT_RECORD VARIANT are the same + MarshalRecordVariantOleToObject(pOle, pObj); } else { - if (byref) - marshal->OleRefToComVariant(pOle, pCom); - else - marshal->OleToComVariant(pOle, pCom); + MethodDescCallSite convertVariantToObject(METHOD__VARIANT__CONVERT_VARIANT_TO_OBJECT); + ARG_SLOT args[] = { PtrToArgSlot(pOle) }; + SetObjectReference( pObj, + convertVariantToObject.Call_RetOBJECTREF(args) ); } } @@ -3523,14 +2813,15 @@ void OleVariant::MarshalComVariantForOleVariant(VARIANT *pOle, VariantData *pCom // the COM variant. // -void OleVariant::MarshalOleVariantForComVariant(VariantData *pCom, VARIANT *pOle) +void OleVariant::MarshalOleVariantForObjectUncommon(OBJECTREF * const & pObj, VARIANT *pOle) { CONTRACTL { THROWS; GC_TRIGGERS; MODE_COOPERATIVE; - PRECONDITION(CheckPointer(pCom)); + PRECONDITION(CheckPointer(pObj)); + PRECONDITION(*pObj == NULL || (IsProtectedByGCFrame (pObj))); PRECONDITION(CheckPointer(pOle)); } CONTRACTL_END; @@ -3540,18 +2831,26 @@ void OleVariant::MarshalOleVariantForComVariant(VariantData *pCom, VARIANT *pOle VariantEmptyHolder veh; veh = pOle; - VARTYPE vt = GetVarTypeForComVariant(pCom); - V_VT(pOle) = vt; - - const Marshaler *marshal = GetMarshalerForVarType(vt, TRUE); - - if (marshal == NULL || marshal->ComToOleVariant == NULL) + if ((*pObj)->GetMethodTable()->IsArray()) { - *(INT64*)&V_R8(pOle) = *(INT64*)pCom->GetData(); + // Get VarType for array + VARTYPE vt = GetElementVarTypeForArrayRef((BASEARRAYREF)*pObj); + if (vt == VT_ARRAY) + vt = VT_VARIANT; + + V_VT(pOle) = vt | VT_ARRAY; + MarshalArrayVariantObjectToOle(pObj, pOle); } else { - marshal->ComToOleVariant(pCom, pOle); + MethodDescCallSite convertObjectToVariant(METHOD__VARIANT__CONVERT_OBJECT_TO_VARIANT); + + ARG_SLOT args[] = { + ObjToArgSlot(*pObj), + PtrToArgSlot(pOle), + }; + + convertObjectToVariant.Call(args); } veh.SuppressRelease(); @@ -3752,79 +3051,6 @@ void OleVariant::MarshalIDispatchArrayComToOle(BASEARRAYREF *pComArray, void *ol * Currency marshaling routines * ------------------------------------------------------------------------- */ -void OleVariant::MarshalCurrencyVariantOleToCom(VARIANT *pOleVariant, - VariantData *pComVariant) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - INJECT_FAULT(COMPlusThrowOM()); - PRECONDITION(CheckPointer(pOleVariant)); - PRECONDITION(CheckPointer(pComVariant)); - } - CONTRACTL_END; - - OBJECTREF pDecimalRef = AllocateObject(CoreLibBinder::GetClass(CLASS__DECIMAL)); - DECIMAL DecVal; - - // Convert the currency to a decimal. - VarDecFromCyCanonicalize(V_CY(pOleVariant), &DecVal); - - // Store the value into the unboxes decimal and store the decimal in the variant. - *(DECIMAL *) pDecimalRef->UnBox() = DecVal; - pComVariant->SetObjRef(pDecimalRef); -} - -void OleVariant::MarshalCurrencyVariantComToOle(VariantData *pComVariant, - VARIANT *pOleVariant) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(CheckPointer(pOleVariant)); - PRECONDITION(CheckPointer(pComVariant)); - } - CONTRACTL_END; - - CURRENCY CyVal; - - // Convert the decimal to a currency. - HRESULT hr = VarCyFromDec((DECIMAL*)pComVariant->GetObjRef()->UnBox(), &CyVal); - IfFailThrow(hr); - - // Store the currency in the VARIANT and set the VT. - V_CY(pOleVariant) = CyVal; -} - -void OleVariant::MarshalCurrencyVariantOleRefToCom(VARIANT *pOleVariant, - VariantData *pComVariant) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - INJECT_FAULT(COMPlusThrowOM()); - PRECONDITION(CheckPointer(pOleVariant)); - PRECONDITION(CheckPointer(pComVariant)); - } - CONTRACTL_END; - - OBJECTREF pDecimalRef = AllocateObject(CoreLibBinder::GetClass(CLASS__DECIMAL)); - DECIMAL DecVal; - - // Convert the currency to a decimal. - VarDecFromCyCanonicalize(*V_CYREF(pOleVariant), &DecVal); - - // Store the value into the unboxes decimal and store the decimal in the variant. - *(DECIMAL *) pDecimalRef->UnBox() = DecVal; - pComVariant->SetObjRef(pDecimalRef); -} - void OleVariant::MarshalCurrencyArrayOleToCom(void *oleArray, BASEARRAYREF *pComArray, MethodTable *pInterfaceMT, PCODE pManagedMarshalerCode) { @@ -4040,8 +3266,8 @@ void OleVariant::ClearVariantArray(void *oleArray, SIZE_T cElements, MethodTable * ------------------------------------------------------------------------- */ #ifdef FEATURE_COMINTEROP -void OleVariant::MarshalArrayVariantOleToCom(VARIANT *pOleVariant, - VariantData *pComVariant) +void OleVariant::MarshalArrayVariantOleToObject(const VARIANT* pOleVariant, + OBJECTREF * const & pObj) { CONTRACTL { @@ -4049,7 +3275,8 @@ void OleVariant::MarshalArrayVariantOleToCom(VARIANT *pOleVariant, GC_TRIGGERS; MODE_COOPERATIVE; PRECONDITION(CheckPointer(pOleVariant)); - PRECONDITION(CheckPointer(pComVariant)); + PRECONDITION(CheckPointer(pObj)); + PRECONDITION(*pObj == NULL || (IsProtectedByGCFrame (pObj))); } CONTRACTL_END; @@ -4075,17 +3302,17 @@ void OleVariant::MarshalArrayVariantOleToCom(VARIANT *pOleVariant, } BASEARRAYREF pArrayRef = CreateArrayRefForSafeArray(pSafeArray, vt, pElemMT); - pComVariant->SetObjRef((OBJECTREF) pArrayRef); - MarshalArrayRefForSafeArray(pSafeArray, (BASEARRAYREF *) pComVariant->GetObjRefPtr(), vt, pStructMarshalStub != nullptr ? pStructMarshalStub->GetMultiCallableAddrOfCode() : NULL, pElemMT); + SetObjectReference(pObj, pArrayRef); + MarshalArrayRefForSafeArray(pSafeArray, (BASEARRAYREF *) pObj, vt, pStructMarshalStub != nullptr ? pStructMarshalStub->GetMultiCallableAddrOfCode() : NULL, pElemMT); } else { - pComVariant->SetObjRef(NULL); + SetObjectReference(pObj, NULL); } } -void OleVariant::MarshalArrayVariantComToOle(VariantData *pComVariant, - VARIANT *pOleVariant) +void OleVariant::MarshalArrayVariantObjectToOle(OBJECTREF * const & pObj, + VARIANT* pOleVariant) { CONTRACTL { @@ -4093,12 +3320,13 @@ void OleVariant::MarshalArrayVariantComToOle(VariantData *pComVariant, GC_TRIGGERS; MODE_COOPERATIVE; PRECONDITION(CheckPointer(pOleVariant)); - PRECONDITION(CheckPointer(pComVariant)); + PRECONDITION(CheckPointer(pObj)); + PRECONDITION(*pObj == NULL || (IsProtectedByGCFrame (pObj))); } CONTRACTL_END; SafeArrayPtrHolder pSafeArray = NULL; - BASEARRAYREF *pArrayRef = (BASEARRAYREF *) pComVariant->GetObjRefPtr(); + BASEARRAYREF *pArrayRef = (BASEARRAYREF *) pObj; MethodTable *pElemMT = NULL; _ASSERTE(pArrayRef); @@ -4128,8 +3356,8 @@ void OleVariant::MarshalArrayVariantComToOle(VariantData *pComVariant, pSafeArray.SuppressRelease(); } -void OleVariant::MarshalArrayVariantOleRefToCom(VARIANT *pOleVariant, - VariantData *pComVariant) +void OleVariant::MarshalArrayVariantOleRefToObject(const VARIANT *pOleVariant, + OBJECTREF * const & pObj) { CONTRACTL { @@ -4137,7 +3365,8 @@ void OleVariant::MarshalArrayVariantOleRefToCom(VARIANT *pOleVariant, GC_TRIGGERS; MODE_COOPERATIVE; PRECONDITION(CheckPointer(pOleVariant)); - PRECONDITION(CheckPointer(pComVariant)); + PRECONDITION(CheckPointer(pObj)); + PRECONDITION(*pObj == NULL || (IsProtectedByGCFrame (pObj))); } CONTRACTL_END; @@ -4160,93 +3389,17 @@ void OleVariant::MarshalArrayVariantOleRefToCom(VARIANT *pOleVariant, } BASEARRAYREF pArrayRef = CreateArrayRefForSafeArray(pSafeArray, vt, pElemMT); - pComVariant->SetObjRef((OBJECTREF) pArrayRef); - MarshalArrayRefForSafeArray(pSafeArray, (BASEARRAYREF *) pComVariant->GetObjRefPtr(), vt, pStructMarshalStub != nullptr ? pStructMarshalStub->GetMultiCallableAddrOfCode() : NULL, pElemMT); + SetObjectReference(pObj, pArrayRef); + MarshalArrayRefForSafeArray(pSafeArray, (BASEARRAYREF *) pObj, vt, pStructMarshalStub != nullptr ? pStructMarshalStub->GetMultiCallableAddrOfCode() : NULL, pElemMT); } else { - pComVariant->SetObjRef(NULL); + SetObjectReference(pObj, NULL); } } #endif //FEATURE_COMINTEROP -/* ------------------------------------------------------------------------- * - * Error marshaling routines - * ------------------------------------------------------------------------- */ - -void OleVariant::MarshalErrorVariantOleToCom(VARIANT *pOleVariant, - VariantData *pComVariant) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(CheckPointer(pOleVariant)); - PRECONDITION(CheckPointer(pComVariant)); - } - CONTRACTL_END; - - // Check to see if the variant represents a missing argument. - if (V_ERROR(pOleVariant) == DISP_E_PARAMNOTFOUND) - { - pComVariant->SetType(CV_MISSING); - } - else - { - pComVariant->SetDataAsInt32(V_ERROR(pOleVariant)); - } -} - -void OleVariant::MarshalErrorVariantOleRefToCom(VARIANT *pOleVariant, - VariantData *pComVariant) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(CheckPointer(pOleVariant)); - PRECONDITION(CheckPointer(pComVariant)); - } - CONTRACTL_END; - - // Check to see if the variant represents a missing argument. - if (*V_ERRORREF(pOleVariant) == DISP_E_PARAMNOTFOUND) - { - pComVariant->SetType(CV_MISSING); - } - else - { - pComVariant->SetDataAsInt32(*V_ERRORREF(pOleVariant)); - } -} - -void OleVariant::MarshalErrorVariantComToOle(VariantData *pComVariant, - VARIANT *pOleVariant) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(CheckPointer(pOleVariant)); - PRECONDITION(CheckPointer(pComVariant)); - } - CONTRACTL_END; - - if (pComVariant->GetType() == CV_MISSING) - { - V_ERROR(pOleVariant) = DISP_E_PARAMNOTFOUND; - } - else - { - V_ERROR(pOleVariant) = pComVariant->GetDataAsInt32(); - } -} - - /* ------------------------------------------------------------------------- * * Safearray allocation & conversion * ------------------------------------------------------------------------- */ @@ -4681,6 +3834,7 @@ void OleVariant::ConvertValueClassToVariant(OBJECTREF *pBoxedValueClass, VARIANT MODE_COOPERATIVE; PRECONDITION(CheckPointer(pBoxedValueClass)); PRECONDITION(CheckPointer(pOleVariant)); + PRECONDITION(*pBoxedValueClass == NULL || (IsProtectedByGCFrame (pBoxedValueClass))); } CONTRACTL_END; diff --git a/src/coreclr/vm/olevariant.h b/src/coreclr/vm/olevariant.h index 1220e7b92be47..7d62924db8e93 100644 --- a/src/coreclr/vm/olevariant.h +++ b/src/coreclr/vm/olevariant.h @@ -24,324 +24,6 @@ #define VTHACK_WINBOOL 254 -//These types must be kept in sync with the CorElementTypes defined in cor.h -//NOTE: If you add values to this enum you need to look at OAVariant.cpp. There is -// a mapping between CV type and VT types found there. -//NOTE: This is also found in a table in OleVariant.cpp. -//NOTE: These are also found in Variant.cs -typedef enum -{ - CV_EMPTY = 0x0, // CV_EMPTY - CV_VOID = ELEMENT_TYPE_VOID, - CV_BOOLEAN = ELEMENT_TYPE_BOOLEAN, - CV_CHAR = ELEMENT_TYPE_CHAR, - CV_I1 = ELEMENT_TYPE_I1, - CV_U1 = ELEMENT_TYPE_U1, - CV_I2 = ELEMENT_TYPE_I2, - CV_U2 = ELEMENT_TYPE_U2, - CV_I4 = ELEMENT_TYPE_I4, - CV_U4 = ELEMENT_TYPE_U4, - CV_I8 = ELEMENT_TYPE_I8, - CV_U8 = ELEMENT_TYPE_U8, - CV_R4 = ELEMENT_TYPE_R4, - CV_R8 = ELEMENT_TYPE_R8, - CV_STRING = ELEMENT_TYPE_STRING, - - // For the rest, we map directly if it is defined in CorHdr.h and fill - // in holes for the rest. - CV_PTR = ELEMENT_TYPE_PTR, - CV_DATETIME = 0x10, // ELEMENT_TYPE_BYREF - CV_TIMESPAN = 0x11, // ELEMENT_TYPE_VALUETYPE - CV_OBJECT = ELEMENT_TYPE_CLASS, - CV_DECIMAL = 0x13, // ELEMENT_TYPE_UNUSED1 - CV_CURRENCY = 0x14, // ELEMENT_TYPE_ARRAY - CV_ENUM = 0x15, // - CV_MISSING = 0x16, // - CV_NULL = 0x17, // - CV_LAST = 0x18, // -} CVTypes; - -//Mapping from CVType to type handle. Used for conversion between the two internally. -extern const BinderClassID CVTypeToBinderClassID[]; - -inline TypeHandle GetTypeHandleForCVType(CVTypes elemType) -{ - CONTRACT (TypeHandle) - { - WRAPPER(THROWS); - WRAPPER(GC_TRIGGERS); - MODE_ANY; - PRECONDITION(elemType < CV_LAST); - } - CONTRACT_END; - - RETURN TypeHandle(CoreLibBinder::GetClass(CVTypeToBinderClassID[elemType])); -} - -// Use this very carefully. There is not a direct mapping between -// CorElementType and CVTypes for a bunch of things. In this case -// we return CV_LAST. You need to check this at the call site. -extern CVTypes CorElementTypeToCVTypes(CorElementType type); - - -#ifdef FEATURE_COMINTEROP - -#include - - -/*** Variant Design Restrictions (ie, decisions we've had to re-do differently): - 1) A Variant containing all zeros should be a valid Variant of type empty. - 2) Variant must contain an OBJECTREF field for Objects, etc. Since we - have no way of expressing a union between an OBJECTREF and an int, we - always box Decimals in a Variant. - 3) The m_flags field is not a CVType and will contain extra bits. People - should use VariantData::GetType() to get the CVType. - 4) You should use SetObjRef and GetObjRef to manipulate the OBJECTREF field. - These will handle write barriers correctly, as well as CV_EMPTY. - - - Empty, Missing & Null: - Variants of type CV_EMPTY will be all zero's. This forces us to add in - special cases for all functions that convert a Variant into an object (such - as copying a Variant into an Object[]). - - Variants of type Missing and Null will have their objectref field set to - Missing.Value and Null.Value respectively. This simplifies the code in - Variant.cs and strewn throughout the EE. -*/ - -#define VARIANT_TYPE_MASK 0xFFFF -#define VT_MASK 0xFF000000 -#define VT_BITSHIFT 24 - -struct VariantData -{ - friend class CoreLibBinder; - -public: - static void NewVariant(VariantData * const& dest, const CVTypes type, INT64 data - DEBUG_ARG(BOOL bDestIsInterior = FALSE)); - - FORCEINLINE CVTypes GetType() const - { - LIMITED_METHOD_CONTRACT; - - return (CVTypes)(m_flags & VARIANT_TYPE_MASK); - } - - FORCEINLINE void SetType(INT32 in) - { - LIMITED_METHOD_CONTRACT; - m_flags = in; - } - - FORCEINLINE VARTYPE GetVT() const - { - LIMITED_METHOD_CONTRACT; - - VARTYPE vt = (m_flags & VT_MASK) >> VT_BITSHIFT; - if (vt & 0x80) - { - vt &= ~0x80; - vt |= VT_ARRAY; - } - return vt; - } - - FORCEINLINE void SetVT(VARTYPE vt) - { - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION( !(vt & VT_BYREF) ); - PRECONDITION( (vt & ~VT_ARRAY) < 128 ); - } - CONTRACTL_END; - - if (vt & VT_ARRAY) - { - vt &= ~VT_ARRAY; - vt |= 0x80; - } - m_flags = (m_flags & ~((INT32)VT_MASK)) | (vt << VT_BITSHIFT); - } - - - FORCEINLINE OBJECTREF GetObjRef() const - { - WRAPPER_NO_CONTRACT; - - return (OBJECTREF)m_objref; - } - - OBJECTREF* GetObjRefPtr() - { - CONTRACT (OBJECTREF*) - { - NOTHROW; - GC_NOTRIGGER; - MODE_COOPERATIVE; - POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); - } - CONTRACT_END; - - RETURN (OBJECTREF*)&m_objref; - } - - void SetObjRef(OBJECTREF objRef) - { - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_COOPERATIVE; - } - CONTRACTL_END; - - if (objRef!=NULL) - { - SetObjectReference((OBJECTREF*)&m_objref, objRef); - } - else - { - // Casting trick to avoid going thru overloaded operator= (which - // in this case would trigger a false write barrier violation assert.) - *(LPVOID*)(OBJECTREF*)&m_objref=NULL; - } - } - - FORCEINLINE void* GetData() const - { - LIMITED_METHOD_CONTRACT; - return (void *)(&m_data); - } - - FORCEINLINE INT8 GetDataAsInt8() const - { - LIMITED_METHOD_CONTRACT; - return (INT8)m_data; - } - - FORCEINLINE UINT8 GetDataAsUInt8() const - { - LIMITED_METHOD_CONTRACT; - return (UINT8)m_data; - } - - FORCEINLINE INT16 GetDataAsInt16() const - { - LIMITED_METHOD_CONTRACT; - return (INT16)m_data; - } - - FORCEINLINE UINT16 GetDataAsUInt16() const - { - LIMITED_METHOD_CONTRACT; - return (UINT16)m_data; - } - - FORCEINLINE INT32 GetDataAsInt32() const - { - LIMITED_METHOD_CONTRACT; - return (INT32)m_data; - } - - FORCEINLINE UINT32 GetDataAsUInt32() const - { - LIMITED_METHOD_CONTRACT; - return (UINT32)m_data; - } - - FORCEINLINE INT64 GetDataAsInt64() const - { - LIMITED_METHOD_CONTRACT; - return (INT64)m_data; - } - - FORCEINLINE UINT64 GetDataAsUInt64() const - { - LIMITED_METHOD_CONTRACT; - return (UINT64)m_data; - } - - FORCEINLINE void SetData(void *in) - { - LIMITED_METHOD_CONTRACT; - - if (!in) - m_data=0; - else - m_data = *(INT64 *)in; - } - - // When possible, please use the most specific SetDataAsXxx function. - // This is necessary to guarantee we do sign extension correctly - // for all types smaller than 32 bits. R4's, R8's, U8's, DateTimes, - // Currencies, and TimeSpans can all be treated as ints of the appropriate - // size - sign extension is irrelevant in those cases. - FORCEINLINE void SetDataAsInt8(INT8 data) - { - LIMITED_METHOD_CONTRACT; - m_data=data; - } - - FORCEINLINE void SetDataAsUInt8(UINT8 data) - { - LIMITED_METHOD_CONTRACT; - m_data=data; - } - - FORCEINLINE void SetDataAsInt16(INT16 data) - { - LIMITED_METHOD_CONTRACT; - m_data=data; - } - - FORCEINLINE void SetDataAsUInt16(UINT16 data) - { - LIMITED_METHOD_CONTRACT; - m_data=data; - } - - FORCEINLINE void SetDataAsInt32(INT32 data) - { - LIMITED_METHOD_CONTRACT; - m_data=data; - } - - FORCEINLINE void SetDataAsUInt32(UINT32 data) - { - LIMITED_METHOD_CONTRACT; - m_data=data; - } - - FORCEINLINE void SetDataAsInt64(INT64 data) - { - LIMITED_METHOD_CONTRACT; - m_data=data; - } - -private: - // Typeloader reorders fields of non-blitable types. This reordering differs between 32-bit and 64-bit platforms. -#ifdef TARGET_64BIT - Object* m_objref; - INT64 m_data; - INT32 m_flags; - INT32 m_padding; -#else - INT64 m_data; - Object* m_objref; - INT32 m_flags; -#endif -}; - -#include - -#endif // FEATURE_COMINTEROP - - class OleVariant { public: @@ -361,8 +43,8 @@ class OleVariant static BSTR AllocateEmptyBSTRForString(STRINGREF *pStringObj); static void ConvertContentsStringToBSTR(STRINGREF *pStringObj, BSTR bstr); static BSTR ConvertStringToBSTR(STRINGREF *pStringObj); - static void MarshalComVariantForOleVariant(VARIANT *pOle, VariantData *pCom); - static void MarshalOleVariantForComVariant(VariantData *pCom, VARIANT *pOle); + static void MarshalObjectForOleVariantUncommon(const VARIANT *pOle, OBJECTREF * const & pObj); + static void MarshalOleVariantForObjectUncommon(OBJECTREF * const & pObj, VARIANT *pOle); #endif // FEATURE_COMINTEROP #ifdef FEATURE_COMINTEROP @@ -412,14 +94,11 @@ class OleVariant // Type conversion utilities static void ExtractContentsFromByrefVariant(VARIANT* pByrefVar, VARIANT* pDestVar); - static void InsertContentsIntoByrefVariant(VARIANT* pSrcVar, VARIANT* pByrefVar); + static void InsertContentsIntoByRefVariant(VARIANT* pSrcVar, VARIANT* pByrefVar); static void CreateByrefVariantForVariant(VARIANT* pSrcVar, VARIANT* pByrefVar); - - static VARTYPE GetVarTypeForComVariant(VariantData* pComVariant); #endif // FEATURE_COMINTEROP - static CVTypes GetCVTypeForVarType(VARTYPE vt); - static VARTYPE GetVarTypeForCVType(CVTypes); + static TypeHandle GetTypeHandleForVarType(VARTYPE vt); static VARTYPE GetVarTypeForTypeHandle(TypeHandle typeHnd); static VARTYPE GetVarTypeForValueClassArrayName(LPCUTF8 pArrayClassName); @@ -450,11 +129,6 @@ class OleVariant struct Marshaler { -#ifdef FEATURE_COMINTEROP - void (*OleToComVariant)(VARIANT* pOleVariant, VariantData* pComVariant); - void (*ComToOleVariant)(VariantData* pComVariant, VARIANT* pOleVariant); - void (*OleRefToComVariant)(VARIANT* pOleVariant, VariantData* pComVariant); -#endif // FEATURE_COMINTEROP void (*OleToComArray)(void* oleArray, BASEARRAYREF* pComArray, MethodTable* pInterfaceMT, PCODE pManagedMarshalerCode); void (*ComToOleArray)(BASEARRAYREF* pComArray, void* oleArray, MethodTable* pInterfaceMT, BOOL fBestFitMapping, BOOL fThrowOnUnmappableChar, @@ -488,9 +162,6 @@ class OleVariant MethodTable* pInterfaceMT, BOOL fBestFitMapping, BOOL fThrowOnUnmappableChar, BOOL fOleArrayValid, SIZE_T cElements, PCODE pManagedMarshalerCode); - static void MarshalCBoolVariantOleToCom(VARIANT* pOleVariant, VariantData* pComVariant); - static void MarshalCBoolVariantComToOle(VariantData* pComVariant, VARIANT* pOleVariant); - static void MarshalCBoolVariantOleRefToCom(VARIANT* pOleVariant, VariantData* pComVariant); static void MarshalCBoolArrayOleToCom(void* oleArray, BASEARRAYREF* pComArray, MethodTable* pInterfaceMT, PCODE pManagedMarshalerCode); static void MarshalCBoolArrayComToOle(BASEARRAYREF* pComArray, void* oleArray, @@ -574,40 +245,10 @@ class OleVariant SIZE_T cElements, PCODE pManagedMarshalerCode); static void ClearInterfaceArray(void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT, PCODE pManagedMarshalerCode); - static void MarshalBoolVariantOleToCom(VARIANT* pOleVariant, VariantData* pComVariant); - - static void MarshalWinBoolVariantOleToCom(VARIANT* pOleVariant, VariantData* pComVariant); - static void MarshalWinBoolVariantComToOle(VariantData* pComVariant, VARIANT* pOleVariant); - static void MarshalWinBoolVariantOleRefToCom(VARIANT* pOleVariant, VariantData* pComVariant); - - static void MarshalAnsiCharVariantOleToCom(VARIANT* pOleVariant, VariantData* pComVariant); - static void MarshalAnsiCharVariantComToOle(VariantData* pComVariant, VARIANT* pOleVariant); - static void MarshalAnsiCharVariantOleRefToCom(VARIANT* pOleVariant, VariantData* pComVariant); - - static void MarshalInterfaceVariantOleToCom(VARIANT* pOleVariant, VariantData* pComVariant); - static void MarshalInterfaceVariantComToOle(VariantData* pComVariant, VARIANT* pOleVariant); - static void MarshalInterfaceVariantOleRefToCom(VARIANT* pOleVariant, VariantData* pComVariant); - - static void MarshalBSTRVariantOleToCom(VARIANT* pOleVariant, VariantData* pComVariant); - static void MarshalBSTRVariantComToOle(VariantData* pComVariant, VARIANT* pOleVariant); - - static void MarshalDateVariantOleToCom(VARIANT* pOleVariant, VariantData* pComVariant); - static void MarshalDateVariantComToOle(VariantData* pComVariant, VARIANT* pOleVariant); - static void MarshalDateVariantOleRefToCom(VARIANT* pOleVariant, VariantData* pComVariant); - - static void MarshalDecimalVariantOleToCom(VARIANT* pOleVariant, VariantData* pComVariant); - static void MarshalDecimalVariantComToOle(VariantData* pComVariant, VARIANT* pOleVariant); - static void MarshalDecimalVariantOleRefToCom(VARIANT* pOleVariant, VariantData* pComVariant); - #ifdef FEATURE_COMINTEROP - static void MarshalRecordVariantOleToCom(VARIANT* pOleVariant, VariantData* pComVariant); - static void MarshalRecordVariantComToOle(VariantData* pComVariant, VARIANT* pOleVariant); - static void MarshalRecordVariantOleRefToCom(VARIANT* pOleVariant, VariantData* pComVariant); + static void MarshalRecordVariantOleToObject(const VARIANT* pOleVariant, OBJECTREF * const & pComVariant); #endif - static void MarshalCurrencyVariantOleToCom(VARIANT* pOleVariant, VariantData* pComVariant); - static void MarshalCurrencyVariantComToOle(VariantData* pComVariant, VARIANT* pOleVariant); - static void MarshalCurrencyVariantOleRefToCom(VARIANT* pOleVariant, VariantData* pComVariant); static void MarshalCurrencyArrayOleToCom(void* oleArray, BASEARRAYREF* pComArray, MethodTable* pInterfaceMT, PCODE pManagedMarshalerCode); static void MarshalCurrencyArrayComToOle(BASEARRAYREF* pComArray, void* oleArray, @@ -624,14 +265,10 @@ class OleVariant static void ClearVariantArray(void* oleArray, SIZE_T cElements, MethodTable* pInterfaceMT, PCODE pManagedMarshalerCode); #ifdef FEATURE_COMINTEROP - static void MarshalArrayVariantOleToCom(VARIANT* pOleVariant, VariantData* pComVariant); - static void MarshalArrayVariantComToOle(VariantData* pComVariant, VARIANT* pOleVariant); - static void MarshalArrayVariantOleRefToCom(VARIANT* pOleVariant, VariantData* pComVariant); + static void MarshalArrayVariantOleToObject(const VARIANT* pOleVariant, OBJECTREF * const & pObj); + static void MarshalArrayVariantOleRefToObject(const VARIANT* pOleVariant, OBJECTREF * const & pObj); + static void MarshalArrayVariantObjectToOle(OBJECTREF * const & pObj, VARIANT* pOleVariant); #endif - - static void MarshalErrorVariantOleToCom(VARIANT* pOleVariant, VariantData* pComVariant); - static void MarshalErrorVariantOleRefToCom(VARIANT* pOleVariant, VariantData* pComVariant); - static void MarshalErrorVariantComToOle(VariantData* pComVariant, VARIANT* pOleVariant); #endif // FEATURE_COMINTEROP }; diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp index 108738af6b9cc..215e2d34ef69a 100644 --- a/src/coreclr/vm/qcallentrypoints.cpp +++ b/src/coreclr/vm/qcallentrypoints.cpp @@ -327,6 +327,7 @@ static const Entry s_QCall[] = DllImportEntry(MngdSafeArrayMarshaler_ClearNative) DllImportEntry(Variant_ConvertSystemColorToOleColor) DllImportEntry(Variant_ConvertOleColorToSystemColor) + DllImportEntry(Variant_ConvertValueTypeToRecord) #endif // FEATURE_COMINTEROP DllImportEntry(NativeLibrary_LoadFromPath) DllImportEntry(NativeLibrary_LoadByName) diff --git a/src/libraries/Common/src/System/HResults.cs b/src/libraries/Common/src/System/HResults.cs index b0de5f2c5fe35..858015f9c4516 100644 --- a/src/libraries/Common/src/System/HResults.cs +++ b/src/libraries/Common/src/System/HResults.cs @@ -109,6 +109,7 @@ internal static partial class HResults internal const int COR_E_VERIFICATION = unchecked((int)0x8013150D); internal const int COR_E_WAITHANDLECANNOTBEOPENED = unchecked((int)0x8013152C); internal const int CO_E_NOTINITIALIZED = unchecked((int)0x800401F0); + internal const int DISP_E_PARAMNOTFOUND = unchecked((int)0x80020004); internal const int DISP_E_TYPEMISMATCH = unchecked((int)0x80020005); internal const int DISP_E_BADVARTYPE = unchecked((int)0x80020008); internal const int DISP_E_OVERFLOW = unchecked((int)0x8002000A); diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index 413995326c959..379251af33cba 100644 --- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -4340,4 +4340,19 @@ Only array or span of primitive or enum types can be initialized from static data. + + CriticalHandle derived types cannot be stored in Variants. + + + SafeHandle derived types cannot be stored in Variants. + + + Method's type signature is not Interop compatible. + + + The method returned a COM Variant type that is not Interop compatible. + + + VariantWrappers cannot be stored in Variants. + 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 5f1cc55b9929c..72f6a1579d80f 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 @@ -2097,9 +2097,6 @@ Common\Interop\Windows\OleAut32\Interop.SysFreeString.cs - - Common\Interop\Windows\OleAut32\Interop.VariantChangeTypeEx.cs - Common\Interop\Windows\Ole32\Interop.CLSIDFromProgID.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ComVariant.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/ComVariant.cs index 1abac3537a14f..ee44d4960718c 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 @@ -255,7 +255,9 @@ 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); + // Although unused bits of native VARIANT is undefined, our managed test + // for Marshal.GetNativeVariantForObject asserts for its whole content. + ComVariant variant = default; if (typeof(T) == typeof(DBNull)) { variant = Null; @@ -393,7 +395,7 @@ public static unsafe ComVariant CreateRaw(VarEnum vt, T rawValue) throw new PlatformNotSupportedException(SR.ComVariant_SafeArray_PlatformNotSupported); } - Unsafe.SkipInit(out ComVariant value); + ComVariant value = default; value.VarType = vt; value.GetRawDataRef() = (vt, sizeof(T)) switch { diff --git a/src/tests/Interop/COM/NETClients/MiscTypes/Program.cs b/src/tests/Interop/COM/NETClients/MiscTypes/Program.cs index de4945b5af13b..0af6a47d6a3a7 100644 --- a/src/tests/Interop/COM/NETClients/MiscTypes/Program.cs +++ b/src/tests/Interop/COM/NETClients/MiscTypes/Program.cs @@ -5,6 +5,8 @@ namespace NetClient { using System; + using System.Drawing; + using System.Reflection; using System.Runtime.InteropServices; using TestLibrary; @@ -14,6 +16,44 @@ namespace NetClient struct Struct {} + enum LongBasedEnum : long {} + + class SomeSafeHandle : SafeHandle + { + public SomeSafeHandle() : base((nint)1, true) {} + public override bool IsInvalid => true; + protected override bool ReleaseHandle() => true; + } + + class SomeCriticalHandle : CriticalHandle + { + public SomeCriticalHandle() : base((nint)1) {} + public override bool IsInvalid => true; + protected override bool ReleaseHandle() => true; + } + + class CustomConvertible : IConvertible + { + public const long Value = 0x1234567890ABCDEF; + public TypeCode GetTypeCode() => TypeCode.Int64; + public bool ToBoolean(IFormatProvider? provider) => throw new NotImplementedException(); + public char ToChar(IFormatProvider? provider) => throw new NotImplementedException(); + public sbyte ToSByte(IFormatProvider? provider) => throw new NotImplementedException(); + public byte ToByte(IFormatProvider? provider) => throw new NotImplementedException(); + public short ToInt16(IFormatProvider? provider) => throw new NotImplementedException(); + public ushort ToUInt16(IFormatProvider? provider) => throw new NotImplementedException(); + public int ToInt32(IFormatProvider? provider) => throw new NotImplementedException(); + public uint ToUInt32(IFormatProvider? provider) => throw new NotImplementedException(); + public long ToInt64(IFormatProvider? provider) => Value; + public ulong ToUInt64(IFormatProvider? provider) => throw new NotImplementedException(); + public float ToSingle(IFormatProvider? provider) => throw new NotImplementedException(); + public double ToDouble(IFormatProvider? provider) => throw new NotImplementedException(); + public decimal ToDecimal(IFormatProvider? provider) => throw new NotImplementedException(); + public DateTime ToDateTime(IFormatProvider? provider) => throw new NotImplementedException(); + public string ToString(IFormatProvider? provider) => throw new NotImplementedException(); + public object ToType(Type conversionType, IFormatProvider? provider) => throw new NotImplementedException(); + } + public unsafe class Program { [Fact] @@ -70,6 +110,14 @@ private static void ValidationTests() var expected = (long)0x07ffffffffffffff; Assert.Equal(expected, miscTypeTesting.Marshal_Variant(expected)); } + { + var expected = 123.456f; + Assert.Equal(expected, miscTypeTesting.Marshal_Variant(expected)); + } + { + var expected = 123.456; + Assert.Equal(expected, miscTypeTesting.Marshal_Variant(expected)); + } { var expected = true; Assert.Equal(expected, miscTypeTesting.Marshal_Variant(expected)); @@ -78,6 +126,22 @@ private static void ValidationTests() var expected = false; Assert.Equal(expected, miscTypeTesting.Marshal_Variant(expected)); } + { + var expected = 123.456m; + Assert.Equal(expected, miscTypeTesting.Marshal_Variant(expected)); + } + { + var expected = unchecked((nint)0x07ffffffffffffff); + Assert.Equal((int)expected, miscTypeTesting.Marshal_Variant(expected)); + } + { + var expected = (LongBasedEnum)0x07ffffffffffffff; + Assert.Equal((long)expected, miscTypeTesting.Marshal_Variant(expected)); + } + { + var expected = new DateTime(9999, 12, 31); + Assert.Equal(expected, miscTypeTesting.Marshal_Variant(expected)); + } Console.WriteLine("-- BSTR <=> VARIANT..."); { @@ -85,6 +149,61 @@ private static void ValidationTests() Assert.Equal(expected, miscTypeTesting.Marshal_Variant(expected)); } + Console.WriteLine("-- Special types <=> VARIANT..."); + { + var expected = Type.Missing; + Assert.Equal(expected, miscTypeTesting.Marshal_Variant(expected)); + } + { + var expected = Color.Red; + Assert.Equal((uint)ColorTranslator.ToOle(expected), miscTypeTesting.Marshal_Variant(expected)); + } + + Console.WriteLine("-- Wrappers <=> VARIANT..."); +#pragma warning disable 0618 // CurrencyWrapper is obsolete + { + var expected = 123.456m; + Assert.Equal(expected, miscTypeTesting.Marshal_Variant(new CurrencyWrapper(expected))); + } +#pragma warning restore 0618 + { + var expected = "The quick Fox jumped over the lazy Dog."; + Assert.Equal(expected, miscTypeTesting.Marshal_Variant(new BStrWrapper(expected))); + } + { + var expected = unchecked((int)0x80004005); + Assert.Equal(expected, miscTypeTesting.Marshal_Variant(new ErrorWrapper(expected))); + } + { + var expected = unchecked((int)0x80020004); // DISP_E_PARAMNOTFOUND + Assert.Equal(Type.Missing, miscTypeTesting.Marshal_Variant(new ErrorWrapper(expected))); + } + { + var expected = miscTypeTesting; + Assert.Equal(expected, miscTypeTesting.Marshal_Variant(new UnknownWrapper(expected))); + } + + Console.WriteLine("-- Arrays <=> VARIANT..."); + { + var expected = new int[] { 1, 2, 3 }; + Assert.Equal(expected, miscTypeTesting.Marshal_Variant(expected)); + } + { + var expected = new string[] { "quick", "brown", "fox" }; + Assert.Equal(expected, miscTypeTesting.Marshal_Variant(expected)); + } + + Console.WriteLine("-- IUnknown <=> VARIANT..."); + { + var expected = miscTypeTesting; + Assert.Equal(expected, miscTypeTesting.Marshal_Variant(expected)); + } + + Console.WriteLine("-- IConvertible <=> VARIANT..."); + { + Assert.Equal(CustomConvertible.Value, miscTypeTesting.Marshal_Variant(new CustomConvertible())); + } + Console.WriteLine("-- System.Guid <=> VARIANT..."); { var expected = new Guid("{8EFAD956-B33D-46CB-90F4-45F55BA68A96}"); @@ -98,6 +217,24 @@ private static void ValidateNegativeTests() var miscTypeTesting = (Server.Contract.Servers.MiscTypesTesting)new Server.Contract.Servers.MiscTypesTestingClass(); + Console.WriteLine("-- DispatchWrapper with non-IDispatch object <=> VARIANT..."); + { + Assert.Throws(() => miscTypeTesting.Marshal_Variant(new DispatchWrapper(miscTypeTesting))); + } + Console.WriteLine("-- Unmappable types <=> VARIANT..."); + { + Assert.Throws(() => miscTypeTesting.Marshal_Variant(TimeSpan.FromSeconds(1))); + } + { + Assert.Throws(() => miscTypeTesting.Marshal_Variant(new SomeSafeHandle())); + } + { + Assert.Throws(() => miscTypeTesting.Marshal_Variant(new SomeCriticalHandle())); + } + { + Assert.Throws(() => miscTypeTesting.Marshal_Variant(new VariantWrapper(null))); + } + Console.WriteLine("-- User defined ValueType <=> VARIANT..."); { Assert.Throws(() => miscTypeTesting.Marshal_Variant(new Struct())); diff --git a/src/tests/Interop/COM/NETServer/MiscTypesTesting.cs b/src/tests/Interop/COM/NETServer/MiscTypesTesting.cs index 2a31507d29ab2..bae083ec20403 100644 --- a/src/tests/Interop/COM/NETServer/MiscTypesTesting.cs +++ b/src/tests/Interop/COM/NETServer/MiscTypesTesting.cs @@ -16,23 +16,12 @@ object Server.Contract.IMiscTypesTesting.Marshal_Variant(object obj) return null; } - if (obj is DBNull) - { - return DBNull.Value; - } - if (obj.GetType().IsValueType) { return CallMemberwiseClone(obj); } - if (obj is string) - { - return obj; - } - - Environment.FailFast($"Arguments must be ValueTypes or strings: {obj.GetType()}"); - return null; + return obj; // object.MemberwiseClone() will bitwise copy for ValueTypes. // This is sufficient for the VARIANT marshalling scenario being @@ -51,4 +40,9 @@ object Server.Contract.IMiscTypesTesting.Marshal_Instance_Variant(string init) Environment.FailFast($"Unknown init value: {init}"); return null; } + + void Server.Contract.IMiscTypesTesting.Marshal_ByRefVariant(ref object result, object value) + { + result = value; + } } \ No newline at end of file diff --git a/src/tests/Interop/COM/NativeClients/MiscTypes/MiscTypes.cpp b/src/tests/Interop/COM/NativeClients/MiscTypes/MiscTypes.cpp index 6fb435be6513c..ad0bb044c8e4e 100644 --- a/src/tests/Interop/COM/NativeClients/MiscTypes/MiscTypes.cpp +++ b/src/tests/Interop/COM/NativeClients/MiscTypes/MiscTypes.cpp @@ -34,6 +34,7 @@ struct ComInit using ComMTA = ComInit; void ValidationTests(); +void ValidationByRefTests(); int __cdecl main() { @@ -50,6 +51,7 @@ int __cdecl main() { CoreShimComActivation csact{ W("NETServer"), W("MiscTypesTesting") }; ValidationTests(); + ValidationByRefTests(); } catch (HRESULT hr) { @@ -98,6 +100,12 @@ void ValidationTests() THROW_IF_FAILED(miscTypesTesting->Marshal_Variant(args.Input, &args.Result)); THROW_FAIL_IF_FALSE(V_VT(&args.Input) == V_VT(&args.Result)); } + { + VariantMarshalTest args{}; + V_VT(&args.Input) = VT_VOID; + THROW_IF_FAILED(miscTypesTesting->Marshal_Variant(args.Input, &args.Result)); + THROW_FAIL_IF_FALSE(VT_EMPTY == V_VT(&args.Result)); + } { VariantMarshalTest args{}; V_VT(&args.Input) = VT_I1; @@ -140,6 +148,93 @@ void ValidationTests() THROW_IF_FAILED(miscTypesTesting->Marshal_Variant(args.Input, &args.Result)); THROW_FAIL_IF_FALSE(V_BOOL(&args.Input) == V_BOOL(&args.Result)); } + { + VariantMarshalTest args{}; + V_VT(&args.Input) = VT_INT; + V_INT(&args.Input) = 0x07ffffff; + THROW_IF_FAILED(miscTypesTesting->Marshal_Variant(args.Input, &args.Result)); + THROW_FAIL_IF_FALSE(VT_I4 == V_VT(&args.Result)); + THROW_FAIL_IF_FALSE(V_I4(&args.Input) == V_I4(&args.Result)); + } + { + VariantMarshalTest args{}; + V_VT(&args.Input) = VT_DECIMAL; + VarDecFromR8(123.456, &V_DECIMAL(&args.Input)); + THROW_IF_FAILED(miscTypesTesting->Marshal_Variant(args.Input, &args.Result)); + THROW_FAIL_IF_FALSE(VarDecCmp(&V_DECIMAL(&args.Input), &V_DECIMAL(&args.Result)) == VARCMP_EQ); + } + { + VariantMarshalTest args{}; + V_VT(&args.Input) = VT_DATE; + V_R8(&args.Input) = -657434.0; + THROW_IF_FAILED(miscTypesTesting->Marshal_Variant(args.Input, &args.Result)); + THROW_FAIL_IF_FALSE(V_DATE(&args.Input) == V_DATE(&args.Result)); + } + { + VariantMarshalTest args{}; + V_VT(&args.Input) = VT_CY; + VarCyFromR8(12.34, &V_CY(&args.Input)); + DECIMAL d; + VarDecFromCy(V_CY(&args.Input), &d); + THROW_IF_FAILED(miscTypesTesting->Marshal_Variant(args.Input, &args.Result)); + THROW_FAIL_IF_FALSE(VarDecCmp(&d, &V_DECIMAL(&args.Result)) == VARCMP_EQ); + } + { + VariantMarshalTest args{}; + V_VT(&args.Input) = VT_ERROR; + V_ERROR(&args.Input) = E_FAIL; + THROW_IF_FAILED(miscTypesTesting->Marshal_Variant(args.Input, &args.Result)); + THROW_FAIL_IF_FALSE(VT_I4 == V_VT(&args.Result)); + THROW_FAIL_IF_FALSE(V_ERROR(&args.Input) == V_ERROR(&args.Result)); + } + { + VariantMarshalTest args{}; + V_VT(&args.Input) = VT_ERROR; + V_ERROR(&args.Input) = DISP_E_PARAMNOTFOUND; + THROW_IF_FAILED(miscTypesTesting->Marshal_Variant(args.Input, &args.Result)); + THROW_FAIL_IF_FALSE(V_VT(&args.Input) == V_VT(&args.Result)); + THROW_FAIL_IF_FALSE(V_ERROR(&args.Input) == V_ERROR(&args.Result)); + } + + ::printf("-- BYREF <=> VARIANT...\n"); + { + VariantMarshalTest args{}; + LONG value = 0x07ffffff; + V_VT(&args.Input) = VT_BYREF|VT_I4; + V_I4REF(&args.Input) = &value; + THROW_IF_FAILED(miscTypesTesting->Marshal_Variant(args.Input, &args.Result)); + THROW_FAIL_IF_FALSE(value == V_I4(&args.Result)); + } + { + VariantMarshalTest args{}; + V_VT(&args.Input) = VT_BYREF|VT_EMPTY; + V_I4REF(&args.Input) = NULL; + THROW_IF_FAILED(miscTypesTesting->Marshal_Variant(args.Input, &args.Result)); +#ifdef HOST_64BIT + THROW_FAIL_IF_FALSE(VT_UI8 == V_VT(&args.Result)); +#else + THROW_FAIL_IF_FALSE(VT_UI4 == V_VT(&args.Result)); +#endif + } + { + VariantMarshalTest args{}; + VARIANT nested{}; + V_VT(&nested) = VT_I4; + V_I4(&nested) = 0x07ffffff; + V_VT(&args.Input) = VT_BYREF|VT_VARIANT; + V_VARIANTREF(&args.Input) = &nested; + THROW_IF_FAILED(miscTypesTesting->Marshal_Variant(args.Input, &args.Result)); + THROW_FAIL_IF_FALSE(V_I4(&nested) == V_I4(&args.Result)); + } + { + VariantMarshalTest args{}; + ComSmartPtr unknown; + (void)miscTypesTesting->QueryInterface(IID_IUnknown, (void**)&unknown); + V_VT(&args.Input) = VT_BYREF|VT_UNKNOWN; + V_UNKNOWNREF(&args.Input) = &unknown; + THROW_IF_FAILED(miscTypesTesting->Marshal_Variant(args.Input, &args.Result)); + THROW_FAIL_IF_FALSE(unknown == V_UNKNOWN(&args.Result)); + } ::printf("-- BSTR <=> VARIANT...\n"); { @@ -150,6 +245,37 @@ void ValidationTests() THROW_FAIL_IF_FALSE(CompareStringOrdinal(V_BSTR(&args.Input), -1, V_BSTR(&args.Result), -1, FALSE) == CSTR_EQUAL); } + ::printf("-- Array <=> VARIANT...\n"); + { + VariantMarshalTest args{}; + V_VT(&args.Input) = VT_ARRAY|VT_I2; + short data[3] = { 12, 34, 56 }; + SAFEARRAYBOUND saBound; + saBound.lLbound = 0; + saBound.cElements = static_cast(sizeof(data) / sizeof(*data)); + V_ARRAY(&args.Input) = ::SafeArrayCreate(VT_I2, 1, &saBound); + memcpy(static_cast(V_ARRAY(&args.Input)->pvData), data, sizeof(data)); + THROW_IF_FAILED(miscTypesTesting->Marshal_Variant(args.Input, &args.Result)); + THROW_FAIL_IF_FALSE((VT_ARRAY|VT_I2) == V_VT(&args.Result)); + THROW_FAIL_IF_FALSE(memcmp(V_ARRAY(&args.Result)->pvData, data, sizeof(data)) == 0); + } + + ::printf("-- IUnknown <=> VARIANT...\n"); + { + VariantMarshalTest args{}; + V_VT(&args.Input) = VT_UNKNOWN; + (void)miscTypesTesting->QueryInterface(IID_IUnknown, (void**)&V_UNKNOWN(&args.Input)); + THROW_IF_FAILED(miscTypesTesting->Marshal_Variant(args.Input, &args.Result)); + THROW_FAIL_IF_FALSE(V_UNKNOWN(&args.Input) == V_UNKNOWN(&args.Result)); + } + { + VariantMarshalTest args{}; + V_VT(&args.Input) = VT_UNKNOWN; + V_UNKNOWN(&args.Input) = NULL; + THROW_IF_FAILED(miscTypesTesting->Marshal_Variant(args.Input, &args.Result)); + THROW_FAIL_IF_FALSE(VT_EMPTY == V_VT(&args.Result)); + } + ::printf("-- System.Guid <=> VARIANT...\n"); { /* 8EFAD956-B33D-46CB-90F4-45F55BA68A96 */ @@ -168,4 +294,108 @@ void ValidationTests() THROW_FAIL_IF_FALSE(V_VT(&args.Input) == V_VT(&args.Result)); THROW_FAIL_IF_FALSE(memcmp(V_RECORD(&args.Input), V_RECORD(&args.Result), sizeof(expected)) == 0); } + + ::printf("-- Unsupported types <=> VARIANT...\n"); + { + VariantMarshalTest args{}; + V_VT(&args.Input) = VT_SAFEARRAY; + HRESULT hr = miscTypesTesting->Marshal_Variant(args.Input, &args.Result); + THROW_FAIL_IF_FALSE(hr == E_INVALIDARG); + } + { + VariantMarshalTest args{}; + V_VT(&args.Input) = VT_HRESULT; + HRESULT hr = miscTypesTesting->Marshal_Variant(args.Input, &args.Result); + THROW_FAIL_IF_FALSE(hr == E_INVALIDARG); + } + { + VariantMarshalTest args{}; + V_VT(&args.Input) = VT_VARIANT; + HRESULT hr = miscTypesTesting->Marshal_Variant(args.Input, &args.Result); + THROW_FAIL_IF_FALSE(hr == E_INVALIDARG); + } + { + VariantMarshalTest args{}; + V_VT(&args.Input) = (VARENUM)0x8888; + HRESULT hr = miscTypesTesting->Marshal_Variant(args.Input, &args.Result); + THROW_FAIL_IF_FALSE(hr == 0x80131531); // COR_E_INVALIDOLEVARIANTTYPE + } +} + +void ValidationByRefTests() +{ + ::printf(__FUNCTION__ "() through CoCreateInstance...\n"); + + HRESULT hr; + + IMiscTypesTesting *miscTypesTesting; + THROW_IF_FAILED(::CoCreateInstance(CLSID_MiscTypesTesting, nullptr, CLSCTX_INPROC, IID_IMiscTypesTesting, (void**)&miscTypesTesting)); + + ::printf("-- Primitives <=> BYREF VARIANT...\n"); + { + VariantMarshalTest args{}; + LONG value = 0; + V_VT(&args.Input) = VT_I4; + V_I4(&args.Input) = 0x07ffffff; + V_VT(&args.Result) = VT_BYREF|VT_I4; + V_I4REF(&args.Result) = &value; + THROW_IF_FAILED(miscTypesTesting->Marshal_ByRefVariant(&args.Result, args.Input)); + THROW_FAIL_IF_FALSE(V_I4(&args.Input) == value); + } + { + VariantMarshalTest args{}; + LONG value = 0; + V_VT(&args.Input) = VT_I8; + V_I8(&args.Input) = 0x07ffffff; + V_VT(&args.Result) = VT_BYREF|VT_I4; + V_I4REF(&args.Result) = &value; + THROW_IF_FAILED(miscTypesTesting->Marshal_ByRefVariant(&args.Result, args.Input)); + THROW_FAIL_IF_FALSE(V_I8(&args.Input) == value); + } + ::printf("-- BSTR <=> BYREF VARIANT...\n"); + { + VariantMarshalTest args{}; + BSTR expected = ::SysAllocString(W("1234")); + V_VT(&args.Input) = VT_I4; + V_I4(&args.Input) = 1234; + BSTR value = ::SysAllocString(W("The quick Fox jumped over the lazy Dog.")); + V_VT(&args.Result) = VT_BYREF|VT_BSTR; + V_BSTRREF(&args.Result) = &value; + THROW_IF_FAILED(miscTypesTesting->Marshal_ByRefVariant(&args.Result, args.Input)); + THROW_FAIL_IF_FALSE(CompareStringOrdinal(expected, -1, value, -1, FALSE) == CSTR_EQUAL); + ::SysFreeString(expected); + } + + ::printf("-- System.Guid <=> BYREF VARIANT...\n"); + { + /* 8EFAD956-B33D-46CB-90F4-45F55BA68A96 */ + const GUID expected = { 0x8EFAD956, 0xB33D, 0x46CB, { 0x90, 0xF4, 0x45, 0xF5, 0x5B, 0xA6, 0x8A, 0x96} }; + + // Get a System.Guid into native + VariantMarshalTest guidVar; + THROW_IF_FAILED(miscTypesTesting->Marshal_Instance_Variant(W("{8EFAD956-B33D-46CB-90F4-45F55BA68A96}"), &guidVar.Input)); + THROW_FAIL_IF_FALSE(V_VT(&guidVar.Input) == VT_RECORD); + THROW_FAIL_IF_FALSE(memcmp(V_RECORD(&guidVar.Input), &expected, sizeof(expected)) == 0); + THROW_IF_FAILED(miscTypesTesting->Marshal_Instance_Variant(W("{00000000-0000-0000-0000-000000000000}"), &guidVar.Result)); + THROW_FAIL_IF_FALSE(V_VT(&guidVar.Result) == VT_RECORD); + + // Use the Guid as input. + VariantMarshalTest args{}; + THROW_IF_FAILED(::VariantCopy(&args.Input, &guidVar.Input)); + THROW_IF_FAILED(::VariantCopy(&args.Result, &guidVar.Result)); + V_VT(&args.Result) = VT_BYREF|VT_RECORD; + THROW_IF_FAILED(miscTypesTesting->Marshal_ByRefVariant(&args.Result, args.Input)); + THROW_FAIL_IF_FALSE((VT_BYREF|VT_RECORD) == V_VT(&args.Result)); + THROW_FAIL_IF_FALSE(memcmp(V_RECORD(&args.Input), V_RECORD(&args.Result), sizeof(expected)) == 0); + } + + ::printf("-- Type mismatch <=> BYREF VARIANT...\n"); + { + VariantMarshalTest args{}; + LONG value = 0; + V_VT(&args.Input) = VT_NULL; + V_VT(&args.Result) = VT_BYREF|VT_I4; + V_I4REF(&args.Result) = &value; + THROW_FAIL_IF_FALSE(miscTypesTesting->Marshal_ByRefVariant(&args.Result, args.Input) == 0x80004002); // COR_E_INVALIDCAST + } } diff --git a/src/tests/Interop/COM/NativeServer/MiscTypesTesting.h b/src/tests/Interop/COM/NativeServer/MiscTypesTesting.h index a3e89902f0b5b..52c1843636f4a 100644 --- a/src/tests/Interop/COM/NativeServer/MiscTypesTesting.h +++ b/src/tests/Interop/COM/NativeServer/MiscTypesTesting.h @@ -19,6 +19,11 @@ class MiscTypesTesting : public UnknownImpl, public IMiscTypesTesting return E_NOTIMPL; } + DEF_FUNC(Marshal_ByRefVariant)(_Inout_ VARIANT* result, _In_ VARIANT value) + { + return E_NOTIMPL; + } + public: // IUnknown STDMETHOD(QueryInterface)( /* [in] */ REFIID riid, diff --git a/src/tests/Interop/COM/ServerContracts/Server.Contracts.cs b/src/tests/Interop/COM/ServerContracts/Server.Contracts.cs index 476899377660d..f4a09a45ec038 100644 --- a/src/tests/Interop/COM/ServerContracts/Server.Contracts.cs +++ b/src/tests/Interop/COM/ServerContracts/Server.Contracts.cs @@ -193,6 +193,8 @@ public interface IMiscTypesTesting // Test API for marshalling an arbitrary type via VARIANT object Marshal_Instance_Variant([MarshalAs(UnmanagedType.LPWStr)] string init); + + void Marshal_ByRefVariant(ref object result, object value); } public struct HResult diff --git a/src/tests/Interop/COM/ServerContracts/Server.Contracts.h b/src/tests/Interop/COM/ServerContracts/Server.Contracts.h index 719659b7ed905..6d5f5cea749e5 100644 --- a/src/tests/Interop/COM/ServerContracts/Server.Contracts.h +++ b/src/tests/Interop/COM/ServerContracts/Server.Contracts.h @@ -376,6 +376,10 @@ IMiscTypesTesting : IUnknown virtual HRESULT STDMETHODCALLTYPE Marshal_Instance_Variant ( /*[in]*/ LPCWSTR init, /*[out,retval]*/ VARIANT* result) = 0; + + virtual HRESULT STDMETHODCALLTYPE Marshal_ByRefVariant ( + /*[inout]*/ VARIANT* result, + /*[in]*/ VARIANT value) = 0; }; struct __declspec(uuid("592386a5-6837-444d-9de3-250815d18556"))