One of the pieces of sample code found in the original OLEUI sources is a sort of standard message filter implementation—not the default one, but a more typical sort that shows the sort of thing you can do within MessagePending to process additional input. (This code is cleaned up a little from the actual sources, with some bits omitted to simplify our discussion.)
/*
* Macro checks for WM_LBUTTONDOWN, WM_LBUTTONDBLCLK,
* WM_NCLBUTTONDOWN, WM_NCLBUTTONDBLCLK, WM_KEYDOWN, and WM_SYSKEYDOWN
* through PeekMessage calls with PM_NOREMOVE | PM_NOYIELD.
*/
#define IS_SIGNIFICANT_MSG(lpmsg) [Expansion omitted]
STDMETHODIMP_(DWORD) OleStdMsgFilter_MessagePending(LPMESSAGEFILTER lpThis
, HTASK htaskCallee, DWORD dwTickCount, DWORD dwPendingType)
{
LPOLESTDMESSAGEFILTER this=(LPOLESTDMESSAGEFILTER)lpThis;
DWORD dwReturn=PENDINGMSG_WAITDEFPROCESS;
MSG msg;
BOOL fIsSignificantMsg=IS_SIGNIFICANT_MSG(&msg);
UINT uRet;
if (dwTickCount > 5000 && fIsSignificantMsg
&& !this->m_bUnblocking)
{
this->m_bUnblocking=TRUE;
//Eat messages in our queue that we do NOT want dispatched.
while (PeekMessage(&msg, NULL, WM_CLOSE, WM_CLOSE
, PM_REMOVE | PM_NOYIELD))
;
[Invoke the dialog box with BZ_NOTRESPONDING.]
uRet=OleUIBusy(&bz);
this->m_bUnblocking = TRUE;
return PENDINGMSG_WAITNOPROCESS;
}
if (this->m_bUnblocking)
return PENDINGMSG_WAITDEFPROCESS;
if (this->m_lpfnMessagePendingCallback)
{
MSG msg;
if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE | PM_NOYIELD))
{
if (this->m_lpfnMessagePendingCallback(&msg))
dwReturn=PENDINGMSG_WAITNOPROCESS;
else
dwReturn=PENDINGMSG_WAITDEFPROCESS;
}
}
return dwReturn;
}
This implementation displays the "not responding" version of the busy dialog box if a significant message (mouse click or keystroke) has occurred and we've waited more than 5 seconds (which you may want to make as little as 2 seconds) for a call to complete. Note that the m_fUnblocking flag protects against reentrant calls. Anyway, only significant messages are considered good enough to warrant the dialog box because something like a mouse move shouldn't really be considered input. Before the dialog box appears, this implementation removes any messages that might be in the queue and that it doesn't want dispatched from the message loop within the Windows DialogBox function (called from OleUIBusy). In this case, the implementation removes WM_CLOSE to prevent the client from disappearing when it's inside this busy state. Not a bad idea!
What happens before the waiting period is over is most interesting. As described earlier in this chapter, you should try to process or cache an end user's pending work (keystrokes and mouse clicks) while waiting for a call to be completed. The preceding code calls an application-supplied hook (a callback) to process the next message in the queue. The hook returns, indicating (by a TRUE or a FALSE) whether the message was processed. If it was processed, the return value from MessagePending tells COM to discard the message; otherwise, COM performs its default action with it.
For your own implementation, you can take this basic code and replace the callback material with whatever message processing you want.