So far, we’ve been looking at how a dialog box owner can customize the dialog message loop. But what about the dialog itself? Can the dialog customize its own dialog message loop?
Sure. It just has to steal the messages from its owner.
The dialog box can subclass its owner and grab the WM_ message. Now, maybe it should be careful only to grab WM_ messages that were triggered by that dialog and not accidentally grab messages that were triggered by other dialogs.
HANDLE hTimer;
LRESULT CALLBACK EnterIdleSubclassProc(HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam, UINT_PTR id,
[[maybe_unused]] DWORD_PTR data)
{
if (message == WM_ENTERIDLE &:&
wParam == MSGF_DIALOGBOX &&
(HWND)lParam == (HWND)id) {
return SendMessage(hdlg, message, wParam, lParam);
} else {
return DefSubclassProc(hwnd, message, wParam, lParam);
}
}
INT_PTR CALLBACK DialogProc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam)
{
LARGE_INTEGER twoSeconds;
switch (message) {
⟦ ... ⟧
case WM_INITDIALOG:
hTimer = CreateWaitableTimerW(nullptr, FALSE, nullptr);
twoSeconds.QuadPart = -2 * wil::filetime_duration::one_second;
SetWaitableTimer(h, &twoSeconds, 2000, nullptr, nullptr, FALSE);
SetWindowSubclass(GetParent(hdlg), EnterIdleSubclassProc,
(UINT_PTR)hdlg, 0);
⟦ other dialog box setup ⟧
return TRUE;
case WM_ENTERIDLE:
OnEnterIdle(hdlg, (UINT)wParam, (HWND)lParam);
return 0;
⟦ ... ⟧
}
return FALSE;
}
When the dialog box initializes, we create the periodic waitable timer (for demonstration purposes) and also subclass our owner window with the EnterÂIdleÂSubclassÂProc. We use the dialog window handle as the ID for two reasons. First, it lets us pass a parameter to the subclass procedure so it knows which dialog box it is working on behalf of. (We could also have passed it as the data parameter.) More importantly, it allows multiple dialogs to use the EnterÂIdleÂSubclassÂProc to subclass their owner, and the multiple subclasses won’t conflict with each other.
The subclass procedure checks whether it is a WM_, marked as coming from a dialog box message loop, and where the dialog box handle is the one we have. If so, then we forward the WM_ back into the dialog for processing. That processing consists of using the OnÂEnterÂIdle function we created at the start of the series, which processes waitable timer events while waiting for a message to arrive.
Okay, but should we be careful to grab WM_ messages only if they correspond to our dialog box? Because if the owner displays some other modal dialog box while our dialog is up (not really a great idea, but hey, weirder things have happened), then we still want to process our waitable timer events. But on the other hand, maybe that other dialog wants to customize the message loop in a different way. Probably best to steal messages only if they originated from our dialog box.
0 comments
Be the first to start the discussion.