Click here to Skip to main content
15,891,908 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
Hello to everyone.
I'll try to be as simple as possible.

I created an MFC dialog based application with am unsorted listbox (m_loglist)
I added a timer in the CTimerTestingDlg class. The timer ticks every second.
I also created an int counter with initial value set to 0.
In the OnTimer handler, i add the following code.

C#
void CTimerTestingDlg::OnTimer(UINT_PTR nIDEvent)
{
    // TODO: Add your message handler code here and/or call default
    counter++;

    CString value;
    value.Format(L"%d", counter);

    if (counter==5)
    {
        AfxMessageBox(L"five seconds",MB_OK | MB_SYSTEMMODAL);
        
    }
    m_loglist.AddString(value);

    CDialog::OnTimer(nIDEvent);
}



The output is:
1
2
3
4
(here a message box appears saying "five seconds")
6
7
8
9
5 (I clicked OK so the missing "5" value appears)
10
11
12
..... and so on

Im trying to understand the mechanism that allows this to happen.

The questions are:

1) Since the message box is modal, shouldn't the message pump of MFC be blocked until the response comes? This means, the values of 6 and above shouldnt appear until i press the OK button..

2)Nowhere in the bibliography is mentioned that the AfxMessageBox function call launches a new thread. If we assume that this is the answer to (1), we have an instance of the OnTimer method of the CTimerTestingDlg object left in the middle.(= the one that hasnt typed the value "5" yet due to the message box)
When the timer ticks again, it seems that the OnTimer method of same CTimerTestingDlg object is called again, while the instance above is in the middle! Im i right? if yes, how can this ever be possible?

3) When i click OK, the execution of the OnTimer instance that was left in the middle continues and types the missing "5" value. (after "9" in my example). Where was this OnTimer instance stored? In the stack?

Thank you for your time, im trying to understand what lies beneath here.
Posted

Perfectly understandable and doesn't require magic and/or threads.

The OnTimer() function is an event called upon the receipt of the "WM_TIMER" windows message. This message is dispatched by the MFC provided "message pump". This single WM_TIMER message was removed from the message queue prior to dispatch to OnTimer().

AfxMessageBox() does it's thing and waits for the "OK" button (or whatever) to be clicked. To detect the click, it needs to process windows messages for itself hence it provides it's own "message pump". Even though this message pump is provided by the message box itself, it will process *any* windows message for this application / thread family.

Along comes another "WM_TIMER" message for the next second and is dispatched to the same OnTimer() function.

Generally, when you are processing events, you run the processing to completion before returning to the "dispatch" portion of the message pump so you do not see these artifacts (throw a 10 or 20 second Sleep() in there instead of the message box and you'll see a more predictable sequence). In this case, AfxMessageBox() needed a message pump to complete it's work and you're timer ticks got processed by it.

Judicious use of KillTimer() and SetTimer() should be used if you want to interrupt the flow of ticks for whatever reason.

(Edited to answer another part of your question)

dlavrantonis wrote:
Where was this OnTimer instance stored? In the stack?


Yup, set a breakpoint on the m_loglist.AddString(value); statement *after* the message box appears. You'll get there for some number > 5. When you are there, examine the stack / call frame backwards, you'll eventually find the other call to OnTimer() for number 5. When you click on "OK", all you're doing is returning up through the stack.
 
Share this answer
 
v3
Comments
dlavrantonis 4-Nov-11 6:01am    
amazing! i would have never thought of this! Thank you very much! But a follow up question comes into my mind now:

Since the AfxMessageBox() creates its own message pump, shouldn't it have its own message map as well? I expected that this message map would only contain an entry that maps the "mouse clicking" message (WM_Whatever) to a OnClick handler. Why does it contain an entry that handles the WM_TIMER message as well?

Furthermore, even if we assume that it does contain such an entry, why the OnTimer of the CTimerTestingDlg object is called? I would expect to see the OnTimer implementation of the AfxMessageBox object to be called instead..
Chuck O'Toole 4-Nov-11 10:27am    
We are wandering outside of my comfort zone (and into the zone of magic, which I said we didn't need). But, following the clues in the documentation....

I didn't see your SetTimer() call but, by default, according to the docs at http://msdn.microsoft.com/en-us/library/49313fdf.aspx, "...specifies the address of the application-supplied TimerProc callback function that processes the WM_TIMER messages. If this parameter is NULL, the WM_TIMER messages are placed in the message queue of the application and handled by the CWnd object."

So while AfxMessageBox() has it's own pump, the WM_TIMER is directed at the CWnd object that did the SetTimer(). In fact, there is only one message queue and the messages are identified by the window that will handle them. If you know the window, you know the MESSAGE_MAP that processes it. So none of that requires the implementation of AfxMessageBox() to handle messages other than what it cares about.

It looks like the timer launches a different thread, for each call of the OnTimer function.

 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900