在单字符行上调用时 CRichEditCtrl::GetLine() 添加的虚假 '\r'?

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

我尝试使用 CRichEditCtrl::GetLine() 在 Unicode 模式下使用 VS2015 构建的 MFC 应用程序中检索 rich-edit 控件的给定行的文本,并在 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() returns 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;
}

但是,我不清楚这种特殊情况行为的原因。


P.S:调用的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 doc for EM_GETLINE 声明 "the return value is the number of TCHARs copied"(在我的例子中,wchar_t)。对于一个字符行,return值是两个,而不是预期的一个。因此,在这种特殊情况下,rich-edit 控件听起来像是 return 后跟一个虚假 \r 的单个字符。

对于包含一个以上字符的行,returned 值是实际的字符数,正如预期的那样(我尝试使用简单的 English/ASCII 字符,以避免 Unicode 代理对和其他东西)。

我通过使用 CRichEditCtrl::GetLine() 的另一个重载使其在没有特殊外壳的情况下工作:

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

EM_GETLINE的参考说你必须将缓冲区的大小写入缓冲区,而这实际上是数量您请求的字符

发送EM_GETLINE的宏Edit_GetLine()的引用是否正确:

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

宏在调用SendMessage()之前将cchMax参数写入缓冲区,这与我上面的代码完全相同。

我还认为 CRichEditCtrl::GetLine() 的 3 参数重载中的条件不正确,如果您请求少于 2 个字符,则会导致异常。

如果该行无效,return 值为 (0)。

如果该行为空,则缓冲区中的 return 1 和 '\r' 是有意义的。这意味着当行号有效时,'\r' 总是 returned。

函数参考说明缓冲区应至少为 4 个字节长,因为 WORD 在传递给 SendMessage 之前写入缓冲区。

ENSURE 函数中的 sizeof(nMaxLength) 是一个 int 或 WORD 的大小。

CRichEditCtrl::GetLine

CRichEditCtrl::GetLineCount 有一些代码。