Spurious '\r' added by CRichEditCtrl::GetLine() when called on single-character lines?

筅森魡賤 提交于 2019-12-24 02:22:47

问题


I tried using CRichEditCtrl::GetLine() to retrieve the text of a given line of a rich-edit control in an MFC application built with VS2015 in Unicode mode, and running on Windows 10.

I wrote this helper function:

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;
}

This code works fine, except for lines containing only one character. In this case, CRichEditCtrl::GetLine() returns 2 (instead of the expected 1), and the output buffer contains the correct character, followed by a \r.

Why is that? Why is the \r added only for single-character lines and not for lines containing more characters?

I was able to fix that adding a special case if like this:

// 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;
}

However, it's not clear to me the reason for this special-case behavior.


P.S: The CRichEditCtrl::GetLine() MFC code that is invoked is:

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);
}

So this seems just a tiny wrapper around the EM_GETLINE message.

The MSDN doc for EM_GETLINE states that "the return value is the number of TCHARs copied" (in my case, the wchar_ts). For one-character lines the return value is two, instead of the expected one. So, sounds like the rich-edit control is actually returning the single character followed by a spurious \r in this special case.

For lines containing more than one characters, the returned value is the actual number of characters, as expected (I tried with simple English/ASCII characters, to avoid complications of Unicode surrogate pairs and other stuff).


回答1:


I got it to work without special-casing by using the other overload of CRichEditCtrl::GetLine():

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

The reference for EM_GETLINE says that you have to write the size of the buffer into the buffer, while this actually is the number of characters you request.

The reference for the macro Edit_GetLine() which sends EM_GETLINE has it correct:

cchMax The maximum number of characters to be copied to the buffer.

The macro writes the cchMax parameter to the buffer before calling SendMessage() which is exactly the same as my code above.

I also think that the condition in the 3-parameter overload of CRichEditCtrl::GetLine() which causes an exception if you request less than 2 characters, is incorrect.




回答2:


The return value is zero (0) if the line is not valid.

If the line is empty it makes sense to return 1 and '\r' in the buffer. That would mean that '\r' is always returned when the line number is valid.

The function reference says that the buffer should be at least 4 bytes long, because a WORD is written to the buffer before being passed to SendMessage.

sizeof(nMaxLength) in the ENSURE function is the size of an int or WORD.

CRichEditCtrl::GetLine

CRichEditCtrl::GetLineCount has some code.



来源:https://stackoverflow.com/questions/46371932/spurious-r-added-by-cricheditctrlgetline-when-called-on-single-character

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!