Click here to Skip to main content
15,893,381 members
Articles / High Performance Computing / Vectorization

A C++ String Class

Rate me:
Please Sign up or sign in to vote.
4.96/5 (29 votes)
3 Jan 2015CPOL13 min read 121.3K   2.6K   93  
A fast, reference counted, copy-on-write string class
#pragma once
#ifndef __HWINVARIANT_H__
#define __HWINVARIANT_H__

#include "hwindef.h"
#include "hwincom.h"
#include "hwinexception.h"
#include "hwindatetime.h"


namespace harlinn
{
    namespace windows
    {
        // ----------------------------------------------------------------------
        // VariantType
        // ----------------------------------------------------------------------
        enum class VariantType : unsigned short
        {
            Empty = 0,
            Null = 1,
            Int2 = 2,
            Short = 2,
            Int4 = 3,
            Long = 3,
            Real4 = 4,
            Float = 4,
            Real8 = 5,
            Double = 5,
            Currency = 6,
            DateTime = 7,
            BStr = 8,
            Dispatch = 9,
            Error = 10,
            Bool = 11,
            Variant = 12,
            Unknown = 13,
            Decimal = 14,
            Int1 = 16,
            SByte = 16,
            UInt1 = 17,
            Byte = 17,
            UInt2 = 18,
            UShort = 18,
            UInt4 = 19,
            ULong = 19,
            Int8 = 20,
            Int64 = 20,
            LongLong = 20,
            UInt8 = 21,
            UInt64 = 21,
            ULongLong = 21,
            Int = 22,
            UInt = 23,
            Void = 24,
            HResult = 25,
            Pointer = 26,
            SafeArray = 27,
            CArray = 28,
            UserDefined = 29,
            LPStr = 30,
            LPWStr = 31,
            Record = 36,
            IntPtr = 37,
            UIntPtr = 38,
            FileTime = 64,
            Blob = 65,
            Stream = 66,
            Storage = 67,
            StreamedObject = 68,
            StoredObject = 69,
            BlobObject = 70,
            CF = 71,
            CLSID = 72,
            VersionedStream = 73,
            BStrBlob = 0xfff,
            Vector = 0x1000,
            Array = 0x2000,
            Byref = 0x4000,
            Reserved = 0x8000,
            Illegal = 0xffff,
            IllegalMasked = 0xfff,
            TypeMask = 0xfff
        };
        DEFINE_ENUM_FLAG_OPERATORS( VariantType )

            // ----------------------------------------------------------------------
            // SysString
            // ----------------------------------------------------------------------
        class SysString
        {
            BSTR bstr;
        public:

            static BSTR Copy( const BSTR bstr )
            {
                if ( bstr )
                {
                    UINT length = SysStringLen( bstr );
                    auto result = SysAllocStringLen( bstr, length );
                    if ( ( !result ) && length )
                    {
                        CheckHRESULT( E_OUTOFMEMORY );
                    }
                    return result;
                }
                return nullptr;
            }

            SysString( )
                : bstr( 0 )
            {
            }

            SysString( const WideString& theString )
                : bstr( 0 )
            {
                bstr = SysAllocStringLen( theString.c_str( ), UINT( theString.length( ) ) );
                if ( ( bstr == nullptr ) && ( theString.length( ) ) )
                {
                    CheckHRESULT( E_OUTOFMEMORY );
                }
            }

            SysString( const wchar_t* theString, bool attach = false )
                : bstr( 0 )
            {
                if ( !attach )
                {
                    bstr = SysAllocString( theString );
                    if ( ( bstr == nullptr ) && theString && theString[0] )
                    {
                        CheckHRESULT( E_OUTOFMEMORY );
                    }
                }
                else
                {
                    bstr = ( BSTR )theString;
                }
            }

            SysString( const wchar_t* theString, size_t theLength )
                : bstr( 0 )
            {
                bstr = SysAllocStringLen( theString, UINT( theLength ) );
                if ( ( bstr == nullptr ) && theString && theString[0] )
                {
                    CheckHRESULT( E_OUTOFMEMORY );
                }
            }

            SysString( const SysString& other )
                : bstr( Copy( other.bstr ) )
            {
            }

            SysString( SysString&& other )
                : bstr( other.bstr )
            {
                other.bstr = nullptr;
            }


            ~SysString( )
            {
                if ( bstr )
                {
                    SysFreeString( bstr );
                }
            }


            SysString& operator = ( const SysString& other )
            {
                if ( bstr != other.bstr )
                {
                    if ( bstr )
                    {
                        SysFreeString( bstr );
                        bstr = nullptr;
                    }
                    bstr = Copy( other.bstr );
                }
                return *this;
            }

            SysString& operator = ( SysString&& other )
            {
                if ( this != &other )
                {
                    if ( bstr )
                    {
                        SysFreeString( bstr );
                        bstr = nullptr;
                    }
                    bstr = other.bstr;
                    other.bstr = nullptr;
                }
                return *this;
            }

            SysString& Attach( BSTR theString )
            {
                if ( bstr != theString )
                {
                    if ( bstr )
                    {
                        SysFreeString( bstr );
                        bstr = nullptr;
                    }
                    bstr = theString;
                }
                return *this;
            }

            BSTR Detach( )
            {
                auto result = bstr;
                bstr = nullptr;
                return result;
            }



            BSTR Copy( ) const
            {
                return Copy( bstr );
            }


            const BSTR c_str( ) const
            {
                return bstr;
            }

            BSTR c_str( )
            {
                return bstr;
            }

            size_t length( ) const
            {
                if ( bstr )
                {
                    return size_t( SysStringLen( bstr ) );
                }
                return 0;
            }

            OLECHAR At( size_t index ) const
            {
                return bstr[index];
            }

            OLECHAR& At( size_t index )
            {
                return bstr[index];
            }

            OLECHAR operator []( size_t index ) const
            {
                return bstr[index];
            }

            OLECHAR& operator []( size_t index )
            {
                return bstr[index];
            }

        };


        // ----------------------------------------------------------------------
        // SafeArray
        // ----------------------------------------------------------------------
        class SafeArray
        {
            SAFEARRAY* ptr;
        public:
            static VariantType GetElementVariantType( SAFEARRAY* safeArray )
            {
                if ( safeArray )
                {
                    if ( safeArray->fFeatures & FADF_DISPATCH )
                    {
                        return VariantType::Dispatch;
                    }
                    if ( safeArray->fFeatures & FADF_UNKNOWN )
                    {
                        return VariantType::Unknown;
                    }
                    if ( safeArray->fFeatures & FADF_VARIANT )
                    {
                        return VariantType::Variant;
                    }
                    if ( safeArray->fFeatures & FADF_BSTR )
                    {
                        return VariantType::BStr;
                    }
                    VARTYPE vt = 0;
                    auto hr = SafeArrayGetVartype( safeArray, &vt );
                    if ( FAILED( hr ) )
                    {
                        CheckHRESULT( hr );
                    }
                }
                else
                {
                    return VariantType::Empty;
                }
            }

            // ----------------------------------------------------------------------
            // Lock
            // ----------------------------------------------------------------------
            friend class SafeArrayLock;
            class SafeArrayLock
            {
                SAFEARRAY* safeArray;
            public:
                SafeArrayLock( SafeArray& theSafeArray )
                {
                    safeArray = theSafeArray.ptr;
                    auto hr = ::SafeArrayLock( safeArray );
                    if ( FAILED( hr ) )
                    {
                        CheckHRESULT( hr );
                    }
                }

                ~SafeArrayLock( )
                {
                    if ( safeArray )
                    {
                        SafeArrayUnlock( safeArray );
                    }
                }
            };
            typedef SafeArrayLock Lock;


            // ----------------------------------------------------------------------
            // DataLock
            // ----------------------------------------------------------------------
            class DataLock
            {
                SAFEARRAY* safeArray;
                void* data;
            public:
                DataLock( SafeArray& theSafeArray )
                {
                    safeArray = theSafeArray.ptr;
                    auto hr = SafeArrayAccessData( safeArray, &data );
                    if ( FAILED( hr ) )
                    {
                        CheckHRESULT( hr );
                    }
                }

                ~DataLock( )
                {
                    if ( safeArray )
                    {
                        SafeArrayUnaccessData( safeArray );
                    }
                }

                template<typename T>
                T* Data( )
                {
                    return reinterpret_cast<T*>( data );
                }


            };



            SafeArray( )
                : ptr( 0 )
            {
            }

            SafeArray( VariantType variantType, UINT numberOfElements )
                : ptr( 0 )
            {
                SAFEARRAYBOUND rgsabound = { numberOfElements, 0 };
                ptr = SafeArrayCreate( VARTYPE( variantType ), 1, &rgsabound );
                if ( !ptr )
                {
                    CheckHRESULT( E_OUTOFMEMORY );
                }
            }

            SafeArray( const SafeArray& other )
                : ptr( 0 )
            {
                if ( other.ptr )
                {
                    auto hr = SafeArrayCopy( other.ptr, &ptr );
                    if ( FAILED( hr ) )
                    {
                        CheckHRESULT( hr );
                    }
                }
            }


            SafeArray( SafeArray&& other )
                : ptr( other.ptr )
            {
                other.ptr = nullptr;
            }


            ~SafeArray( )
            {
                if ( ptr )
                {
                    auto hr = SafeArrayDestroy( ptr );
                    CheckHRESULT( hr );
                }
            }



            SafeArray& operator = ( const SafeArray& other )
            {
                if ( other.ptr && ( ptr != other.ptr ) )
                {
                    if ( ptr )
                    {
                        auto hr = SafeArrayDestroy( ptr );
                        CheckHRESULT( hr );
                        ptr = nullptr;
                    }
                    auto hr = SafeArrayCopy( other.ptr, &ptr );
                    if ( FAILED( hr ) )
                    {
                        CheckHRESULT( hr );
                    }
                }
                return *this;
            }

            SafeArray& operator = ( SafeArray&& other )
            {
                if ( this != &other )
                {
                    if ( ptr )
                    {
                        auto hr = SafeArrayDestroy( ptr );
                        CheckHRESULT( hr );
                        ptr = nullptr;
                    }
                    ptr = other.ptr;
                    other.ptr = nullptr;
                }
                return *this;
            }


        };




        // ----------------------------------------------------------------------
        // Variant
        // ----------------------------------------------------------------------
        class Variant : public VARIANT
        {
            void SetVariantType( VariantType variantType )
            {
                vt = USHORT( variantType );
            }
        public:
            static int Compare( const VARIANT& first, const VARIANT& second )
            {
                if ( first.vt == USHORT( VariantType::Empty ) )
                {
                    if ( second.vt == USHORT( VariantType::Empty ) )
                    {
                        return 0;
                    }
                    return -1;
                }
                else if ( second.vt == USHORT( VariantType::Empty ) )
                {
                    return 1;
                }
                else if ( first.vt == USHORT( VariantType::Null ) )
                {
                    if ( second.vt == USHORT( VariantType::Null ) )
                    {
                        return 0;
                    }
                    return -1;
                }
                else if ( second.vt == USHORT( VariantType::Null ) )
                {
                    return 1;
                }

                auto lcid = GetUserDefaultLCID( );
                auto result = VarCmp( ( VARIANT* )&first, ( VARIANT* )&second, lcid );
                if ( FAILED( result ) )
                {
                    CheckHRESULT( result );
                }
                return result - 1;
            }

            VariantType Type( ) const
            {
                return VariantType( vt );
            }

            VariantType ElementType( ) const
            {
                return VariantType( vt & VT_TYPEMASK );
            }

            bool IsEmpty( ) const
            {
                return Type( ) == VariantType::Empty;
            }

            bool IsNull( ) const
            {
                return Type( ) == VariantType::Null;
            }

            bool IsReference( ) const
            {
                return ( Type( ) & VariantType::Byref ) != VariantType::Empty;
            }

            bool IsArray( ) const
            {
                return ( Type( ) & VariantType::Array ) != VariantType::Empty;
            }



            Variant( )
            {
                SetVariantType( VariantType::Empty );
            }
            Variant( long long theValue )
            {
                SetVariantType( VariantType::Int64 );
                llVal = theValue;
            }
            Variant( unsigned long long theValue )
            {
                SetVariantType( VariantType::UInt64 );
                ullVal = theValue;
            }
            Variant( LONG theValue )
            {
                SetVariantType( VariantType::Long );
                lVal = theValue;
            }

            Variant( LONG theValue, VariantType variantType )
            {
                if ( variantType == VariantType::Long || variantType == VariantType::Error )
                {
                    SetVariantType( variantType );
                    lVal = theValue;
                }
                else
                {
                    SetVariantType( VariantType::Error );
                    scode = E_INVALIDARG;
                    CheckHRESULT( scode );
                }
            }

            Variant( BYTE theValue )
            {
                SetVariantType( VariantType::Byte );
                bVal = theValue;
            }
            Variant( SHORT theValue )
            {
                SetVariantType( VariantType::Short );
                iVal = theValue;
            }
            Variant( FLOAT theValue )
            {
                SetVariantType( VariantType::Float );
                fltVal = theValue;
            }
            Variant( DOUBLE theValue )
            {
                SetVariantType( VariantType::Double );
                dblVal = theValue;
            }

            Variant( DOUBLE theValue, VariantType variantType )
            {
                if ( variantType == VariantType::Double || variantType == VariantType::DateTime )
                {
                    SetVariantType( variantType );
                    dblVal = theValue;
                }
                else
                {
                    SetVariantType( VariantType::Error );
                    scode = E_INVALIDARG;
                    CheckHRESULT( scode );
                }
            }

            Variant( bool theValue )
            {
                SetVariantType( VariantType::Bool );
                boolVal = theValue ? VARIANT_TRUE : VARIANT_FALSE;
            }

            Variant( const CY& theValue )
            {
                SetVariantType( VariantType::Currency );
                cyVal = theValue;
            }
            Variant( const DateTime& theValue )
            {
                SetVariantType( VariantType::DateTime );
                date = theValue.ToOADate( );
            }
            Variant( const TimeSpan& theValue )
            {
                SetVariantType( VariantType::DateTime );
                date = theValue.TotalDays( );
            }


            Variant( const SysString& theValue )
            {
                SetVariantType( VariantType::BStr );
                bstrVal = theValue.Copy( );
            }

            Variant( const WideString& theValue )
            {
                SetVariantType( VariantType::BStr );
                bstrVal = nullptr;
                if ( theValue.length( ) )
                {
                    bstrVal = SysAllocStringLen( theValue.c_str( ), UINT( theValue.length( ) ) );
                    if ( !bstrVal )
                    {
                        CheckHRESULT( E_OUTOFMEMORY );
                    }
                }
            }


            Variant( IUnknown* pInterface )
            {
                SetVariantType( VariantType::Unknown );
                punkVal = pInterface;
                if ( punkVal )
                {
                    punkVal->AddRef( );
                }
            }

            Variant( IDispatch* pInterface )
            {
                SetVariantType( VariantType::Dispatch );
                pdispVal = pInterface;
                if ( pdispVal )
                {
                    pdispVal->AddRef( );
                }
            }

            Variant( SAFEARRAY* safeArray )
            {
                SetVariantType( VariantType::Array );
                if ( safeArray )
                {
                    auto vType = SafeArray::GetElementVariantType( safeArray );
                    SetVariantType( VariantType::Array | vType );
                    auto hr = SafeArrayCopy( safeArray, &parray );
                    CheckHRESULT( hr );
                }
                else
                {
                    parray = nullptr;
                }
            }

            Variant( CHAR theValue )
            {
                SetVariantType( VariantType::SByte );
                cVal = theValue;
            }

            Variant( USHORT theValue )
            {
                SetVariantType( VariantType::UShort );
                uiVal = theValue;
            }

            Variant( ULONG theValue )
            {
                SetVariantType( VariantType::ULong );
                ulVal = theValue;
            }




            Variant( const Variant& other )
            {
                VariantInit( this );
                auto hr = VariantCopy( this, &other );
                CheckHRESULT( hr );
            }

            Variant( Variant&& other )
            {
                memcpy( &vt, &other.vt, sizeof( VARIANT ) );
                memset( &other.vt, 0, sizeof( VARIANT ) );
            }

            Variant& Clear( )
            {
                switch ( vt )
                {
                    case VT_EMPTY:
                    case VT_NULL:
                    case VT_I1:
                    case VT_I2:
                    case VT_I4:
                    case VT_I8:
                    case VT_UI1:
                    case VT_UI2:
                    case VT_UI4:
                    case VT_UI8:
                    case VT_R4:
                    case VT_R8:
                    case VT_CY:
                    case VT_DATE:
                        vt = VT_EMPTY;
                        break;
                    default:
                        auto hr = VariantClear( this );
                        CheckHRESULT( hr );
                        break;

                }
                return *this;
            }

            ~Variant( )
            {
                if ( vt != VT_EMPTY )
                {
                    Clear( );
                }
            }

            Variant& operator = ( const Variant& other )
            {
                if ( &vt != &other.vt )
                {
                    if ( vt != VT_EMPTY )
                    {
                        auto hr = VariantClear( this );
                        CheckHRESULT( hr );
                    }
                    auto hr = VariantCopy( this, &other );
                    CheckHRESULT( hr );
                }
                return *this;
            }

            Variant& operator = ( Variant&& other )
            {
                if ( this != &other )
                {
                    if ( vt != VT_EMPTY )
                    {
                        auto hr = VariantClear( this );
                        CheckHRESULT( hr );
                    }
                    memcpy( &vt, &other.vt, sizeof( VARIANT ) );
                    memset( &other.vt, 0, sizeof( VARIANT ) );
                }
                return *this;
            }

            int CompareTo( const VARIANT& other ) const
            {
                return Compare( *this, other );
            }

            int CompareTo( const Variant& other ) const
            {
                return Compare( *this, other );
            }

            bool operator == ( const VARIANT& other ) const
            {
                return CompareTo( other ) == 0;
            }
            bool operator != ( const VARIANT& other ) const
            {
                return CompareTo( other ) != 0;
            }
            bool operator <= ( const VARIANT& other ) const
            {
                return CompareTo( other ) <= 0;
            }
            bool operator <  ( const VARIANT& other ) const
            {
                return CompareTo( other ) <  0;
            }
            bool operator >  ( const VARIANT& other ) const
            {
                return CompareTo( other ) >  0;
            }
            bool operator >= ( const VARIANT& other ) const
            {
                return CompareTo( other ) >= 0;
            }

            bool operator == ( const Variant& other ) const
            {
                return CompareTo( other ) == 0;
            }
            bool operator != ( const Variant& other ) const
            {
                return CompareTo( other ) != 0;
            }
            bool operator <= ( const Variant& other ) const
            {
                return CompareTo( other ) <= 0;
            }
            bool operator <  ( const Variant& other ) const
            {
                return CompareTo( other ) <  0;
            }
            bool operator >  ( const Variant& other ) const
            {
                return CompareTo( other ) >  0;
            }
            bool operator >= ( const Variant& other ) const
            {
                return CompareTo( other ) >= 0;
            }


            HRESULT AssignTo( VARIANT& other ) const
            {
                HRESULT result = S_OK;
                if ( other.vt != VT_EMPTY )
                {
                    result = VariantClear( &other );
                    if ( FAILED( result ) )
                    {
                        return result;
                    }
                    other.vt = VT_EMPTY;
                }
                if ( IsEmpty( ) == FALSE )
                {
                    result = VariantCopy( &other, this );
                }
                return result;
            }

            Variant& Assign( long long theValue )
            {
                Clear( );
                SetVariantType( VariantType::Int64 );
                llVal = theValue;
                return *this;
            }
            Variant& Assign( unsigned long long theValue )
            {
                Clear( );
                SetVariantType( VariantType::UInt64 );
                ullVal = theValue;
                return *this;
            }
            Variant& Assign( LONG theValue )
            {
                Clear( );
                SetVariantType( VariantType::Long );
                lVal = theValue;
                return *this;
            }

            Variant& Assign( LONG theValue, VariantType variantType )
            {
                Clear( );
                if ( variantType == VariantType::Long || variantType == VariantType::Error )
                {
                    SetVariantType( variantType );
                    lVal = theValue;
                }
                else
                {
                    SetVariantType( VariantType::Error );
                    scode = E_INVALIDARG;
                    CheckHRESULT( scode );
                }
                return *this;
            }

            Variant& Assign( BYTE theValue )
            {
                Clear( );
                SetVariantType( VariantType::Byte );
                bVal = theValue;
                return *this;
            }
            Variant& Assign( SHORT theValue )
            {
                Clear( );
                SetVariantType( VariantType::Short );
                iVal = theValue;
                return *this;
            }
            Variant& Assign( FLOAT theValue )
            {
                Clear( );
                SetVariantType( VariantType::Float );
                fltVal = theValue;
                return *this;
            }
            Variant& Assign( DOUBLE theValue )
            {
                Clear( );
                SetVariantType( VariantType::Double );
                dblVal = theValue;
                return *this;
            }

            Variant& Assign( DOUBLE theValue, VariantType variantType )
            {
                Clear( );
                if ( variantType == VariantType::Double || variantType == VariantType::DateTime )
                {
                    SetVariantType( variantType );
                    dblVal = theValue;
                }
                else
                {
                    SetVariantType( VariantType::Error );
                    scode = E_INVALIDARG;
                    CheckHRESULT( scode );
                }
                return *this;
            }

            Variant& Assign( bool theValue )
            {
                Clear( );
                SetVariantType( VariantType::Bool );
                boolVal = theValue ? VARIANT_TRUE : VARIANT_FALSE;
                return *this;
            }

            Variant& Assign( const CY& theValue )
            {
                Clear( );
                SetVariantType( VariantType::Currency );
                cyVal = theValue;
                return *this;
            }
            Variant& Assign( const DateTime& theValue )
            {
                Clear( );
                SetVariantType( VariantType::DateTime );
                date = theValue.ToOADate( );
                return *this;
            }
            Variant& Assign( const TimeSpan& theValue )
            {
                Clear( );
                SetVariantType( VariantType::Double );
                date = theValue.TotalDays( );
                return *this;
            }

            Variant& Assign( const SysString& theValue )
            {
                Clear( );
                SetVariantType( VariantType::BStr );
                bstrVal = theValue.Copy( );
                return *this;
            }

            Variant& Assign( const WideString& theValue )
            {
                Clear( );
                SetVariantType( VariantType::BStr );
                bstrVal = nullptr;
                if ( theValue.length( ) )
                {
                    bstrVal = SysAllocStringLen( theValue.c_str( ), UINT( theValue.length( ) ) );
                    if ( !bstrVal )
                    {
                        CheckHRESULT( E_OUTOFMEMORY );
                    }
                }
                return *this;
            }


            Variant& Assign( IUnknown* pInterface )
            {
                Clear( );
                SetVariantType( VariantType::Unknown );
                punkVal = pInterface;
                if ( punkVal )
                {
                    punkVal->AddRef( );
                }
                return *this;
            }

            Variant& Assign( IDispatch* pInterface )
            {
                Clear( );
                SetVariantType( VariantType::Dispatch );
                pdispVal = pInterface;
                if ( pdispVal )
                {
                    pdispVal->AddRef( );
                }
                return *this;
            }

            Variant& Assign( SAFEARRAY* safeArray )
            {
                Clear( );
                SetVariantType( VariantType::Array );
                if ( safeArray )
                {
                    auto vType = SafeArray::GetElementVariantType( safeArray );
                    SetVariantType( VariantType::Array | vType );
                    auto hr = SafeArrayCopy( safeArray, &parray );
                    CheckHRESULT( hr );
                }
                else
                {
                    parray = nullptr;
                }
                return *this;
            }

            Variant& Assign( CHAR theValue )
            {
                Clear( );
                SetVariantType( VariantType::SByte );
                cVal = theValue;
                return *this;
            }

            Variant& Assign( USHORT theValue )
            {
                Clear( );
                SetVariantType( VariantType::UShort );
                uiVal = theValue;
                return *this;
            }

            Variant& Assign( ULONG theValue )
            {
                Clear( );
                SetVariantType( VariantType::ULong );
                ulVal = theValue;
                return *this;
            }

            template <typename T>
            Variant& operator = ( const T& theValue )
            {
                return Assign( theValue );
            }

            bool AsBoolean( ) const
            {
                switch ( Type( ) )
                {
                    case VariantType::Empty:
                        return false;
                        break;
                    case VariantType::Null:
                        return false;
                        break;
                    case VariantType::Bool:
                        return boolVal != VARIANT_FALSE;
                        break;
                    case VariantType::Int1:
                        return cVal != 0;
                        break;
                    case VariantType::UInt1:
                        return bVal != 0;
                        break;
                    case VariantType::Int2:
                        return iVal != 0;
                        break;
                    case VariantType::UInt2:
                        return uiVal != 0;
                        break;
                    case VariantType::Int4:
                        return lVal != 0;
                        break;
                    case VariantType::UInt4:
                        return ulVal != 0;
                        break;
                    case VariantType::Int8:
                        return llVal != 0;
                        break;
                    case VariantType::UInt8:
                        return ullVal != 0;
                        break;
                    case VariantType::Real4:
                        return fltVal != 0.0f;
                        break;
                    case VariantType::Real8:
                        return dblVal != 0.0;
                        break;
                    default:
                    {
                        VARIANT result = { 0, };
                        auto hr = VariantChangeType( &result, this, 0, ( VARTYPE )VariantType::Bool );
                        CheckHRESULT( hr );
                        return result.boolVal != VARIANT_FALSE;
                    }
                        break;
                }
            }

            char AsSByte( ) const
            {
                char result = 0;
                switch ( Type( ) )
                {
                    case VariantType::Bool:
                        result = boolVal != VARIANT_FALSE ? 1 : 0;
                        break;
                    case VariantType::Int1:
                        result = static_cast<decltype( result )>( cVal );
                        break;
                    case VariantType::UInt1:
                        result = static_cast<decltype( result )>( bVal );
                        break;
                    case VariantType::Int2:
                        result = static_cast<decltype( result )>( iVal );
                        break;
                    case VariantType::UInt2:
                        result = static_cast<decltype( result )>( uiVal );
                        break;
                    case VariantType::Int4:
                        result = static_cast<decltype( result )>( lVal );
                        break;
                    case VariantType::UInt4:
                        result = static_cast<decltype( result )>( ulVal );
                        break;
                    case VariantType::Int8:
                        result = static_cast<decltype( result )>( llVal );
                        break;
                    case VariantType::UInt8:
                        result = static_cast<decltype( result )>( ullVal );
                        break;
                    case VariantType::Real4:
                        result = static_cast<decltype( result )>( fltVal );
                        break;
                    case VariantType::Real8:
                        result = static_cast<decltype( result )>( dblVal );
                        break;
                    default:
                    {
                        VARIANT result = { 0, };
                        auto hr = VariantChangeType( &result, this, 0, ( VARTYPE )VariantType::Int1 );
                        CheckHRESULT( hr );
                        return result.cVal;
                    }
                        break;
                }
                return result;
            }

            unsigned char AsByte( ) const
            {
                unsigned char result = 0;
                switch ( Type( ) )
                {
                    case VariantType::Bool:
                        result = boolVal != VARIANT_FALSE ? 1 : 0;
                        break;
                    case VariantType::Int1:
                        result = static_cast<decltype( result )>( cVal );
                        break;
                    case VariantType::UInt1:
                        result = static_cast<decltype( result )>( bVal );
                        break;
                    case VariantType::Int2:
                        result = static_cast<decltype( result )>( iVal );
                        break;
                    case VariantType::UInt2:
                        result = static_cast<decltype( result )>( uiVal );
                        break;
                    case VariantType::Int4:
                        result = static_cast<decltype( result )>( lVal );
                        break;
                    case VariantType::UInt4:
                        result = static_cast<decltype( result )>( ulVal );
                        break;
                    case VariantType::Int8:
                        result = static_cast<decltype( result )>( llVal );
                        break;
                    case VariantType::UInt8:
                        result = static_cast<decltype( result )>( ullVal );
                        break;
                    case VariantType::Real4:
                        result = static_cast<decltype( result )>( fltVal );
                        break;
                    case VariantType::Real8:
                        result = static_cast<decltype( result )>( dblVal );
                        break;
                    default:
                    {
                        VARIANT result = { 0, };
                        auto hr = VariantChangeType( &result, this, 0, ( VARTYPE )VariantType::UInt1 );
                        CheckHRESULT( hr );
                        return result.bVal;
                    }
                        break;
                }
                return result;
            }

            short AsInt16( ) const
            {
                short result = 0;
                switch ( Type( ) )
                {
                    case VariantType::Bool:
                        result = boolVal != VARIANT_FALSE ? 1 : 0;
                        break;
                    case VariantType::Int1:
                        result = static_cast<decltype( result )>( cVal );
                        break;
                    case VariantType::UInt1:
                        result = static_cast<decltype( result )>( bVal );
                        break;
                    case VariantType::Int2:
                        result = static_cast<decltype( result )>( iVal );
                        break;
                    case VariantType::UInt2:
                        result = static_cast<decltype( result )>( uiVal );
                        break;
                    case VariantType::Int4:
                        result = static_cast<decltype( result )>( lVal );
                        break;
                    case VariantType::UInt4:
                        result = static_cast<decltype( result )>( ulVal );
                        break;
                    case VariantType::Int8:
                        result = static_cast<decltype( result )>( llVal );
                        break;
                    case VariantType::UInt8:
                        result = static_cast<decltype( result )>( ullVal );
                        break;
                    case VariantType::Real4:
                        result = static_cast<decltype( result )>( fltVal );
                        break;
                    case VariantType::Real8:
                        result = static_cast<decltype( result )>( dblVal );
                        break;
                    default:
                    {
                        VARIANT result = { 0, };
                        auto hr = VariantChangeType( &result, this, 0, ( VARTYPE )VariantType::Int2 );
                        CheckHRESULT( hr );
                        return result.iVal;
                    }
                        break;
                }
                return result;
            }

            unsigned short AsUInt16( ) const
            {
                unsigned short result = 0;
                switch ( Type( ) )
                {
                    case VariantType::Bool:
                        result = boolVal != VARIANT_FALSE ? 1 : 0;
                        break;
                    case VariantType::Int1:
                        result = static_cast<decltype( result )>( cVal );
                        break;
                    case VariantType::UInt1:
                        result = static_cast<decltype( result )>( bVal );
                        break;
                    case VariantType::Int2:
                        result = static_cast<decltype( result )>( iVal );
                        break;
                    case VariantType::UInt2:
                        result = static_cast<decltype( result )>( uiVal );
                        break;
                    case VariantType::Int4:
                        result = static_cast<decltype( result )>( lVal );
                        break;
                    case VariantType::UInt4:
                        result = static_cast<decltype( result )>( ulVal );
                        break;
                    case VariantType::Int8:
                        result = static_cast<decltype( result )>( llVal );
                        break;
                    case VariantType::UInt8:
                        result = static_cast<decltype( result )>( ullVal );
                        break;
                    case VariantType::Real4:
                        result = static_cast<decltype( result )>( fltVal );
                        break;
                    case VariantType::Real8:
                        result = static_cast<decltype( result )>( dblVal );
                        break;
                    default:
                    {
                        VARIANT result = { 0, };
                        auto hr = VariantChangeType( &result, this, 0, ( VARTYPE )VariantType::UInt2 );
                        CheckHRESULT( hr );
                        return result.uiVal;
                    }
                        break;
                }
                return result;
            }

            int AsInt32( ) const
            {
                int result = 0;
                switch ( Type( ) )
                {
                    case VariantType::Bool:
                        result = boolVal != VARIANT_FALSE ? 1 : 0;
                        break;
                    case VariantType::Int1:
                        result = static_cast<decltype( result )>( cVal );
                        break;
                    case VariantType::UInt1:
                        result = static_cast<decltype( result )>( bVal );
                        break;
                    case VariantType::Int2:
                        result = static_cast<decltype( result )>( iVal );
                        break;
                    case VariantType::UInt2:
                        result = static_cast<decltype( result )>( uiVal );
                        break;
                    case VariantType::Int4:
                        result = static_cast<decltype( result )>( lVal );
                        break;
                    case VariantType::UInt4:
                        result = static_cast<decltype( result )>( ulVal );
                        break;
                    case VariantType::Int8:
                        result = static_cast<decltype( result )>( llVal );
                        break;
                    case VariantType::UInt8:
                        result = static_cast<decltype( result )>( ullVal );
                        break;
                    case VariantType::Real4:
                        result = static_cast<decltype( result )>( fltVal );
                        break;
                    case VariantType::Real8:
                        result = static_cast<decltype( result )>( dblVal );
                        break;
                    default:
                    {
                        VARIANT result = { 0, };
                        auto hr = VariantChangeType( &result, this, 0, ( VARTYPE )VariantType::Int4 );
                        CheckHRESULT( hr );
                        return result.lVal;
                    }
                        break;
                }
                return result;
            }

            unsigned int AsUInt32( ) const
            {
                unsigned int result = 0;
                switch ( Type( ) )
                {
                    case VariantType::Bool:
                        result = boolVal != VARIANT_FALSE ? 1 : 0;
                        break;
                    case VariantType::Int1:
                        result = static_cast<decltype( result )>( cVal );
                        break;
                    case VariantType::UInt1:
                        result = static_cast<decltype( result )>( bVal );
                        break;
                    case VariantType::Int2:
                        result = static_cast<decltype( result )>( iVal );
                        break;
                    case VariantType::UInt2:
                        result = static_cast<decltype( result )>( uiVal );
                        break;
                    case VariantType::Int4:
                        result = static_cast<decltype( result )>( lVal );
                        break;
                    case VariantType::UInt4:
                        result = static_cast<decltype( result )>( ulVal );
                        break;
                    case VariantType::Int8:
                        result = static_cast<decltype( result )>( llVal );
                        break;
                    case VariantType::UInt8:
                        result = static_cast<decltype( result )>( ullVal );
                        break;
                    case VariantType::Real4:
                        result = static_cast<decltype( result )>( fltVal );
                        break;
                    case VariantType::Real8:
                        result = static_cast<decltype( result )>( dblVal );
                        break;
                    default:
                    {
                        VARIANT result = { 0, };
                        auto hr = VariantChangeType( &result, this, 0, ( VARTYPE )VariantType::UInt4 );
                        CheckHRESULT( hr );
                        return result.ulVal;
                    }
                        break;
                }
                return result;
            }

            long long AsInt64( ) const
            {
                long long result = 0;
                switch ( Type( ) )
                {
                    case VariantType::Bool:
                        result = boolVal != VARIANT_FALSE ? 1 : 0;
                        break;
                    case VariantType::Int1:
                        result = static_cast<decltype( result )>( cVal );
                        break;
                    case VariantType::UInt1:
                        result = static_cast<decltype( result )>( bVal );
                        break;
                    case VariantType::Int2:
                        result = static_cast<decltype( result )>( iVal );
                        break;
                    case VariantType::UInt2:
                        result = static_cast<decltype( result )>( uiVal );
                        break;
                    case VariantType::Int4:
                        result = static_cast<decltype( result )>( lVal );
                        break;
                    case VariantType::UInt4:
                        result = static_cast<decltype( result )>( ulVal );
                        break;
                    case VariantType::Int8:
                        result = static_cast<decltype( result )>( llVal );
                        break;
                    case VariantType::UInt8:
                        result = static_cast<decltype( result )>( ullVal );
                        break;
                    case VariantType::Real4:
                        result = static_cast<decltype( result )>( fltVal );
                        break;
                    case VariantType::Real8:
                        result = static_cast<decltype( result )>( dblVal );
                        break;
                    default:
                    {
                        VARIANT result = { 0, };
                        auto hr = VariantChangeType( &result, this, 0, ( VARTYPE )VariantType::Int64 );
                        CheckHRESULT( hr );
                        return result.llVal;
                    }
                        break;
                }
                return result;
            }

            unsigned long long AsUInt64( ) const
            {
                unsigned long long result = 0;
                switch ( Type( ) )
                {
                    case VariantType::Bool:
                        result = boolVal != VARIANT_FALSE ? 1 : 0;
                        break;
                    case VariantType::Int1:
                        result = static_cast<decltype( result )>( cVal );
                        break;
                    case VariantType::UInt1:
                        result = static_cast<decltype( result )>( bVal );
                        break;
                    case VariantType::Int2:
                        result = static_cast<decltype( result )>( iVal );
                        break;
                    case VariantType::UInt2:
                        result = static_cast<decltype( result )>( uiVal );
                        break;
                    case VariantType::Int4:
                        result = static_cast<decltype( result )>( lVal );
                        break;
                    case VariantType::UInt4:
                        result = static_cast<decltype( result )>( ulVal );
                        break;
                    case VariantType::Int8:
                        result = static_cast<decltype( result )>( llVal );
                        break;
                    case VariantType::UInt8:
                        result = static_cast<decltype( result )>( ullVal );
                        break;
                    case VariantType::Real4:
                        result = static_cast<decltype( result )>( fltVal );
                        break;
                    case VariantType::Real8:
                        result = static_cast<decltype( result )>( dblVal );
                        break;
                    default:
                    {
                        VARIANT result = { 0, };
                        auto hr = VariantChangeType( &result, this, 0, ( VARTYPE )VariantType::UInt64 );
                        CheckHRESULT( hr );
                        return result.ullVal;
                    }
                        break;
                }
                return result;
            }

            float AsSingle( ) const
            {
                float result = 0;
                switch ( Type( ) )
                {
                    case VariantType::Bool:
                        result = boolVal != VARIANT_FALSE ? 1.0f : 0.0f;
                        break;
                    case VariantType::Int1:
                        result = static_cast<decltype( result )>( cVal );
                        break;
                    case VariantType::UInt1:
                        result = static_cast<decltype( result )>( bVal );
                        break;
                    case VariantType::Int2:
                        result = static_cast<decltype( result )>( iVal );
                        break;
                    case VariantType::UInt2:
                        result = static_cast<decltype( result )>( uiVal );
                        break;
                    case VariantType::Int4:
                        result = static_cast<decltype( result )>( lVal );
                        break;
                    case VariantType::UInt4:
                        result = static_cast<decltype( result )>( ulVal );
                        break;
                    case VariantType::Int8:
                        result = static_cast<decltype( result )>( llVal );
                        break;
                    case VariantType::UInt8:
                        result = static_cast<decltype( result )>( ullVal );
                        break;
                    case VariantType::Real4:
                        result = static_cast<decltype( result )>( fltVal );
                        break;
                    case VariantType::Real8:
                        result = static_cast<decltype( result )>( dblVal );
                        break;
                    default:
                    {
                        VARIANT result = { 0, };
                        auto hr = VariantChangeType( &result, this, 0, ( VARTYPE )VariantType::Real4 );
                        CheckHRESULT( hr );
                        return result.fltVal;
                    }
                        break;
                }
                return result;
            }

            double AsDouble( ) const
            {
                double result = 0;
                switch ( Type( ) )
                {
                    case VariantType::Bool:
                        result = boolVal != VARIANT_FALSE ? 1 : 0;
                        break;
                    case VariantType::Int1:
                        result = static_cast<decltype( result )>( cVal );
                        break;
                    case VariantType::UInt1:
                        result = static_cast<decltype( result )>( bVal );
                        break;
                    case VariantType::Int2:
                        result = static_cast<decltype( result )>( iVal );
                        break;
                    case VariantType::UInt2:
                        result = static_cast<decltype( result )>( uiVal );
                        break;
                    case VariantType::Int4:
                        result = static_cast<decltype( result )>( lVal );
                        break;
                    case VariantType::UInt4:
                        result = static_cast<decltype( result )>( ulVal );
                        break;
                    case VariantType::Int8:
                        result = static_cast<decltype( result )>( llVal );
                        break;
                    case VariantType::UInt8:
                        result = static_cast<decltype( result )>( ullVal );
                        break;
                    case VariantType::Real4:
                        result = static_cast<decltype( result )>( fltVal );
                        break;
                    case VariantType::Real8:
                        result = static_cast<decltype( result )>( dblVal );
                        break;
                    default:
                    {
                        VARIANT result = { 0, };
                        auto hr = VariantChangeType( &result, this, 0, ( VARTYPE )VariantType::Real8 );
                        CheckHRESULT( hr );
                        return result.dblVal;
                    }
                        break;
                }
                return result;
            }

            String AsString( ) const
            {
                if ( Type( ) == VariantType::BStr )
                {
                    if ( bstrVal )
                    {
                        return String::From( bstrVal );
                    }
                    else
                    {
                        return String( );
                    }
                }
                else
                {
                    Variant result;
                    auto hr = VariantChangeType( &result, this, 0, ( VARTYPE )VariantType::BStr );
                    CheckHRESULT( hr );
                    if ( result.bstrVal )
                    {
                        return String::From( result.bstrVal );
                    }
                    else
                    {
                        return String( );
                    }
                }
            }

            WideString AsWideString( ) const
            {
                if ( Type( ) == VariantType::BStr )
                {
                    if ( bstrVal )
                    {
                        return WideString::From( bstrVal );
                    }
                    else
                    {
                        return WideString( );
                    }
                }
                else
                {
                    Variant result;
                    auto hr = VariantChangeType( &result, this, 0, ( VARTYPE )VariantType::BStr );
                    CheckHRESULT( hr );
                    if ( result.bstrVal )
                    {
                        return WideString::From( result.bstrVal );
                    }
                    else
                    {
                        return WideString( );
                    }
                }
            }


            DateTime AsDateTime( ) const
            {
                if ( Type( ) == VariantType::DateTime )
                {
                    return DateTime::FromOADate( date );
                }
                else
                {
                    Variant result;
                    auto hr = VariantChangeType( &result, this, 0, ( VARTYPE )VariantType::DateTime );
                    CheckHRESULT( hr );
                    return DateTime::FromOADate( result.date );
                }
            }

            TimeSpan AsTimeSpan( ) const
            {
                auto type = Type( );
                if ( type == VariantType::Real8 )
                {
                    return TimeSpan::FromDays( dblVal );
                }
                else if ( type == VariantType::Real4 )
                {
                    return TimeSpan::FromDays( fltVal );
                }
                else
                {
                    Variant result;
                    auto hr = VariantChangeType( &result, this, 0, ( VARTYPE )VariantType::Real8 );
                    CheckHRESULT( hr );
                    return TimeSpan::FromDays( result.dblVal );
                }
            }

            Guid AsGuid( ) const
            {
                return Guid( AsWideString( ) );
            }




            Variant Abs( ) const
            {
                Variant result;
                auto hr = VarAbs( ( LPVARIANT )this, &result );
                if ( FAILED( hr ) )
                {
                    CheckHRESULT( hr );
                }
                return result;
            }

            Variant Add( const Variant& other ) const
            {
                Variant result;
                auto hr = VarAdd( ( LPVARIANT )this, ( LPVARIANT )&other, &result );
                if ( FAILED( hr ) )
                {
                    CheckHRESULT( hr );
                }
                return result;
            }

            friend Variant operator + ( const Variant& left, const Variant& right )
            {
                return left.Add( right );
            }

            Variant And( const Variant& other ) const
            {
                Variant result;
                auto hr = VarAnd( ( LPVARIANT )this, ( LPVARIANT )&other, &result );
                if ( FAILED( hr ) )
                {
                    CheckHRESULT( hr );
                }
                return result;
            }

            friend Variant operator & ( const Variant& left, const Variant& right )
            {
                return left.And( right );
            }

            Variant Concatenate( const Variant& other ) const
            {
                Variant result;
                auto hr = VarCat( ( LPVARIANT )this, ( LPVARIANT )&other, &result );
                if ( FAILED( hr ) )
                {
                    CheckHRESULT( hr );
                }
                return result;
            }


            Variant Div( const Variant& other ) const
            {
                Variant result;
                auto hr = VarDiv( ( LPVARIANT )this, ( LPVARIANT )&other, &result );
                if ( FAILED( hr ) )
                {
                    CheckHRESULT( hr );
                }
                return result;
            }

            friend Variant operator / ( const Variant& left, const Variant& right )
            {
                return left.Div( right );
            }


            Variant IDiv( const Variant& other ) const
            {
                Variant result;
                auto hr = VarIdiv( ( LPVARIANT )this, ( LPVARIANT )&other, &result );
                if ( FAILED( hr ) )
                {
                    CheckHRESULT( hr );
                }
                return result;
            }

            Variant Trunc( ) const
            {
                Variant result;
                auto hr = VarFix( ( LPVARIANT )this, &result );
                if ( FAILED( hr ) )
                {
                    CheckHRESULT( hr );
                }
                return result;
            }

            Variant Mod( const Variant& other ) const
            {
                Variant result;
                auto hr = VarMod( ( LPVARIANT )this, ( LPVARIANT )&other, &result );
                if ( FAILED( hr ) )
                {
                    CheckHRESULT( hr );
                }
                return result;
            }


            friend Variant operator % ( const Variant& left, const Variant& right )
            {
                return left.Mod( right );
            }

            Variant Mul( const Variant& other ) const
            {
                Variant result;
                auto hr = VarMul( ( LPVARIANT )this, ( LPVARIANT )&other, &result );
                if ( FAILED( hr ) )
                {
                    CheckHRESULT( hr );
                }
                return result;
            }

            friend Variant operator * ( const Variant& left, const Variant& right )
            {
                return left.Mod( right );
            }

            Variant Neg( ) const
            {
                Variant result;
                auto hr = VarNeg( ( LPVARIANT )this, &result );
                if ( FAILED( hr ) )
                {
                    CheckHRESULT( hr );
                }
                return result;
            }

            Variant Not( ) const
            {
                Variant result;
                auto hr = VarNot( ( LPVARIANT )this, &result );
                if ( FAILED( hr ) )
                {
                    CheckHRESULT( hr );
                }
                return result;
            }

            Variant operator ! ( ) const
            {
                return Not( );
            }


            Variant Or( const Variant& other ) const
            {
                Variant result;
                auto hr = VarOr( ( LPVARIANT )this, ( LPVARIANT )&other, &result );
                if ( FAILED( hr ) )
                {
                    CheckHRESULT( hr );
                }
                return result;
            }

            friend Variant operator | ( const Variant& left, const Variant& right )
            {
                return left.Or( right );
            }

            Variant Sub( const Variant& other ) const
            {
                Variant result;
                auto hr = VarSub( ( LPVARIANT )this, ( LPVARIANT )&other, &result );
                if ( FAILED( hr ) )
                {
                    CheckHRESULT( hr );
                }
                return result;
            }

            friend Variant operator - ( const Variant& left, const Variant& right )
            {
                return left.Sub( right );
            }

            Variant Pow( const Variant& other ) const
            {
                Variant result;
                auto hr = VarPow( ( LPVARIANT )this, ( LPVARIANT )&other, &result );
                if ( FAILED( hr ) )
                {
                    CheckHRESULT( hr );
                }
                return result;
            }


        };

        // ----------------------------------------------------------------------
        // PropertyVariant
        // ----------------------------------------------------------------------
        class PropertyVariant : public PROPVARIANT
        {
            void SetVariantType( VariantType variantType )
            {
                vt = USHORT( variantType );
            }
        public:
            // Temporary solution, will probably not work well for those types
            // that are specific to PROPVARIANT.
            // Relies on the fact that VARIANT and PROPVARIANT have the same 
            // binary layout.  
            static int Compare( const PROPVARIANT& first, const PROPVARIANT& second )
            {
                if ( first.vt == USHORT( VariantType::Empty ) )
                {
                    if ( second.vt == USHORT( VariantType::Empty ) )
                    {
                        return 0;
                    }
                    return -1;
                }
                else if ( second.vt == USHORT( VariantType::Empty ) )
                {
                    return 1;
                }
                else if ( first.vt == USHORT( VariantType::Null ) )
                {
                    if ( second.vt == USHORT( VariantType::Null ) )
                    {
                        return 0;
                    }
                    return -1;
                }
                else if ( second.vt == USHORT( VariantType::Null ) )
                {
                    return 1;
                }

                auto lcid = GetUserDefaultLCID( );
                auto result = VarCmp( ( VARIANT* )&first, ( VARIANT* )&second, lcid );
                if ( FAILED( result ) )
                {
                    CheckHRESULT( result );
                }
                return result - 1;
            }

            VariantType Type( ) const
            {
                return VariantType( vt );
            }

            VariantType ElementType( ) const
            {
                return VariantType( vt & VT_TYPEMASK );
            }

            bool IsEmpty( ) const
            {
                return Type( ) == VariantType::Empty;
            }

            bool IsNull( ) const
            {
                return Type( ) == VariantType::Null;
            }

            bool IsReference( ) const
            {
                return ( Type( ) & VariantType::Byref ) != VariantType::Empty;
            }

            bool IsArray( ) const
            {
                return ( Type( ) & VariantType::Array ) != VariantType::Empty;
            }



            PropertyVariant( )
            {
                SetVariantType( VariantType::Empty );
            }
            PropertyVariant( INT64 theValue )
            {
                SetVariantType( VariantType::Int64 );
                hVal.QuadPart = theValue;
            }
            PropertyVariant( UINT64 theValue )
            {
                SetVariantType( VariantType::UInt64 );
                uhVal.QuadPart = theValue;
            }
            PropertyVariant( LONG theValue )
            {
                SetVariantType( VariantType::Long );
                lVal = theValue;
            }

            PropertyVariant( LONG theValue, VariantType variantType )
            {
                if ( variantType == VariantType::Long || variantType == VariantType::Error )
                {
                    SetVariantType( variantType );
                    lVal = theValue;
                }
                else
                {
                    SetVariantType( VariantType::Error );
                    scode = E_INVALIDARG;
                    CheckHRESULT( scode );
                }
            }

            PropertyVariant( BYTE theValue )
            {
                SetVariantType( VariantType::Byte );
                bVal = theValue;
            }
            PropertyVariant( SHORT theValue )
            {
                SetVariantType( VariantType::Short );
                iVal = theValue;
            }
            PropertyVariant( FLOAT theValue )
            {
                SetVariantType( VariantType::Float );
                fltVal = theValue;
            }
            PropertyVariant( DOUBLE theValue )
            {
                SetVariantType( VariantType::Double );
                dblVal = theValue;
            }

            PropertyVariant( DOUBLE theValue, VariantType variantType )
            {
                if ( variantType == VariantType::Double || variantType == VariantType::DateTime )
                {
                    SetVariantType( variantType );
                    dblVal = theValue;
                }
                else
                {
                    SetVariantType( VariantType::Error );
                    scode = E_INVALIDARG;
                    CheckHRESULT( scode );
                }
            }

            PropertyVariant( bool theValue )
            {
                SetVariantType( VariantType::Bool );
                boolVal = theValue ? VARIANT_TRUE : VARIANT_FALSE;
            }

            PropertyVariant( const CY& theValue )
            {
                SetVariantType( VariantType::Currency );
                cyVal = theValue;
            }
            PropertyVariant( const DateTime& theValue )
            {
                SetVariantType( VariantType::DateTime );
                date = theValue.ToOADate( );
            }
            PropertyVariant( const TimeSpan& theValue )
            {
                SetVariantType( VariantType::DateTime );
                date = theValue.TotalDays( );
            }

            PropertyVariant( const FILETIME& theValue )
            {
                SetVariantType( VariantType::FileTime );
                filetime = theValue;
            }

            PropertyVariant( const SysString& theValue )
            {
                SetVariantType( VariantType::BStr );
                bstrVal = theValue.Copy( );
            }

            PropertyVariant( IUnknown* pInterface )
            {
                SetVariantType( VariantType::Unknown );
                punkVal = pInterface;
                if ( punkVal )
                {
                    punkVal->AddRef( );
                }
            }

            PropertyVariant( IDispatch* pInterface )
            {
                SetVariantType( VariantType::Dispatch );
                pdispVal = pInterface;
                if ( pdispVal )
                {
                    pdispVal->AddRef( );
                }
            }

            PropertyVariant( SAFEARRAY* safeArray )
            {
                SetVariantType( VariantType::Array );
                if ( safeArray )
                {
                    auto vType = SafeArray::GetElementVariantType( safeArray );
                    SetVariantType( VariantType::Array | vType );
                    auto hr = SafeArrayCopy( safeArray, &parray );
                    CheckHRESULT( hr );
                }
                else
                {
                    parray = nullptr;
                }
            }

            PropertyVariant( CHAR theValue )
            {
                SetVariantType( VariantType::SByte );
                cVal = theValue;
            }

            PropertyVariant( USHORT theValue )
            {
                SetVariantType( VariantType::UShort );
                uiVal = theValue;
            }

            PropertyVariant( ULONG theValue )
            {
                SetVariantType( VariantType::ULong );
                ulVal = theValue;
            }

            PropertyVariant( const PropertyVariant& other )
            {
                PropVariantInit( this );
                auto hr = PropVariantCopy( this, &other );
                CheckHRESULT( hr );
            }

            PropertyVariant( PropertyVariant&& other )
            {
                memcpy( &vt, &other.vt, sizeof( VARIANT ) );
                memset( &other.vt, 0, sizeof( VARIANT ) );
            }

            PropertyVariant& Clear( )
            {
                switch ( vt )
                {
                    case VT_EMPTY:
                    case VT_NULL:
                    case VT_I1:
                    case VT_I2:
                    case VT_I4:
                    case VT_I8:
                    case VT_UI1:
                    case VT_UI2:
                    case VT_UI4:
                    case VT_UI8:
                    case VT_R4:
                    case VT_R8:
                    case VT_CY:
                    case VT_DATE:
                        vt = VT_EMPTY;
                        break;
                    default:
                        auto hr = PropVariantClear( this );
                        CheckHRESULT( hr );
                        break;

                }
                return *this;
            }

            ~PropertyVariant( )
            {
                if ( vt != VT_EMPTY )
                {
                    Clear( );
                }
            }

            PropertyVariant& operator = ( const PropertyVariant& other )
            {
                if ( &vt != &other.vt )
                {
                    if ( vt != VT_EMPTY )
                    {
                        Clear( );
                    }
                    auto hr = PropVariantCopy( this, &other );
                    CheckHRESULT( hr );
                }
                return *this;
            }

            PropertyVariant& operator = ( PropertyVariant&& other )
            {
                if ( this != &other )
                {
                    if ( vt != VT_EMPTY )
                    {
                        Clear( );
                    }
                    memcpy( &vt, &other.vt, sizeof( VARIANT ) );
                    memset( &other.vt, 0, sizeof( VARIANT ) );
                }
            }

            PropertyVariant& Assign( INT64 theValue )
            {
                Clear( );
                SetVariantType( VariantType::Int64 );
                hVal.QuadPart = theValue;
                return *this;
            }
            PropertyVariant& Assign( UINT64 theValue )
            {
                Clear( );
                SetVariantType( VariantType::UInt64 );
                uhVal.QuadPart = theValue;
                return *this;
            }
            PropertyVariant& Assign( LONG theValue )
            {
                Clear( );
                SetVariantType( VariantType::Long );
                lVal = theValue;
                return *this;
            }

            PropertyVariant& Assign( LONG theValue, VariantType variantType )
            {
                Clear( );
                if ( variantType == VariantType::Long || variantType == VariantType::Error )
                {
                    SetVariantType( variantType );
                    lVal = theValue;
                }
                else
                {
                    SetVariantType( VariantType::Error );
                    scode = E_INVALIDARG;
                    CheckHRESULT( scode );
                }
                return *this;
            }

            PropertyVariant& Assign( BYTE theValue )
            {
                Clear( );
                SetVariantType( VariantType::Byte );
                bVal = theValue;
                return *this;
            }
            PropertyVariant& Assign( SHORT theValue )
            {
                Clear( );
                SetVariantType( VariantType::Short );
                iVal = theValue;
                return *this;
            }
            PropertyVariant& Assign( FLOAT theValue )
            {
                Clear( );
                SetVariantType( VariantType::Float );
                fltVal = theValue;
                return *this;
            }
            PropertyVariant& Assign( DOUBLE theValue )
            {
                Clear( );
                SetVariantType( VariantType::Double );
                dblVal = theValue;
                return *this;
            }

            PropertyVariant& Assign( DOUBLE theValue, VariantType variantType )
            {
                Clear( );
                if ( variantType == VariantType::Double || variantType == VariantType::DateTime )
                {
                    SetVariantType( variantType );
                    dblVal = theValue;
                }
                else
                {
                    SetVariantType( VariantType::Error );
                    scode = E_INVALIDARG;
                    CheckHRESULT( scode );
                }
                return *this;
            }

            PropertyVariant& Assign( bool theValue )
            {
                Clear( );
                SetVariantType( VariantType::Bool );
                boolVal = theValue ? VARIANT_TRUE : VARIANT_FALSE;
                return *this;
            }

            PropertyVariant& Assign( const CY& theValue )
            {
                Clear( );
                SetVariantType( VariantType::Currency );
                cyVal = theValue;
                return *this;
            }
            PropertyVariant& Assign( const DateTime& theValue )
            {
                Clear( );
                SetVariantType( VariantType::DateTime );
                date = theValue.ToOADate( );
                return *this;
            }
            PropertyVariant& Assign( const TimeSpan& theValue )
            {
                Clear( );
                SetVariantType( VariantType::Double );
                date = theValue.TotalDays( );
                return *this;
            }

            PropertyVariant& Assign( const SysString& theValue )
            {
                Clear( );
                SetVariantType( VariantType::BStr );
                bstrVal = theValue.Copy( );
                return *this;
            }

            PropertyVariant& Assign( IUnknown* pInterface )
            {
                Clear( );
                SetVariantType( VariantType::Unknown );
                punkVal = pInterface;
                if ( punkVal )
                {
                    punkVal->AddRef( );
                }
                return *this;
            }

            PropertyVariant& Assign( IDispatch* pInterface )
            {
                Clear( );
                SetVariantType( VariantType::Dispatch );
                pdispVal = pInterface;
                if ( pdispVal )
                {
                    pdispVal->AddRef( );
                }
                return *this;
            }

            PropertyVariant& Assign( SAFEARRAY* safeArray )
            {
                Clear( );
                SetVariantType( VariantType::Array );
                if ( safeArray )
                {
                    auto vType = SafeArray::GetElementVariantType( safeArray );
                    SetVariantType( VariantType::Array | vType );
                    auto hr = SafeArrayCopy( safeArray, &parray );
                    CheckHRESULT( hr );
                }
                else
                {
                    parray = nullptr;
                }
                return *this;
            }

            PropertyVariant& Assign( CHAR theValue )
            {
                Clear( );
                SetVariantType( VariantType::SByte );
                cVal = theValue;
                return *this;
            }

            PropertyVariant& Assign( USHORT theValue )
            {
                Clear( );
                SetVariantType( VariantType::UShort );
                uiVal = theValue;
                return *this;
            }

            PropertyVariant& Assign( ULONG theValue )
            {
                Clear( );
                SetVariantType( VariantType::ULong );
                ulVal = theValue;
                return *this;
            }

        };
    }
}

#endif //__HWINVARIANT_H__

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)


Written By
Architect Sea Surveillance AS
Norway Norway
Chief Architect - Sea Surveillance AS.

Specializing in integrated operations and high performance computing solutions.

I’ve been fooling around with computers since the early eighties, I’ve even done work on CP/M and MP/M.

Wrote my first “real” program on a BBC micro model B based on a series in a magazine at that time. It was fun and I got hooked on this thing called programming ...

A few Highlights:

  • High performance application server development
  • Model Driven Architecture and Code generators
  • Real-Time Distributed Solutions
  • C, C++, C#, Java, TSQL, PL/SQL, Delphi, ActionScript, Perl, Rexx
  • Microsoft SQL Server, Oracle RDBMS, IBM DB2, PostGreSQL
  • AMQP, Apache qpid, RabbitMQ, Microsoft Message Queuing, IBM WebSphereMQ, Oracle TuxidoMQ
  • Oracle WebLogic, IBM WebSphere
  • Corba, COM, DCE, WCF
  • AspenTech InfoPlus.21(IP21), OsiSoft PI


More information about what I do for a living can be found at: harlinn.com or LinkedIn

You can contact me at espen@harlinn.no

Comments and Discussions