HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Sending a string from anonymous thread to UI with PostMessage

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
anonymouswithsendingthreadfrompostmessagestring

Problem

I am sending a string from an anonymous thread to the UI with PostMessage in the following code:

unit Unit2;

interface

uses
  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?

Solution

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;

interface

uses
  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 messages
var
  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.

Code Snippets

unit SendingStringWithPostMessageUsingObjectMainForm;

interface

uses
  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 messages
var
  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.

Context

StackExchange Code Review Q#162167, answer score: 4

Revisions (0)

No revisions yet.