9

I am currently in the process of migrating our software solution from Delphi 7 to 2010. Mostly the changes have been simple and there are only a small amount of hurdles left to go.

On a form we use a TRichEdit which displayed rtf text grabbed from a blob field in a MSSQL db. This is how it worked in Delphi 7:

//Get RTF text from Blob field using TADOQuery
rtfStream := sql.CreateBlobStream(sql.FieldByName('rtftext'), BmRead) as TMemoryStream;

//Load into TRichEdit
RichEdit.PlainText := False;
RichEdit.Lines.LoadFromStream(rtfStream);

This would display the RTF as expected in the TRichEdit component, but the same code in Delphi 2010 displays the RTF as plain text with tabs between each character. I assume this has a lot to do with the change from Ansi to Unicode, but I haven't had any luck rectifying the problem.

Any help getting this to work would be much appreciated. Thanks

Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105
Simon Hartcher
  • 3,400
  • 3
  • 30
  • 34

2 Answers2

15

Okay I figured it out.

For loading the rtf text:

//Get the data from the database as AnsiString
rtfString := sql.FieldByName('rtftext').AsAnsiString;

//Write the string into a stream
stream := TMemoryStream.Create;
stream.Clear;
stream.Write(PAnsiChar(rtfString)^, Length(rtfString));
stream.Position := 0;

//Load the stream into the RichEdit
RichEdit.PlainText := False;
RichEdit.Lines.LoadFromStream(stream);

stream.Free;

For saving the rtf text:

//Save to stream
stream := TMemoryStream.Create;
stream.Clear;

RichEdit.Lines.SaveToStream(stream);
stream.Position := 0;

//Read from the stream into an AnsiString (rtfString)
if (stream.Size > 0) then begin
    SetLength(rtfString, stream.Size);
    if (stream.Read(rtfString[1], stream.Size) <= 0) then
        raise EStreamError.CreateFmt('End of stream reached with %d bytes left to read.', [stream.Size]);
end;

stream.Free;

//Save to database
sql.FieldByName('rtftext').AsAnsiString := rtfString;

This took me way too long to figure out :) I guess I have learned one thing though... if something goes wrong in Delphi 2010, its usually related to unicode ;)

Simon Hartcher
  • 3,400
  • 3
  • 30
  • 34
  • http://kspnew.googlecode.com/svn-history/r334/trunk/additional/bass/AnsiStringStream.pas or something similar ? – Arioch 'The Jul 22 '13 at 16:09
  • 1
    This solution works for me and hey, it's 2020 and this issue still applies. I have done upgrades in the past from Delphi 7 to Delphi XE3 to Delphi Rio 10.3 – L. Piotrowski Nov 17 '20 at 17:46
5

When PlainText is False, LoadFromStream() first attempts to load the RTF code, and if that fails then LoadFromStream() attempts to load the stream again as plain text. That has always been the case in all Delphi versions. With the introduction of Unicode, I suppose something could have broken in LoadFromStream()'s EM_STREAMIN callback handler. I suggest you step into LoadFromStream()'s actual source code with the debugger and see what is really happening.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Thanks for the tip. I was unable to trace into the LoadFromStream code for some reason, but this got me thinking about it the right way which led to my solution. – Simon Hartcher Nov 03 '10 at 04:07
  • 1
    Traditionally Delphi used RTDEdit v.1.0 and ignored v.2.0 and v.3.0 *(which were used by RxLib, JediVCL, TRichView etc). And one can read that UNICODE is prohibited for EM_STREAMIN by http://msdn.microsoft.com/en-us/library/windows/desktop/bb774302.aspx if Only Delphi had TAnsiStringStream or used more modern RTF edit controls – Arioch 'The Jul 22 '13 at 16:08
  • 1
    Unicode is not prohibited for `EM_STREAMIN`, it can be used but only with the `SF_TEXT` flag, which is how `TRichEdit` does use it. `SF_UNICODE` is not supported in RE 1.0, but `TRichEdit` in recent VCL versions (including 2010) explicitly load RE 2.0 (which silently loads RE 3.0 on Windows versions that support 3.0). – Remy Lebeau Jul 22 '13 at 22:47
  • 1
    @RemyLebeau Mea culpa indeed. Digged deep into ad hoc RTF string generator and matched to specs and it realyl was incorrect. So in XE2 at least they fixed loadfromstream for rtf. It might be less efficient than AnsiStringStream, but it works. – Arioch 'The Jul 23 '13 at 07:22