Click here to Skip to main content
12,701,601 members (34,267 online)
Click here to Skip to main content

Stats

46.1K views
1.4K downloads
126 bookmarked
Posted

Clipz - A Friendly Introduction to the Windows 7 Taskbar Features

, 17 Dec 2009 CPOL
An overview of the Windows 7 taskbar features, and how to use then in your own applications.
Clipz
bin
Debug
Clipz.csproj.user
CopyIcon.ico
DeleteIcon.ico
Model
Native Methods
Properties
Resources
Audio.png
Clipboard.png
NextIcon.ico
PreviousIcon.ico
Utility
Core
AppRestartRecovery
Dialogs
Common
TaskDialogs
Interop
AppRestartRecovery
Dialogs
NetworkList
PowerManagement
TaskDialogs
NetworkList
PowerManagement
Properties
PropertySystem
SafeHandles
Libraries
StructureMap.dll
Shell
Common
CommonFileDialogs
Controls
Design
ShellObjects.cd
ShellThumbnailClassDiagram.cd
DesktopWindowManager
ExplorerBrowser
ExplorerBrowserDiagram.cd
Interop
Common
Dialogs
ExplorerBrowser
KnownFolders
PropertySystem
StockIcons
Taskbar
KnownFolders
Properties
PropertySystem
StockIcons
Taskbar
//Copyright (c) Microsoft Corporation.  All rights reserved.

namespace MS.WindowsAPICodePack.Internal
{
    using System;
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    using Microsoft.WindowsAPICodePack.Shell.PropertySystem;

    /// <summary>
    /// Represents the OLE struct PROPVARIANT.
    /// This class is intended for internal use only.
    /// </summary>
    /// <remarks>
    /// Must call Clear when finished to avoid memory leaks. If you get the value of
    /// a VT_UNKNOWN prop, an implicit AddRef is called, thus your reference will
    /// be active even after the PropVariant struct is cleared.
    /// Correct usage:
    /// 
    ///     PropVariant propVar;
    ///     GetProp(out propVar);
    ///     try
    ///     {
    ///         object value = propVar.Value;
    ///     }
    ///     finally { propVar.Clear(); }
    ///     
    /// Originally sourced from http://blogs.msdn.com/adamroot/pages/interop-with-propvariants-in-net.aspx
    /// and modified to support additional types inculding vectors and ability to set values
    /// </remarks>
    [StructLayout(LayoutKind.Sequential)]
    public struct PropVariant
    {
        #region Fields

        // The layout of these elements needs to be maintained.
        //
        // NOTE: We could use LayoutKind.Explicit, but we want
        //       to maintain that the IntPtr may be 8 bytes on
        //       64-bit architectures, so we'll let the CLR keep
        //       us aligned.
        //

        // This is actually a VarEnum value, but the VarEnum type
        // requires 4 bytes instead of the expected 2.
        ushort valueType;
        
        // Reserved Fields
        ushort wReserved1;
        ushort wReserved2;
        ushort wReserved3;


        // In order to allow x64 compat, we need to allow for
        // expansion of the IntPtr. However, the BLOB struct
        // uses a 4-byte int, followed by an IntPtr, so
        // although the valueData field catches most pointer values,
        // we need an additional 4-bytes to get the BLOB
        // pointer. The valueDataExt field provides this, as well as
        // the last 4-bytes of an 8-byte value on 32-bit
        // architectures.
        IntPtr valueData;
        Int32 valueDataExt;        
        #endregion // struct fields

        #region public Methods

        /// <summary>
        /// Creates a PropVariant from an object
        /// </summary>
        /// <param name="value">The object containing the data.</param>
        /// <returns>An initialized PropVariant</returns>
        public static PropVariant FromObject( object value )
        {
            PropVariant propVar = new PropVariant( );

            if( value == null )
            {
                propVar.Clear( );
                return propVar;
            }

            if( value.GetType( ) == typeof( string ) )
            {
                //Strings require special consideration, because they cannot be empty as well
                if( String.IsNullOrEmpty( value as string ) || String.IsNullOrEmpty( (value as string).Trim( ) ) )
                    throw new ArgumentException( "String argument cannot be null or empty." );
                propVar.SetString( value as string );
            }
            else if( value.GetType( ) == typeof( bool? ) )
            {
                propVar.SetBool( (value as bool?).Value );
            }
            else if( value.GetType( ) == typeof( bool ) )
            {
                propVar.SetBool( (bool)value );
            }
            else if( value.GetType( ) == typeof( byte? ) )
            {
                propVar.SetByte( (value as byte?).Value );
            }
            else if( value.GetType( ) == typeof( byte ) )
            {
                propVar.SetByte( (byte)value );
            }
            else if( value.GetType( ) == typeof( sbyte? ) )
            {
                propVar.SetSByte( (value as sbyte?).Value );
            }
            else if( value.GetType( ) == typeof( sbyte ) )
            {
                propVar.SetSByte( (sbyte)value );
            }
            else if( value.GetType( ) == typeof( short? ) )
            {
                propVar.SetShort( (value as short?).Value );
            }
            else if( value.GetType( ) == typeof( short ) )
            {
                propVar.SetShort( (short)value );
            }
            else if( value.GetType( ) == typeof( ushort? ) )
            {
                propVar.SetUShort( (value as ushort?).Value );
            }
            else if( value.GetType( ) == typeof( ushort ) )
            {
                propVar.SetUShort( (ushort)value );
            }
            else if( value.GetType( ) == typeof( int? ) )
            {
                propVar.SetInt( (value as int?).Value );
            }
            else if( value.GetType( ) == typeof( int ) )
            {
                propVar.SetInt( (int)value );
            }
            else if( value.GetType( ) == typeof( uint? ) )
            {
                propVar.SetUInt( (value as uint?).Value );
            }
            else if( value.GetType( ) == typeof( uint ) )
            {
                propVar.SetUInt( (uint)value );
            }
            else if( value.GetType( ) == typeof( long? ) )
            {
                propVar.SetLong( (value as long?).Value );
            }
            else if( value.GetType( ) == typeof( long ) )
            {
                propVar.SetLong( (long)value );
            }
            else if( value.GetType( ) == typeof( ulong? ) )
            {
                propVar.SetULong( (value as ulong?).Value );
            }
            else if( value.GetType( ) == typeof( ulong ) )
            {
                propVar.SetULong( (ulong)value );
            }
            else if( value.GetType( ) == typeof( double? ) )
            {
                propVar.SetDouble( (value as double?).Value );
            }
            else if( value.GetType( ) == typeof( double ) )
            {
                propVar.SetDouble( (double)value );
            }
            else if( value.GetType( ) == typeof( float? ) )
            {
                propVar.SetDouble( (double)((value as float?).Value) );
            }
            else if( value.GetType( ) == typeof( float ) )
            {
                propVar.SetDouble( (double)(float)value );
            }
            else if( value.GetType( ) == typeof( DateTime? ) )
            {
                propVar.SetDateTime( (value as DateTime?).Value );
            }
            else if( value.GetType( ) == typeof( DateTime ) )
            {
                propVar.SetDateTime( (DateTime)value );
            }
            else if( value.GetType( ) == typeof( string[ ] ) )
            {
                propVar.SetStringVector( (value as string[ ]) );
            }
            else if( value.GetType( ) == typeof( short[ ] ) )
            {
                propVar.SetShortVector( (value as short[ ]) );
            }
            else if( value.GetType( ) == typeof( ushort[ ] ) )
            {
                propVar.SetUShortVector( (value as ushort[ ]) );
            }
            else if( value.GetType( ) == typeof( int[ ] ) )
            {
                propVar.SetIntVector( (value as int[ ]) );
            }
            else if( value.GetType( ) == typeof( uint[ ] ) )
            {
                propVar.SetUIntVector( (value as uint[ ]) );
            }
            else if( value.GetType( ) == typeof( long[ ] ) )
            {
                propVar.SetLongVector( (value as long[ ]) );
            }
            else if( value.GetType( ) == typeof( ulong[ ] ) )
            {
                propVar.SetULongVector( (value as ulong[ ]) );
            }
            else if( value.GetType( ) == typeof( DateTime[ ] ) )
            {
                propVar.SetDateTimeVector( (value as DateTime[ ]) );
            }
            else if( value.GetType( ) == typeof( bool[ ] ) )
            {
                propVar.SetBoolVector( (value as bool[ ]) );
            }
            else
            {
                throw new ArgumentException( "This Value type is not supported." );
            }

            return propVar;
        }


        /// <summary>
        /// Called to clear the PropVariant's referenced and local memory.
        /// </summary>
        /// <remarks>
        /// You must call Clear to avoid memory leaks.
        /// </remarks>
        public void Clear()
        {
            // Can't pass "this" by ref, so make a copy to call PropVariantClear with
            PropVariant var = this;
            PropVariantNativeMethods.PropVariantClear(ref var);

            // Since we couldn't pass "this" by ref, we need to clear the member fields manually
            // NOTE: PropVariantClear already freed heap data for us, so we are just setting
            //       our references to null.
            valueType = (ushort)VarEnum.VT_EMPTY;
            wReserved1 = wReserved2 = wReserved3 = 0;
            valueData = IntPtr.Zero;
            valueDataExt = 0;
        }

        /// <summary>
        /// Set a string value
        /// </summary>
        /// <param name="value">The new value to set.</param>
        public void SetString(string value)
        {
            valueType = (ushort)VarEnum.VT_LPWSTR;
            valueData = Marshal.StringToCoTaskMemUni(value);
        }

        /// <summary>
        /// Set a string vector
        /// </summary>
        /// <param name="value">The new value to set.</param>
        public void SetStringVector(string[] value)
        {
            PropVariant propVar;
            PropVariantNativeMethods.InitPropVariantFromStringVector(value, (uint) value.Length, out propVar);
            CopyData(propVar);

        }

        /// <summary>
        /// Set a bool vector
        /// </summary>
        /// <param name="value">The new value to set.</param>
        public void SetBoolVector(bool[] value)
        {
            PropVariant propVar;
            PropVariantNativeMethods.InitPropVariantFromBooleanVector(value, (uint)value.Length, out propVar);
            CopyData(propVar);
        }

        /// <summary>
        /// Set a short vector
        /// </summary>
        /// <param name="value">The new value to set.</param>
        public void SetShortVector(short[] value)
        {
            PropVariant propVar;
            PropVariantNativeMethods.InitPropVariantFromInt16Vector(value, (uint)value.Length, out propVar);
            CopyData(propVar);
        }

        /// <summary>
        /// Set a short vector
        /// </summary>
        /// <param name="value">The new value to set.</param>
        public void SetUShortVector(ushort[] value)
        {
            PropVariant propVar;
            PropVariantNativeMethods.InitPropVariantFromUInt16Vector(value, (uint)value.Length, out propVar);
            CopyData(propVar);
        }

        /// <summary>
        /// Set an int vector
        /// </summary>
        /// <param name="value">The new value to set.</param>
        public void SetIntVector(int[] value)
        {
            PropVariant propVar;
            PropVariantNativeMethods.InitPropVariantFromInt32Vector(value, (uint)value.Length, out propVar);
            CopyData(propVar);
        }

        /// <summary>
        /// Set an uint vector
        /// </summary>
        /// <param name="value">The new value to set.</param>
        public void SetUIntVector(uint[] value)
        {
            PropVariant propVar;
            PropVariantNativeMethods.InitPropVariantFromUInt32Vector(value, (uint)value.Length, out propVar);
            CopyData(propVar);
        }

        /// <summary>
        /// Set a long vector
        /// </summary>
        /// <param name="value">The new value to set.</param>
        public void SetLongVector(long[] value)
        {
            PropVariant propVar;
            PropVariantNativeMethods.InitPropVariantFromInt64Vector(value, (uint)value.Length, out propVar);
            CopyData(propVar);
        }

        /// <summary>
        /// Set a ulong vector
        /// </summary>
        /// <param name="value">The new value to set.</param>
        public void SetULongVector(ulong[] value)
        {
            PropVariant propVar;
            PropVariantNativeMethods.InitPropVariantFromUInt64Vector(value, (uint)value.Length, out propVar);
            CopyData(propVar);
        }

        /// <summary>
        /// Set a double vector
        /// </summary>
        /// <param name="value">The new value to set.</param>
        public void SetDoubleVector(double[] value)
        {
            PropVariant propVar;
            PropVariantNativeMethods.InitPropVariantFromDoubleVector(value, (uint)value.Length, out propVar);
            CopyData(propVar);
        }

        /// <summary>
        /// Set a DateTime vector
        /// </summary>
        /// <param name="value">The new value to set.</param>
        public void SetDateTimeVector(DateTime[] value)
        {
            System.Runtime.InteropServices.ComTypes.FILETIME[] fileTimeArr = 
                new System.Runtime.InteropServices.ComTypes.FILETIME[value.Length];

            for (int i = 0; i < value.Length; i++ )
            {
                fileTimeArr[i] = DateTimeTotFileTime(value[i]);
            }

            PropVariant propVar;
            PropVariantNativeMethods.InitPropVariantFromFileTimeVector(fileTimeArr, (uint)fileTimeArr.Length, out propVar);
            CopyData(propVar);
        }

        /// <summary>
        /// Set an IUnknown value
        /// </summary>
        /// <param name="value">The new value to set.</param>
        public void SetIUnknown(object value)
        {
            valueType = (ushort)VarEnum.VT_UNKNOWN;
            valueData = Marshal.GetIUnknownForObject(value);
        }

        /// <summary>
        /// Set a bool value
        /// </summary>
        /// <param name="value">The new value to set.</param>
        public void SetBool(bool value)
        {
            valueType = (ushort)VarEnum.VT_BOOL;
            valueData = (value == true) ? (IntPtr)(-1) : (IntPtr)0;
        }

        /// <summary>
        /// Set a DateTime value
        /// </summary>
        /// <param name="value">The new value to set.</param>
        public void SetDateTime(DateTime value)
        {
            valueType = (ushort)VarEnum.VT_FILETIME;

            PropVariant propVar;
            System.Runtime.InteropServices.ComTypes.FILETIME ft = DateTimeTotFileTime(value);
            PropVariantNativeMethods.InitPropVariantFromFileTime(ref ft, out propVar);
            CopyData(propVar);
        }

        /// <summary>
        /// Set a safe array value
        /// </summary>
        /// <param name="array">The new value to set.</param>
        public void SetSafeArray(Array array)
        {
            const ushort vtUnknown = 13;
            IntPtr psa = PropVariantNativeMethods.SafeArrayCreateVector(vtUnknown, 0, (uint)array.Length);

            IntPtr pvData = PropVariantNativeMethods.SafeArrayAccessData(psa);
            try // to remember to release lock on data
            {
                for (int i = 0; i < array.Length; ++i)
                {
                    object obj = array.GetValue(i);
                    IntPtr punk = (obj != null) ? Marshal.GetIUnknownForObject(obj) : IntPtr.Zero;
                    Marshal.WriteIntPtr(pvData, i * IntPtr.Size, punk);
                }
            }
            finally
            {
                PropVariantNativeMethods.SafeArrayUnaccessData(psa);
            }

            this.valueType = (ushort)VarEnum.VT_ARRAY | (ushort)VarEnum.VT_UNKNOWN;
            this.valueData = psa;
        }

        /// <summary>
        /// Set a byte value
        /// </summary>
        /// <param name="value">The new value to set.</param>
        public void SetByte(byte value)
        {
            valueType = (ushort)VarEnum.VT_UI1;
            valueData = (IntPtr)value;
        }

        /// <summary>
        /// Set a sbyte value
        /// </summary>
        /// <param name="value">The new value to set.</param>
        public void SetSByte(sbyte value)
        {
            valueType = (ushort)VarEnum.VT_I1;
            valueData = (IntPtr)value;
        }

        /// <summary>
        /// Set a short value
        /// </summary>
        /// <param name="value">The new value to set.</param>
        public void SetShort(short value)
        {
            valueType = (ushort)VarEnum.VT_I2;
            valueData = (IntPtr)value;
        }

        /// <summary>
        /// Set an unsigned short value
        /// </summary>
        /// <param name="value">The new value to set.</param>
        public void SetUShort(ushort value)
        {
            valueType = (ushort)VarEnum.VT_UI2;
            valueData = (IntPtr)value;
        }

        /// <summary>
        /// Set an int value
        /// </summary>
        /// <param name="value">The new value to set.</param>
        public void SetInt(int value)
        {
            valueType = (ushort)VarEnum.VT_I4;
            valueData = (IntPtr)value;
        }

        /// <summary>
        /// Set an unsigned int value
        /// </summary>
        /// <param name="value">The new value to set.</param>
        public void SetUInt(uint value)
        {
            valueType = (ushort)VarEnum.VT_UI4;
            valueData = (IntPtr)(int)value;
        }

        /// <summary>
        /// Set a decimal  value
        /// </summary>
        /// <param name="value">The new value to set.</param>
        public void SetDecimal(decimal value)
        {
            int[] bits = Decimal.GetBits(value);
            valueData = (IntPtr)bits[0];
            valueDataExt = bits[1];
            wReserved3 = (ushort)(bits[2] >> 16);
            wReserved2 = (ushort)(bits[2] & 0x0000FFFF);
            wReserved1 = (ushort)(bits[3] >> 16);
            valueType = (ushort)VarEnum.VT_DECIMAL;
        }

        /// <summary>
        /// Set a long
        /// </summary>
        /// <param name="value">The new value to set.</param>
        public void SetLong(long value)
        {
            long[] valueArr = new long[] { value };
            
            PropVariant propVar;
            PropVariantNativeMethods.InitPropVariantFromInt64Vector(valueArr, 1, out propVar);

            CreatePropVariantFromVectorElement(propVar);
        }

        /// <summary>
        /// Set a ulong
        /// </summary>
        /// <param name="value">The new value to set.</param>
        public void SetULong(ulong value)
        {
            PropVariant propVar;
            ulong[] valueArr = new ulong[] { value };
            PropVariantNativeMethods.InitPropVariantFromUInt64Vector(valueArr, 1, out propVar);

            CreatePropVariantFromVectorElement(propVar);
        }

        /// <summary>
        /// Set a double
        /// </summary>
        /// <param name="value">The new value to set.</param>
        public void SetDouble(double value)
        {
            double[] valueArr = new double[] { value };

            PropVariant propVar;
            PropVariantNativeMethods.InitPropVariantFromDoubleVector(valueArr, 1, out propVar);

            CreatePropVariantFromVectorElement(propVar);
        }

        /// <summary>
        /// Sets the value type to empty
        /// </summary>
        public void SetEmptyValue()
        {
            valueType = (ushort) VarEnum.VT_EMPTY;
        }

        /// <summary>
        /// Checks if this has an empty or null value
        /// </summary>
        /// <returns></returns>
        public bool IsNullOrEmpty
        {
            get
            {
                return (valueType == (ushort)VarEnum.VT_EMPTY || valueType == (ushort)VarEnum.VT_NULL);
            }
        }
        
        #endregion

        #region public Properties

        /// <summary>
        /// Gets or sets the variant type.
        /// </summary>
        public VarEnum VarType
        {
            get { return (VarEnum)valueType; }
            set { valueType = (ushort) value; }
        }

        /// <summary>
        /// Gets the variant value.
        /// </summary>
        public object Value
        {
            get
            {
                switch ((VarEnum)valueType)
                {
                    case VarEnum.VT_I1:
                        return cVal;
                    case VarEnum.VT_UI1:
                        return bVal;
                    case VarEnum.VT_I2:
                        return iVal;
                    case VarEnum.VT_UI2:
                        return uiVal;
                    case VarEnum.VT_I4:
                    case VarEnum.VT_INT:
                        return lVal;
                    case VarEnum.VT_UI4:
                    case VarEnum.VT_UINT:
                        return ulVal;
                    case VarEnum.VT_I8:
                        return hVal;
                    case VarEnum.VT_UI8:
                        return uhVal;
                    case VarEnum.VT_R4:
                        return fltVal;
                    case VarEnum.VT_R8:
                        return dblVal;
                    case VarEnum.VT_BOOL:
                        return boolVal;
                    case VarEnum.VT_ERROR:
                        return scode;
                    case VarEnum.VT_CY:
                        return cyVal;
                    case VarEnum.VT_DATE:
                        return date;
                    case VarEnum.VT_FILETIME:
                        return DateTime.FromFileTime(hVal);
                    case VarEnum.VT_BSTR:
                        return Marshal.PtrToStringBSTR(valueData);
                    case VarEnum.VT_BLOB:
                        return GetBlobData();
                    case VarEnum.VT_LPSTR:
                        return Marshal.PtrToStringAnsi(valueData);
                    case VarEnum.VT_LPWSTR:
                        return Marshal.PtrToStringUni(valueData);
                    case VarEnum.VT_UNKNOWN:
                        return Marshal.GetObjectForIUnknown(valueData);
                    case VarEnum.VT_DISPATCH:
                        return Marshal.GetObjectForIUnknown(valueData);
                    case VarEnum.VT_DECIMAL:
                        return decVal;
                    case VarEnum.VT_ARRAY | VarEnum.VT_UNKNOWN:
                        return CrackSingleDimSafeArray(valueData);
                    case (VarEnum.VT_VECTOR | VarEnum.VT_LPWSTR):
                        return GetStringVector();
                    case (VarEnum.VT_VECTOR | VarEnum.VT_I2):
                        return GetVector<Int16>();
                    case (VarEnum.VT_VECTOR | VarEnum.VT_UI2):
                            return GetVector<UInt16>();
                    case (VarEnum.VT_VECTOR | VarEnum.VT_I4):
                            return GetVector<Int32>();
                    case (VarEnum.VT_VECTOR | VarEnum.VT_UI4):
                            return GetVector<UInt32>();
                    case (VarEnum.VT_VECTOR | VarEnum.VT_I8):
                            return GetVector<Int64>();
                    case (VarEnum.VT_VECTOR | VarEnum.VT_UI8):
                            return GetVector<UInt64>();
                    case (VarEnum.VT_VECTOR | VarEnum.VT_R8):
                            return GetVector<Double>();
                    case (VarEnum.VT_VECTOR | VarEnum.VT_BOOL):
                            return GetVector<Boolean>();
                    case (VarEnum.VT_VECTOR | VarEnum.VT_FILETIME):
                            return GetVector<DateTime>();
                    default:
                        // if the value cannot be marshaled
                        return null;
                }
            }
        }

        #endregion

        #region PropVariant Simple Data types

        sbyte cVal // CHAR cVal;
        {
            get { return (sbyte)GetDataBytes()[0]; }
        }

        byte bVal // UCHAR bVal;
        {
            get { return GetDataBytes()[0]; }
        }

        short iVal // SHORT iVal;
        {
            get { return BitConverter.ToInt16(GetDataBytes(), 0); }
        }

        ushort uiVal // USHORT uiVal;
        {
            get { return BitConverter.ToUInt16(GetDataBytes(), 0); }
        }

        int lVal // LONG lVal;
        {
            get { return BitConverter.ToInt32(GetDataBytes(), 0); }
        }

        uint ulVal // ULONG ulVal;
        {
            get { return BitConverter.ToUInt32(GetDataBytes(), 0); }
        }

        long hVal // LARGE_INTEGER hVal;
        {
            get { return BitConverter.ToInt64(GetDataBytes(), 0); }
        }

        ulong uhVal // ULARGE_INTEGER uhVal;
        {
            get { return BitConverter.ToUInt64(GetDataBytes(), 0); }
        }

        float fltVal // FLOAT fltVal;
        {
            get { return BitConverter.ToSingle(GetDataBytes(), 0); }
        }

        double dblVal // DOUBLE dblVal;
        {
            get { return BitConverter.ToDouble(GetDataBytes(), 0); }
        }

        bool boolVal // VARIANT_BOOL boolVal;
        {
            get { return (iVal == 0 ? false : true); }
        }

        int scode // SCODE scode;
        {
            get { return lVal; }
        }

        decimal cyVal // CY cyVal;
        {
            get { return decimal.FromOACurrency(hVal); }
        }

        DateTime date // DATE date;
        {
            get { return DateTime.FromOADate(dblVal); }
        }

        Decimal decVal  // Decimal value
        {
            get
            {
                int[] bits = new int[4];
                bits[0] = (int)valueData;
                bits[1] = valueDataExt;
                bits[2] = (wReserved3 << 16) | wReserved2;
                bits[3] = (wReserved1 << 16);
                return new decimal(bits);
            }
        }

        #endregion 

        #region Private Methods

        private void CopyData(PropVariant propVar)
        {
            this.valueType = propVar.valueType;
            this.valueData = propVar.valueData;
            this.valueDataExt = propVar.valueDataExt;
        }

        private void CreatePropVariantFromVectorElement(PropVariant propVar)
        {
            //Copy the first vector element to a new PropVariant
            CopyData(propVar);
            PropVariantNativeMethods.InitPropVariantFromPropVariantVectorElem(ref this, 0, out propVar);

            //Overwrite the existing data
            CopyData(propVar);
        }

        private static long FileTimeToDateTime(ref System.Runtime.InteropServices.ComTypes.FILETIME val)
        {
            return (((long)val.dwHighDateTime) << 32) + val.dwLowDateTime;
        }

        private static System.Runtime.InteropServices.ComTypes.FILETIME DateTimeTotFileTime(DateTime value)
        {
            long hFT = value.ToFileTime();
            System.Runtime.InteropServices.ComTypes.FILETIME ft =
                new System.Runtime.InteropServices.ComTypes.FILETIME();
            ft.dwLowDateTime = (int)(hFT & 0xFFFFFFFF);
            ft.dwHighDateTime = (int)(hFT >> 32);
            return ft;
        }

        private object GetBlobData()
        {
            byte[] blobData = new byte[lVal];
            IntPtr pBlobData;
            if (IntPtr.Size == 4)
            {
                pBlobData = new IntPtr(valueDataExt);
            }
            else if( IntPtr.Size == 8 )
            {
                // In this case, we need to derive a pointer at offset 12,
                // because the size of the blob is represented as a 4-byte int
                // but the pointer is immediately after that.
                pBlobData = new IntPtr(
                    (Int64)(BitConverter.ToInt32( GetDataBytes( ), sizeof( int ) )) +
                    (Int64)(BitConverter.ToInt32( GetDataBytes( ), 2 * sizeof( int ) ) << 32) );
            }
            else
            {
                throw new NotSupportedException( );
            }
            Marshal.Copy(pBlobData, blobData, 0, lVal);
 
            return blobData;
        }

        private Array GetVector<T>() where T : struct
        {
            int count = PropVariantNativeMethods.PropVariantGetElementCount(ref this);
            if (count <= 0)
                return null;

            Array arr = new T[count];

            for (uint i = 0; i < count; i++)
            {
                if (typeof(T) == typeof(Int16))
                {
                    short val;
                    PropVariantNativeMethods.PropVariantGetInt16Elem(ref this, i, out val);
                    arr.SetValue(val, i);
                }
                else if (typeof(T) == typeof(UInt16))
                {
                    ushort val;
                    PropVariantNativeMethods.PropVariantGetUInt16Elem(ref this, i, out val);
                    arr.SetValue(val, i);
                }
                else if (typeof(T) == typeof(Int32))
                {
                    int val;
                    PropVariantNativeMethods.PropVariantGetInt32Elem(ref this, i, out val);
                    arr.SetValue(val, i);
                }
                else if (typeof(T) == typeof(UInt32))
                {
                    uint val;
                    PropVariantNativeMethods.PropVariantGetUInt32Elem(ref this, i, out val);
                    arr.SetValue(val, i);
                }
                else if (typeof(T) == typeof(Int64))
                {
                    long val;
                    PropVariantNativeMethods.PropVariantGetInt64Elem(ref this, i, out val);
                    arr.SetValue(val, i);
                }
                else if (typeof(T) == typeof(UInt64))
                {
                    ulong val;
                    PropVariantNativeMethods.PropVariantGetUInt64Elem(ref this, i, out val);
                    arr.SetValue(val, i);
                }
                else if (typeof(T) == typeof(DateTime))
                {
                    System.Runtime.InteropServices.ComTypes.FILETIME val;
                    PropVariantNativeMethods.PropVariantGetFileTimeElem(ref this, i, out val);

                    long fileTime = FileTimeToDateTime(ref val);


                    arr.SetValue(DateTime.FromFileTime(fileTime), i);
                }
                else if (typeof(T) == typeof(Boolean))
                {
                    bool val;
                    PropVariantNativeMethods.PropVariantGetBooleanElem(ref this, i, out val);
                    arr.SetValue(val, i);
                }
                else if (typeof(T) == typeof(Double))
                {
                    double val;
                    PropVariantNativeMethods.PropVariantGetDoubleElem(ref this, i, out val);
                    arr.SetValue(val, i);
                }
                else if (typeof(T) == typeof(String))
                {
                    string val;
                    PropVariantNativeMethods.PropVariantGetStringElem(ref this, i, out val);
                    arr.SetValue(val, i);
                }
            }

            return arr;
        }

        // A string requires a special case because it's not a struct or value type
        private string[] GetStringVector()
        {
            int count = PropVariantNativeMethods.PropVariantGetElementCount(ref this);
            if (count <= 0)
                return null;

            string[] strArr = new string[count];
            for (uint i = 0; i < count; i++)
            {
                PropVariantNativeMethods.PropVariantGetStringElem(ref this, i, out strArr[i]);
            }

            return strArr;
        }

        /// <summary>
        /// Gets a byte array containing the data bits of the struct.
        /// </summary>
        /// <returns>A byte array that is the combined size of the data bits.</returns>
        private byte[] GetDataBytes()
        {
            byte[] ret = new byte[IntPtr.Size + sizeof(int)];
            if (IntPtr.Size == 4)
                BitConverter.GetBytes(valueData.ToInt32()).CopyTo(ret, 0);
            else if (IntPtr.Size == 8)
                BitConverter.GetBytes(valueData.ToInt64()).CopyTo(ret, 0);
            BitConverter.GetBytes(valueDataExt).CopyTo(ret, IntPtr.Size);
            return ret;
        }

        Array CrackSingleDimSafeArray(IntPtr psa)
        {
            uint cDims = PropVariantNativeMethods.SafeArrayGetDim(psa);
            if (cDims != 1) 
                throw new ArgumentException("Multi-dimensional SafeArrays not supported.");

            int lBound = PropVariantNativeMethods.SafeArrayGetLBound(psa, 1U);
            int uBound = PropVariantNativeMethods.SafeArrayGetUBound(psa, 1U);

            int n = uBound - lBound + 1; // uBound is inclusive

            object[] array = new object[n];
            for (int i = lBound; i <= uBound; ++i)
            {
                array[i] = PropVariantNativeMethods.SafeArrayGetElement(psa, ref i);
            }

            return array;
        }

        #endregion

    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

TylerBrinks
Web Developer PageLabs
United States United States
I'm the founder of PageLabs, a web-based performance and SEO optimization site.

Give your site a boost in performance, even take a free speed test!

http://www.pagelabs.com

You may also be interested in...

Pro
| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170118.1 | Last Updated 17 Dec 2009
Article Copyright 2009 by TylerBrinks
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid