I have dialog created using CreateDialogParam
. It has only a single ListView
child control. In the dialog WM_INITDIALOG
message handler, I subclass the ListView
to customize header redrawing.
Now I want to prevent the user from resizing the ListView
column (header) and, to do this, I just need to handle the HDN_BEGINTRACKA
notification message in the ListView
's WndProc
, like below:
case WM_NOTIFY:
{
if ((((LPNMHDR)lParam)->code == HDN_BEGINTRACKA)
|| (((LPNMHDR)lParam)->code == HDN_BEGINTRACKW))
return TRUE; // to disable column resizing
}
This works OK; but, for some reason I want to handle this message in the parent (dialog) procedure. So, I forward this message to that parent as below:
case WM_NOTIFY:
{
if ((((LPNMHDR)lParam)->code == HDN_BEGINTRACKA)
|| (((LPNMHDR)lParam)->code == HDN_BEGINTRACKW))
{
BOOL b = FALSE;
HWND hParent = GetRealParent(hwnd);
if (hParent) b = SendMessage(hParent, msg, wParam, lParam);
return b; // to disable column resizing return TRUE;
}
}
break;
The message is sent OK but, even though I return TRUE
from the dialog procedure, here in the ListView
procedure, the return value of the SendMessage
call is FALSE
.
In the dialog procedure, the code is as below:
case WM_NOTIFY:
{
if ((((LPNMHDR)lParam)->code == HDN_BEGINTRACKA)
|| (((LPNMHDR)lParam)->code == HDN_BEGINTRACKW))
return TRUE;
}
So, my question is why directly sending (forwarding) the WM_NOTIFY
message to the parent returns a different result, or simply just doesn't work?
Edit :-
In the past, I have faced the same problem; to solve it, I tried a user-defined message, like:
#define UWM_WM_NOTIFY (WM_APP 7)
and use that with SendMessage
to communicate between child and parent, or between any other dialogs. But it also fails to get proper return values.
So, I am using SendMessage
as follow:
BOOL b = FALSE;
SendMessageA(hDlg, UWM_ANY_WM, 0, (LPARAM) &b);
return b;
Sending address of variable as LPARAM
to get return value. Is there any better way to do this. Or Why SendMessageA
return value is different?
CodePudding user response:
From the Microsoft documentation for the WM_NOTIFY
message1:
If the message handler is in a dialog box procedure, you must use the
SetWindowLong
function withDWL_MSGRESULT
to set a return value.
So, using the more up-to-date SetWindowLongPtr
function, your parent (dialog box) handling for the WM_NOTIFY
message should look something like this:
case WM_NOTIFY:
{
if ((((LPNMHDR)lParam)->code == HDN_BEGINTRACKA)
|| (((LPNMHDR)lParam)->code == HDN_BEGINTRACKW))
{
SetWindowLongPtr(hWnd, DWL_MSGRESULT, TRUE); // hWnd is dialog's HWND
return TRUE;
}
}
Also note that your handler should continue to return TRUE
, as noted in this document:
If you use
SetWindowLong
with theDWL_MSGRESULT
index to set the return value for a message processed by a dialog procedure, you should returnTRUE
directly afterward. Otherwise, if you call any function that results in your dialog procedure receiving a window message, the nested window message could overwrite the return value you set usingDWL_MSGRESULT
.
1 Actually, you need to use the outlined mechanism to set the return value for (almost) any message handled by a dialog procedure, as nicely described in this blog by Raymond Chen.