Давеча пришлось дорабатывать одну из утилит сбора информации о системе и как-то неожиданно для меня от отдела тестирования пришел багрепорт плана:
Утилита формирует и сохраняет данные правильно, но загружает их в искаженном виде.
Ну точнее не то, чтобы неожиданно...
С чем-то подобным я уже ранее встречался, когда писал компаратор карт памяти процесса, вот для этой утилиты, но тогда, если честно, не сильно обратил на этот нюанс внимание, ибо тогда мне нужна была скорость загрузки информации в RichEdit.
Но та работа была в виде хобби, а тут собственно рабочий проект.
Если честно, причины такого поведения я не знаю, да и разбираться не сильно есть время, поэтому просто приведу решение данной проблемы.
Такой код загружает файл большого объема в RichEdit с ошибками как на верхней картинке:
А вот такой, грузит правильно:
Сравнительный результат:
Сам код: http://rouse.drkb.ru/blog/rtf.zip
Судя по всему ошибка внутри метода загрузки в VCL обертке.
Утилита формирует и сохраняет данные правильно, но загружает их в искаженном виде.
Ну точнее не то, чтобы неожиданно...
С чем-то подобным я уже ранее встречался, когда писал компаратор карт памяти процесса, вот для этой утилиты, но тогда, если честно, не сильно обратил на этот нюанс внимание, ибо тогда мне нужна была скорость загрузки информации в RichEdit.
Но та работа была в виде хобби, а тут собственно рабочий проект.
Если честно, причины такого поведения я не знаю, да и разбираться не сильно есть время, поэтому просто приведу решение данной проблемы.
Такой код загружает файл большого объема в RichEdit с ошибками как на верхней картинке:
RichEdit1.Lines.LoadFromFile('updates.rtf');
А вот такой, грузит правильно:
function RichEditStreamCallBack(Cookie: TMemoryStream; pbBuff: PByte; cb: Longint; var pcb: Longint): Longint; stdcall; begin Result := 0; try pcb := Cookie.Read(pbBuff^, cb); except Result := 1; end; end; procedure TForm1.Button1Click(Sender: TObject); var M: TMemoryStream; Param: TEditStream; begin M := TMemoryStream.Create; try M.LoadFromFile('updates.rtf'); {$IFDEF WIN64} Param.dwCookie := DWORD_PTR(M); {$ELSE} Param.dwCookie := LongInt(M); // LongInt для совместимости со старыми версиями Delphi {$ENDIF} Param.dwError := 0; param.pfnCallback := @RichEditStreamCallBack; SendMessage(RichEdit2.Handle, EM_STREAMIN, SF_RTF, LPARAM(@Param)); finally M.Free; end; end;
Сравнительный результат:
Сам код: http://rouse.drkb.ru/blog/rtf.zip
Судя по всему ошибка внутри метода загрузки в VCL обертке.
А там нету ещё Борландового IStream.CopyTo? Там помнится были проезды по памяти.
ОтветитьУдалитьНадо в QC запостить.
ОтветитьУдалитьВ QC смысла постить большого не имеет, т.к. причина такого поведения в том что после отправки сообщения EM_STREAMIN, возвращается ошибка STG_E_MEDIUMFULL в EditStream.dwError, после чего данные грузятся как PlainText.
ОтветитьУдалитьЭтот код выставляется внутри RICHED20.DLL, а почему - не понятно.
Да, кстати, под ХЕ4 ошибка загрузки в таком виде не воспроизводится, нужно грузить данные немного по другому.
В XE3 все работает как часы
ОтветитьУдалитьhttp://i011.radikal.ru/1402/7a/4f7ac5fd472b.jpg
Во всех юникодных работает нормально, но если данные приготовить немного не так, то будет ошибка. Завтра выложу демку. Причем там так же причины поведения понять не могу - тот-же массив данных (что со стрима что с файла), но либо ошибка если грузить из памяти, либо все нормально если с диска - прям беда :)
Удалить* ошибка - во всех "юникодных" работает нормально, если грузить именно с диска.
УдалитьХотя разница не понятна - там по любому преобразования на юникод нет.
Ок, жду думку... И комментарии о том, что значит "данные приготовить немного не так", а я завтра на работе на D7 гляну... не то, чтобы не доверяю, просто я с такой проблемой не сталкивался, хотя rtf в richedit загружал не однократно :)
УдалитьТам загрузка стрима из ZIP архива, я завтра постараюсь это воспроизвести на стандартом наборе классов, ну а если не получится (хоты врятли) тогда уже покажу вариант через свой FWZipReader.
УдалитьСоль даже не в этом, Delphi7 гарантированно воспроизводит ошибку, хотя откуда ей взяться то?
Ан нет, я был не прав что грешил на ZIP, не в этом оказалось дело.
УдалитьПод ХЕ4 такое поведение воспроизводится в том случае, если изначально (в самом DFM) параметр Lines был очищен. Если же он содержит хотя бы одну строку - такого поведения не наблюдается.
Обновил исходный код примера (с правленым DFM) можно проверять.
Да, теперь ошибка воспроизводится стабильно. Спасибо за пример решения, положу в копилку, пригодится :)
УдалитьЯ его чуть-чуть еще раз обновил :)
УдалитьПисал на скорую руку и забыл про совместимость с 64 битами, пардон...
в прошлом десятилетии еще ковырялся - невнятных глюков все равно много остаётся(встречаются неперевариваимые документы)
Удалитьчерез Text Services Framework - вроде стабильнее работает...
( DllName: 'MSFTEDIT.DLL'; WndClass: MSFTEDIT_CLASS; Version: -1 )
вместо
( DllName: 'RICHED20.DLL'; WndClass: RICHEDIT_CLASSW; Version: -1 ),
http://flocke.vssd.de/prog/code/pascal/rtflabel/
Copyright (C) 2006 Volker Siebert
{$IFDEF USE_TOM}
if(RichEdit_GetOleInterface(Handle, FOle))then begin
QueryThiscallInterface(FOle, IID_ITextServices, FServices);
end;
{$ENDIF}
...
{$IFDEF USE_TOM}
FServices.TxSendMessage(EM_STREAMIN, TextType, LongWord(@ems), res);
{$ENDIF}
Угу, спасибо - возьму на заметочку.
УдалитьТакой способ грузит только часть текста, а не весь.
ОтветитьУдалитьhttp://delphimaster.net/view/3-1160110659
УдалитьRichEdit1.MaxLength:= 2147483632; //Рішення проблеми
RichEdit1.Lines.LoadFromFile(OpenDialog1.FileName);