This topic has not yet been rated - Rate this topic

Entering the Message Loop

Once the main window is created and displayed, the WinMain function can begin its primary task, which is to read messages from the application queue and dispatch them to the appropriate window.

The system does not send input directly to an application. Instead, it places all mouse and keyboard input from the user into a message queue, along with messages posted by the system and other applications. The application must read the message queue, retrieve the messages, and dispatch them so that the window procedure can process them.

The Generic application uses the following message loop. Note that bRet is a variable of type BOOL.

   while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0 ) 
   {
      if (bRet == -1)
      {
         // handle the error and possibly exit
      }
      else
      {
         TranslateMessage( &msg );
         DispatchMessage( &msg );
      }
   }

The GetMessage function retrieves a message from the queue. The DispatchMessage function sends each message to the appropriate window procedure. The TranslateMessage function translates virtual-key message into character messages. In Generic, this is necessary to implement menu access keys.

See Also

Source Code

 

 

Build date: 3/25/2010

Did you find this helpful?
(1500 characters remaining)
Community Content Add
Annotations FAQ
Also, non-standard use of BOOL return value is troublesome...
I can understand the reason for keeping it BOOL, officially, because that's the rule: in case the BOOL typedef ever changes to something other than a 32-bit int. But that just isn't going to happen in practice. Since the only specified possible return values are 'zero', 'non-zero' and explicitly -1, it might be less confusing to use int as the return type, or even suggest casting to a larger data type, as in:

...
#include "asssert.h"
...

MSG msg = {0};
for(;;)
{
   assert(sizeof(int) >= sizeof(BOOL)); // int ok to receive return value of GetMessage()
   int res = GetMessage(&msg, 0, 0, 0);
   assert(res != -1); // can't be anything wrong with call to GetMessage()
   if(res == 0)
     break;
  TranslateMessage(&msg);
  DispatchMessage(&msg);
}

return (int)msg.wParam;

*******************************************************************************************************

Or use __int64 and cast return value if you want to be pedantic:

...

begin_message_loop0:
  MSG msg = {0};
  __int64 res = 0;
  assert(sizeof(res) >= sizeof(BOOL)); // pedantically future proof
  while((res = (__int64)GetMessage(&msg, 0, 0, 0)) != 0)
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }

  assert(res != -1); // can't be anything wrong with GetMessage() unless undocumented issue,
  if(res == -1)
  {
    assert(IsValidWritePtr(&msg, sizeof(msg)));
    goto begin_message_loop0; // must be an undocumented OS issue,
                                            //  in which case we almost certainly want to carry on anyway
  }


********************************************************************************************************

Bottom line, the majority of - if not all - applications that run on Windows are not Real Time Systems that fly Jets or control the ABS or Traction Control systems on a car; there is no imperative to always handle failure gracefully. Programs crash sometimes, so don't go overboard with the error checking, except where it is appropriate to do so.
Strict correctness vs. Petzold msg loop
Although the sample above suggests you must check for a -1 return value from GetMessage(), in practice GetMessage() will only fail if you pass invalid parameters to it. For example, if you pass an invalid window handle or an invalid MSG* pointer (pointer to something other than writable memory with sizeof==sizeof(MSG)). Since in most cases your main message loop will call GetMessage() with everything 0 apart from the address of MSG struct, if you are writing a main application loop there really isn't any reason to check for -1 explicitly: just make sure your MSG object is valid. Otherwise you're essentially adding unnecessary code to check for a syntax error.

Bear in mind also that the message loop is what is being executed between messages in any windows application, so if you're checking for -1 with every GetMessage() call, you're introducing an additional comparison and conditional jump into code that is executed very often. So, unless you are passing specific params to GetMessage() and you cannot be certain of their validity, don't bother checking for -1, just make sure your MSG struct is valid.

So, for a main message loop in WinMain(), using <code>MSG msg = {0}; while(GetMessage(&msg, 0, 0, 0)){...}</code> is actually fine because you know all the params are valid, so GetMessage() has no reason to fail. And if it does, the most likely culprit would be corruption of the stack around your MSG object which would almost certainly result in a crash regardless of whether you check the return value for == -1, and is indicitive of a much more serious problem in any case.