2

我尝试CRichEditCtrl::GetLine()在使用 VS2015 以 Unicode 模式构建并在 Windows 10 上运行的 MFC 应用程序中检索富编辑控件的给定行的文本。

我写了这个辅助函数:

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 doc forEM_GETLINE声明“返回值是TCHAR复制的 s 数”(在我的例子中是wchar_ts)。对于一个字符的行,返回值是,而不是预期的一。\r因此,在这种特殊情况下,听起来富编辑控件实际上是在返回单个字符后跟一个虚假字符。

对于包含多个字符的行,返回值是实际的字符数,正如预期的那样(我尝试使用简单的英文/ASCII 字符,以避免 Unicode 代理对和其他东西的复杂性)。

4

2 回答 2

2

通过使用其他重载,我让它在没有特殊情况的情况下工作CRichEditCtrl::GetLine()

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

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

Edit_GetLine()发送的宏的参考EM_GETLINE正确:

cchMax 要复制到缓冲区的最大字符数。

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

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

于 2017-09-22T23:33:29.503 回答
-2

如果该行无效,则返回值为零(0)。

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

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

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

CRichEditCtrl::GetLine

CRichEditCtrl::GetLineCount 有一些代码。

于 2017-09-23T04:03:18.080 回答