Win32 Message Processing Primer

A Tutorial on the Differences Between Getmessage and Peekmessage

© Guy Lecky-Thompson

May 11, 2007
A message processing tutorial article for Win32 programmers illustrating the difference between GetMessage and PeekMessage inside and outside the message processing loop

Introduction

In this GetMessage vs. PeekMessage tutorial we look at the difference between the two function calls, and how they can be used practically when writing Win32 applications. The tutorial is language independent, but we have used C calling conventions for illustration purposes. Please refer to your compiler / development kit documentation for details on how to interface with the Windows library routines supplied with your development environment.

The Message Loop

The Windows message loop is part of the WinMain function called when the application starts up. Its job is to:

  • Retrieve messages from the queue;
  • Send messages to the WndProc.

The loop itself looks something like:

while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}

The TranslateMessage and DispatchMessage functions process the incoming message, in the first instance translating any accelerators, and in the second passing the message to the message processing function specified in the WNDCLASS member lpfnWndProc. This is usually set to the WndProc function.

GetMessage

The GetMessage function returns nonzero as long as the WM_QUIT message is not retrieved from the message queue. Hence, it can be tested as in the message processing loop and provide an exit from the loop before the WM_QUIT message is processed. Subsequently, if there is any processing that needs to be done upon program exit, it must be done before the WM_QUIT message is placed on the queue.

GetMessage also takes four parameters:

  • lpMsg - a pointer to the message;
  • hWnd - the handle to the window (or NULL for the thread owner);
  • wMsgFilterMin & wMsgFilterMax - the first/last messages to be retrieved.

The filtering system allows the programmer to use pre-defined constants such as WM_MOUSEFIRST and WM_MOUSELAST to retrieve only (in this instance) mouse messages. These are not much help in the message loop, however.

Since GetMessage removes messages from the queue, it is usually only ever found in the message loop. It does not remove WM_PAINT messages, however, which remain in the queue until they are processed. All other messages are removed, whether they are processed or not.

By way of contrast, let us look at the PeekMessage function.

PeekMessage

The PeekMessage function allows the program to look at the message queue, retrieve messages, but not necessarily remove them. It returns zero if there are no messages on the queue, or nonzero if messages are available. PeekMessage takes 5 parameters:

  • lpMsg - a pointer to the message;
  • hWnd - the handle to the window (or NULL for the thread owner);
  • wMsgFilterMin & wMsgFilterMax - the first/last messages to be retrieved;
  • wRemoveMessage - a flag for message removal.

The additional parameter can be set to PM_REMOVE or PM_NOREMOVE to indicate whether a message should be removed or not. Subsequently, we could re-write the message loop using PeekMessage as follows:

do
{
if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
} while (msg.message != WM_QUIT);

This approach is presented here by way of illustration, and is not recommended. Like GetMessage, PeekMessage will not remove a WM_PAINT message from the queue, even if instructed to do so. Unlike GetMessage, there is an exception - if the update area is null, then PeekMessage will remove the WM_PAINT message if PM_REMOVE is specified.

Outside the Message Loop

If a programmer needs access to the message queue outside of the message loop, then they should only ever use PeekMessage, and be very careful about removing messages from the queue. The key difference between Windows pre-Win32 and Win32 programming is that since software applications run concurrently in Win32, there should be no need to look into the message queue at all.

This is illustrated by the WinWord.exe application, which used to use a PeekMessage loop to wait for incoming messages rather than an idle loop (message loop). This method consumes 100% of the CPU resources allocated to it, as it is caught in a busy-waiting loop; PeekMessage returns zero until a message is available. Pre-Win32 this could cause the machine to hang, were it not for the fact that the PM_YIELD flag was set in the wRemoveMessage paremeter (PM_REMOVE|PM_YIELD).

With the advent of Win32 however, PM_YIELD becomes obsolete as all applications run concurrently. However, older versions of WinWord may use 100% of their time slice, due to the fact the the PM_YIELD flag is no longer recognised. This is the risk of using PeekMessage outside the message loop.

Links


The copyright of the article Win32 Message Processing Primer in Windows Programming is owned by Guy Lecky-Thompson. Permission to republish Win32 Message Processing Primer in print or online must be granted by the author in writing.




Post this Article to facebook Add this Article to del.icio.us! Digg this Article furl this Article Add this Article to Reddit Add this Article to Technorati Add this Article to Newsvine Add this Article to Windows Live Add this Article to Yahoo Add this Article to StumbleUpon Add this Article to BlinkLists Add this Article to Spurl Add this Article to Google Add this Article to Ask Add this Article to Squidoo

Post Your Comment
NOTE: Because you are not a Suite101 member, your comment will be moderated before it is viewable.
What is 9+8? Incorrect, please resolve x + y!