Sunday, February 10, 2008

New 0.9.26 features. Part 1. SendMessage and PostMessage

If you ever wrote some big application or component, I am sure you met the problem of postponed execution of some code. Delphi programmers usually used 2 solutions: timers and Windows message system abilities. This article is about message system approach. Note that Lazarus has a third solution: Application.QueueAsyncCall.

I suppose you already know something about the Windows message system. And you are familiar with SendMessage and PostMessage commands. They are used to deliver messages to controls. SendMessage sends message dirrectly to control window procedure. PostMessage adds message to the message queue, so control will get it only after processing all other pending messages.

Group of message numbers from 0 to WM_USER are used by Windows itself. So if you want to use message system in personal purpose you should use message numbers >= WM_USER.

Lets return to Lazarus where you want to indirectly perform some actions. Very usual task is when you need to destroy some control (your form for example) in event handler. Ofcource your application crash if you call Free in event handler - so you need to call Free somehow after event handler. But how? Call PostMessage in event handler and process posted message in message handler.

Delphi example:

const
MY_MESSAGE = WM_USER + 1; // <-- your message number
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject); // <-- some event handler
private
procedure MyMsgHandler(var Message: TMessage); message MY_MESSAGE; // <-- message handler
end;

...

procedure TForm1.Button1Click(Sender: TObject);
begin
... //code before
PostMessage(Handle, MY_MESSAGE, 1, 0); // <-- here you post message to message queue
... // code after
end;

procedure TForm1.MyMsgHandler(var Message: TMessage);
begin
Free;
end;

If you used similar constructions in Delphi, you should know that they did not work in Lazarus. In the win32 widgetset code all WM_USER messages were blocked for some reasons:
- other widgetsets had no support for PostMessage and SendMessage
- few WM_USER messages were used by Windows and cause errors in LCL

After releasing 0.9.24 we reevaluated our decision since gtk and qt supported PostMessage and SendMessage. Then an implementation for Carbon appeared. Of course it would be a joke to block messages under Windows when all other widgetsets (where messages are aliens) support them. Now you can use PostMessage and SendMessage with few limitations:
- use Message numbers >= LM_USER
- sending messages outside application does not work (you cannot send message to another application)

And the last - if you need example - look at lazarus\examples\messages.

4 comments:

Fabio Luis Girardi said...

And how to send a message in broadcast (to all controls)?

shizhi hong said...

hi,

May I ask one question ?
I launch a child-process under
Lazarus.
And .....

The child-process finally shows
"Press any key to end"..

I want to send key from my
main-process to this child-process,

May you let me know how to do this ?

I googled some data about sendmessage, findhandle,
but I could not get it.

thank you in advacne.

shizhi hong said...

oh, by the way,
my OS is windows-xp,
and the child-process is a
command utility program.

thanks.

Capitán Trueno said...

http://wiki.lazarus.freepascal.org/Executing_External_Programs