The Labs \ Source Viewer \ SSCLI \ System \ Variant

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. /*============================================================
  16. **
  17. ** Class:  Variant
  18. **
  19. **
  20. ** Purpose: The CLR implementation of Variant.
  21. **
  22. **
  23. ===========================================================*/
  24. namespace System
  25. {
  26.    
  27.     using System;
  28.     using System.Reflection;
  29.     using System.Threading;
  30.     using System.Runtime.InteropServices;
  31.     using System.Globalization;
  32.     using System.Runtime.CompilerServices;
  33.    
  34.     [Serializable()]
  35.     [StructLayout(LayoutKind.Sequential)]
  36.     internal struct Variant
  37.     {
  38.        
  39.         //Do Not change the order of these fields.
  40.         //They are mapped to the native VariantData * data structure.
  41.         private object m_objref;
  42.         private int m_data1;
  43.         private int m_data2;
  44.         private int m_flags;
  45.        
  46.        
  47.         // The following will call the internal routines to initalize the
  48.         // native side of variant.
  49.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  50.         private static extern void InitVariant();
  51.         static Variant()
  52.         {
  53.             InitVariant();
  54.         }
  55.        
  56.         private static Type _voidPtr = null;
  57.        
  58.         // The following bits have been taken up as follows
  59.         // bits 0-15 - Type code
  60.         // bit 16 - Array
  61.         // bits 19-23 - Enums
  62.         // bits 24-31 - Optional VT code (for roundtrip VT preservation)
  63.        
  64.        
  65.         //What are the consequences of making this an enum?
  66.         ///////////////////////////////////////////////////////////////////////
  67.         // If you update this, update the corresponding stuff in OAVariantLib.cs,
  68.         // COMOAVariant.cpp (2 tables, forwards and reverse), and perhaps OleVariant.h
  69.         ///////////////////////////////////////////////////////////////////////
  70.         internal const int CV_EMPTY = 0;
  71.         internal const int CV_VOID = 1;
  72.         internal const int CV_BOOLEAN = 2;
  73.         internal const int CV_CHAR = 3;
  74.         internal const int CV_I1 = 4;
  75.         internal const int CV_U1 = 5;
  76.         internal const int CV_I2 = 6;
  77.         internal const int CV_U2 = 7;
  78.         internal const int CV_I4 = 8;
  79.         internal const int CV_U4 = 9;
  80.         internal const int CV_I8 = 10;
  81.         internal const int CV_U8 = 11;
  82.         internal const int CV_R4 = 12;
  83.         internal const int CV_R8 = 13;
  84.         internal const int CV_STRING = 14;
  85.         internal const int CV_PTR = 15;
  86.         internal const int CV_DATETIME = 16;
  87.         internal const int CV_TIMESPAN = 17;
  88.         internal const int CV_OBJECT = 18;
  89.         internal const int CV_DECIMAL = 19;
  90.         internal const int CV_ENUM = 21;
  91.         internal const int CV_MISSING = 22;
  92.         internal const int CV_NULL = 23;
  93.         internal const int CV_LAST = 24;
  94.        
  95.         internal const int TypeCodeBitMask = 65535;
  96.         internal const int VTBitMask = unchecked((int)4278190080u);
  97.         internal const int VTBitShift = 24;
  98.         internal const int ArrayBitMask = 65536;
  99.        
  100.         // Enum enum and Mask
  101.         internal const int EnumI1 = 1048576;
  102.         internal const int EnumU1 = 2097152;
  103.         internal const int EnumI2 = 3145728;
  104.         internal const int EnumU2 = 4194304;
  105.         internal const int EnumI4 = 5242880;
  106.         internal const int EnumU4 = 6291456;
  107.         internal const int EnumI8 = 7340032;
  108.         internal const int EnumU8 = 8388608;
  109.         internal const int EnumMask = 15728640;
  110.        
  111.         static internal readonly Type[] ClassTypes = {typeof(System.Empty), typeof(void), typeof(bool), typeof(char), typeof(sbyte), typeof(byte), typeof(Int16), typeof(UInt16), typeof(Int32), typeof(UInt32),
  112.         typeof(Int64), typeof(UInt64), typeof(float), typeof(double), typeof(string), typeof(void), typeof(DateTime), typeof(TimeSpan), typeof(object), typeof(decimal),
  113.             // ptr for the moment
  114.             // Treat enum as Object
  115.         typeof(object), typeof(System.Reflection.Missing), typeof(System.DBNull)};
  116.        
  117.         static internal readonly Variant Empty = new Variant();
  118.         static internal readonly Variant Missing = new Variant(Variant.CV_MISSING, Type.Missing, 0, 0);
  119.         static internal readonly Variant DBNull = new Variant(Variant.CV_NULL, System.DBNull.Value, 0, 0);
  120.        
  121.         //
  122.         // Native Methods
  123.         //
  124.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  125.         internal extern double GetR8FromVar();
  126.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  127.         internal extern float GetR4FromVar();
  128.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  129.         internal extern void SetFieldsR4(float val);
  130.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  131.         internal extern void SetFieldsR8(double val);
  132.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  133.         internal extern void SetFieldsObject(object val);
  134.        
  135.         // Use this function instead of an ECALL - saves about 150 clock cycles
  136.         // by avoiding the ecall transition and because the JIT inlines this.
  137.         // Ends up only taking about 1/8 the time of the ECALL version.
  138.         internal long GetI8FromVar()
  139.         {
  140.             return ((long)m_data2 << 32 | ((long)m_data1 & 4294967295ul));
  141.         }
  142.        
  143.         //
  144.         // Constructors
  145.         //
  146.        
  147.         internal Variant(int flags, object or, int data1, int data2)
  148.         {
  149.             m_flags = flags;
  150.             m_objref = or;
  151.             m_data1 = data1;
  152.             m_data2 = data2;
  153.         }
  154.        
  155.         public Variant(bool val)
  156.         {
  157.             m_objref = null;
  158.             m_flags = CV_BOOLEAN;
  159.             m_data1 = (val) ? Boolean.True : Boolean.False;
  160.             m_data2 = 0;
  161.         }
  162.        
  163.         public Variant(sbyte val)
  164.         {
  165.             m_objref = null;
  166.             m_flags = CV_I1;
  167.             m_data1 = (int)val;
  168.             m_data2 = (int)(((long)val) >> 32);
  169.         }
  170.        
  171.        
  172.         public Variant(byte val)
  173.         {
  174.             m_objref = null;
  175.             m_flags = CV_U1;
  176.             m_data1 = (int)val;
  177.             m_data2 = 0;
  178.         }
  179.        
  180.         public Variant(short val)
  181.         {
  182.             m_objref = null;
  183.             m_flags = CV_I2;
  184.             m_data1 = (int)val;
  185.             m_data2 = (int)(((long)val) >> 32);
  186.         }
  187.        
  188.         public Variant(ushort val)
  189.         {
  190.             m_objref = null;
  191.             m_flags = CV_U2;
  192.             m_data1 = (int)val;
  193.             m_data2 = 0;
  194.         }
  195.        
  196.         public Variant(char val)
  197.         {
  198.             m_objref = null;
  199.             m_flags = CV_CHAR;
  200.             m_data1 = (int)val;
  201.             m_data2 = 0;
  202.         }
  203.        
  204.         public Variant(int val)
  205.         {
  206.             m_objref = null;
  207.             m_flags = CV_I4;
  208.             m_data1 = val;
  209.             m_data2 = val >> 31;
  210.         }
  211.        
  212.         public Variant(uint val)
  213.         {
  214.             m_objref = null;
  215.             m_flags = CV_U4;
  216.             m_data1 = (int)val;
  217.             m_data2 = 0;
  218.         }
  219.        
  220.         public Variant(long val)
  221.         {
  222.             m_objref = null;
  223.             m_flags = CV_I8;
  224.             m_data1 = (int)val;
  225.             m_data2 = (int)(val >> 32);
  226.         }
  227.        
  228.         public Variant(ulong val)
  229.         {
  230.             m_objref = null;
  231.             m_flags = CV_U8;
  232.             m_data1 = (int)val;
  233.             m_data2 = (int)(val >> 32);
  234.         }
  235.        
  236.         public Variant(float val)
  237.         {
  238.             m_objref = null;
  239.             m_flags = CV_R4;
  240.             m_data1 = 0;
  241.             m_data2 = 0;
  242.             SetFieldsR4(val);
  243.         }
  244.        
  245.         public Variant(double val)
  246.         {
  247.             m_objref = null;
  248.             m_flags = CV_R8;
  249.             m_data1 = 0;
  250.             m_data2 = 0;
  251.             SetFieldsR8(val);
  252.         }
  253.        
  254.         public Variant(DateTime val)
  255.         {
  256.             m_objref = null;
  257.             m_flags = CV_DATETIME;
  258.             ulong ticks = (ulong)val.Ticks;
  259.             m_data1 = (int)ticks;
  260.             m_data2 = (int)(ticks >> 32);
  261.         }
  262.        
  263.         public Variant(decimal val)
  264.         {
  265.             m_objref = (object)val;
  266.             m_flags = CV_DECIMAL;
  267.             m_data1 = 0;
  268.             m_data2 = 0;
  269.         }
  270.        
  271.         public Variant(object obj)
  272.         {
  273.             m_data1 = 0;
  274.             m_data2 = 0;
  275.            
  276.             VarEnum vt = VarEnum.VT_EMPTY;
  277.            
  278.             if (obj is DateTime) {
  279.                 m_objref = null;
  280.                 m_flags = CV_DATETIME;
  281.                 ulong ticks = (ulong)((DateTime)obj).Ticks;
  282.                 m_data1 = (int)ticks;
  283.                 m_data2 = (int)(ticks >> 32);
  284.                 return;
  285.             }
  286.            
  287.             if (obj is string) {
  288.                 m_flags = CV_STRING;
  289.                 m_objref = obj;
  290.                 return;
  291.             }
  292.            
  293.             if (obj == null) {
  294.                 this = Empty;
  295.                 return;
  296.             }
  297.             if (obj == System.DBNull.Value) {
  298.                 this = DBNull;
  299.                 return;
  300.             }
  301.             if (obj == Type.Missing) {
  302.                 this = Missing;
  303.                 return;
  304.             }
  305.            
  306.             if (obj is Array) {
  307.                 m_flags = CV_OBJECT | ArrayBitMask;
  308.                 m_objref = obj;
  309.                 return;
  310.             }
  311.            
  312.             // Compiler appeasement
  313.             m_flags = CV_EMPTY;
  314.             m_objref = null;
  315.            
  316.            
  317.             if (obj != null) {
  318.                 SetFieldsObject(obj);
  319.             }
  320.            
  321.             // If the object passed in is one of the wrappers then set the VARIANT type.
  322.             if (vt != VarEnum.VT_EMPTY)
  323.                 m_flags |= ((int)vt << VTBitShift);
  324.         }
  325.        
  326.        
  327.         unsafe public Variant(void* voidPointer, Type pointerType)
  328.         {
  329.             if (pointerType == null)
  330.                 throw new ArgumentNullException("pointerType");
  331.             if (!pointerType.IsPointer)
  332.                 throw new ArgumentException(Environment.GetResourceString("Arg_MustBePointer"), "pointerType");
  333.            
  334.             m_objref = pointerType;
  335.             m_flags = CV_PTR;
  336.             m_data1 = (int)voidPointer;
  337.             m_data2 = 0;
  338.            
  339.         }
  340.        
  341.         //This is a family-only accessor for the CVType.
  342.         //This is never to be exposed externally.
  343.         internal int CVType {
  344.             get { return (m_flags & TypeCodeBitMask); }
  345.         }
  346.        
  347.         public object ToObject()
  348.         {
  349.             switch (CVType) {
  350.                 case CV_EMPTY:
  351.                     return null;
  352.                 case CV_BOOLEAN:
  353.                     return (object)(m_data1 != 0);
  354.                 case CV_I1:
  355.                     return (object)((sbyte)m_data1);
  356.                 case CV_U1:
  357.                     return (object)((byte)m_data1);
  358.                 case CV_CHAR:
  359.                     return (object)((char)m_data1);
  360.                 case CV_I2:
  361.                     return (object)((short)m_data1);
  362.                 case CV_U2:
  363.                     return (object)((ushort)m_data1);
  364.                 case CV_I4:
  365.                     return (object)(m_data1);
  366.                 case CV_U4:
  367.                     return (object)((uint)m_data1);
  368.                 case CV_I8:
  369.                     return (object)(GetI8FromVar());
  370.                 case CV_U8:
  371.                     return (object)((ulong)GetI8FromVar());
  372.                 case CV_R4:
  373.                     return (object)(GetR4FromVar());
  374.                 case CV_R8:
  375.                     return (object)(GetR8FromVar());
  376.                 case CV_DATETIME:
  377.                     return new DateTime(GetI8FromVar());
  378.                 case CV_TIMESPAN:
  379.                     return new TimeSpan(GetI8FromVar());
  380.                 case CV_ENUM:
  381.                     return BoxEnum();
  382.                 case CV_MISSING:
  383.                     return Type.Missing;
  384.                 case CV_NULL:
  385.                     return System.DBNull.Value;
  386.                 case CV_DECIMAL:
  387.                 case CV_STRING:
  388.                 case CV_OBJECT:
  389.                 default:
  390.                     return m_objref;
  391.             }
  392.         }
  393.        
  394.        
  395.         // This routine will return an boxed enum.
  396.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  397.         private extern object BoxEnum();
  398.        
  399.        
  400.         // Helper code for marshaling managed objects to VARIANT's (we use
  401.         // managed variants as an intermediate type.
  402.         static internal void MarshalHelperConvertObjectToVariant(object o, ref Variant v)
  403.         {
  404.             IConvertible ic = System.Runtime.Remoting.RemotingServices.IsTransparentProxy(o) ? null : o as IConvertible;
  405.             if (o == null) {
  406.                 v = Empty;
  407.             }
  408.             else if (ic == null) {
  409.                 // This path should eventually go away. But until
  410.                 // the work is done to have all of our wrapper types implement
  411.                 // IConvertible, this is a cheapo way to get the work done.
  412.                 v = new Variant(o);
  413.             }
  414.             else {
  415.                 IFormatProvider provider = CultureInfo.InvariantCulture;
  416.                 switch (ic.GetTypeCode()) {
  417.                     case TypeCode.Empty:
  418.                         v = Empty;
  419.                         break;
  420.                     case TypeCode.Object:
  421.                        
  422.                         v = new Variant((object)o);
  423.                         break;
  424.                     case TypeCode.DBNull:
  425.                        
  426.                         v = DBNull;
  427.                         break;
  428.                     case TypeCode.Boolean:
  429.                        
  430.                         v = new Variant(ic.ToBoolean(provider));
  431.                         break;
  432.                     case TypeCode.Char:
  433.                        
  434.                         v = new Variant(ic.ToChar(provider));
  435.                         break;
  436.                     case TypeCode.SByte:
  437.                        
  438.                         v = new Variant(ic.ToSByte(provider));
  439.                         break;
  440.                     case TypeCode.Byte:
  441.                        
  442.                         v = new Variant(ic.ToByte(provider));
  443.                         break;
  444.                     case TypeCode.Int16:
  445.                        
  446.                         v = new Variant(ic.ToInt16(provider));
  447.                         break;
  448.                     case TypeCode.UInt16:
  449.                        
  450.                         v = new Variant(ic.ToUInt16(provider));
  451.                         break;
  452.                     case TypeCode.Int32:
  453.                        
  454.                         v = new Variant(ic.ToInt32(provider));
  455.                         break;
  456.                     case TypeCode.UInt32:
  457.                        
  458.                         v = new Variant(ic.ToUInt32(provider));
  459.                         break;
  460.                     case TypeCode.Int64:
  461.                        
  462.                         v = new Variant(ic.ToInt64(provider));
  463.                         break;
  464.                     case TypeCode.UInt64:
  465.                        
  466.                         v = new Variant(ic.ToUInt64(provider));
  467.                         break;
  468.                     case TypeCode.Single:
  469.                        
  470.                         v = new Variant(ic.ToSingle(provider));
  471.                         break;
  472.                     case TypeCode.Double:
  473.                        
  474.                         v = new Variant(ic.ToDouble(provider));
  475.                         break;
  476.                     case TypeCode.Decimal:
  477.                        
  478.                         v = new Variant(ic.ToDecimal(provider));
  479.                         break;
  480.                     case TypeCode.DateTime:
  481.                        
  482.                         v = new Variant(ic.ToDateTime(provider));
  483.                         break;
  484.                     case TypeCode.String:
  485.                        
  486.                         v = new Variant(ic.ToString(provider));
  487.                         break;
  488.                     default:
  489.                        
  490.                         throw new NotSupportedException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("NotSupported_UnknownTypeCode"), ic.GetTypeCode()));
  491.                         break;
  492.                 }
  493.             }
  494.         }
  495.        
  496.         // Helper code for marshaling VARIANTS to managed objects (we use
  497.         // managed variants as an intermediate type.
  498.         static internal object MarshalHelperConvertVariantToObject(ref Variant v)
  499.         {
  500.             return v.ToObject();
  501.         }
  502.        
  503.         // Helper code: on the back propagation path where a VT_BYREF VARIANT*
  504.         // is marshaled to a "ref Object", we use this helper to force the
  505.         // updated object back to the original type.
  506.         static internal void MarshalHelperCastVariant(object pValue, int vt, ref Variant v)
  507.         {
  508.             IConvertible iv = pValue as IConvertible;
  509.             if (iv == null) {
  510.                 switch (vt) {
  511.                     case 12:
  512.                        
  513.                         /*VT_VARIANT*/v = new Variant(pValue);
  514.                         break;
  515.                     case 36:
  516.                        
  517.                        
  518.                         /*VT_RECORD*/v = new Variant(pValue);
  519.                         break;
  520.                     case 8:
  521.                        
  522.                         /*VT_BSTR*/if (pValue == null) {
  523.                             v = new Variant(null);
  524.                             v.m_flags = CV_STRING;
  525.                         }
  526.                         else {
  527.                             throw new InvalidCastException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("InvalidCast_CannotCoerceByRefVariant")));
  528.                         }
  529.                         break;
  530.                     default:
  531.                        
  532.                         throw new InvalidCastException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("InvalidCast_CannotCoerceByRefVariant")));
  533.                         break;
  534.                 }
  535.             }
  536.             else {
  537.                 IFormatProvider provider = CultureInfo.InvariantCulture;
  538.                 switch (vt) {
  539.                     case 0:
  540.                         /*VT_EMPTY*/v = Empty;
  541.                         break;
  542.                     case 1:
  543.                        
  544.                         /*VT_NULL*/v = DBNull;
  545.                         break;
  546.                     case 2:
  547.                        
  548.                         /*VT_I2*/v = new Variant(iv.ToInt16(provider));
  549.                         break;
  550.                     case 3:
  551.                        
  552.                         /*VT_I4*/v = new Variant(iv.ToInt32(provider));
  553.                         break;
  554.                     case 4:
  555.                        
  556.                         /*VT_R4*/v = new Variant(iv.ToSingle(provider));
  557.                         break;
  558.                     case 5:
  559.                        
  560.                         /*VT_R8*/v = new Variant(iv.ToDouble(provider));
  561.                         break;
  562.                     case 7:
  563.                        
  564.                        
  565.                         /*VT_DATE*/v = new Variant(iv.ToDateTime(provider));
  566.                         break;
  567.                     case 8:
  568.                        
  569.                         /*VT_BSTR*/v = new Variant(iv.ToString(provider));
  570.                         break;
  571.                     case 11:
  572.                        
  573.                        
  574.                         /*VT_BOOL*/v = new Variant(iv.ToBoolean(provider));
  575.                         break;
  576.                     case 12:
  577.                        
  578.                         /*VT_VARIANT*/v = new Variant((object)iv);
  579.                         break;
  580.                     case 14:
  581.                        
  582.                        
  583.                         /*VT_DECIMAL*/v = new Variant(iv.ToDecimal(provider));
  584.                         break;
  585.                     case 16:
  586.                        
  587.                         // case 15: /*unused*/
  588.                         // NOT SUPPORTED
  589.                        
  590.                         /*VT_I1*/v = new Variant(iv.ToSByte(provider));
  591.                         break;
  592.                     case 17:
  593.                        
  594.                         /*VT_UI1*/v = new Variant(iv.ToByte(provider));
  595.                         break;
  596.                     case 18:
  597.                        
  598.                         /*VT_UI2*/v = new Variant(iv.ToUInt16(provider));
  599.                         break;
  600.                     case 19:
  601.                        
  602.                         /*VT_UI4*/v = new Variant(iv.ToUInt32(provider));
  603.                         break;
  604.                     case 20:
  605.                        
  606.                         /*VT_I8*/v = new Variant(iv.ToInt64(provider));
  607.                         break;
  608.                     case 21:
  609.                        
  610.                         /*VT_UI8*/v = new Variant(iv.ToUInt64(provider));
  611.                         break;
  612.                     case 22:
  613.                        
  614.                         /*VT_INT*/v = new Variant(iv.ToInt32(provider));
  615.                         break;
  616.                     case 23:
  617.                        
  618.                         /*VT_UINT*/v = new Variant(iv.ToUInt32(provider));
  619.                         break;
  620.                     default:
  621.                        
  622.                         throw new InvalidCastException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("InvalidCast_CannotCoerceByRefVariant")));
  623.                         break;
  624.                 }
  625.             }
  626.         }
  627.     }
  628. }

Developer Fusion