Understanding the Message Loop
Understanding the message loop and entire message sending structure of windows
programs is essential in order to write anything but the most trivial programs.
Now that we've tried out message handling a little, we should look a little deeper
into the whole process, as things can get very confusing later on if you don't
understand why things happen the way they do.
What is a Message?
A message is an integer value. If you look up in your Win32 definition files (which is
good and common practice when investigating the workings of API's), e.g. the WINUSER.DEF file,
you can find things like:
WM_INITDIALOG = 0110H;
WM_COMMAND = 0111H;
WM_LBUTTONDOWN = 0201H;
...and so on. Messages are used to communicate pretty much everything in
windows at least on basic levels. If you want a window or control (which is
just a specialized window) to do something you send it a message. If another
window wants you to do something it sends you a message. If an event happens
such as the user typing on the keyboard, moving the mouse, clicking a button,
then messages are sent by the system to the windows affected. If you are
one of those windows, you handle the message and act accordingly.
Each windows message may have up to two parameters,
wParam was 16 bit and
lParam was 32 bit, but in Win32 they are
both 32 bit. Not every message uses these parameters, and each message uses
them differently. For example the
WM_CLOSE message doesn't use either, and
you should ignore them both. The
WM_COMMAND message uses both,
HIWORD(wParam) is the notification message (if applicable)
LOWORD(wParam) is the control or menu id that sent the message.
HWND (window handle) to the control which sent the message or
the messages isn't from a control.
LOWORD() are macros defined by windows (WINUSER.DEF) that single
out the two high bytes (High Word) of a 32 bit value (
FFFF0000H) and the low word
0000FFFFH) respectively. In Win32 a
WORD is a 16bit value, making
DWORD (or Double Word) a 32bit value.
To send a message you can use
PostMessage() puts the message into the Message Queue and returns immediatly.
That means once the call to
PostMessage() is done the message may or may not have been
SendMessage() sends the message directly to the window and
does not return untill the window has finished processing it. If we wanted
to close a window we could send it a
WM_CLOSE message like this
PostMessage(hwnd, WM_CLOSE, 0, 0); which would
have the same effect as clicking on the
button on the top of the window.
lParam are both
0. This is because, as mentioned,
they aren't used for
Once you begin to use dialog boxes, you will need to send messages to the controls in order
to communicate with them. You can do this either by using
to get the handle to the control using the ID and then use
you can use
SendDlgItemMessage() which combines the steps. You give it a window
handle and a child ID and it will get the child handle, and then send it the message.
SendDlgItemMessage() and similar APIs like
work on all windows, not just dialog boxes.
What is the Message Queue
Lets say you were busy handling the
WM_PAINT message and suddenly the user types
a bunch of stuff on the keyboard. What should happen? Should you be interrupted
in your drawing to handle the keys or should the keys just be discarded?
Wrong! Obviously neither of these options is reasonable, so we have the message
queue, when messages are posted they are added to the message queue and when
you handle them they are removed. This ensure that you aren't going to miss
messages, if you are handling one, the others will be queued up untill you get to
What is a Message Loop
WHILE GetMessage( Msg, NIL, 0, 0) DO
- The message loop calls
GetMessage(), which looks in your message queue. If the
message queue is empty your program waits for one.
- When an event occurs causing a message to be added to the queue (for example the system
registers a mouse click)
GetMessages() returns TRUE indicating there is a message
to be processed, and that it has filled in the members of the
MSG structure we passed it.
FALSE if it hits
WM_QUIT, and a negative value if an error occured.
- We take the message (in the
and pass it to
TranslateMessage(), this does a bit of additional processing,
translating virtual key messages into character messages. This step may seem optional, but
certain things won't work if it's not there.
- Once that's done we pass the message to
DispatchMessage() does is take
the message, checks which window it is for and then looks up the Window
Procedure for the window. It then calls that procedure, sending as parameters
the handle of the window, the message, and
- In your window procedure you check the message and it's parameters, and do whatever you
want with them! If you aren't handling the specific message, you almost always call
which will perform the default actions for you (which often means it does nothing).
- Once you have finished processing the message, your windows procedure returns,
returns, and we go back to the beginning of the loop.
This is a very important concept for windows programs. Your window procedure is not magically
called by the system, in effect you call it yourself indirectly by calling
As you can see, your application spends the majority of it's time spinning round and round
in this message loop, where you joyfully send out messages to the happy windows that will
process them. But what do you do when you want your program to exit? Since we're using
WHILE loop, if
GetMessage() were to return
the loop would end and we would reach the end of our program.
This is exactly what
PostQuitMessage() accomplishes. It places a
message into the queue, and instead of returning a positive value,
in the Msg structure and returns
FALSE, thus terminating the program.
Note that we never call our WndProc procedure directly.
If we want our application window to process a specific command, or perform an action,
we instruct our window to do so by sending it a message, using
I hope you now have a better understanding of the windows message loop, if not, do not fear,
things will make more sense once you have been using them for a while.
Copyright © 1998-2011, Brook Miles. All rights reserved. Adapted for Modula-2 by Frank Schoonjans, with permission.