Mfc Msftedit在文件末尾处理段落标记(\par)时似乎不一致

Mfc Msftedit在文件末尾处理段落标记(\par)时似乎不一致,mfc,richtextbox,rtf,cricheditctrl,Mfc,Richtextbox,Rtf,Cricheditctrl,我已经实现了使用cricheditctrl来压缩rtf文本,并且在文件末尾遇到了\par问题。写字板使用相同的生成器并执行相同的操作。(Msftedit 5.41.21.2510) 如果I,其中wtrf是一个CRICHEDITCRL: const char* header = "this is a test header\r\n"; wrtf.SetWindowTextA(header); 结果rtf为: {\rtf1\ansi\ansicpg1252\deff0\deflang1033{\

我已经实现了使用
cricheditctrl
来压缩rtf文本,并且在文件末尾遇到了
\par
问题。写字板使用相同的生成器并执行相同的操作。(Msftedit 5.41.21.2510)

如果I,其中wtrf是一个CRICHEDITCRL:

const char*  header = "this is a test header\r\n";
wrtf.SetWindowTextA(header);
结果rtf为:

{\rtf1\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{\f0\fswiss\fprq2\fcharset0 System;}}
{\*\generator Msftedit 5.41.21.2510;}\viewkind4\uc1\pard\b\f0\fs20 this is a test header\par
\par}
最后有两个
\par

从更大的角度来看,我正在用rtf内容做我自己的事情。如果我没有在结尾使用双精度
\par
进行创作,请执行以下操作:

std::string dest(_RichEditPreamble);
dest+= std::string("\\cf1 this is a test\\par\\par}";
SetRichText(wrtf,dest.c_str());
wrtf.SetSel(-1, -1);   // Select last character
SetRichText(wrtf, more_rtf, SF_RTF | SFF_SELECTION);
我不会在这两个条目之间设置段落分隔符。他们将互相对峙。在word pad中,如果我输入一个简单的:

test
通过一条换行,我得到:

...\viewkind4\uc1\pard\sa120\cf1\f0\fs24 test\par
\f1\par
}
所以,至少,这在我的机器上总是一致的。但是我在报纸上找不到关于它的话题

我担心的是,这不是恒定的行为,我可能会在其他机器上得到不同的结果。然后,也许我遗漏了一些关于如何正确结束RTF文档的内容。我真的找到了这个。 谢谢

更新: 我为这张照片感到抱歉,但我认为它有帮助。这只会让人更加困惑

因此,我从数据库中提取内容,您可以看到内容是:

{rtf_stuff ... content\par}
进入顶部窗口,你可以看到段落标记正在工作,只有一个

sel= GetRichText( re, SF_RTF );
std::ofstream ts(R"(C:\cpp\ReserveAnalyst_14\StockCommentParser\test.txt)");
ts << sel;
现在有两个
\par
。在第二个RTF窗口中,我将数据放置在:

SetRichText( pCommentFrm->GetRichCtrl( ), text, SF_RTF | SFF_SELECTION ); //todo ??
最后我写了两段!(第二个rtf窗口)

所以,以防万一,这是我用了20年的回电:

DWORD CALLBACK EditStreamCallBack(
    DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb )
{
    _afxRichEditStreamCookie* pCookie = (_afxRichEditStreamCookie*)dwCookie;
    CArchive& ar = pCookie->m_ar;
    DWORD dw = 0;
    *pcb = cb;
    TRY
    {
        if ( ar.IsStoring( ) )
        ar.GetFile( )->Write( pbBuff, cb );
        else
            *pcb = ar.GetFile( )->Read( pbBuff, cb );
    }
        CATCH( CFileException, e )
    {
        *pcb = 0;
        pCookie->m_dwError = (DWORD)e->m_cause;
        dw = 1;
        e->Delete( );
    }
    AND_CATCH_ALL( e )
    {
        *pcb = 0;
        pCookie->m_dwError = -1;
        dw = 1;
        e->Delete( );
    }
    END_CATCH_ALL
        return dw;
}
更新2:现在我不得不相信这是控件中的一个缺陷。我看到了它,但它没有在我的脑海中注册。因此:

std::string source1(_RichEditPreamble);
source1 += "\\cf1 test 1\\par}";
SetRichText(wrtf,source1.c_str());
std::string source2(_RichEditPreamble);
source2 += "\\cf0 test 2\\par";
wrtf.SetSel(-1, -1);   // Select last character
SetRichText(wrtf, source2.c_str(), SF_RTF | SFF_SELECTION);

auto result = GetRichText(wrtf);
std::ofstream ts("..\\rtf_io.rtf");
ts << result;

wrtf.SetSel(-1,-1)将插入点放在最后一个
\par
的前面,而不是后面。线索是从第一次插入的最后一个PAR有一个颜色标签“代码> \ CF1< /代码>。在本例中,它正在删除我的一个
\par
,而在上一例中,它不是这样的,所以看起来我得到了额外的
\par
。这让我快发疯了!:)

经过一些测试并使用CRichEditCtrl,我发现它不是用来连接RTF文档的。即使使用
SetSel(-1,-1)
,它也会像对待插入一样对待插入。这意味着插入上面的文本的所有特征都被附加到文档的末尾。对我来说,我需要一个真正的附加,插入中的特征将位于文档的末尾。我想让用户得到他们所看到的,如果他们要添加更多的内容到文档。我确实想出了一个我认为足够的方法。它可能并不总是有效的,但至少不应该以例外结束

BOOL AppendRichText( CRichEditCtrl& rtf, LPCTSTR buf )
{
    rtf.SetSel(-1, -1);
    if( ! SetRichText(rtf,buf, SF_RTF | SFF_SELECTION))
        return FALSE;
    auto buffer = GetRichText(rtf);
    char* che= buffer.get();
    for(; *che; ++che);//to end
    char* ch= che;
    for(; *ch != ' '; --ch);//back to first space
    for(; *ch != '\\'; ++ch);//then to first '\', assumes not \\,\},\{ for now
    if( ch + 10 > che )
        return FALSE;//but it should fit....
    auto re = R"(\par\par})"; // the replacement
    for( size_t i= 0; i < 10; ++i)
        *ch++ = *re++;
    return SetRichText(rtf,buffer.get());
}
BOOL AppendRichText(CRichEditCtrl&rtf,LPCTSTR buf)
{
rtf固定值(-1,-1);
如果(!SetRichText(rtf、buf、SF|rtf|SFF|选择))
返回FALSE;
自动缓冲区=GetRichText(rtf);
char*che=buffer.get();
对于(;*che;++che);//结束
char*ch=che;
for(;*ch!='';--ch);//返回第一个空格
对于(;*ch!='\\';++ch);//然后到第一个'\',假设现在不\\,\},\{
如果(通道+10>che)
return FALSE;//但它应该适合。。。。
自动re=R“(\par\par})”;//替代品
对于(尺寸i=0;i<10;++i)
*ch++=*re++;
返回SetRichText(rtf,buffer.get());
}
这将删除文档末尾的任何格式,只留下几个
\par

我从这篇文章的标题中学到的另一件事是,要用段落标记结束文档,必须用两个
\par
控制字结束文档。我重新检查了
2007:RTF规范,版本1.9.1。
。用
\par
结尾文档时,我找不到任何区别。如果单个
\par
没有段落属性,则需要两个段落才能在文档末尾工作。我检查了一下,写字板、微软Word和OpenOffice都能做到


我已经放了一个控制台测试项目的副本,这里有一个OLE无窗口的CRichEditCtrl,您可能会发现它很有用。

如果您输入
“line1\r\nline2\r\n”
您将得到类似
{…line1\par line2\par\par}/code>的新代码,还有一个额外的
\par
作为文件结尾。大概你好,Barmak Shemirani,谢谢。我看过一些关于
\line
的东西,但它是从老读者那里处理的,而在新读者中,它的价值相当低。但请务必查看我的更新2我的意思是,文件末尾的
\par
是预期的。如果您尝试
wrtf.SetWindowTextA(“测试1\r\n测试2\r\n”)
然后
GetRichText
将返回
{…testing 1\par testing 2\par\par}
。请注意,第1行和第2行之间只有一个
\par
。另外,如果输入
wrtf.SetWindowTextA(“”)
然后
GetRichText
将返回以
\par
结尾的rtf字符串。我认为这是RTF工作的奇怪方式。文件中的最后一个
\par
似乎表明它需要一个新段落。我无法跟踪更新2。在Windows 10和RichEdit2.0上,
“..\cf0 test1\par\par test2\par\par}”
将导致
“test1\r\n\r\n\test2\r\n”
-RichEdit5也需要Unicode,我不确定如何运行代码。您好@Barmak Shemirani,rtf是最典型的ANSI,Unicode是可选的。我的拖缆是字节宽的,
SetRichText
GetRichText
也是如此。我已经上传了一个类解决方案,用于使用rtf控件进行连接。完成后,我将github项目并发布答案。谢谢你,丹。
{\rtf1\,,,\viewkind4\uc1\pard\sa120\cf1\f0\fs24 test 1\cf2 test 2\cf1\par}
BOOL AppendRichText( CRichEditCtrl& rtf, LPCTSTR buf )
{
    rtf.SetSel(-1, -1);
    if( ! SetRichText(rtf,buf, SF_RTF | SFF_SELECTION))
        return FALSE;
    auto buffer = GetRichText(rtf);
    char* che= buffer.get();
    for(; *che; ++che);//to end
    char* ch= che;
    for(; *ch != ' '; --ch);//back to first space
    for(; *ch != '\\'; ++ch);//then to first '\', assumes not \\,\},\{ for now
    if( ch + 10 > che )
        return FALSE;//but it should fit....
    auto re = R"(\par\par})"; // the replacement
    for( size_t i= 0; i < 10; ++i)
        *ch++ = *re++;
    return SetRichText(rtf,buffer.get());
}