News | Articles | Libraries | Developer Tools | Books | Forum Links | Search   
Sections:
 

QA: Why ON_UPDATE_COMMAND_UI handlers get called again and again?

By Alexander Shargin, June 18, 2002.
Print version

Question

I added some ON_UPDATE_COMMAND_UI handlers in order to update buttons on my menubar. I noticed that my handlers are called again and again all the time even if I do nothing with my program. This happens on 2002 devices but not on 2000 devices. Why is this happening and how can I fix this?

Answer

Background

MFC updates all command bars in idle time. This mechanism works like this. While there are messages in the mesage queue, MFC performs standard GetMessage/DispatchMessage stuff to deliver messages to appropriate handlers. But when the last message is processed and message queue is exhaused, MFC performs some idle work before blocking on GetMessage until next message arrives. This work is performed in CWinThread::OnIdle method. This method is important for correct MFC operation. Thus, all temporary objects created by MFC methods are destroyed here. Also, OnIdle message sends WM_IDLEUPDATECMDUI message to the main window and its descendants (including menubar) to make them update themselves.

Not all messages should cause idle processing to occur. For example, WM_PAINT message alone should not cause it since a well-written WM_PAINT handler never changes program state. To check if the message should trigger idle processing or not, MFC uses CWinThread::IsIdleMessage method:

// reset "no idle" state after pumping "normal" message if (AfxGetThread()->IsIdleMessage(pMsg)) { bIdle = TRUE; lIdleCount = 0; }

Default implementation filters out WM_PAINT message, redundant WM_MOUSEMOVE messages and system timer message used for caret blinking.

Problem

Now to the interesting part. On Pocket PC 2002 there is an undocumented message 0x3FC which gets posted to all threads whenever any other message is processed by the app. This message is not supposed to be handled in any particular way and the apps just ignore it. But here is the problem: IsIdleMessage doesn't know about it and so this message triggers idle processing! So here is what's happening. When you update your menubar this causes WM_PAINT to come. WM_PAINT is followed by 0x3FC message. This message causes idle processing to begin once again, menu bar gets updated one more time etc. This process never stops. Of course, on Pocket PC 2000 devices everything works fine since there is no 0x3FC message there.

Solution

With MFC you often miss a virtual function to override when you need it most. Fortunately, this is not the case with IsIdleMessage: this method is virtual and you can easily override it in your CWinApp-derived class. Here is how to do this to filter out 0x3FC message:

virtual BOOL IsIdleMessage(MSG* pMsg) { if(CWinApp::IsIdleMessage(pMsg) == FALSE) return FALSE; return (pMsg->message != 0x3FC); }

Add this handler to your application class and the problem will be solved.

Related resources:

Discuss

Discuss this article. Here you can write your comments and read comments of other developers.
Rate this article:     Poor Excellent    
 12345 
© 2001-2005 Pocket PC Developer Network, a division of Spb Software House