如何将PWCHAR转换为FILETIME结构?

时间:2016-09-16 17:16:32

标签: winapi stl

我的想法是使用STL并将PWCHAR时间戳转换为wstring,将其加载到流中并使用>> operator将给定的拆分分配给SYSTEMTIME结构的相应成员,并使用Win32函数将其转换为FILETIME结构。

VOID StringToFileTime(const PWCHAR timeString, FILETIME &ft) {
    if(NULL == timeString)
        return;

    wstring time(L"2013-May-14 20:33:13.132814");
    std::wistringstream stream(time);
    SYSTEMTIME st = {0};
    stream >> st.wYear;
    stream.ignore(1, '-');
    stream >> st.wMonth;
    stream.ignore(1, '-');
    stream >> st.wDay;
    stream.ignore(1, ' ');
    stream >> st.wHour;
    stream.ignore(1, ':');
    stream >> st.wMinute;
    stream.ignore(1, ':');
    stream >> st.wSecond;
    stream.ignore(1, '.');
    stream >> st.wMilliseconds;

    SystemTimeToFileTime(&st, &ft);
}

我遇到的问题是在st.wYear之后没有填写SYSTEMTIME结构。因此,这一年将设定为2013年,但之后的成员为0。 看看变量内容我会更加困惑。硬编码时间戳未出现在调试器变量视图的wstring时间变量中。而是为时间变量列出了nPOS编号和错误。

如何将字符串转换为FILETIME结构?

我在Windows 10上使用Visual Studio 2013 Update 3.

enter image description here

1 个答案:

答案 0 :(得分:1)

问题是stream >> st.wMonth失败了,因为它试图将字符串值May读入数字WORD,这不是受支持的转换。您没有重置stream错误状态,因此>>ignore()的后续使用也会失败,因此在SYSTEMTIME之后wYear无法填写。

如果您有C ++ 11编译器,则可以使用std::get_time()来解析timeString

#include <sstream>
#include <iomanip>  

bool StringToFileTime(LPCWSTR timeString, FILETIME &ft)
{
    SYSTEMTIME st = {0};

    std::wistringstream stream(timeString);
    std::tm tmb;

    // std::get_time() does not support reading milliseconds...
    if (!(stream >> std::get_time(&tmb, L"%Y-%b-%d %H:%M:%S")))
        return false;

    st.wYear = 1900 + tmb.tm_year;
    st.wMonth = tmb.tm_mon + 1;
    st.wDayOfWeek = tmb.tm_wday;
    st.wDay = tmb.tm_mday;
    st.wHour = tmb.tm_hour;
    st.wMinute = tmb.tm_min;
    st.wSecond = tmb.tm_sec;

    if (!stream.eof())
    {
        stream.ignore(1, L'.');

        // st.wMilliseconds is a 16bit WORD, so it can only go up to 65535.
        // There are only 1000 ms in a second, so 132814 is clearly not
        // expressed in milliseconds.  Is it nanoseconds? 100-nanoseconds?
        // Whatever it is, convert it to st.wMilliseconds as needed...

        int iValue;
        if (!(stream >> iValue))
            return false;

        st.wMilliseconds = ...;
    }

    return SystemTimeToFileTime(&st, &ft);
}

如果你没有C ++ 11编译器,你仍然可以使用std::wistringstream,你只需要手动提取值:

#include <sstream>

bool StringToFileTime(LPCWSTR timeString, FILETIME &ft)
{
    SYSTEMTIME st = {0};

    std::wistringstream stream(timeString);
    std::string sMonth;

    if (!(stream >> st.wYear)) return false;
    if (!stream.ignore(1, L'-')) return false;

    // st.wMonth is a 16bit WORD, but a month name is given instead.
    // parse it into st.wMonth as needed...
    if (!std::getline(stream, sMonth, L'-')) return false;
    st.wMonth = ...;

    if (!stream.ignore(1, L'-')) return false;
    if (!(stream >> st.wDay)) return false;
    if (!stream.ignore(1, L' ')) return false;
    if (!(stream >> st.wHour)) return false;
    if (!stream.ignore(1, L':')) return false;
    if (!(stream >> st.wMinute)) return false;
    if (!stream.ignore(1, L':')) return false;
    if (!(stream >> st.wSecond)) return false;

    if (!stream.eof())
    {
        stream.ignore(1, L'.');

        // convert to st.wMilliseconds as needed...

        int iValue;
        if (!(stream >> iValue))
            return false;

        st.wMilliseconds = ...;
    }

    return SystemTimeToFileTime(&st, &ft);
}

或者,您可以使用swscanf()代替std::wistringstream

bool StringToFileTime(LPCWSTR timeString, FILETIME &ft)
{
    SYSTEMTIME st = {0};
    WCHAR szMonth[12];
    int iValue = 0;

    int numRead = swscanf(timeString, L"%hu-%[^-]-%hu &hu:&hu:&hu.%d", &st.wYear, szMonth, &st.wDay, &st.wHour, &st.wMinute, st.wSecond, &iValue);

    if (numRead < 6) return false;

    // parse szMonth into st.wMonth as needed...

    if (numRead == 7)
    {
        // convert iValue into st.wMilliseconds as needed...
    }

    return SystemTimeToFileTime(&st, &ft);
}