Click here to Skip to main content
15,888,202 members
Articles / Programming Languages / C#

Windows Development in C++, COM API Clients

Rate me:
Please Sign up or sign in to vote.
4.98/5 (31 votes)
3 Jan 2015CPOL7 min read 62.9K   1.6K   106  
Using the Facade Pattern to simplify development with COM based APIs
#include "stdafx.h"

#include "hwindatetime.h"
#include "hwinenvironment.h"
#include "hwinexception.h"
#include "hwincalendar.h"
#include "hwinresources.h"



namespace harlinn
{
    namespace windows
    {
        namespace
        {
            const long long TicksPerMillisecond = 10000;
            const long long TicksPerSecond = TicksPerMillisecond * 1000; 
            const long long TicksPerMinute = TicksPerSecond * 60;
            const long long TicksPerHour = TicksPerMinute * 60; 
            const long long TicksPerDay = TicksPerHour * 24; 

            const double MillisecondsPerTick = 1.0 / TicksPerMillisecond;
            const double SecondsPerTick =  1.0 / TicksPerSecond;
            const double MinutesPerTick = 1.0 / TicksPerMinute;
            const double HoursPerTick = 1.0 / TicksPerHour;
            const double DaysPerTick = 1.0 / TicksPerDay;

            const unsigned long long KindUnspecified        = 0x0000000000000000;
            const unsigned long long KindUtc                = 0x4000000000000000; 
            const unsigned long long KindLocal              = 0x8000000000000000;
            const unsigned long long TicksMask              = 0x3FFFFFFFFFFFFFFF; 
            const unsigned long long FlagsMask              = KindUtc | KindLocal;
            
            const int KindShift = 62;
            
            const int MillisPerSecond = 1000;
            const int MillisPerMinute = MillisPerSecond * 60;
            const int MillisPerHour = MillisPerMinute * 60;
            const int MillisPerDay = MillisPerHour * 24; 

            
            const int DaysPerYear = 365; 
            const int DaysPer4Years = DaysPerYear * 4 + 1; 
            const int DaysPer100Years = DaysPer4Years * 25 - 1;
            const int DaysPer400Years = DaysPer100Years * 4 + 1; 

            
            const int DaysTo1601 = DaysPer400Years * 4; 
            const int DaysTo1899 = DaysPer400Years * 4 + DaysPer100Years * 3 - 367; 
            const int DaysTo10000 = DaysPer400Years * 25 - 366;

            const long long MinTicks = 0; 
            const long long MaxTicks = DaysTo10000 * TicksPerDay - 1;
            const long long MaxMillis = (long long)DaysTo10000 * MillisPerDay; 
 
            const long long FileTimeOffset = DaysTo1601 * TicksPerDay;
            const long long DoubleDateOffset = DaysTo1899 * TicksPerDay;

            
            const long long OADateMinAsTicks = (DaysPer100Years - DaysPerYear) * TicksPerDay;

            const int DaysToMonth365[13] = 
            {
                0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
            }; 
            const int DaysToMonth366[13] = 
            { 
                0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366
            };

            const double OADateMinAsDouble = -657435.0;
            const double OADateMaxAsDouble = 2958466.0; 

        }


        // ----------------------------------------------------------------------
        // TimeSpan
        // ----------------------------------------------------------------------
        HWIN_EXPORT const TimeSpan TimeSpan::Zero(0);

        
 
        HWIN_EXPORT const TimeSpan TimeSpan::MaxValue(MAXINT64); 
        HWIN_EXPORT const TimeSpan TimeSpan::MinValue(MININT64);

        HWIN_EXPORT long long TimeSpan::TimeToTicks(int theDays, int theHours, int theMinutes, int theSeconds, int theMilliseconds)
        {
            long long milliSeconds = ((long long)theDays * 3600 * 24 + 
                                            (long long)theHours * 3600 + 
                                            (long long)theMinutes * 60 + theSeconds) * 1000 + 
                                            theMilliseconds; 

            if (milliSeconds > MaxMilliSeconds || milliSeconds < MinMilliSeconds)
            {
                throw ArgumentOutOfRangeException("", Environment::GetResourceString(Resources::OVERFLOW_TIMESPANTOOLONG));
            }
            long long result =  milliSeconds * TicksPerMillisecond;
            return result;
        }

        HWIN_EXPORT TimeSpan TimeSpan::Add(const TimeSpan& theOther) const 
        {
            long long result = ticks + theOther.ticks; 
            if ((ticks >> 63 == theOther.ticks >> 63) && (ticks >> 63 != result >> 63)) 
            {
                throw OverflowException(Environment::GetResourceString(Resources::OVERFLOW_TIMESPANTOOLONG));
            }
            return TimeSpan(result); 
        } 

        HWIN_EXPORT TimeSpan TimeSpan::Interval(double theValue, int theScale) 
        {
            if (_isnan(theValue))
            {
                throw ArgumentException(Environment::GetResourceString(Resources::ARG_CANNOTBENAN)); 
            }
            double milliSeconds = theValue * theScale; 
            milliSeconds = milliSeconds + (theValue >= 0? 0.5: -0.5); 

            if ((milliSeconds > MAXINT64 / TicksPerMillisecond) || (milliSeconds < MININT64 / TicksPerMillisecond))
            {
                throw OverflowException(Environment::GetResourceString(Resources::OVERFLOW_NEGATETWOSCOMPNUM)); 
            }
            return TimeSpan((long long)milliSeconds * TicksPerMillisecond);
        }


        HWIN_EXPORT TimeSpan TimeSpan::Duration() const
        { 
            if (ticks == MinValue.ticks)
            {
                throw OverflowException(Environment::GetResourceString(Resources::OVERFLOW_DURATION)); 
            }
            return TimeSpan(ticks >= 0? ticks: -ticks);
        }

        HWIN_EXPORT TimeSpan TimeSpan::Negate() const
        {
            if (ticks==MinValue.ticks) 
            {
                throw OverflowException(Environment::GetResourceString(Resources::OVERFLOW_NEGATETWOSCOMPNUM));
            }
            return TimeSpan(-ticks); 
        }

        HWIN_EXPORT TimeSpan TimeSpan::Subtract(const TimeSpan& theOther) const 
        {
            long long result = ticks - theOther.ticks; 
            if ((ticks >> 63 != theOther.ticks >> 63) && (ticks >> 63 != result >> 63))
            {
                throw OverflowException(Environment::GetResourceString(Resources::OVERFLOW_TIMESPANTOOLONG));
            }
            return TimeSpan(result);
        } 

        HWIN_EXPORT String TimeSpan::ToString() const
        {
            wchar_t buffer[128];
            size_t length = GetDurationFormat(LOCALE_USER_DEFAULT,0,nullptr,ticks,nullptr, buffer, 128);
            if(length == 0)
            {
                ThrowLastOSError();    
            }
            return String(buffer,length);
        }

        HWIN_EXPORT double TimeSpan::TotalDays() const
        { 
            return ((double)ticks) * DaysPerTick;
        }

        HWIN_EXPORT double TimeSpan::TotalHours() const
        { 
            return (double(ticks)) * HoursPerTick; 
        } 

        HWIN_EXPORT double TimeSpan::TotalMilliseconds() const
        {
            double result = ((double)ticks) * MillisecondsPerTick; 
            if (result > MaxMilliSeconds)
            {
                return (double)MaxMilliSeconds; 
            }
 
            if (result < MinMilliSeconds)
            {
                return (double)MinMilliSeconds; 
            }

            return result;
        }

        HWIN_EXPORT double TimeSpan::TotalMinutes() const
        { 
            return (double)ticks * MinutesPerTick;
        }

        HWIN_EXPORT double TimeSpan::TotalSeconds() const
        { 
            return (double)ticks * SecondsPerTick; 
        } 

        // ----------------------------------------------------------------------
        // DateTime
        // ----------------------------------------------------------------------
        
            

        HWIN_EXPORT const DateTime DateTime::MinValue(MinTicks, DateTimeKind::Unspecified);
        HWIN_EXPORT const DateTime DateTime::MaxValue(MaxTicks, DateTimeKind::Unspecified);

        


        HWIN_EXPORT DateTime::DateTime(long long ticks) 
        { 
            if (ticks < MinTicks || ticks > MaxTicks)
            {
                throw ArgumentOutOfRangeException("ticks", Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_DATETIMEBADTICKS)); 
            }
            data = (unsigned long long)ticks;
        } 

        HWIN_EXPORT DateTime::DateTime(unsigned long long theDateData) 
            : data(theDateData)
        {
            
        } 


        HWIN_EXPORT DateTime::DateTime(long long ticks, DateTimeKind kind) 
        { 
            if (ticks < MinTicks || ticks > MaxTicks) 
            { 
                throw ArgumentOutOfRangeException("ticks", Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_DATETIMEBADTICKS));
            } 
            if (kind < DateTimeKind::Unspecified || kind > DateTimeKind::Local) 
            {
                throw ArgumentException(Environment::GetResourceString(Resources::ARGUMENT_INVALIDDATETIMEKIND), "kind");
            }
            
            data = ((unsigned long long)ticks | ((unsigned long long)kind << KindShift));
        } 


        HWIN_EXPORT long long DateTime::ToTicks(int year, int month, int day, const globalization::Calendar& calendar) 
        {
            return ToTicks(year, month, day,0,0,0,0,calendar);
        }

        HWIN_EXPORT long long DateTime::ToTicks(int year, int month, int day, int hour, int minute, int second, int millisecond,const globalization::Calendar& calendar) 
        {
            if (millisecond < 0 || millisecond >= MillisPerSecond) 
            { 
                throw ArgumentOutOfRangeException("millisecond", Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_RANGE, 0, MillisPerSecond - 1));
            } 
            long long ticks = calendar.ToDateTime(year, month, day, hour, minute, second, 0).data & TicksMask;
            ticks += millisecond * TicksPerMillisecond; 
            if (ticks < MinTicks || ticks > MaxTicks)
            {
                throw ArgumentException(Environment::GetResourceString(Resources::ARG_DATETIMERANGE));
            }
            return ticks;
        }

        HWIN_EXPORT long long DateTime::DateToTicks(int year, int month, int day) 
        { 
            if (year >= 1 && year <= 9999 && month >= 1 && month <= 12) 
            { 
                const int* days = IsLeapYear(year)? DaysToMonth366: DaysToMonth365;
                if (day >= 1 && day <= days[month] - days[month - 1]) 
                { 
                    int y = year - 1;
                    int n = y * 365 + y / 4 - y / 100 + y / 400 + days[month - 1] + day - 1;
                    return n * TicksPerDay;
                } 
            }
            throw ArgumentOutOfRangeException(nullptr, Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_BADYEARMONTHDAY)); 
        } 

        HWIN_EXPORT long long DateTime::SystemTimeToTicks(const SYSTEMTIME& systemTime)
        {
            if (systemTime.wMilliseconds >= MillisPerSecond) 
            {
                throw ArgumentOutOfRangeException("systemTime.wMilliseconds", Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_RANGE, 0, MillisPerSecond - 1)); 
            }
            unsigned long long ticks = DateToTicks(systemTime.wYear, systemTime.wMonth, systemTime.wDay) + TimeToTicks(systemTime.wHour, systemTime.wMinute, systemTime.wSecond);
            ticks += systemTime.wMilliseconds * TicksPerMillisecond; 
            if (ticks < MinTicks || ticks > MaxTicks)
            {
                throw new ArgumentException(Environment::GetResourceString(Resources::ARG_DATETIMERANGE)); 
            }
            return ticks;
        }

        HWIN_EXPORT long long DateTime::TimeToTicks(int hour, int minute, int second)
        {
            if (hour >= 0 && hour < 24 && minute >= 0 && minute < 60 && second >=0 && second < 60) 
            { 
                return TimeSpan::TimeToTicks(0,hour, minute, second);
            } 
            throw ArgumentOutOfRangeException(nullptr, Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_BADHOURMINUTESECOND));
        }


        HWIN_EXPORT DateTime::DateTime(int year, int month, int day) 
        {
            data = (unsigned long long) DateToTicks(year, month, day);
        }

        HWIN_EXPORT DateTime::DateTime(int year, int month, int day, const globalization::Calendar& calendar)
            : data(ToTicks( year, month, day, 0, 0, 0,0, calendar)) 
        {
        }


        HWIN_EXPORT DateTime::DateTime(int year, int month, int day, int hour, int minute, int second) 
            : data(DateToTicks(year, month, day) + TimeToTicks(hour, minute, second))
        {
        }

        HWIN_EXPORT DateTime::DateTime(int year, int month, int day, int hour, int minute, int second, DateTimeKind kind) 
        {
            if (kind < DateTimeKind::Unspecified || kind > DateTimeKind::Local) 
            { 
                throw ArgumentException(Environment::GetResourceString(Resources::ARGUMENT_INVALIDDATETIMEKIND), "kind");
            } 
            long long ticks = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second);
            data = ((long long)ticks | ((long long)kind << KindShift)); 
        }

        HWIN_EXPORT DateTime::DateTime(int year, int month, int day, int hour, int minute, int second, const globalization::Calendar& calendar) 
        { 
            data = (unsigned long long)calendar.ToDateTime(year, month, day, hour, minute, second, 0).Ticks();
        }

        HWIN_EXPORT DateTime::DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond) 
        { 
            if (millisecond < 0 || millisecond >= MillisPerSecond) 
            {
                throw ArgumentOutOfRangeException("millisecond", Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_RANGE, 0, MillisPerSecond - 1)); 
            }
            long long ticks = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second);
            ticks += millisecond * TicksPerMillisecond; 
            if (ticks < MinTicks || ticks > MaxTicks)
            {
                throw new ArgumentException(Environment::GetResourceString(Resources::ARG_DATETIMERANGE)); 
            }
            data = (unsigned long long)ticks;
        }

        
 
        HWIN_EXPORT DateTime::DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, DateTimeKind kind) 
        {
            if (millisecond < 0 || millisecond >= MillisPerSecond) 
            {
                throw ArgumentOutOfRangeException("millisecond", Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_RANGE, 0, MillisPerSecond - 1));
            } 
            if (kind < DateTimeKind::Unspecified || kind > DateTimeKind::Local) 
            {
                throw ArgumentException(Environment::GetResourceString(Resources::ARGUMENT_INVALIDDATETIMEKIND), "kind"); 
            } 
            long long ticks = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second); 
            ticks += millisecond * TicksPerMillisecond;
            if (ticks < MinTicks || ticks > MaxTicks)
            {
                throw ArgumentException(Environment::GetResourceString(Resources::ARG_DATETIMERANGE));
            }
            data = ((unsigned long long)ticks | ((unsigned long long)kind << KindShift)); 
        }
 
        HWIN_EXPORT DateTime::DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, const globalization::Calendar& calendar) 
        {
            if (millisecond < 0 || millisecond >= MillisPerSecond) 
            { 
                throw ArgumentOutOfRangeException("millisecond", Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_RANGE, 0, MillisPerSecond - 1));
            } 
            long long ticks = calendar.ToDateTime(year, month, day, hour, minute, second, 0).Ticks();
            ticks += millisecond * TicksPerMillisecond; 
            if (ticks < MinTicks || ticks > MaxTicks)
            {
                throw ArgumentException(Environment::GetResourceString(Resources::ARG_DATETIMERANGE));
            }
            data = (unsigned long long)ticks;
        } 

        HWIN_EXPORT DateTime::DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, const globalization::Calendar& calendar, DateTimeKind kind) 
        { 
            if (millisecond < 0 || millisecond >= MillisPerSecond) 
            { 
                throw ArgumentOutOfRangeException("millisecond", Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_RANGE, 0, MillisPerSecond - 1));
            }
            if (kind < DateTimeKind::Unspecified || kind > DateTimeKind::Local) 
            {
                throw ArgumentException(Environment::GetResourceString(Resources::ARGUMENT_INVALIDDATETIMEKIND), "kind"); 
            }
            long long ticks = calendar.ToDateTime(year, month, day, hour, minute, second, 0).Ticks(); 
            ticks += millisecond * TicksPerMillisecond;
            if (ticks < MinTicks || ticks > MaxTicks) 
            {
                throw ArgumentException(Environment::GetResourceString(Resources::ARG_DATETIMERANGE));
            }
            data = ((unsigned long long)ticks | ((unsigned long long)kind << KindShift));
        }
 
        HWIN_EXPORT DateTime DateTime::Add(const TimeSpan& value) const 
        {
            return AddTicks(value.ticks); 
        }

        HWIN_EXPORT DateTime DateTime::Add(double value, int scale) const
        {
            long long millis = (long long)(value * scale + (value >= 0? 0.5: -0.5)); 
            if (millis <= -MaxMillis || millis >= MaxMillis)
            {
                throw ArgumentOutOfRangeException("value", Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_ADDVALUE));
            }
            return AddTicks(millis * TicksPerMillisecond); 
        }

        HWIN_EXPORT DateTime DateTime::AddDays(double value) const
        { 
            return Add(value, MillisPerDay);
        }

        HWIN_EXPORT DateTime DateTime::AddHours(double value) const
        {
            return Add(value, MillisPerHour);
        }
 
        HWIN_EXPORT DateTime DateTime::AddMilliseconds(double value) const
        {
            return Add(value, 1);
        } 

        HWIN_EXPORT DateTime DateTime::AddMinutes(double value) const
        {
            return Add(value, MillisPerMinute); 
        }
 
        HWIN_EXPORT DateTime DateTime::AddMonths(int months) const
        { 
            if (months < -120000 || months > 120000) 
            {
                throw ArgumentOutOfRangeException("months", Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_DATETIMEBADMONTHS)); 
            }
            int y = GetDatePart(DatePart::Year); 
            int m = GetDatePart(DatePart::Month);
            int d = GetDatePart(DatePart::Day);
            int i = m - 1 + months;
            if (i >= 0) 
            { 
                m = i % 12 + 1;
                y = y + i / 12; 
            } 
            else 
            {
                m = 12 + (i + 1) % 12; 
                y = y + (i - 11) / 12;
            }
            if (y < 1 || y > 9999) 
            {
                throw ArgumentOutOfRangeException("months", Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_DATEARITHMETIC)); 
            }
            int days = DaysInMonth(y, m); 
            if (d > days) 
            {
                d = days; 
            }
            return DateTime((unsigned long long)(DateToTicks(y, m, d) + (data & TicksMask) % TicksPerDay) | (data & FlagsMask));
        } 

        HWIN_EXPORT DateTime DateTime::AddSeconds(double value) const
        {
            return Add(value, MillisPerSecond); 
        }

        HWIN_EXPORT DateTime DateTime::AddTicks(long long value) const
        { 
            long long ticks = data & TicksMask;
            if (value > MaxTicks - ticks || value < MinTicks - ticks) 
            { 
                throw ArgumentOutOfRangeException("value", Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_DATEARITHMETIC));
            }
            return DateTime((unsigned long long)(ticks + value) | (data & FlagsMask));
        } 

        HWIN_EXPORT DateTime DateTime::AddYears(int value) const
        {
            if (value < -10000 || value > 10000) 
            {
                throw ArgumentOutOfRangeException("years", Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_DATETIMEBADYEARS)); 
            }
            return AddMonths(value * 12);
        } 

        HWIN_EXPORT const DateTime& DateTime::AssingTo(SYSTEMTIME& systemTime) const
        {
            long long filetime = data & TicksMask;
            filetime -= FileTimeOffset;
            FileTimeToSystemTime((FILETIME*)&filetime,&systemTime);
            return *this;
        }

        HWIN_EXPORT std::string DateTime::DateToAnsiString() const
        {
            char buffer[128];
            SYSTEMTIME systemTime;
            AssingTo(systemTime);
            size_t length = GetDateFormatA(LOCALE_USER_DEFAULT, 0,&systemTime,nullptr,buffer,128);
            if(length == 0)
            {
                ThrowLastOSError();
            }
            std::string result(buffer,length);
            return result;
        }
        HWIN_EXPORT String DateTime::DateToString() const
        {
            wchar_t buffer[128];
            SYSTEMTIME systemTime;
            AssingTo(systemTime);
            size_t length = GetDateFormatW(LOCALE_USER_DEFAULT, 0,&systemTime,nullptr,buffer,128);
            if(length == 0)
            {
                ThrowLastOSError();
            }
            String result(buffer,length);
            return result;
        }

        HWIN_EXPORT std::string DateTime::TimeToAnsiString() const
        {
            char buffer[128];
            SYSTEMTIME systemTime;
            AssingTo(systemTime);
            size_t length = GetTimeFormatA(LOCALE_USER_DEFAULT, 0,&systemTime,nullptr,buffer,128);
            if(length == 0)
            {
                ThrowLastOSError();
            }
            std::string result(buffer,length);
            return result;
        }
        HWIN_EXPORT String DateTime::TimeToString() const
        {
            wchar_t buffer[128];
            SYSTEMTIME systemTime;
            AssingTo(systemTime);
            size_t length = GetTimeFormatW(LOCALE_USER_DEFAULT, 0,&systemTime,nullptr,buffer,128);
            if(length == 0)
            {
                ThrowLastOSError();
            }
            String result(buffer,length);
            return result;
        }

        HWIN_EXPORT std::string DateTime::ToAnsiString() const
        {
            char buffer[128];
            SYSTEMTIME systemTime;
            AssingTo(systemTime);
            int length = GetDateFormatA(LOCALE_USER_DEFAULT, 0,&systemTime,nullptr,buffer,128);
            if(length == 0)
            {
                ThrowLastOSError();
            }
            buffer[length] = '\x20';

            int length2 = GetTimeFormatA(LOCALE_USER_DEFAULT, 0,&systemTime,nullptr,&buffer[length+1],128-(length+1));
            if(length2 == 0)
            {
                ThrowLastOSError();
            }

            std::string result(buffer,size_t(length+length2+1));
            return result;
        }

        HWIN_EXPORT String DateTime::ToString() const
        {
            wchar_t buffer[128];
            SYSTEMTIME systemTime;
            AssingTo(systemTime);
            int length = GetDateFormatW(LOCALE_USER_DEFAULT, 0,&systemTime,nullptr,buffer,128);
            if(length == 0)
            {
                ThrowLastOSError();
            }
            buffer[length] = '\x20';

            int length2 = GetTimeFormatW(LOCALE_USER_DEFAULT, 0,&systemTime,nullptr,&buffer[length+1],128-(length+1));
            if(length2 == 0)
            {
                ThrowLastOSError();
            }

            String result(buffer,size_t(length+length2+1));
            return result;
        }


        HWIN_EXPORT int DateTime::Compare(const DateTime& t1, const DateTime& t2) 
        {
            long long ticks1 = t1.data & TicksMask; 
            long long ticks2 = t2.data & TicksMask; 
            if (ticks1 > ticks2) return 1;
            if (ticks1 < ticks2) return -1; 
            return 0;
        }

 
        HWIN_EXPORT int DateTime::CompareTo(const DateTime& value) const
        {
            long long valueTicks = value.data & TicksMask; 
            long long ticks = data & TicksMask; 
            if (ticks > valueTicks) 
            {
                return 1;
            }
            if (ticks < valueTicks) 
            {
                return -1; 
            }
            return 0;
        }

            
        HWIN_EXPORT int DateTime::DaysInMonth(int year, int month) 
        { 
            if (month < 1 || month > 12) 
            {
                throw ArgumentOutOfRangeException("month", Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_MONTH));
            }
            const int* days = IsLeapYear(year)? DaysToMonth366: DaysToMonth365;
            return days[month] - days[month - 1];
        } 

        HWIN_EXPORT long long DateTime::DoubleDateToTicks(double value) 
        {
            if (value >= OADateMaxAsDouble || value <= OADateMinAsDouble) 
            {
                throw new ArgumentException(Environment::GetResourceString(Resources::ARG_OLEAUTDATEINVALID));
            }
            long long millis = (long long)(value * MillisPerDay + (value >= 0? 0.5: -0.5));

            // fixup for negative milliseconds
            if (millis < 0) 
            { 
                millis -= (millis % MillisPerDay) * 2; 
            }
 
            millis += DoubleDateOffset / TicksPerMillisecond;

            if (millis < 0 || millis >= MaxMillis) 
            {
                throw new ArgumentException(Environment::GetResourceString(Resources::ARG_OLEAUTDATESCALE));
            }
            return millis * TicksPerMillisecond; 
        }
 


        HWIN_EXPORT DateTime DateTime::FromBinary(long long data)
        {
            long long ticks = data & TicksMask; 
            if (ticks < MinTicks || ticks > MaxTicks) 
            {
                throw ArgumentException(Environment::GetResourceString(Resources::ARGUMENT_DATETIMEBADBINARYDATA), "data");
            }
            return DateTime(data); 
        }

        HWIN_EXPORT DateTime DateTime::FromFileTime(long long fileTime) 
        { 
            return FromFileTimeUtc(fileTime).ToLocalTime();
        } 

        HWIN_EXPORT DateTime DateTime::FromFileTimeUtc(long long fileTime) 
        {
            if (fileTime < 0 || fileTime > MaxTicks - FileTimeOffset) 
            {
                throw new ArgumentOutOfRangeException("fileTime", Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_FILETIMEINVALID)); 
            }
            
            long long universalTicks = fileTime + FileTimeOffset; 
            return DateTime(universalTicks, DateTimeKind::Utc);
        }

        HWIN_EXPORT DateTime DateTime::FromOADate(double d) 
        { 
            return DateTime(DoubleDateToTicks(d), DateTimeKind::Unspecified); 
        }
 

        HWIN_EXPORT bool DateTime::IsDaylightSavingTime() const
        { 
            if ( Kind() == DateTimeKind::Utc) 
            { 
                return false;
            }

            USHORT year = USHORT(Year());
            TIME_ZONE_INFORMATION tzi;
            if(GetTimeZoneInformationForYear(year,nullptr,&tzi) == FALSE)
            {
                ThrowLastOSError();
            }

            tzi.DaylightDate.wYear = year;
            tzi.StandardDate.wYear = year;

            long long daylightDateInTicks = SystemTimeToTicks( tzi.DaylightDate );
            long long standardDateInTicks = SystemTimeToTicks( tzi.StandardDate );
            long long ticks = data & TicksMask;


            if(daylightDateInTicks > standardDateInTicks)
            {
                if((ticks > standardDateInTicks)&&( ticks < daylightDateInTicks) )
                {
                    return true;
                }
            }
            else if(daylightDateInTicks < standardDateInTicks)
            {
                if((ticks > daylightDateInTicks)&&( ticks < standardDateInTicks) )
                {
                    return true;
                }
            }
            return false;
        }

        HWIN_EXPORT DateTime DateTime::SpecifyKind(const DateTime& value, DateTimeKind kind) 
        { 
            return DateTime(value.data & TicksMask, kind);
        } 

        HWIN_EXPORT long long DateTime::ToBinary() const
        {
            return data;
        } 

        HWIN_EXPORT DateTime DateTime::Date() const 
        { 
            long long ticks = data & TicksMask;
            return DateTime((unsigned long long)(ticks - ticks % TicksPerDay) | (data & FlagsMask)); 
        } 
 
        HWIN_EXPORT int DateTime::GetDatePart(DatePart part) const
        {
            long long ticks = data & TicksMask;
            int n = (int)(ticks / TicksPerDay); 
            int periodsOf400years = n / DaysPer400Years; 
            n -= periodsOf400years * DaysPer400Years;
            int periodsOf100years = n / DaysPer100Years;
            if (periodsOf100years == 4) 
            {
                periodsOf100years = 3;
            }
            n -= periodsOf100years * DaysPer100Years;
            int periodsOf4years = n / DaysPer4Years; 
            n -= periodsOf4years * DaysPer4Years; 
            int y1 = n / DaysPerYear;
            if (y1 == 4)
            {
                y1 = 3; 
            }

            if (part == DatePart::Year) 
            { 
                return periodsOf400years * 400 + periodsOf100years * 100 + periodsOf4years * 4 + y1 + 1; 
            }
            n -= y1 * DaysPerYear;
            if (part == DatePart::DayOfYear) 
            {
                return n + 1;
            }

            bool leapYear = y1 == 3 && (periodsOf4years != 24 || periodsOf100years == 3);

            const int* days = leapYear? DaysToMonth366: DaysToMonth365; 

            int m = (n >> 5) + 1;

            while (n >= days[m]) 
            {
                m++;
            }
            if (part == DatePart::Month) 
            {
                return m;
            }
            return n - days[m - 1] + 1; 
        }
 
        HWIN_EXPORT int DateTime::Day() const 
        { 
            return GetDatePart(DatePart::Day);
        }

        HWIN_EXPORT DayOfWeek DateTime::DayOfWeek() const 
        {
            long long ticks = data & TicksMask;
            return (harlinn::windows::DayOfWeek)((ticks / TicksPerDay + 1) % 7); 
        }
 
        HWIN_EXPORT int DateTime::DayOfYear() const
        {
            return GetDatePart(DatePart::DayOfYear);
        }


        HWIN_EXPORT int DateTime::Hour( ) const
        { 
            long long ticks = data & TicksMask;
            return (int)((ticks / TicksPerHour) % 24);
        } 


        HWIN_EXPORT DateTimeKind DateTime::Kind() const 
        {
            long long kind = data & FlagsMask;
            switch (kind) 
            {
                case KindUnspecified:
                    return DateTimeKind::Unspecified;
                case KindUtc: 
                    return DateTimeKind::Utc;
                default: 
                    return DateTimeKind::Local; 
            }
        }

        HWIN_EXPORT int DateTime::Millisecond() const 
        { 
            long long ticks = data & TicksMask;
            return (int)((ticks/ TicksPerMillisecond) % 1000); 
        } 
 
        HWIN_EXPORT int DateTime::Minute() const 
        {
            long long ticks = data & TicksMask;
            return (int)((ticks / TicksPerMinute) % 60); 
        }

        HWIN_EXPORT int DateTime::Month() const 
        {
            return GetDatePart(DatePart::Month);
        }

 
            
        HWIN_EXPORT DateTime DateTime::Now() 
        {
            DateTime utc = UtcNow(); 
            return utc.ToLocalTime();
        } 

        HWIN_EXPORT DateTime DateTime::UtcNow() 
        {
            long long ticks = 0;
            GetSystemTimeAsFileTime((FILETIME*)&ticks);
            return DateTime( ((unsigned long long)(ticks + FileTimeOffset)) | KindUtc);
        }

        HWIN_EXPORT int DateTime::Second() const
        {
            long long ticks = data & TicksMask;
            return (int)((ticks / TicksPerSecond) % 60); 
        }
 
        HWIN_EXPORT long long DateTime::Ticks() const
        { 
            long long ticks = data & TicksMask;
            return ticks; 
        }
         

        HWIN_EXPORT TimeSpan DateTime::TimeOfDay() const 
        {
            long long ticks = data & TicksMask;
            return TimeSpan(ticks % TicksPerDay);
        }
 
        HWIN_EXPORT DateTime DateTime::Today() 
        { 
            return DateTime::Now().Date();
        } 

        HWIN_EXPORT int DateTime::Year() const
        { 
            return GetDatePart(DatePart::Year); 
        } 
        
        HWIN_EXPORT bool DateTime::IsLeapYear(int year) 
        {
            if (year < 1 || year > 9999) 
            {
                throw ArgumentOutOfRangeException("year", Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_YEAR));
            } 
            return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); 
        } 

        HWIN_EXPORT TimeSpan DateTime::Subtract(const DateTime& value) const
        { 
            long long ticks = data & TicksMask;
            long long valueTicks = value.data & TicksMask;
            return TimeSpan(ticks - valueTicks);
        } 
 
        HWIN_EXPORT DateTime DateTime::Subtract(const TimeSpan& value) const
        {
            long long ticks = data & TicksMask; 
            long long valueTicks = value.ticks;
            if (ticks - MinTicks < valueTicks || ticks - MaxTicks > valueTicks) 
            {
                throw ArgumentOutOfRangeException("value", Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_DATEARITHMETIC));
            } 
            return DateTime((unsigned long long)(ticks - valueTicks) | (data & FlagsMask));
        } 
 
        HWIN_EXPORT double DateTime::TicksToOADate(long long value) 
        { 
            if (value == 0)
            {
                return 0.0;
            }
            if (value < TicksPerDay)
            {
                value += DoubleDateOffset;
            }
            if (value < OADateMinAsTicks)
            {
                throw OverflowException(Environment::GetResourceString(Resources::ARG_OLEAUTDATEINVALID)); 
            }
            long long millis = (value  - DoubleDateOffset) / TicksPerMillisecond; 
            if (millis < 0) 
            {
                long long frac = millis % MillisPerDay;
                if (frac != 0) 
                {
                    millis -= (MillisPerDay + frac) * 2;
                }
            } 
            return ((double)millis) / MillisPerDay;
        } 
 
        HWIN_EXPORT double DateTime::ToOADate() const
        {
            long long ticks = data & TicksMask; 
            return TicksToOADate(ticks);
        }
 
        HWIN_EXPORT long long DateTime::ToFileTime() const
        {
            return ToUniversalTime().ToFileTimeUtc(); 
        }
 
        HWIN_EXPORT long long DateTime::ToFileTimeUtc() const
        {
            long long ticks = data & KindLocal ? ToUniversalTime().data & TicksMask : data & TicksMask;
            ticks -= FileTimeOffset; 
            if (ticks < 0) 
            {
                throw ArgumentOutOfRangeException(nullptr, Environment::GetResourceString(Resources::ARGUMENTOUTOFRANGE_FILETIMEINVALID)); 
            } 
            return ticks;
        } 

        HWIN_EXPORT DateTime DateTime::ToLocalTime() const
        {
            if (data & KindLocal) 
            {
                return *this; 
            }
            long long ticks = data & TicksMask;
            ticks -= FileTimeOffset; 
            long long localTicks = 0;
            FileTimeToLocalFileTime((FILETIME*)&ticks,(FILETIME*)&localTicks);
            localTicks += FileTimeOffset;
            return DateTime(localTicks, DateTimeKind::Local);
        }
 
        HWIN_EXPORT DateTime DateTime::ToUniversalTime() const
        { 
            if (data & KindUtc) 
            {
                return *this; 
            }
            long long ticks = data & TicksMask;
            ticks -= FileTimeOffset; 
            long long utcTicks = 0;
            LocalFileTimeToFileTime((FILETIME*)&ticks,(FILETIME*)&utcTicks);
            utcTicks += FileTimeOffset;
            return DateTime(utcTicks, DateTimeKind::Utc);
        } 

        HWIN_EXPORT bool DateTime::TryCreate(int year, int month, int day, int hour, int minute, int second, int millisecond, DateTime& result) 
        {
            result = MinValue; 
            if (year < 1 || year > 9999 || month < 1 || month > 12) 
            { 
                return false;
            } 
            const int* days = IsLeapYear(year) ? DaysToMonth366 : DaysToMonth365;
            if (day < 1 || day > days[month] - days[month - 1]) 
            {
                return false;
            } 
            
            if (hour < 0 || hour >= 24 || minute < 0 || minute >= 60 || second < 0 || second >= 60) 
            {
                return false; 
            } 
            if (millisecond < 0 || millisecond >= MillisPerSecond) 
            {
                return false; 
            }
            long long ticks = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second);

            ticks += millisecond * TicksPerMillisecond; 
            if (ticks < MinTicks || ticks > MaxTicks) 
            {
                return false; 
            } 
            result = DateTime(ticks, DateTimeKind::Unspecified);
            return true; 
        }

        // ----------------------------------------------------------------------
        // Stopwatch
        // ----------------------------------------------------------------------
        long long Stopwatch::frequency( TicksPerSecond ); 
        HWIN_EXPORT const bool Stopwatch::IsHighResolution = Stopwatch::InitializeStopwatch();
        double Stopwatch::tickFrequency = 1.0;

        bool Stopwatch::InitializeStopwatch() 
        {
            long long frq = 0;
            bool result = QueryPerformanceFrequency((LARGE_INTEGER*)&frq) != FALSE; 
            if(result) 
            {
                frequency = frq;
                tickFrequency = double(TicksPerSecond)/double(frequency);
            }
            return result;
        }

        HWIN_EXPORT long long Stopwatch::Frequency()
        {
            return frequency;
        }


        HWIN_EXPORT Stopwatch::Stopwatch() 
            : elapsedTicks(0),
              isRunning(false),
              startedAt(0)
        { 
            
        } 
 
        HWIN_EXPORT void Stopwatch::Start() 
        {
            if(!isRunning) 
            {
                startedAt = GetTimestamp();
                isRunning = true;
            } 
        }

        HWIN_EXPORT void Stopwatch::Restart() 
        { 
            elapsedTicks = 0;
            startedAt = GetTimestamp(); 
            isRunning = true; 
        }


        HWIN_EXPORT Stopwatch Stopwatch::StartNew() 
        { 
            Stopwatch result;
            result.Start(); 
            return result;
        }

        HWIN_EXPORT void Stopwatch::Stop() 
        { 
            if( isRunning) 
            { 
                isRunning = false;

                long long endTimeStamp = GetTimestamp(); 
                long long elapsedThisPeriod = endTimeStamp - startedAt;
                elapsedTicks += elapsedThisPeriod; 

                if(elapsedTicks < 0)
                {
                    elapsedTicks = 0;
                }
            }
        } 

        HWIN_EXPORT void Stopwatch::Reset() 
        { 
            elapsedTicks = 0; 
            isRunning = false;
            startedAt = 0; 
        }

 
        HWIN_EXPORT bool Stopwatch::IsRunning() const 
        {
            return isRunning;
        }
 
        HWIN_EXPORT TimeSpan Stopwatch::Elapsed() const
        {
            return TimeSpan( GetElapsedDateTimeTicks()); 
        } 

        HWIN_EXPORT long long Stopwatch::ElapsedMilliseconds() const
        { 
            return GetElapsedDateTimeTicks()/TicksPerMillisecond; 
        }

        HWIN_EXPORT long long Stopwatch::ElapsedTicks() const
        { 
            long long timeElapsed = elapsedTicks;
 
            if( isRunning) 
            {
                long long currentTimeStamp = GetTimestamp();
                long long elapsedUntilNow = currentTimeStamp - startedAt; 
                timeElapsed += elapsedUntilNow;
            }
            return timeElapsed; 
        } 
 
        HWIN_EXPORT long long Stopwatch::GetTimestamp() 
        {
            if(IsHighResolution) 
            { 
                long long timestamp = 0;
                QueryPerformanceCounter((LARGE_INTEGER*)&timestamp);
                return timestamp;
            } 
            else 
            {
                return DateTime::UtcNow().Ticks(); 
            } 
        }

        HWIN_EXPORT double Stopwatch::GetTimestampInSeconds()
        {
            double ts = tickFrequency * double(Stopwatch::GetTimestamp())*SecondsPerTick; 
            return ts;
        }
        HWIN_EXPORT double Stopwatch::GetTimestampInMilliseconds()
        {
            double ts = tickFrequency * double(Stopwatch::GetTimestamp())*MillisecondsPerTick;
            return ts;
        }

        long long Stopwatch::GetElapsedDateTimeTicks() const
        { 
            long long ticks = ElapsedTicks();
            if( IsHighResolution) 
            { 
                double dticks = double(ticks);
                dticks *= tickFrequency;
                return long long(dticks); 
            }
            else 
            { 
                return ticks; 
            }
        } 

    }
}

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