Поддельные '\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:: GetLineCount имеет некоторый код.