0

My dialog procedure:

INT_PTR CALLBACK DlgProc(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
    INT_PTR result = TRUE;
    switch(iMessage)
    {
    case WM_NOTIFY:

        switch (((LPNMHDR)lParam)->idFrom)
        {
            case ID_xxx:
                // process notify from control ID_xxx
                break;
            case ID_yyy:
                // process notify from control ID_yyy
                break;
            default:
                result = FALSE;
        }
        default:
        result = FALSE;
    }
    return result;
}

In case the notification is from a control that I don't use, or suppose I am not interested in the LVN_ITEMCHANGED notification of a particular listcontrol, I would set result to FALSE, causing the default windows procedure to be called.

Do I always have to do this? Is it a problem if I don't?

Bart
  • 547
  • 3
  • 16
  • 1
    simply return 0 (false). - *If the dialog box procedure returns FALSE, the dialog manager performs the default dialog operation in response to the message.* – RbMm Jan 04 '18 at 10:24
  • you must not process all messages from all controls. if some message not processed - this is not a problem. process any control notification is optional – RbMm Jan 04 '18 at 10:28
  • You are missing a `break` after `switch (((LPNMHDR)lParam)->idFrom){ }`. Because of this, the `default` branch will always be entered so you always return `FALSE` from `DlgProc`. Also you can simplify the code by getting rid of the `result` variable. Replace `return result` with `return FALSE`. Put `return TRUE` in a `case` branch when you don't want the default processing. – zett42 Jan 04 '18 at 12:12

2 Answers2

1

In case of notification messages, whether you return TRUE or FALSE from the DlgProc normally doesn't matter. These messages are sent to notify the parent about something that happens in a child. The default window procedure of the parent does not know what to do in response to something that happens in a child, so even when you return FALSE from DlgProc it will do nothing.

Anyway I would return TRUE for notifications that I handled to make immediately clear for any reader of my code that I handled the message completely on my own and don't need any default processing.

So I would write DlgProc like this:

INT_PTR CALLBACK DlgProc(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
    switch(iMessage)
    {
        case WM_NOTIFY:
            switch (((LPNMHDR)lParam)->idFrom)
            {
                case ID_xxx:
                    // process notify from control ID_xxx
                    return TRUE;
                case ID_yyy:
                    // process notify from control ID_yyy
                    return TRUE;
            }
            break;
    }

    // We are not interested in the message. Let dialog manager do any default processing.
    return FALSE; 
}

By getting rid of the result variable and returning early from the case branches, the code is simplified and becomes easier to read and maintain. When trying to figure out what a particular case branch does, I no longer have to trace in my mind the state of the result variable down to the final return statement. When I see a return statement in a case branch I can just skip over reading the remaining part of the code.

zett42
  • 25,437
  • 3
  • 35
  • 72
0

Per the WM_NOTIFY documentation:

The return value is ignored except for notification messages that specify otherwise.

So, return whatever value you want, except for specific notifications that actually define a return value.

For instance, the LVN_ITEMCHANGED documentation states:

No return value.

However, the DialogProc documentation states:

Return value

Type: INT_PTR

Typically, the dialog box procedure should return TRUE if it processed the message, and FALSE if it did not. If the dialog box procedure returns FALSE, the dialog manager performs the default dialog operation in response to the message.

If the dialog box procedure processes a message that requires a specific return value, the dialog box procedure should set the desired return value by calling SetWindowLong(hwndDlg, DWL_MSGRESULT, lResult) immediately before returning TRUE. Note that you must call SetWindowLong immediately before returning TRUE; doing so earlier may result in the DWL_MSGRESULT value being overwritten by a nested dialog box message.

The following messages are exceptions to the general rules stated above. Consult the documentation for the specific message for details on the semantics of the return value.

  • WM_CHARTOITEM
  • WM_COMPAREITEM
  • WM_CTLCOLORBTN
  • WM_CTLCOLORDLG
  • WM_CTLCOLOREDIT
  • WM_CTLCOLORLISTBOX
  • WM_CTLCOLORSCROLLBAR
  • WM_CTLCOLORSTATIC
  • WM_INITDIALOG
  • WM_QUERYDRAGICON
  • WM_VKEYTOITEM

So, just return TRUE for any message that you don't want the default message handler to see, and use DWL_MSGRESULT for any message that requires a return value.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770