diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
index 43bd4484b505a0..9e90c51042f69f 100644
--- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -286,6 +286,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 a51ec6f0132e47..81c480c4d951de 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 1ee6acc5be1c47..35052c0f9feb85 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 1a3cf7e75bb441..74baf2b62087c5 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 12c5a3d36d53dd..597cf76d720881 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 e29b2c75f16ac3..aef92ce036054b 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 7e9c3e9cc3fecf..6962fdfec89b53 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 671ae48e7ee7c5..4cffd124370fec 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 9286bd1ec39fab..ee05c624a1cc18 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 9cadd51c06ae4b..7dc5e664dfd423 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 6d38d94a46004c..d528fa10e16425 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 3bc78c1e1ff0f6..b3666f385a55b2 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 19cc399478a19a..eaa50c2f8421c0 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 5f7913b07b720d..ab42391080e039 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 1220e7b92be470..7d62924db8e935 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 108738af6b9cca..215e2d34ef69a9 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 b0de5f2c5fe35c..858015f9c45163 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 413995326c9598..379251af33cbaa 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 8ab45e10dfa8bd..8b731d2ce35154 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
@@ -2099,9 +2099,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 1abac3537a14f5..ee44d4960718ce 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 de4945b5af13bc..0af6a47d6a3a7c 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 2a31507d29ab22..bae083ec204030 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 6fb435be6513c2..ad0bb044c8e4e0 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 a3e89902f0b5b5..52c1843636f4a7 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 476899377660d9..f4a09a45ec0386 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 719659b7ed905e..6d5f5cea749e5c 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"))