Variant.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / clr / src / BCL / System / Runtime / InteropServices / Variant.cs / 1305376 / Variant.cs

                            /* **************************************************************************** 
 *
 * Copyright (c) Microsoft Corporation.
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 * 
 * You must not remove this notice, or any other, from this software.
 *
 *
 * ***************************************************************************/ 

 
namespace System.Runtime.InteropServices { 
    using System.Diagnostics;
 
    /// 
    /// Variant is the basic COM type for late-binding. It can contain any other COM data type.
    /// This type definition precisely matches the unmanaged data layout so that the struct can be passed
    /// to and from COM calls. 
    /// 
    [StructLayout(LayoutKind.Explicit)] 
    [System.Security.SecurityCritical] 
    internal struct Variant {
 
#if DEBUG
        static Variant() {
            // Variant size is the size of 4 pointers (16 bytes) on a 32-bit processor,
            // and 3 pointers (24 bytes) on a 64-bit processor. 
            int variantSize = Marshal.SizeOf(typeof(Variant));
            if (IntPtr.Size == 4) { 
                BCLDebug.Assert(variantSize == (4 * IntPtr.Size), "variant"); 
            } else {
                BCLDebug.Assert(IntPtr.Size == 8, "variant"); 
                BCLDebug.Assert(variantSize == (3 * IntPtr.Size), "variant");
            }
        }
#endif 

        // Most of the data types in the Variant are carried in _typeUnion 
        [FieldOffset(0)] private TypeUnion _typeUnion; 

        // Decimal is the largest data type and it needs to use the space that is normally unused in TypeUnion._wReserved1, etc. 
        // Hence, it is declared to completely overlap with TypeUnion. A Decimal does not use the first two bytes, and so
        // TypeUnion._vt can still be used to encode the type.
        [FieldOffset(0)] private Decimal _decimal;
 
        [StructLayout(LayoutKind.Sequential)]
        private struct TypeUnion { 
            internal ushort _vt; 
            internal ushort _wReserved1;
            internal ushort _wReserved2; 
            internal ushort _wReserved3;

            internal UnionTypes _unionTypes;
        } 

        [StructLayout(LayoutKind.Sequential)] 
        private struct Record { 
            private IntPtr _record;
            private IntPtr _recordInfo; 
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1049:TypesThatOwnNativeResourcesShouldBeDisposable")]
        [StructLayout(LayoutKind.Explicit)] 
        private struct UnionTypes {
            #region Generated Variant union types 
 
            // *** BEGIN GENERATED CODE ***
            // generated by function: gen_UnionTypes from: generate_comdispatch.py 

            [FieldOffset(0)] internal SByte _i1;
            [FieldOffset(0)] internal Int16 _i2;
            [FieldOffset(0)] internal Int32 _i4; 
            [FieldOffset(0)] internal Int64 _i8;
            [FieldOffset(0)] internal Byte _ui1; 
            [FieldOffset(0)] internal UInt16 _ui2; 
            [FieldOffset(0)] internal UInt32 _ui4;
            [FieldOffset(0)] internal UInt64 _ui8; 
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
            [FieldOffset(0)] internal IntPtr _int;
            [FieldOffset(0)] internal UIntPtr _uint;
            [FieldOffset(0)] internal Int32 _bool; 
            [FieldOffset(0)] internal Int32 _error;
            [FieldOffset(0)] internal Single _r4; 
            [FieldOffset(0)] internal Double _r8; 
            [FieldOffset(0)] internal Int64 _cy;
            [FieldOffset(0)] internal double _date; 
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
            [FieldOffset(0)] internal IntPtr _bstr;
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
            [FieldOffset(0)] internal IntPtr _unknown; 
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
            [FieldOffset(0)] internal IntPtr _dispatch; 
 
            // *** END GENERATED CODE ***
 
            #endregion

            [FieldOffset(0)] internal IntPtr _byref;
            [FieldOffset(0)] internal Record _record; 
        }
 
        ///  
        /// Primitive types are the basic COM types. It includes valuetypes like ints, but also reference types
        /// like BStrs. It does not include composite types like arrays and user-defined COM types (IUnknown/IDispatch). 
        /// 
        internal static bool IsPrimitiveType(VarEnum varEnum) {
            switch(varEnum) {
                #region Generated Variant IsPrimitiveType 

                // *** BEGIN GENERATED CODE *** 
                // generated by function: gen_IsPrimitiveType from: generate_comdispatch.py 

                case VarEnum.VT_I1: 
                case VarEnum.VT_I2:
                case VarEnum.VT_I4:
                case VarEnum.VT_I8:
                case VarEnum.VT_UI1: 
                case VarEnum.VT_UI2:
                case VarEnum.VT_UI4: 
                case VarEnum.VT_UI8: 
                case VarEnum.VT_INT:
                case VarEnum.VT_UINT: 
                case VarEnum.VT_BOOL:
                case VarEnum.VT_R4:
                case VarEnum.VT_R8:
                case VarEnum.VT_DECIMAL: 
                case VarEnum.VT_DATE:
                case VarEnum.VT_BSTR: 
 
                // *** END GENERATED CODE ***
 
                #endregion
                    return true;
            }
 
            return false;
        } 
 
        unsafe public void CopyFromIndirect(object value) {
 
            VarEnum vt = (VarEnum)(((int)this.VariantType) & ~((int)VarEnum.VT_BYREF));

            if (value == null) {
                if (vt == VarEnum.VT_DISPATCH || vt == VarEnum.VT_UNKNOWN || vt == VarEnum.VT_BSTR) { 
                    *(IntPtr*)this._typeUnion._unionTypes._byref = IntPtr.Zero;
                } 
                return; 
            }
 
            switch (vt) {
                case VarEnum.VT_I1:
                    *(sbyte*)this._typeUnion._unionTypes._byref = (sbyte)value;
                    break; 

                case VarEnum.VT_UI1: 
                    *(byte*)this._typeUnion._unionTypes._byref = (byte)value; 
                    break;
 
                case VarEnum.VT_I2:
                    *(short*)this._typeUnion._unionTypes._byref = (short)value;
                    break;
 
                case VarEnum.VT_UI2:
                    *(ushort*)this._typeUnion._unionTypes._byref = (ushort)value; 
                    break; 

                case VarEnum.VT_BOOL: 
                    *(short*)this._typeUnion._unionTypes._byref = (bool)value ? (short)-1 : (short)0;
                    break;

                case VarEnum.VT_I4: 
                case VarEnum.VT_INT:
                    *(int*)this._typeUnion._unionTypes._byref = (int)value; 
                    break; 

                case VarEnum.VT_UI4: 
                case VarEnum.VT_UINT:
                    *(uint*)this._typeUnion._unionTypes._byref = (uint)value;
                    break;
 
                case VarEnum.VT_ERROR:
                    *(int*)this._typeUnion._unionTypes._byref = ((ErrorWrapper)value).ErrorCode; 
                    break; 

                case VarEnum.VT_I8: 
                    *(Int64*)this._typeUnion._unionTypes._byref = (Int64)value;
                    break;

                case VarEnum.VT_UI8: 
                    *(UInt64*)this._typeUnion._unionTypes._byref = (UInt64)value;
                    break; 
 
                case VarEnum.VT_R4:
                    *(float*)this._typeUnion._unionTypes._byref = (float)value; 
                    break;

                case VarEnum.VT_R8:
                    *(double*)this._typeUnion._unionTypes._byref = (double)value; 
                    break;
 
                case VarEnum.VT_DATE: 
                    *(double*)this._typeUnion._unionTypes._byref = ((DateTime)value).ToOADate();
                    break; 

                case VarEnum.VT_UNKNOWN:
                    *(IntPtr*)this._typeUnion._unionTypes._byref = Marshal.GetIUnknownForObject(value);
                    break; 

                case VarEnum.VT_DISPATCH: 
                    *(IntPtr*)this._typeUnion._unionTypes._byref = Marshal.GetIDispatchForObject(value); 
                    break;
 
                case VarEnum.VT_BSTR:
                    *(IntPtr*)this._typeUnion._unionTypes._byref = Marshal.StringToBSTR((string)value);
                    break;
 
                case VarEnum.VT_CY:
                    *(long*)this._typeUnion._unionTypes._byref = decimal.ToOACurrency((decimal)value); 
                    break; 

                case VarEnum.VT_DECIMAL: 
                    *(decimal*)this._typeUnion._unionTypes._byref = (decimal)value;
                    break;

                default: 
                    throw new ArgumentException("invalid argument type");
            } 
        } 

        ///  
        /// Get the managed object representing the Variant.
        /// 
        /// 
        public object ToObject() { 
            // Check the simple case upfront
            if (IsEmpty) { 
                return null; 
            }
 
            switch (VariantType) {
                case VarEnum.VT_NULL: return DBNull.Value;

                #region Generated Variant ToObject 

                // *** BEGIN GENERATED CODE *** 
                // generated by function: gen_ToObject from: generate_comdispatch.py 

                case VarEnum.VT_I1: return AsI1; 
                case VarEnum.VT_I2: return AsI2;
                case VarEnum.VT_I4: return AsI4;
                case VarEnum.VT_I8: return AsI8;
                case VarEnum.VT_UI1: return AsUi1; 
                case VarEnum.VT_UI2: return AsUi2;
                case VarEnum.VT_UI4: return AsUi4; 
                case VarEnum.VT_UI8: return AsUi8; 
                case VarEnum.VT_INT: return AsInt;
                case VarEnum.VT_UINT: return AsUint; 
                case VarEnum.VT_BOOL: return AsBool;
                case VarEnum.VT_ERROR: return AsError;
                case VarEnum.VT_R4: return AsR4;
                case VarEnum.VT_R8: return AsR8; 
                case VarEnum.VT_DECIMAL: return AsDecimal;
                case VarEnum.VT_CY: return AsCy; 
                case VarEnum.VT_DATE: return AsDate; 
                case VarEnum.VT_BSTR: return AsBstr;
                case VarEnum.VT_UNKNOWN: return AsUnknown; 
                case VarEnum.VT_DISPATCH: return AsDispatch;

                // *** END GENERATED CODE ***
 
                #endregion
 
                default: 
                    try {
                        unsafe { 
                            fixed (void* pThis = &this) {
                                return Marshal.GetObjectForNativeVariant((System.IntPtr)pThis);
                            }
                        } 
                    }
                    catch (Exception ex) { 
                        throw new NotImplementedException("Variant.ToObject cannot handle" + VariantType, ex); 
                    }
            } 
        }

        /// 
        /// Release any unmanaged memory associated with the Variant 
        /// 
        ///  
        public void Clear() { 
            // We do not need to call OLE32's VariantClear for primitive types or ByRefs
            // to safe ourselves the cost of interop transition. 
            // ByRef indicates the memory is not owned by the VARIANT itself while
            // primitive types do not have any resources to free up.
            // Hence, only safearrays, BSTRs, interfaces and user types are
            // handled differently. 
            VarEnum vt = VariantType;
            if ((vt & VarEnum.VT_BYREF) != 0) { 
                VariantType = VarEnum.VT_EMPTY; 
            } else if (
                ((vt & VarEnum.VT_ARRAY) != 0) || 
                ((vt) == VarEnum.VT_BSTR) ||
                ((vt) == VarEnum.VT_UNKNOWN) ||
                ((vt) == VarEnum.VT_DISPATCH) ||
                ((vt) == VarEnum.VT_VARIANT) || 
                ((vt) == VarEnum.VT_RECORD)
                ) { 
                unsafe { 
                    fixed (void* pThis = &this) {
                        NativeMethods.VariantClear((IntPtr)pThis); 
                    }
                }
                BCLDebug.Assert(IsEmpty, "variant");
            } else { 
                VariantType = VarEnum.VT_EMPTY;
            } 
        } 

        public VarEnum VariantType { 
            get {
                return (VarEnum)_typeUnion._vt;
            }
            set { 
                _typeUnion._vt = (ushort)value;
            } 
        } 

        internal bool IsEmpty { 
            get {
                return _typeUnion._vt == ((ushort)VarEnum.VT_EMPTY);
            }
        } 

        internal bool IsByRef { 
            get { 
                return (_typeUnion._vt & ((ushort)VarEnum.VT_BYREF)) != 0;
            } 
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly")] //
        public void SetAsNULL() { 
            BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise
            VariantType = VarEnum.VT_NULL; 
        } 

        #region Generated Variant accessors 

        // *** BEGIN GENERATED CODE ***
        // generated by function: gen_accessors from: generate_comdispatch.py
 
        // VT_I1
 
        public SByte AsI1 { 
            get {
                BCLDebug.Assert(VariantType == VarEnum.VT_I1, "variant"); 
                return _typeUnion._unionTypes._i1;
            }
            set {
                BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise 
                VariantType = VarEnum.VT_I1;
                _typeUnion._unionTypes._i1 = value; 
            } 
        }
 
        // VT_I2

        public Int16 AsI2 {
            get { 
                BCLDebug.Assert(VariantType == VarEnum.VT_I2, "variant");
                return _typeUnion._unionTypes._i2; 
            } 
            set {
                BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise 
                VariantType = VarEnum.VT_I2;
                _typeUnion._unionTypes._i2 = value;
            }
        } 

        // VT_I4 
 
        public Int32 AsI4 {
            get { 
                BCLDebug.Assert(VariantType == VarEnum.VT_I4, "variant");
                return _typeUnion._unionTypes._i4;
            }
            set { 
                BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise
                VariantType = VarEnum.VT_I4; 
                _typeUnion._unionTypes._i4 = value; 
            }
        } 

        // VT_I8

        public Int64 AsI8 { 
            get {
                BCLDebug.Assert(VariantType == VarEnum.VT_I8, "variant"); 
                return _typeUnion._unionTypes._i8; 
            }
            set { 
                BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise
                VariantType = VarEnum.VT_I8;
                _typeUnion._unionTypes._i8 = value;
            } 
        }
 
        // VT_UI1 

        public Byte AsUi1 { 
            get {
                BCLDebug.Assert(VariantType == VarEnum.VT_UI1, "variant");
                return _typeUnion._unionTypes._ui1;
            } 
            set {
                BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise 
                VariantType = VarEnum.VT_UI1; 
                _typeUnion._unionTypes._ui1 = value;
            } 
        }

        // VT_UI2
 
        public UInt16 AsUi2 {
            get { 
                BCLDebug.Assert(VariantType == VarEnum.VT_UI2, "variant"); 
                return _typeUnion._unionTypes._ui2;
            } 
            set {
                BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise
                VariantType = VarEnum.VT_UI2;
                _typeUnion._unionTypes._ui2 = value; 
            }
        } 
 
        // VT_UI4
 
        public UInt32 AsUi4 {
            get {
                BCLDebug.Assert(VariantType == VarEnum.VT_UI4, "variant");
                return _typeUnion._unionTypes._ui4; 
            }
            set { 
                BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise 
                VariantType = VarEnum.VT_UI4;
                _typeUnion._unionTypes._ui4 = value; 
            }
        }

        // VT_UI8 

        public UInt64 AsUi8 { 
            get { 
                BCLDebug.Assert(VariantType == VarEnum.VT_UI8, "variant");
                return _typeUnion._unionTypes._ui8; 
            }
            set {
                BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise
                VariantType = VarEnum.VT_UI8; 
                _typeUnion._unionTypes._ui8 = value;
            } 
        } 

        // VT_INT 

        public IntPtr AsInt {
            get {
                BCLDebug.Assert(VariantType == VarEnum.VT_INT, "variant"); 
                return _typeUnion._unionTypes._int;
            } 
            set { 
                BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise
                VariantType = VarEnum.VT_INT; 
                _typeUnion._unionTypes._int = value;
            }
        }
 
        // VT_UINT
 
        public UIntPtr AsUint { 
            get {
                BCLDebug.Assert(VariantType == VarEnum.VT_UINT, "variant"); 
                return _typeUnion._unionTypes._uint;
            }
            set {
                BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise 
                VariantType = VarEnum.VT_UINT;
                _typeUnion._unionTypes._uint = value; 
            } 
        }
 
        // VT_BOOL

        public bool AsBool {
            get { 
                BCLDebug.Assert(VariantType == VarEnum.VT_BOOL, "variant");
                return _typeUnion._unionTypes._bool != 0; 
            } 
            set {
                BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise 
                VariantType = VarEnum.VT_BOOL;
                _typeUnion._unionTypes._bool = value ? -1 : 0;
            }
        } 

        // VT_ERROR 
 
        public Int32 AsError {
            get { 
                BCLDebug.Assert(VariantType == VarEnum.VT_ERROR, "variant");
                return _typeUnion._unionTypes._error;
            }
            set { 
                BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise
                VariantType = VarEnum.VT_ERROR; 
                _typeUnion._unionTypes._error = value; 
            }
        } 

        // VT_R4

        public Single AsR4 { 
            get {
                BCLDebug.Assert(VariantType == VarEnum.VT_R4, "variant"); 
                return _typeUnion._unionTypes._r4; 
            }
            set { 
                BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise
                VariantType = VarEnum.VT_R4;
                _typeUnion._unionTypes._r4 = value;
            } 
        }
 
        // VT_R8 

        public Double AsR8 { 
            get {
                BCLDebug.Assert(VariantType == VarEnum.VT_R8, "variant");
                return _typeUnion._unionTypes._r8;
            } 
            set {
                BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise 
                VariantType = VarEnum.VT_R8; 
                _typeUnion._unionTypes._r8 = value;
            } 
        }

        // VT_DECIMAL
 
        public Decimal AsDecimal {
            get { 
                BCLDebug.Assert(VariantType == VarEnum.VT_DECIMAL, "variant"); 
                // The first byte of Decimal is unused, but usually set to 0
                Variant v = this; 
                v._typeUnion._vt = 0;
                return v._decimal;
            }
            set { 
                BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise
                VariantType = VarEnum.VT_DECIMAL; 
                _decimal = value; 
                // _vt overlaps with _decimal, and should be set after setting _decimal
                _typeUnion._vt = (ushort)VarEnum.VT_DECIMAL; 
            }
        }

        // VT_CY 

        public Decimal AsCy { 
            get { 
                BCLDebug.Assert(VariantType == VarEnum.VT_CY, "variant");
                return Decimal.FromOACurrency(_typeUnion._unionTypes._cy); 
            }
            set {
                BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise
                VariantType = VarEnum.VT_CY; 
                _typeUnion._unionTypes._cy = Decimal.ToOACurrency(value);
            } 
        } 

        // VT_DATE 

        public DateTime AsDate {
            get {
                BCLDebug.Assert(VariantType == VarEnum.VT_DATE, "variant"); 
                return DateTime.FromOADate(_typeUnion._unionTypes._date);
            } 
            set { 
                BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise
                VariantType = VarEnum.VT_DATE; 
                _typeUnion._unionTypes._date = value.ToOADate();
            }
        }
 
        // VT_BSTR
 
        public String AsBstr { 
            get {
                BCLDebug.Assert(VariantType == VarEnum.VT_BSTR, "variant"); 
                return (string)Marshal.PtrToStringBSTR(this._typeUnion._unionTypes._bstr);
            }
            set {
                BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise 
                VariantType = VarEnum.VT_BSTR;
                this._typeUnion._unionTypes._bstr = Marshal.StringToBSTR(value); 
            } 
        }
 
        // VT_UNKNOWN

        public Object AsUnknown {
            get { 
                BCLDebug.Assert(VariantType == VarEnum.VT_UNKNOWN, "variant");
                if (_typeUnion._unionTypes._unknown == IntPtr.Zero) 
                    return null; 
                return Marshal.GetObjectForIUnknown(_typeUnion._unionTypes._unknown);
            } 
            set {
                BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise
                VariantType = VarEnum.VT_UNKNOWN;
                if (value == null) 
                    _typeUnion._unionTypes._unknown = IntPtr.Zero;
                else 
                    _typeUnion._unionTypes._unknown = Marshal.GetIUnknownForObject(value); 
            }
        } 

        // VT_DISPATCH

        public Object AsDispatch { 
            get {
                BCLDebug.Assert(VariantType == VarEnum.VT_DISPATCH, "variant"); 
                if (_typeUnion._unionTypes._dispatch == IntPtr.Zero) 
                    return null;
                return Marshal.GetObjectForIUnknown(_typeUnion._unionTypes._dispatch); 
            }
            set {
                BCLDebug.Assert(IsEmpty, "variant"); // The setter can only be called once as VariantClear might be needed otherwise
                VariantType = VarEnum.VT_DISPATCH; 
                if (value == null)
                    _typeUnion._unionTypes._dispatch = IntPtr.Zero; 
                else 
                    _typeUnion._unionTypes._dispatch = Marshal.GetIDispatchForObject(value);
            } 
        }


        // *** END GENERATED CODE *** 

        #endregion 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK