June 1995, Microsoft System Journal
Paul Dilascia is a free software consultant, expertise is training and software development (C and windows). He is Windows : Writing Reusable Code In C (Addison-Wesley, 1992) author.
Q: My problem is ONIDLE to work in the usual document / view program, but it doesn't seem to be in the dialog-based program. My Capp :: InitInstance calls DLG.Domodal, call a function: Do not call the onIdle's CWnd :: RunmodOop. I think I should do some background processing in WM_EnterIdle, but this message is the parent window sent to the dialog. In this case, the parent window does not exist. please help!
Jim Kallimani
As you can see, the Modal dialog is actually non-modal in MFC4.0. When you call CDialog :: Domodal, MFC does not call :: Dialogbox, like it, but call CreateDialogindirect (after thinking twice) and then disables the parent window and enter its own message loop simulation modal behavior. This is :: Dialogbox's essence work. The advantage of this is the message loop of the MFC has a dialog. It used to be hidden by the Windows API function :: Dialogbox. Such an MFC uses the modality dialog message by usually MFC's message pump CWINTHREAD :: PumpMessage, like other windows. Special, you can overload CWnd :: PretranslateMessage-, for example, the accelerator button for the modal dialog box. The early version of the MFC allows you to implement your own PretranslateMessage for the modal dialog, but is not called by the system, because cdialog :: Domodal executes :: Dialogbox until your dialog message handler calls EndDialog returns. Similarly, use: Dialogbox, using the usual MFC method to perform message processing, because the program control disappears in :: DialogBox until the dialog end is returned.
As an alternative, Windows has its own mechanism, WM_Enteridle, performs message processing in the Modal dialog. After processing one or more messages, Windows sends WM_ EnterIdle to a modal dialog or menu, if there is no message in the message queue. Only the modal dialog sends WM_EnterIdle, and the Non-Modular Dialog is not sent. Because MFC now uses a non-modular dialog, it is actually using the Non-Modular dialog when using the modal dialog, the MFC has to send WM_EnterIdle to imitate the modal dialog - but only when the dialog is It's only to do when the parent window is. JIM encounters trouble because there is no parent window to receive WM_Enteridle. Is your head faint?
If the MFC pumps a modal dialog message via a standard message, why not call CWINAPP :: OnIdle as part of your message processing? The title is CWND :: Runmodalloop calls CWINTHREAD :: PumpMessage But OnIdle appears in CwinThread :: Run. When your application calls the InitInstance function, the MFC calls cwinthread :: run runs your application. CWINTHREAD :: Run's concentrated form looks like this:
// (from thrdcore.cpp) int CWINTHREAD :: Run () {// For idle state processing
Bool bidle = true; long LidleCount = 0; for (;;) {while (Bidle &&! :: peekMessage (...) {// When you call onIdleif (! OnIdle (LidleCount )) // "Non-idle" State Bidle = false;} // Get / Prerequisites / Dispatch Messages / / (Call CWINTHREAD :: PumpMESSAGE)}}
I cut a lot to emphasize how idle processing work. If there is no message waiting, the MFC repeats CWINTHREAD: ONIDLE, passed to a counter parameter per increase. You can use this parameter to distinguish between different types of idle processing priorities. You may format a clock indicating the day time when the idle count is 1. When your OnIdle returns false, the MFC stops calling it and waits until your thread get another message, so the idle cycle starts from the beginning.
The Modal dialog never performs this code because CWnd :: Runmodalloop calls Cwinthread :: PumpMessage in your own message loop. It didn't call Cwinthread :: Run, so never call CwinThread :: OnIdle. The staff of Redmond told me that this is determined by the design. Obviously, call OnIdle is dangerous in the Modal dialog, because many message processing functions establish a temporary CWND object, they are expected to exist in the dialog survival. A part of the default idle processing is to release a temporary handle map. (Translator Note: The temporary CWND object exists on the temporary handle map ..)
(I have to tell you, according to what I see, the entire MFC is used to connect to HWND and CWND, the temporary / permanent handle map mechanism is one of the disasters in the entire architecture, even more bad than their message mapping. Temporary mapping mechanism The problem is constantly appearing in the program - especially in multi-threaded applications, making them difficult to write with MFC.)
In this way, how do you perform messages in a dialog-based application, when the dialog does not have a parent window? Fortunately, it is like a confusing. MFC developers provide a hook: WM_KICKIDLE. Runmodalloop constantly sends this MFC private message. When there is no message in the message queue - just like CWINTHREAD :: Run calls OnIdle. Runmodalloop even provides you with a counter and increments in turn. In fact, WM_KICKIdle is the onIdle alternative to the dialog. (Historical information: Early version of MFC for attributes this modal / non-modular switching and providing WM_KICKIDLE. Obviously it works so good, so that they decided to make all modal dialogs non-modularity.)
To warn you: You may be in the onkickidle function, you want to call your primary application's onIdle function
Lresult CMYDLG :: ONKICKIDLE (WPARAM, LPARAM LCOUNT)
{
Return AFXGetApp () -> OnIdle (LCOUNT);
}
MFC personnel tell me that this is dangerous; because of a temporary mapping issue. Perform your free handling more secure in ONKICKIDLE. If necessary, you can combine shared idle processing into an auxiliary function, call in Capp :: OnIdle and CMYDLG :: OnkickIdle.
When I have issued the problem of idle processing, I found that all programmers know that cdoctemplate and cdocument's OnIdle function! If you want to perform free processing in a document or document template, you only need to overload these functions. Internet: paul dilascia72400.2702@compuserve.com
From the june 1996 Issue of Microsoft Systems Journal.
July 1997, Microsoft System Journal
......
Below I will point out how to make the ON_COMMAND_UPDATE_UI handle to work in the dialog box. In the usual MFC document / view application, MFC uses internal messages WM_IdleUpdatecMDUI to update the menu item, the toolbar button, the status bar and other user interface objects. As part of idle processing, IDleUpdatecmdui broadcasts to all window of all your applications. The toolbar, status bar, and dialog box command processing calls UpdatedialogControls broadcast another command, cn_update_command_ui, all controls on the window. From your programmer's perspective, these messages are invisible. You only need to implement on_update_command_ui to handle your menu items and buttons, then, see? They are changed by magic. (For more information, see me in June 1995 MSJ. "Meandering Through The Maze of Mfc Message and Command Routing") Unfortunately, this wonderful UI update mechanism cannot be used for dialog - at least Not automatic. You must patch yourself. Fortunately it is very simple. You only need to handle WM_KICKIDLE, an MFC private message; send it when the dialog is idle (similar to the onIdle processing). You call UpdatedialogControls. .
Lresult CTabDialog :: ONKICKIDLE (WPARAM WP,
LPARAM LCOUNT)
{
UpdatedialogControls (this, true);
Return 0;
}
CWnd :: UpdateDialogControls Send Magic CN_ Update_Command_ui messages to all dialog controls, the result is that ON_COMMAND_ UPDATE_UI processing is suddenly working in the dialog box.