1

我不想使用 WMI 来获取上次启动时间,而是想使用::GetSystemTime()and来计算它::GetTickCount64。但是一旦我达到毫秒,我不知道如何回到 FILETIME 对象。

我试过这个:

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 或因为它对我不可用。

4

2 回答 2

4

系统时间(转换后)为:52428:52428:52428

当你得到奇怪的值时,总是先转换为十六进制。52428 == 0xcccc。这是调试构建生成的代码用于初始化变量的值。因此,您正在查看未初始化的内存。

下一个防御策略是永远不要忽略 Windows api 函数的返回值。使用 VERIFY() 宏,如 MFC 中可用的宏。然后您会很容易看到 FileTimeToSystemTime() 失败。

错误是-10000。

于 2012-06-20T15:40:40.010 回答
3

原来我做的算术不正确。一旦我阅读ULARGE_INTEGERand FILETIME,我发现我可以直接使用 the QuadPartULARGE_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 结构中。

于 2012-06-20T15:38:22.103 回答