summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Variant.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System/Variant.cs')
-rw-r--r--src/mscorlib/src/System/Variant.cs681
1 files changed, 681 insertions, 0 deletions
diff --git a/src/mscorlib/src/System/Variant.cs b/src/mscorlib/src/System/Variant.cs
new file mode 100644
index 0000000000..26e2e4aa1a
--- /dev/null
+++ b/src/mscorlib/src/System/Variant.cs
@@ -0,0 +1,681 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+**
+**
+** Purpose: The CLR implementation of Variant.
+**
+**
+===========================================================*/
+namespace System {
+
+ using System;
+ using System.Reflection;
+ using System.Threading;
+ using System.Runtime.InteropServices;
+ using System.Globalization;
+ using System.Runtime.CompilerServices;
+ using System.Runtime.Versioning;
+ using System.Diagnostics.Contracts;
+
+ [Serializable]
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct Variant {
+
+ //Do Not change the order of these fields.
+ //They are mapped to the native VariantData * data structure.
+ private Object m_objref;
+ private int m_data1;
+ private int m_data2;
+ private int m_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,
+ // COMOAVariant.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;
+
+ // Enum enum and Mask
+ internal const int EnumI1 =0x100000;
+ internal const int EnumU1 =0x200000;
+ internal const int EnumI2 =0x300000;
+ internal const int EnumU2 =0x400000;
+ internal const int EnumI4 =0x500000;
+ internal const int EnumU4 =0x600000;
+ internal const int EnumI8 =0x700000;
+ internal const int EnumU8 =0x800000;
+ internal const int EnumMask =0xF00000;
+
+ internal static readonly Type [] ClassTypes = {
+ typeof(System.Empty),
+ typeof(void),
+ typeof(Boolean),
+ typeof(Char),
+ typeof(SByte),
+ typeof(Byte),
+ typeof(Int16),
+ typeof(UInt16),
+ typeof(Int32),
+ typeof(UInt32),
+ typeof(Int64),
+ typeof(UInt64),
+ typeof(Single),
+ typeof(Double),
+ typeof(String),
+ typeof(void), // ptr for the moment
+ typeof(DateTime),
+ typeof(TimeSpan),
+ typeof(Object),
+ typeof(Decimal),
+ typeof(Object), // Treat enum as Object
+ typeof(System.Reflection.Missing),
+ typeof(System.DBNull),
+ };
+
+ internal static readonly Variant Empty = new Variant();
+ internal static readonly Variant Missing = new Variant(Variant.CV_MISSING, Type.Missing, 0, 0);
+ internal static readonly Variant DBNull = new Variant(Variant.CV_NULL, System.DBNull.Value, 0, 0);
+
+ //
+ // Native Methods
+ //
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ internal extern double GetR8FromVar();
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ internal extern float GetR4FromVar();
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ internal extern void SetFieldsR4(float val);
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ internal extern void SetFieldsR8(double val);
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ internal extern void SetFieldsObject(Object val);
+
+ // Use this function instead of an ECALL - saves about 150 clock cycles
+ // by avoiding the ecall transition and because the JIT inlines this.
+ // Ends up only taking about 1/8 the time of the ECALL version.
+ internal long GetI8FromVar()
+ {
+ return ((long)m_data2<<32 | ((long)m_data1 & 0xFFFFFFFFL));
+ }
+
+ //
+ // Constructors
+ //
+
+ internal Variant(int flags, Object or, int data1, int data2) {
+ m_flags = flags;
+ m_objref=or;
+ m_data1=data1;
+ m_data2=data2;
+ }
+
+ public Variant(bool val) {
+ m_objref= null;
+ m_flags = CV_BOOLEAN;
+ m_data1 = (val)?Boolean.True:Boolean.False;
+ m_data2 = 0;
+ }
+
+ public Variant(sbyte val) {
+ m_objref=null;
+ m_flags=CV_I1;
+ m_data1=(int)val;
+ m_data2=(int)(((long)val)>>32);
+ }
+
+
+ public Variant(byte val) {
+ m_objref=null;
+ m_flags=CV_U1;
+ m_data1=(int)val;
+ m_data2=0;
+ }
+
+ public Variant(short val) {
+ m_objref=null;
+ m_flags=CV_I2;
+ m_data1=(int)val;
+ m_data2=(int)(((long)val)>>32);
+ }
+
+ public Variant(ushort val) {
+ m_objref=null;
+ m_flags=CV_U2;
+ m_data1=(int)val;
+ m_data2=0;
+ }
+
+ public Variant(char val) {
+ m_objref=null;
+ m_flags=CV_CHAR;
+ m_data1=(int)val;
+ m_data2=0;
+ }
+
+ public Variant(int val) {
+ m_objref=null;
+ m_flags=CV_I4;
+ m_data1=val;
+ m_data2=val >> 31;
+ }
+
+ public Variant(uint val) {
+ m_objref=null;
+ m_flags=CV_U4;
+ m_data1=(int)val;
+ m_data2=0;
+ }
+
+ public Variant(long val) {
+ m_objref=null;
+ m_flags=CV_I8;
+ m_data1 = (int)val;
+ m_data2 = (int)(val >> 32);
+ }
+
+ public Variant(ulong val) {
+ m_objref=null;
+ m_flags=CV_U8;
+ m_data1 = (int)val;
+ m_data2 = (int)(val >> 32);
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public Variant(float val) {
+ m_objref=null;
+ m_flags=CV_R4;
+ m_data1=0;
+ m_data2=0;
+ SetFieldsR4(val);
+ }
+
+ [System.Security.SecurityCritical] // auto-generated
+ public Variant(double val) {
+ m_objref=null;
+ m_flags=CV_R8;
+ m_data1=0;
+ m_data2=0;
+ SetFieldsR8(val);
+ }
+
+ public Variant(DateTime val) {
+ m_objref=null;
+ m_flags=CV_DATETIME;
+ ulong ticks = (ulong)val.Ticks;
+ m_data1 = (int)ticks;
+ m_data2 = (int)(ticks>>32);
+ }
+
+ public Variant(Decimal val) {
+ m_objref = (Object)val;
+ m_flags = CV_DECIMAL;
+ m_data1=0;
+ m_data2=0;
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public Variant(Object obj) {
+ m_data1=0;
+ m_data2=0;
+
+ VarEnum vt = VarEnum.VT_EMPTY;
+
+ if (obj is DateTime) {
+ m_objref=null;
+ m_flags=CV_DATETIME;
+ ulong ticks = (ulong)((DateTime)obj).Ticks;
+ m_data1 = (int)ticks;
+ m_data2 = (int)(ticks>>32);
+ return;
+ }
+
+ if (obj is String) {
+ m_flags=CV_STRING;
+ m_objref=obj;
+ return;
+ }
+
+ if (obj == null) {
+ this = Empty;
+ return;
+ }
+ if (obj == System.DBNull.Value) {
+ this = DBNull;
+ return;
+ }
+ if (obj == Type.Missing) {
+ this = Missing;
+ return;
+ }
+
+ if (obj is Array) {
+ m_flags=CV_OBJECT | ArrayBitMask;
+ m_objref=obj;
+ return;
+ }
+
+ // Compiler appeasement
+ m_flags = CV_EMPTY;
+ m_objref = null;
+
+ // 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;
+ obj = ((DispatchWrapper)obj).WrappedObject;
+ }
+ else if (obj is ErrorWrapper)
+ {
+ vt = VarEnum.VT_ERROR;
+ obj = (Object)(((ErrorWrapper)obj).ErrorCode);
+ Contract.Assert(obj != null, "obj != null");
+ }
+ else if (obj is CurrencyWrapper)
+ {
+ vt = VarEnum.VT_CY;
+ obj = (Object)(((CurrencyWrapper)obj).WrappedObject);
+ Contract.Assert(obj != null, "obj != null");
+ }
+ else if (obj is BStrWrapper)
+ {
+ vt = VarEnum.VT_BSTR;
+ obj = (Object)(((BStrWrapper)obj).WrappedObject);
+ }
+
+ if (obj != null)
+ {
+ SetFieldsObject(obj);
+ }
+
+ // If the object passed in is one of the wrappers then set the VARIANT type.
+ if (vt != VarEnum.VT_EMPTY)
+ m_flags |= ((int)vt << VTBitShift);
+ }
+
+
+ [System.Security.SecurityCritical] // auto-generated
+ unsafe public Variant(void* voidPointer,Type pointerType) {
+ if (pointerType == null)
+ throw new ArgumentNullException("pointerType");
+ if (!pointerType.IsPointer)
+ throw new ArgumentException(Environment.GetResourceString("Arg_MustBePointer"),"pointerType");
+ Contract.EndContractBlock();
+
+ m_objref = pointerType;
+ m_flags=CV_PTR;
+ m_data1=(int)voidPointer;
+ m_data2=0;
+
+ }
+
+ //This is a family-only accessor for the CVType.
+ //This is never to be exposed externally.
+ internal int CVType {
+ get {
+ return (m_flags&TypeCodeBitMask);
+ }
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public Object ToObject() {
+ switch (CVType) {
+ case CV_EMPTY:
+ return null;
+ case CV_BOOLEAN:
+ return (Object)(m_data1!=0);
+ case CV_I1:
+ return (Object)((sbyte)m_data1);
+ case CV_U1:
+ return (Object)((byte)m_data1);
+ case CV_CHAR:
+ return (Object)((char)m_data1);
+ case CV_I2:
+ return (Object)((short)m_data1);
+ case CV_U2:
+ return (Object)((ushort)m_data1);
+ case CV_I4:
+ return (Object)(m_data1);
+ case CV_U4:
+ return (Object)((uint)m_data1);
+ case CV_I8:
+ return (Object)(GetI8FromVar());
+ case CV_U8:
+ return (Object)((ulong)GetI8FromVar());
+ case CV_R4:
+ return (Object)(GetR4FromVar());
+ case CV_R8:
+ return (Object)(GetR8FromVar());
+ case CV_DATETIME:
+ return new DateTime(GetI8FromVar());
+ case CV_TIMESPAN:
+ return new TimeSpan(GetI8FromVar());
+ case CV_ENUM:
+ return BoxEnum();
+ case CV_MISSING:
+ return Type.Missing;
+ case CV_NULL:
+ return System.DBNull.Value;
+ case CV_DECIMAL:
+ case CV_STRING:
+ case CV_OBJECT:
+ default:
+ return m_objref;
+ }
+ }
+
+ // This routine will return an boxed enum.
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private extern Object BoxEnum();
+
+
+ // Helper code for marshaling managed objects to VARIANT's (we use
+ // managed variants as an intermediate type.
+ [System.Security.SecuritySafeCritical] // auto-generated
+ internal static void MarshalHelperConvertObjectToVariant(Object o, ref Variant v)
+ {
+#if FEATURE_REMOTING
+ IConvertible ic = System.Runtime.Remoting.RemotingServices.IsTransparentProxy(o) ? null : o as IConvertible;
+#else
+ IConvertible ic = o as IConvertible;
+#endif
+ if (o == null)
+ {
+ v = Empty;
+ }
+ else if (ic == null)
+ {
+ // 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);
+ }
+ else
+ {
+ IFormatProvider provider = CultureInfo.InvariantCulture;
+ switch (ic.GetTypeCode())
+ {
+ case TypeCode.Empty:
+ v = Empty;
+ break;
+
+ case TypeCode.Object:
+ v = new Variant((Object)o);
+ break;
+
+ case TypeCode.DBNull:
+ v = DBNull;
+ break;
+
+ case TypeCode.Boolean:
+ v = new Variant(ic.ToBoolean(provider));
+ break;
+
+ case TypeCode.Char:
+ v = new Variant(ic.ToChar(provider));
+ break;
+
+ case TypeCode.SByte:
+ v = new Variant(ic.ToSByte(provider));
+ break;
+
+ case TypeCode.Byte:
+ v = new Variant(ic.ToByte(provider));
+ break;
+
+ case TypeCode.Int16:
+ v = new Variant(ic.ToInt16(provider));
+ break;
+
+ case TypeCode.UInt16:
+ v = new Variant(ic.ToUInt16(provider));
+ break;
+
+ case TypeCode.Int32:
+ v = new Variant(ic.ToInt32(provider));
+ break;
+
+ case TypeCode.UInt32:
+ v = new Variant(ic.ToUInt32(provider));
+ break;
+
+ case TypeCode.Int64:
+ v = new Variant(ic.ToInt64(provider));
+ break;
+
+ case TypeCode.UInt64:
+ v = new Variant(ic.ToUInt64(provider));
+ break;
+
+ case TypeCode.Single:
+ v = new Variant(ic.ToSingle(provider));
+ break;
+
+ case TypeCode.Double:
+ v = new Variant(ic.ToDouble(provider));
+ break;
+
+ case TypeCode.Decimal:
+ v = new Variant(ic.ToDecimal(provider));
+ break;
+
+ case TypeCode.DateTime:
+ v = new Variant(ic.ToDateTime(provider));
+ break;
+
+ case TypeCode.String:
+ v = new Variant(ic.ToString(provider));
+ break;
+
+ default:
+ throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnknownTypeCode", ic.GetTypeCode()));
+ }
+ }
+ }
+
+ // 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.
+ [System.Security.SecurityCritical] // auto-generated
+ internal static void MarshalHelperCastVariant(Object pValue, int vt, ref Variant v)
+ {
+ IConvertible iv = pValue as IConvertible;
+ if (iv == null)
+ {
+ switch (vt)
+ {
+ case 9: /*VT_DISPATCH*/
+ v = new Variant(new DispatchWrapper(pValue));
+ break;
+
+ case 12: /*VT_VARIANT*/
+ v = new Variant(pValue);
+ break;
+
+ case 13: /*VT_UNKNOWN*/
+ v = new Variant(new UnknownWrapper(pValue));
+ break;
+
+ case 36: /*VT_RECORD*/
+ v = new Variant(pValue);
+ break;
+
+ case 8: /*VT_BSTR*/
+ if (pValue == null)
+ {
+ v = new Variant(null);
+ v.m_flags = CV_STRING;
+ }
+ else
+ {
+ throw new InvalidCastException(Environment.GetResourceString("InvalidCast_CannotCoerceByRefVariant"));
+ }
+ break;
+
+ default:
+ throw new InvalidCastException(Environment.GetResourceString("InvalidCast_CannotCoerceByRefVariant"));
+ }
+ }
+ else
+ {
+ IFormatProvider provider = CultureInfo.InvariantCulture;
+ switch (vt)
+ {
+ case 0: /*VT_EMPTY*/
+ v = Empty;
+ break;
+
+ case 1: /*VT_NULL*/
+ v = DBNull;
+ break;
+
+ case 2: /*VT_I2*/
+ v = new Variant(iv.ToInt16(provider));
+ break;
+
+ case 3: /*VT_I4*/
+ v = new Variant(iv.ToInt32(provider));
+ break;
+
+ case 4: /*VT_R4*/
+ v = new Variant(iv.ToSingle(provider));
+ break;
+
+ case 5: /*VT_R8*/
+ v = new Variant(iv.ToDouble(provider));
+ break;
+
+ case 6: /*VT_CY*/
+ v = new Variant(new CurrencyWrapper(iv.ToDecimal(provider)));
+ break;
+
+ case 7: /*VT_DATE*/
+ v = new Variant(iv.ToDateTime(provider));
+ break;
+
+ case 8: /*VT_BSTR*/
+ v = new Variant(iv.ToString(provider));
+ break;
+
+ case 9: /*VT_DISPATCH*/
+ v = new Variant(new DispatchWrapper((Object)iv));
+ break;
+
+ case 10: /*VT_ERROR*/
+ v = new Variant(new ErrorWrapper(iv.ToInt32(provider)));
+ break;
+
+ case 11: /*VT_BOOL*/
+ v = new Variant(iv.ToBoolean(provider));
+ break;
+
+ case 12: /*VT_VARIANT*/
+ v = new Variant((Object)iv);
+ break;
+
+ case 13: /*VT_UNKNOWN*/
+ v = new Variant(new UnknownWrapper((Object)iv));
+ break;
+
+ case 14: /*VT_DECIMAL*/
+ v = new Variant(iv.ToDecimal(provider));
+ break;
+
+ // case 15: /*unused*/
+ // NOT SUPPORTED
+
+ case 16: /*VT_I1*/
+ v = new Variant(iv.ToSByte(provider));
+ break;
+
+ case 17: /*VT_UI1*/
+ v = new Variant(iv.ToByte(provider));
+ break;
+
+ case 18: /*VT_UI2*/
+ v = new Variant(iv.ToUInt16(provider));
+ break;
+
+ case 19: /*VT_UI4*/
+ v = new Variant(iv.ToUInt32(provider));
+ break;
+
+ case 20: /*VT_I8*/
+ v = new Variant(iv.ToInt64(provider));
+ break;
+
+ case 21: /*VT_UI8*/
+ v = new Variant(iv.ToUInt64(provider));
+ break;
+
+ case 22: /*VT_INT*/
+ v = new Variant(iv.ToInt32(provider));
+ break;
+
+ case 23: /*VT_UINT*/
+ v = new Variant(iv.ToUInt32(provider));
+ break;
+
+ default:
+ throw new InvalidCastException(Environment.GetResourceString("InvalidCast_CannotCoerceByRefVariant"));
+ }
+ }
+ }
+ }
+}