Msftedit кажется несовместимым с обработкой маркера paragaph (\ par) в конце файла - PullRequest
2 голосов
/ 30 марта 2019

Я реализовал использование cricheditctrl для объединения текста RTF и столкнулся с проблемой с \par в конце файла.Wordpad использует тот же генератор и делает то же самое.(Msftedit 5.41.21.2510).

Если I, где wtrf - это cricheditctrl:

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

Я не получу разделитель абзаца между двумя записями.Они будут противостоять друг другу.В панели ввода слов, если я введу простое:

test

с одной новой строкой, я получу:

...\viewkind4\uc1\pard\sa120\cf1\f0\fs24 test\par
\f1\par
}

Так что, по крайней мере, это всегда согласуется на моей машине.Но я не могу говорить об этом в спецификации Word 2007: Rich Text Format (RTF), версия 1.9.1 .

Меня беспокоит то, что это не постоянное поведение, и я могуполучить другие результаты на других машинах.А потом, может быть, я что-то упустил о том, как правильно завершить RTF-документ.Я действительно нашел это.Спасибо.

ОБНОВЛЕНИЕ : И я извиняюсь за изображение, но я думаю, что это помогает.Это становится все более запутанным.

enter image description here Итак, я извлекаю контент из базы данных, и вы можете видеть, что контент:

{rtf_stuff ... content\par}

И вверхнее окно, и вы можете видеть, что маркер абзаца работает, только один.

sel= GetRichText( re, SF_RTF );
std::ofstream ts(R"(C:\cpp\ReserveAnalyst_14\StockCommentParser\test.txt)");
ts << sel;

И test.txt имеет:

{\rtf1\stuff ... asphalt sealing.\par
\par
}

Теперь есть два \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;
}

UPDATE2 : сейчасЯ должен верить, что это недостаток контроля.Я видел это, но это не регистрировалось в моей голове.Итак, с этим:

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;

Результат в файле:

{\rtf1\,,,\viewkind4\uc1\pard\sa120\cf1\f0\fs24 test 1\cf2 test 2\cf1\par}

wrtf.SetSel(-1, -1); помещает точку вставки перед последней \par, а не после нее,Подсказка о последнем равенстве имеет цветную метку \cf1 с первой вставки.И в этом случае он сбрасывает один из моих \par, где в предыдущем случае это не так, похоже, я только получаю дополнительные \par.Это сводит меня с ума!:)

1 Ответ

2 голосов
/ 03 апреля 2019

После некоторого тестирования и работы с 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());
}

Это удаляет любое форматирование с конца документа и оставляет только пару \par

Еще одна вещь, которую я узнал из названия этого поста, заключается в том, что для завершения документа маркером абзаца необходимо завершить документ двумя управляющими словами \par. Я перепроверил 2007: Rich Text Format (RTF) Specification, version 1.9.1.. Нигде я не мог найти никакого различия в окончании документа с \par. И что у одного \par нет свойства абзаца, для работы в конце документа требуются два. Я проверил, и Wordpad, MS Word и Open Office все это делают.

Я поместил копию моего тестового проекта консоли здесь и здесь Здесь используется OLE безоконный CRichEditCtrl, который может оказаться полезным.

...