I am sending a string from an anonymous thread to the UI with PostMessage in the following code:unit Unit2;interfaceuses  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;const  WM_SETCAPTION = WM_USER;type  TForm2 = class(TForm)    Button1: TButton;    procedure Button1Click(Sender: TObject);  private    { Private declarations }  public    { Public declarations }    procedure WMSetCaption(var msg: TMessage); message WM_SETCAPTION;  end;var  Form2: TForm2;implementation{$R *.dfm}procedure TForm2.WMSetCaption(var msg: TMessage);begin  Self.Caption := PChar(msg.LParam);end;procedure TForm2.Button1Click(Sender: TObject);begin  System.Classes.TThread.CreateAnonymousThread(    procedure    begin      PostMessage(Handle, WM_SETCAPTION, 0, LParam(PChar('My new caption')));    end).Start;end;end.This works seemingly well, but could this potentially create memory leaks? Or is there a better way to accomplish this?
Sending a string from anonymous thread to UI with PostMessage
multithreading;thread safety;delphi
Create an object containing the string as a property and pass the pointer to the object as Integer LParam. Then, in the message handler, use the string and free the object. In this way, you could not only send strings but also other data as well.unit SendingStringWithPostMessageUsingObjectMainForm;interfaceuses  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;const  WM_STRINGMESSAGE = WM_USER;type  TStrMsgObject = class(TObject)  private    fMsg: string;  public    constructor Create(const aMsg: string);    property Msg: string read fMsg;  end;type  TForm2 = class(TForm)    btnSetCaption: TButton;    btnChangeCaption: TButton;    procedure btnChangeCaptionClick(Sender: TObject);    procedure btnSetCaptionClick(Sender: TObject);  private    { Private declarations }    procedure WMStringMessage(var Msg: TMessage); message WM_STRINGMESSAGE;  public    { Public declarations }  end;var  Form2: TForm2;implementation{$R *.dfm}const  // WM_STRINGMESSAGE Actions:  ACTION_SETCAPTION    = 0;  ACTION_CHANGECAPTION = 1;constructor TStrMsgObject.Create(const aMsg: string);begin  inherited Create;  fMsg := aMsg;end;procedure TForm2.WMStringMessage(var Msg: TMessage);// Process WM_STRINGMESSAGE messagesvar  mo: TStrMsgObject;begin  mo := TStrMsgObject(Msg.LParam);  try    case Msg.WParam of      ACTION_SETCAPTION:        begin          Caption := mo.Msg;        end;      ACTION_CHANGECAPTION:        begin          Caption := Caption + mo.Msg;        end;    end  finally    mo.Free;  end;end;procedure TForm2.btnSetCaptionClick(Sender: TObject);begin  System.Classes.TThread.CreateAnonymousThread(    procedure    begin      PostMessage(Handle, WM_STRINGMESSAGE, ACTION_SETCAPTION, Integer(TStrMsgObject.Create('My new caption')));    end).Start;end;procedure TForm2.btnChangeCaptionClick(Sender: TObject);begin  System.Classes.TThread.CreateAnonymousThread(    procedure    begin      PostMessage(Handle, WM_STRINGMESSAGE, ACTION_CHANGECAPTION, Integer(TStrMsgObject.Create(' changed')));    end).Start;end;end.