2012-06-20 41 views
1

與其使用WMI獲取最後一次啓動時間,我想用::GetSystemTime()::GetTickCount64來計算它。但是,一旦我達到毫秒,我不知道如何回到FILETIME對象。如何從ULONGLONG毫秒創建SYSTEMTIME結構?

我嘗試這樣做:

static ULONGLONG FileTimeToMillis(const FILETIME &ft) 
{ 
    ULARGE_INTEGER uli; 
    uli.LowPart = ft.dwLowDateTime; // could use memcpy here! 
    uli.HighPart = ft.dwHighDateTime; 

    return uli.QuadPart/10000; 
} 

static void MillisToSystemTime(ULONGLONG millis, SYSTEMTIME *st) 
{ 
    UINT64 t = static_cast<UINT64>(-10000) * static_cast<UINT64>(millis); 

    FILETIME ft; 
    ft.dwLowDateTime = static_cast<DWORD(t & 0xFFFFFFFF); 
    ft.dwHighDateTime = static_cast<DWORD>(t >> 32); 

    ::FileTimeToSystemTime(&ft, st); 
} 

void main() 
{ 
    SYSTEMTIME st, lt, st2, lt2; 

    ::GetSystemTime(&st); 
    ::GetLocalTime(&lt); 

    cout << "The system time is: " << st.wHour << ":" << st.wMinute << ":" << st.wSecond << endl; 
    cout << "The local time is: " << lt.wHour << ":" << lt.wMinute << ":" << lt.wSecond << endl; 

    FILETIME sft, lft; 
    ::SystemTimeToFileTime(&st, &sft); 
    ::SystemTimeToFileTime(&lt, &lft); 

    cout << "The system time in millis is: " << FileTimeToMillis(sft) << endl; 
    cout << "The local time in millis is: " << FileTimeToMillis(lft) << endl; 

    MillisToSystemTime(FileTimeToMillis(sft), &st2); 
    MillisToSystemTime(FileTimeToMillis(sft), &lt2); 

    cout << "The system time (post conversion) is: " << st2.wHour << ":" << st2.wMinute << ":" << st2.wSecond << endl; 
    cout << "The local time (post conversion) is: " << lt2.wHour << ":" << lt2.wMinute << ":" << lt2.wSecond << endl; 
} 

但我肯定沒有得到自己的預期。相反,我得到:

The system time is: 15:5:2 
The local time is: 10:5:2 
The system time in millis is: 12984678302935 
The local time in millis is: 12984660302935 
The system time (post conversion) is: 52428:52428:52428 
The local time (post conversion) is: 52428:52428:52428 

任何想法?請不要告訴我使用Boost或因爲它不適用於我。

+0

在僞代碼中,您希望'FileTimeToSystemTime(GetSystemTimeAsFileTime - (10000 * GetTickCount64))' – arx

+0

@arx MSDN建議不要對FILETIME結構本身執行算術運算。 –

+0

這就是爲什麼它是僞代碼。 – arx

回答

3

系統時間(轉換後)爲:52428:52428:52428

當你怪人值,總是先轉換爲十六進制。 52428 == 0xcccc。這是調試構建生成的代碼用於初始化變量的值。所以你正在尋找未初始化的內存。

接下來的防禦策略是從來沒有忽略了Windows api函數的返回值。使用VERIFY()宏,就像MFC中可用的一樣。然後您會很容易地看到FileTimeToSystemTime()失敗。

該錯誤是-10000。

+0

D'Oh!將一個負數填入unsigned是一個菜鳥錯誤!我使用的代碼是通過Google找到的,他們使用的是__int64,我沒有將-10000更改爲10000。 –

2

原來我正在做錯誤的算術。一旦我讀到了ULARGE_INTEGERFILETIME,我發現我可以直接使用的ULARGE_INTEGER,然後正確拔出高位和低位,同時避免位移和混淆。

static UINT64 FileTimeToMillis(const FILETIME &ft) 
{ 
    ULARGE_INTEGER uli; 
    uli.LowPart = ft.dwLowDateTime; // could use memcpy here! 
    uli.HighPart = ft.dwHighDateTime; 

    return static_cast<UINT64>(uli.QuadPart/10000); 
} 

static void MillisToSystemTime(UINT64 millis, SYSTEMTIME *st) 
{ 
    UINT64 multiplier = 10000; 
    UINT64 t = multiplier * millis; 

    ULARGE_INTEGER li; 
    li.QuadPart = t; 
    // NOTE, DON'T have to do this any longer because we're putting 
    // in the 64bit UINT directly 
    //li.LowPart = static_cast<DWORD>(t & 0xFFFFFFFF); 
    //li.HighPart = static_cast<DWORD>(t >> 32); 

    FILETIME ft; 
    ft.dwLowDateTime = li.LowPart; 
    ft.dwHighDateTime = li.HighPart; 

    ::FileTimeToSystemTime(&ft, st); 
} 

主要是閱讀從MSDN如下:

不建議您從 FILETIME結構加減值來獲得相對時間。相反,您應該將 文件時間的低階部分和高階部分複製到ULARGE_INTEGER結構中,在QuadPart成員上執行64位算術運算,並將LowPart和HighPart成員複製到FILETIME結構中。 複製 成員。