Search code examples
c++winapi

Message handling for a dialog


When using a dialog as a main form, what is the bare minimum of checks prior to having the TranslateMessage and DispatchMessage? In a code:

MSG msg;
BOOL ret;

hwndDialog = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), nullptr, (DLGPROC)DialogProc);
ShowWindow(hwndDialog, SW_SHOW);

while ((ret = GetMessage(&msg, 0, 0, 0)) != 0) {
    if (ret == -1) {
        return -1;
    }
    if (!IsWindow(hwndDialog) || !IsDialogMessage(hwndDialog, &msg)) { // are all these checks needed?
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}
return 0;

Are !IsWindow(hwndDialog) and !IsDialogMessage(hwndDialog, &msg) conditions needed and would a simple: if (hwndDialog== (HWND) NULL) suffice for a modeless dialog?


Solution

  • The code in question seems to be based on Creating a Modeless Dialog Box. The scenario serving as the motivation for the example described in the documentation is different from what this question is about: It assumes a GUI that dynamically creates and destroys a modeless dialog.

    The dynamic nature of this modeless dialog informed (part of) the design of the message loop showcased in the sample. The call to IsWindow() specifically serves as a convenience to support a single message loop body that operates reliably regardless of whether the modeless dialog is live.

    Since the question is about an application where the lifetime of the (modeless) dialog and the application coincide the IsWindow() check can safely be dropped.

    IsDialogMessage(), however, is a different beast altogether. Despite its similarity in naming it doesn't just verify a property of a message. The documentation describes its effect as:

    Determines whether a message is intended for the specified dialog box and, if it is, processes the message.

    The part in bold (rather than its return value) is the primary reason we call this API. "Processes the message" is a cryptic way of saying: "Implements the dialog's keyboard interface". Omitting the call to IsDialogMessage() on a thread's message loop that owns a modeless dialog renders that dialog dead to keyboard navigation.

    In a similar vein, the return value of IsDialogMessage() is more meaningful than the "uh huh, good to know" of IsWindow()'s response. Its prescriptions are spelled out in the fine print:

    Because the IsDialogMessage function performs all necessary translating and dispatching of messages, a message processed by IsDialogMessage must not be passed to the TranslateMessage or DispatchMessage function.

    The return value is documented as:

    If the message has been processed, the return value is nonzero.

    In summary, while

    if (!IsWindow(hwndDialog) || !IsDialogMessage(hwndDialog, &msg))
    

    appears to be evaluating two conditions, either side of the ||-operator does vastly different things.


    With the groundwork covered let's address the question asked:

    When using a dialog as a main form, what is the bare minimum [required]?

    If that is the goal things are far simpler: Use a modal dialog and have the system deal with the intricacies of implementing message translation and dispatching. DialogBoxW() does everything for you already: It creates the dialog, displays it, and runs a message loop.

    The only change you'll need to make to your DlgProc is calling EndDialog() (instead of DestroyWindow()) from your WM_CLOSE message handler to exit the message loop the system spun up.