Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

About the Windows Message Queue

0.00/5 (No votes)
17 Apr 2002 4  
This article is written for the Win32 API programmers on the subject of Windows message queues.

Sample Image - queue.gif

Introduction

Everybody knows MFC as the most powerful instrument for developing applications on the Windows system. Its classes are specialized on the entire family of difficult tasks you can imagine and the flexibility of the chosen solutions is remarkable. It's the best approach on developing large software and keeps the programmer away from several kind of detail problems. This should be the greatest advantage when having to deal with a window-based system but...

The Thread

We're not talking about a window-based system here. "The atomic working entity of a program is the thread", says the MSDN book. Among many background details like  stack and paths of execution, it also has to cover the implementation of a message queue. It's not a rule but you will find it on every thread that sustains a window. This is the reason for a very popular confusion: the window has a message queue. Wrong! The message queue belongs to the thread and the messages posted to the window are dispatched to it by the message loop in the thread. I will illustrate this by the program attached to this article.

The Program

Is a console based application; the modeless dialog manages its messages through the console's message queue, so it's not about having two queues at a time. The code offers you a class and the main function.

CConsoleQueue

This class implements the message loop and a primitive system of handling messages. It has the following methods:

RunQueue - runs the classical message loop

  while (GetMessage(&msg, NULL, 0, 0))    // extract the message 

                                          // from the queue

  {
    if (fctMan=(*this)[msg.message])
      fctMan((void *)msg.wParam);
    else
    {
      TranslateMessage(&msg); // necessary to listen the keyboard

      DispatchMessage(&msg);  // message goes to the default 

                              // procedure

    }
  }

EndQueue - terminates the message loop by posting WM_QUIT

  PostMessage(NULL, WM_QUIT, 0, 0);     // message to interrupt

                                        // the loop by returning

                                        // FALSE on GetMessage

RegisterMessageHandler - registers a handler function to a particular message. When the message is received in the message loop, the handler is called. To pass a value for the handle, you should put it through the WPARAM when calling PostMessage.

Note: this could be considered as a skeleton of the reactor concept proposed by The Adaptive Communication Environment (ACE).

RemoveAll - removes all the associations (from the reactor)

main

The purposes of this function are - step by step - the following:

1. Creating a modeless dialog box used to send messages to the queue:

  hWndDialog=CreateDialog(NULL, MAKEINTRESOURCE(IDD_DIALOG_TEST),
    NULL, DialogProcedure); 
  ShowWindow(hWndDialog, SW_SHOW); 

2. Setting a timer on the thread:

  nTimer=SetTimer(NULL, 0, nDelay*1000, TimerProcedure);

3. Registering a handler for an user-defined message:

  queue.RegisterMessageHandler(WM_USER_DEFINED, UserDefined);

4. Running the queue:

  queue.RunQueue();

Behavior

The purpose is to drop WM_TIMER messages in the message queue; each WM_TIMER will print to console a global buffer. If the buffer doesn't modify for the last nKeepQueueSteps WM_TIMERs, the last one will kill the timer and will end the message queue. Modifying the buffer is done in the modeless dialog box by writing in the edit box and pressing "send buffer". Pressing "send user-defined" will post the WM_USER_DEFINED message to the queue.

Final

Observe that calling PostMessage with NULL for the first parameter will drop the message in the current thread's message queue.

Another observation is about setting the timer. This one lives only among the queue's events and is not a window's resource. It belongs to the thread and could reach a window only if is set to and only by a call of DispatchMessage.

The last word is about the message loop. This expression is a source of limitation for the programmer. In fact you could have more message loops in a single thread's execution. To test this, simply multiply the actual content of main in the function's body like this:

  hWndDialog=CreateDialog(NULL, MAKEINTRESOURCE(IDD_DIALOG_TEST), 
    NULL, DialogProcedure); 
  // ...

  cout<<endl<<"program ends here..."<<endl;
  
  hWndDialog=CreateDialog(NULL, MAKEINTRESOURCE(IDD_DIALOG_TEST), 
    NULL, DialogProcedure); 
  // ...

  cout<<endl<<"program ends here..."<<endl;
  
  // ...  

  
  hWndDialog=CreateDialog(NULL, MAKEINTRESOURCE(IDD_DIALOG_TEST), 
    NULL, DialogProcedure); 
  // ...

  cout<<endl<<"program ends here..."<<endl;

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here