Search code examples
delphiindy-9

Memo Line Breaks


I'm building a tool that sends a request besides my browser request using TIdMappedPortTCP from Indy 9.

I want to use string #$d#$A (line breaks) by writing it in memo as %0D%0A but it's not working fine, as you can see in the image.

What's the correct code I should use to make this work?

procedure TForm1.IdMappedPortTCP1Execute(AThread: TIdMappedPortThread);
var
  memo:string;
begin
  memo:= Memo1.text;
  if Combobox4.text='Back' then begin
    AThread.NetData := AThread.NetData +memo  ;
    form2.Memo1.Lines.Add(AThread.NetData);

IdMappedPortTCP request & log


Solution

  • TIdMappedPortTCP is a multi-threaded component. The OnExecute event is triggered in the context of a worker thread. You CANNOT access your TMemo and TComboBox controls directly like you have shown. You MUST synchronize with the UI thread in order to access them safely and correctly.

    Try something more like this:

    uses
      ..., IdSync;
    
    type
      TGetForm1BackMemoTextSync = class(TIdSync)
      protected
        FText: string;
        procedure DoSynchronize; override;
      public
        class function GetText: string;
      end;
    
      TAddToForm2MemoSync = class(TIdSync)
      protected
        FText: string;
        procedure DoSynchronize; override;
      public
        class procedure AddToMemo(const S: string);
      end;
    
    procedure TGetForm1BackMemoTextSync.DoSynchronize;
    begin
      if Form1.ComboBox4.Text = 'Back' then
        FText := Form1.Memo1.Text;
    end;
    
    class function TGetForm1BackMemoTextSync.GetText: string;
    begin
      with Create do
      try
        Synchronize;
        Result := FText;
      finally
        Free;
      end;
    end;
    
    procedure TAddToForm2MemoSync.DoSynchronize;
    begin
      Form2.Memo1.Lines.Add(FText);
    end;
    
    class procedure TAddToForm2MemoSync.AddToMemo(const S: string);
    begin
      with Create do
      try  
        FText := S;
        Synchronize;
      finally
        Free;
      end;
    end;
    
    //...
    
    procedure TForm1.IdMappedPortTCP1Execute(AThread: TIdMappedPortThread);
    var
      memo: string;
    begin
      memo := TGetMemoBackTextSync.GetText;
      if memo <> '' then begin
        AThread.NetData := AThread.NetData + memo;
        TAddToForm2MemoSync.AddToMemo(AThread.NetData);
      //...
    end;
    

    With that said, you should not be putting %0D%0A in the Memo text at all. Each line in a Memo is already separated by a line break. Reading the Memo.Text property returns a string where each line is separated by the value of the RTL's sLineBreak constant (which is defined as #13#10 on Windows). So just omit %0D%0A from your text and type in natural line breaks instead, and let the RTL handle the rest for you.

    If you absolutely must keep %0D%0A in the text, you will have to strip off the native line breaks and then convert %0D%0A into native line breaks manually, eg:

    procedure TGetForm1BackMemoTextSync.DoSynchronize;
    begin
      if Form1.ComboBox4.Text = 'Back' then
      begin
        FText := StringReplace(Form1.Memo1.Text, sLineBreak, '', [rfReplaceAll]);
        FText := StringReplace(FText, '%0D%0A', #13#10, [rfReplaceAll]);
      end;
    end;