Поддельные '\r', добавленные CRichEditCtrl::GetLine() при вызове в односимвольных строках?

Я пытался с помощью CRichEditCtrl::GetLine() чтобы получить текст заданной строки элемента управления rich-edit в приложении MFC, созданном с VS2015 в режиме Unicode и работающем в Windows 10.

Я написал эту вспомогательную функцию:

CString GetLine(CRichEditCtrl& richEdit, const int lineNum)
{
    int lineLength = richEdit.LineLength(richEdit.LineIndex(lineNum));
    if (lineLength == 0)
    {
        // Empty line
        return CString();
    }

    const int kMinBufferLength = sizeof(int) / sizeof(wchar_t);
    const int bufferLength = max(kMinBufferLength, lineLength);

    CString line;
    wchar_t* buffer = line.GetBuffer(bufferLength);   
    lineLength = richEdit.GetLine(lineNum, buffer, bufferLength);      
    line.ReleaseBuffer(lineLength);

    return line;
}

Этот код работает нормально, за исключением строк, содержащих только один символ. В этом случае, CRichEditCtrl::GetLine() возвращает 2 (вместо ожидаемого 1), а выходной буфер содержит правильный символ, за которым следует \r,

Это почему? Почему \r добавлено только для односимвольных строк, а не для строк, содержащих больше символов?

Я смог исправить это, добавив специальный случай if как это:

// Code inserted after the richEdit.GetLine() call, before the line.ReleaseBuffer() call:    

// *** Special Case ***
// It seems that when there's only one character (e.g. 'C') in the line,
// CRichEditCtrl::GetLine() returns 2, and appends a '\r' after 
// the read character in the output buffer.
if ((lineLength == 2) && (buffer[1] == L'\r'))
{
    // Chop off the spurious '\r'
    lineLength = 1;
}

Однако мне не совсем понятна причина такого особого поведения.


PS: CRichEditCtrl::GetLine() Код MFC, который вызывается:

int CRichEditCtrl::GetLine(_In_ int nIndex, _Out_writes_to_(nMaxLength, return) LPTSTR lpszBuffer, _In_ int nMaxLength) const
{
    ASSERT(::IsWindow(m_hWnd));
    ENSURE(sizeof(nMaxLength)<=nMaxLength*sizeof(TCHAR)&&nMaxLength>0);
    *(LPINT)lpszBuffer = nMaxLength;
    return (int)::SendMessage(m_hWnd, EM_GETLINE, nIndex, (LPARAM)lpszBuffer);
}

Так что это кажется просто крошечной оберткой вокруг EM_GETLINE сообщение.

Документ MSDN для EM_GETLINE утверждает, что "возвращаемое значение является числом TCHAR скопировано " (в моем случае wchar_t с). Для строк с одним символом возвращаемое значение равно двум вместо ожидаемого. Итак, похоже, что элемент управления rich-edit на самом деле возвращает один символ, за которым следует ложный \r в этом особом случае.

Для строк, содержащих более одного символа, возвращаемое значение - это фактическое количество символов, как и ожидалось (я пытался с простыми символами английского языка /ASCII, чтобы избежать сложностей суррогатных пар Unicode и других вещей).

2 ответа

Решение

Я получил его на работу без специального корпуса, используя другую перегрузку CRichEditCtrl::GetLine():

*(int*) buffer = lineLength;
lineLength = richEdit.GetLine(lineNum, buffer);

Ссылка для EM_GETLINE говорит, что вы должны записать размер буфера в буфер, тогда как на самом деле это количество символов, которое вы запрашиваете.

Ссылка для макроса Edit_GetLine() который отправляет EM_GETLINE правильно ли это:

cchMax Максимальное количество символов, которое будет скопировано в буфер.

Макрос пишет cchMax параметр в буфер перед вызовом SendMessage() что точно так же, как мой код выше.

Я также думаю, что условие перегрузки с 3 параметрами CRichEditCtrl::GetLine() что вызывает исключение, если вы запрашиваете менее 2 символов, неверно.

Возвращаемое значение равно нулю (0), если строка недействительна.

Если строка пуста, имеет смысл вернуть 1 и '\r' в буфер. Это будет означать, что "\ r" всегда возвращается, когда номер строки действителен.

Ссылка на функцию говорит, что длина буфера должна быть не менее 4 байтов, потому что WORD записывается в буфер перед передачей в SendMessage.

sizeof (nMaxLength) в функции ENSURE - это размер типа int или WORD.

CRichEditCtrl:: GetLine

CRichEditCtrl:: GetLineCount имеет некоторый код.

Другие вопросы по тегам