Other people have covered this topic long before (for instance, here and here). I just want to put the information here as well.
MFC has a built-in mechanism for idle-time processing using the overridable OnIdle function of CWinApp. This is suitable for some situations but it does not get called when a modal dialog box is active. This is particularly annoying because there are some techniques which are quite useful for dialog boxes but which require some form of idle-time processing.
However, it turns out that MFC has a "private" message called WM_KICKIDLE which is sent to dialog boxes and does exactly what is necessary here. Technically this is an implementation detail of MFC that probably isn't guaranteed for the future. But in practice, MFC doesn't seem to ever change in ways that would break compatibility. WM_KICKIDLE has been around for a long time and will most likely continue to be.
Of course, since this is a "private" message, Visual Studio's interface doesn't give much help (as it would be normal window messages). To start off, you have to manually add a generic message handler declaration like:
afx_msg LRESULT OnKickIdle(WPARAM, LPARAM);
Next, include afxpriv.h in the cpp file of the dialog.
Then add an entry in the dialog's message map:
And finally, implement the message handler:
LRESULT CYourDialog::OnKickIdle(WPARAM, LPARAM)
// your code here
Note that teturning TRUE from the KickIdle handler will cause another idle message to be generated immediately, just like the behavior of OnIdle. So you would return FALSE when done with the current batch of idle processing.
One important thing to take note of is that you should be very cautious about using UpdateData() to read data from controls into any mapped variables while inside the idle message handler. If one of the dialog's DDX or DDV routines (which are called within UpdateData) causes a message box to be displayed, then as soon as the user dismisses the message box another WM_KICKIDLE message will be generated. At that point, your idle message handler would be called again which would call UpdateData again and the code would end up stuck in a sort of infinite loop, continuously reporting the data problem to the user but never giving them a chance to correct it.