microsoft / ConcordExtensibilitySamples

Visual Studio Debug Engine Extensibility Samples
Other
122 stars 50 forks source link

Bug in CCppCustomVisualizerService::FiletimeToText() function #51

Closed maxruben closed 4 years ago

maxruben commented 4 years ago

When trying out the CppCustomVisualizer project in Visual Studio 2019 in order to try to make my own visualizer for CTime I found that the debugger always showed "Invalid Value" for a FILETIME value. After debugging the code it turned out that the function CCppCustomVisualizerService::FileTimeToText() does not perform as it should if the if the length for the date format (from GetDateFormatW()) is longer than the length for the time format (from GetTimeFormatW()) as it is for me. I am in Sweden and my locale length for the date is 10 characters (2019-12-25) and 8 characters for the time (13:26:49).

This is because the cch variable is used to get the length needed for both the date and time string and then also used to tell GetDateFormatW() how much space to use, which is the value for the previous call to GetTimeFormatW(), which is then to short for the date.

Change the function like this and it will work when the length for the time string is shorter than the date string also:

`HRESULT CCppCustomVisualizerService::FileTimeToText(const FILETIME& fileTime, CString& text) { text.Empty();

SYSTEMTIME systemTime;
if (!FileTimeToSystemTime(&fileTime, &systemTime))
{
    return WIN32_LAST_ERROR();
}

// Deterime how much to allocate for the date
int cchDate; // Length needed for the date
cchDate = GetDateFormatW(
    GetThreadLocale(),
    DATE_SHORTDATE,
    &systemTime,
    nullptr,
    nullptr,
    0
    );
if (cchDate == 0)
{
    return WIN32_LAST_ERROR();
}

int allocLength = cchDate
    - 1 // To convert from a character count (including null terminator) to a length
    + 1; // For the space (' ') character between the date and time

// Deterime how much to allocate for the time
int cchTime; // Length needed for the time
cchTime = GetTimeFormatW(
    GetThreadLocale(),
    /*flags*/0,
    &systemTime,
    nullptr,
    nullptr,
    0
    );
if (cchTime == 0)
{
    return WIN32_LAST_ERROR();
}

allocLength += (cchTime - 1); // '-1' is to convert from a character count (including null terminator) to a length
CString result;
LPWSTR pBuffer = result.GetBuffer(allocLength);

// Add the date
int cch;
cch = GetDateFormatW(
    GetThreadLocale(),
    DATE_SHORTDATE,
    &systemTime,
    nullptr,
    pBuffer,
    cchDate   // Use length for date here instead of the returnvalue from
                    // the previous GetTimeFormatW() call.
    );
if (cch == 0)
{
    return WIN32_LAST_ERROR();
}

pBuffer += (cch-1); // '-1' is to convert from a character count (including null terminator) to a length
int remainaingLength = allocLength - (cch-1);

// Add a space between the date and the time
if (remainaingLength <= 1)
{
    return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
*pBuffer = ' ';
pBuffer++;
remainaingLength--;

// Add the time
cch = GetTimeFormatW(
    GetThreadLocale(),
    /*flags*/0,
    &systemTime,
    nullptr,
    pBuffer,
    remainaingLength + 1 // '+1' is for null terminator
    );
if (cch == 0)
{
    return WIN32_LAST_ERROR();
}

result.ReleaseBuffer();
text = result;

return S_OK;

}`

/Ruben