March 27th, 2026
0 reactions

What if a dialog wants to intercept its own message loop?

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_ENTER­IDLE message. Now, maybe it should be careful only to grab WM_ENTER­IDLE 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 &amp:&
        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_ENTER­IDLE, 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_ENTER­IDLE 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_ENTER­IDLE 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.

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

0 comments