How to send and handle a custom Windows message
These notes apply to Delphi running
on a Microsoft Windows platform.
Delphi allows you to define your own messages when can then be posted
on the Windows message queue and then handled by your own custom handler
in your application.
The notes here show how to:
- Define your own custom message
- Define a handler for the message
- Send a message
- Pass data via messages
Define your own custom message
Each message must have a unique id. The constant
is defined (in the Messages unit) as the first message number available
for application use.
WM_MY_MESSAGE = WM_USER + 0;
WM_ANO_MESSAGE = WM_USER + 1;
These messages should be defined in the interface section of the unit
containing the form that will be handling them. Alternately, to guarantee
that all messages are unique within an application consider defining all
your messages together in a single unit.
WM_USER is fine for internal application messages.
WM_APP for messages between applications.
- Use the
RegisterMessage API call if you need a message
number that is guaranteed to be unique in a system.
Define a handler for the message
To add a message handler to a form, define a procedure that takes an
argument of type
TMessage and add the directive "
with the message id that the procedure is to handle.
TMyForm = class(TForm)
procedure OnMyMessage(var Msg: TMessage); message WM_MY_MESSAGE;
procedure OnAnoMessage(var Msg: TMessage); message WM_ANO_MESSAGE;
Send the message
To send a message use either:
PostMessage(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam:
SendMessage(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam:
both of which are defined in the Windows unit. Both of these will append
the message to the end of the application's Windows message queue. The difference
between them is that
SendMessage will not return until the
message has been handled, whereas
PostMessage will return straight
For example, for a form to send itself one of the messages defined above:
Pass data via messages
The additional parameters
provide a mechanism to pass some additional information along with the message.
Both of these parameters are defined as type
Integer. At the
recipient end the values can be extracted from the message by simply referencing
LParam members of
Note: The technique described here is suited for sending data from a
thread to the main process (or form) of the application.
lParam members are ideally suited
for passing integer data, but can also be used to pass objects, for example:
and at the recipient end:
procedure TMyForm.OnAnoMessage(var Msg: TMessage);
myObject := TMyClass(msg.WParam);
The things to be aware of if you use this approach:
- It can only be used if you are sending messages within the same
process - because memory in the sending process cannot be accessed by
- If you do send messages within the same process (and are using
SendMessage) then only use the technique to send messages
from a separate Thread.
- You must ensure that the pointer being sent is still valid when
it is used by the recipient. A simple approach is to use
PostMessage. Consider if you use
and then free the object being sent, the recipient may pick up the reference
to the object after it has been freed - at best this will be a source
of difficult to find bugs, at worst it may crash your program.
These notes are believed to be correct for Delphi 6 and
Delphi 7 running under Microsoft Windows.
About the author: Brian Cryer
is a dedicated software developer and webmaster. For his day job he
develops websites and desktop applications as well as providing
IT services. He moonlights as a technical author and consultant.