Mega Search
23.2 Million


Sign Up

Make a donation  
Problem with TRichEdit in XE5: EM_STREAMIN adds a new line!  
News Group: embarcadero.public.delphi.vcl.components.using

Hi there,

During the migration of an D7 application to Delphi XE5 I encountered a problem with the TRichEdit component.

My application allows the user to write formatted text and to insert formatted text templates/modules into the text.
All the necessary moving of formatted text between the diffrent RichEdit components is managed by a set of functions using the EM_STREAMIN and EM_STREAMOUT messages.
These functions worked properly in D7 and I've included them at the end of this post so you can have a look at them.

When these functions are used in XE5 this is happening: 
GetRTFSelection seems to work correctly and gets the selected part of the richedit code. But when this data is streamed into another richEdit using EM_STREAMIN
there is always an additional line inserted! And it's not just an additonal CR+LF it's an extra paragraph in the richedit code as well (\pard\par) !

I've done a simple test: typing two rows of text in one richedit and stream them into another one. See what's happened to the rtf-code:

RTF-Code in the source richEdit:

{\rtf1\ansi\ansicpg1252\deff0\deflang1031{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\f0\fs16 FirstRow\par
SecondRow\par
}

RTF-Code of the target RichEdit:

{\rtf1\ansi\ansicpg1252\deff0\deflang1031{\fonttbl{\f0\fnil\fcharset0 Tahoma;}}
\viewkind4\uc1\pard\f0\fs16 FirstRow\par
SecondRow\par
*\pard\par*
}

I dont't think it's a D7-migration related problem because I wrote a small test application in XE5 and it behaves just the same.
It could be something with the interpretation of the CRLF because in one function the text of the RichEdit is moved character by character to 
another RichEdit (kind of parsing) and the CRLF isn't recognized properly: Calling GetTextLen shows a CRLF is counted as two but during the parsing only CR is found no LF.

Does XE5 use a different version of Win32 RichEdit control than D7? 

The error doesn't occur when EM_STREAMOUT is called with the replacement option (SF_RTF) instead of (SF_RTF or SFF_Selection), but I need to keep existing text in the target so that's not an option.

Thanks in advance for any help,
regards

Regine


//EditStreamCallback callback functions
function GetRTFSelCB(dwCookie: DWORD_PTR; pbBuff: PByte; cb: Longint; var pcb: Longint): Longint; stdcall;
begin
  pcb := cb;
  if cb > 0 then begin
    TStream(dwCookie).WriteBuffer(pbBuff^, cb);
    Result := 0;
  end else
    Result := 1;
end;

function SetRTFSelCB(dwCookie: DWORD_PTR; pbBuff: PByte; cb: Longint; var pcb: Longint): Longint; stdcall;
begin
  pcb := TStream(dwCookie).Read(pbBuff^, cb);
  if pcb > 0 then
    Result := 0
  else
    Result := 1;
end;


//Gets the selected contents of a richedit 
function GetRTFSelection(RichEdit: TRichEdit): AnsiString;
var
  Str: TStringStream;
  ES: TEditStream;
begin
  Str := TStringStream.Create('',TEncoding.ANSI);
  try
    ES.dwCookie := DWORD_PTR(Str);
    ES.dwError := 0;
    ES.pfnCallback:=GetRTFSelCB;
   {Causes a rich edit control to pass its contents to an
    application–defined EditStreamCallback callback function.}
    RichEdit.Perform(EM_STREAMOUT, SF_RTF or SFF_SELECTION, Integer(@ES));
    if ES.dwError <> 0 then
      raise EOutOfResources.Create(sRichEditSaveFail);

//    Result := Str.DataString; //nullterminated
    Result := pAnsiChar(Str.Memory);  //not nullterminated
    Str.SaveToFile('result.rtf');
  finally
    Str.Free
  end
end;

//Sets the rtf-code in RichEdit at cursorpos
procedure SetRTFSelection(RichEdit:TRichEdit; const Source: AnsiString);
var
  Str: TStringStream;
  ES: TEditStream;
begin
  RichEdit.Lines.BeginUpdate;
  Str := TStringStream.Create(Source);
  try
    ES.dwCookie := DWORD_PTR(Str);
    ES.dwError := 0;
    ES.pfnCallback := SetRTFSelCB;
    RichEdit.Perform(EM_STREAMIN, SF_RTF or SFF_SELECTION, Integer(@ES));
    if ES.dwError <> 0 then
      raise EOutOfResources.Create(sRichEditSaveFail);
  finally
    Str.Free;
    RichEdit.Lines.EndUpdate;
  end;
end;

//copies selected part of source to target richedit
procedure RTFToRTF(Source, Target: TRichEdit; OverwriteTarget, ClearSource: Boolean);
var
   S: AnsiString;
begin
   If OverwriteTarget then
      Target.Clear
   else
      Target.SelStart:=Length(Target.Text);

   Source.SelStart:=0;
   Source.SelLength:=Length(Source.Text);
   S:=GetRTFSelection(Source);
   SetRTFSelection(Target, S);
   If ClearSource then Source.Clear;
end;

Vote for best question.
Score: 0  # Vote:  0
Date Posted: 14-Jan-2014, at 7:00 AM EST
From: Regine Mayer