Click here to Skip to main content
15,885,767 members
Articles / Desktop Programming / MFC
Article

About the Windows Message Queue

Rate me:
Please Sign up or sign in to vote.
3.67/5 (5 votes)
17 Apr 20023 min read 171.7K   1.7K   37   26
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_TIMER
s, 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


Written By
Software Developer (Senior)
Europe Europe
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Generalshow desktop Pin
amt_alla7-May-04 0:56
amt_alla7-May-04 0:56 
Generalcontrol client resorces Pin
amt_alla6-May-04 9:30
amt_alla6-May-04 9:30 
GeneralRe: control client resorces Pin
Hans Ruck6-May-04 22:52
Hans Ruck6-May-04 22:52 
GeneralRe: control client resorces Pin
amt_alla7-May-04 1:15
amt_alla7-May-04 1:15 
GeneralRe: control client resorces Pin
Hans Ruck7-May-04 1:33
Hans Ruck7-May-04 1:33 
GeneralPassing strings using Post Message Pin
hedonist23-Apr-04 15:06
hedonist23-Apr-04 15:06 
GeneralRe: Passing strings using Post Message Pin
Garth J Lancaster23-Apr-04 15:36
professionalGarth J Lancaster23-Apr-04 15:36 
GeneralRe: Passing strings using Post Message Pin
hedonist23-Apr-04 19:16
hedonist23-Apr-04 19:16 
GeneralRe: Passing strings using Post Message Pin
Garth J Lancaster24-Apr-04 1:20
professionalGarth J Lancaster24-Apr-04 1:20 
GeneralRe: Passing strings using Post Message Pin
hedonist25-Apr-04 21:44
hedonist25-Apr-04 21:44 
GeneralRe: Passing strings using Post Message Pin
Garth J Lancaster26-Apr-04 0:04
professionalGarth J Lancaster26-Apr-04 0:04 
ok .. I usually use registered messages, so, :-

static UINT UWM_LOG_ERROR = ::RegisterWindowMessage("UWM_LOG_ERROR-{A8FBA1C0-0170-11d6-93D2-00C04F15C09B}");

does the trick here ...

now, assuming my dialog app is CxxDlg, in the header I have :-

CxxDlg.h

class CxxDlg : public CDialog
{
// Construction
public:
CxxDlg(CWnd* pParent = NULL); // standard constructor
~CxxDlg();

...

// Generated message map functions
//{{AFX_MSG(CxxDlg)

afx_msg LRESULT OnLogError(WPARAM, LPARAM);

DECLARE_EVENTSINK_MAP()
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};

(look at the afx_msg... , Ive removed everything not pertinent to this)

and in the cpp :-

CxxDlg.cpp

BEGIN_MESSAGE_MAP(CxxDlg, CDialog)
ON_REGISTERED_MESSAGE(UWM_LOG_ERROR, OnLogError)
...
//{{AFX_MSG_MAP(CLogtest1Dlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
...
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

LRESULT CxxDlg::OnLogError(WPARAM wParam, LPARAM lParam) {
CString * s = (CString *)wParam;
// Could do s->Format(...) here, but in this case its already been done
c_Log.AddString(new TraceError(TraceEvent::None, *s));
delete s;
return 0;
}

(note the ON_REGISTERED_MESSGE in the message map, and the CxxDlg function Ive defined Cxxdlg::OnLogError to process the message - in this case c_Log is in instance of a listbox type control)

the last bit required is to send the message - the next snippet is from a seperate cpp (a page handler from a tabbed dialogue)

CString * strErr1 = new CString;
strErr1->Format("Page 4 : %s(%s) NOT Deleted", strSourceFile, strRnmSrcFile);
AfxGetMainWnd()->PostMessage(UWM_LOG_ERROR, (WPARAM)strErr1, (LPARAM)0);

(where strSourceFile & strRnmSrcFile have been populated appropriately)

so, how does that grab you ???

'G'
ps .. sorry of this isnt formatted well, I'm working remotely at home right now, my screen is a bit off


GeneralRe: Passing strings using Post Message Pin
hedonist26-Apr-04 2:24
hedonist26-Apr-04 2:24 
GeneralRe: Passing strings using Post Message Pin
Garth J Lancaster26-Apr-04 11:53
professionalGarth J Lancaster26-Apr-04 11:53 
GeneralRe: Passing strings using Post Message Pin
hedonist26-Apr-04 19:54
hedonist26-Apr-04 19:54 
GeneralRe: Passing strings using Post Message Pin
Garth J Lancaster26-Apr-04 20:42
professionalGarth J Lancaster26-Apr-04 20:42 
GeneralRe: Passing strings using Post Message Pin
hedonist27-Apr-04 6:01
hedonist27-Apr-04 6:01 
GeneralRe: Passing strings using Post Message Pin
hedonist27-Apr-04 6:06
hedonist27-Apr-04 6:06 
GeneralRe: Passing strings using Post Message Pin
Tom Wright11-Nov-04 10:35
Tom Wright11-Nov-04 10:35 
GeneralRe: Passing strings using Post Message Pin
Garth J Lancaster11-Nov-04 12:05
professionalGarth J Lancaster11-Nov-04 12:05 
GeneralIt isn't working in an other project Pin
TPSC2-Mar-04 21:37
TPSC2-Mar-04 21:37 
GeneralRe: It isn't working in an other project Pin
Hans Ruck2-Mar-04 23:22
Hans Ruck2-Mar-04 23:22 
GeneralRe: It isn't working in an other project Pin
Anonymous3-Mar-04 0:13
Anonymous3-Mar-04 0:13 
GeneralRe: It isn't working in an other project Pin
TPSC3-Mar-04 0:15
TPSC3-Mar-04 0:15 
GeneralRe: It isn't working in an other project Pin
Hans Ruck3-Mar-04 1:02
Hans Ruck3-Mar-04 1:02 
Questionwhy? Pin
Prakash Nadar27-Feb-04 4:06
Prakash Nadar27-Feb-04 4:06 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.