Sujay Ghosh
Sujay Ghosh

Reputation: 2868

Understanding SendMessage wparam

I am working on an MFC project, which has the following code:

NMHDR pNMHDR;
pNMHDR.hwndFrom = GetSafeHwnd();
pNMHDR.idFrom = GetDlgCtrlID();
pNMHDR.code = EN_CHANGE;
GetParent()->SendMessage(WM_NOTIFY, (EN_CHANGE << 16) | GetDlgCtrlID(), ( LPARAM ) &pNMHDR);

Please help me in understanding what (EN_CHANGE << 16) | GetDlgCtrlID() does.

Upvotes: 1

Views: 468

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 595702

Per the EN_CHANGE documentation for standard EDIT controls:

wParam

The LOWORD contains the identifier of the edit control. The HIWORD specifies the notification code.

So, the code is taking the constant EN_CHANGE, shifting its bits to the left 16 places, and then OR'ing the bits of the control ID. Thus, EN_CHANGE ends up in bits 16-31, and the control ID ends up in bits 0-15:

                              WPARAM
-----------------------------------------------------------------
|            EN_CHANGE          |             CtrlID            |
-----------------------------------------------------------------
 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0  

However, the code should be using the MAKEWPARAM() macro instead of shifting + OR'ing bits manually, eg:

GetParent()->SendMessage(WM_NOTIFY, MAKEWPARAM(GetDlgCtrlID(), EN_CHANGE), (LPARAM) &pNMHDR);

Now, that being said, a standard EDIT control sends EN_CHANGE via WM_COMMAND, not WM_NOTIFY. But a standard windowless RICHEDIT control sends EN_CHANGE via WM_NOTIFY, which carries only the control ID by itself in the wParam parameter. The command ID is carried in the NMHDR struct pointed at by the lParam parameter (except, RICHEDIT uses the CHANGENOTIFY struct, which is unrelated to NMHDR).

So, this code's use of EN_CHANGE is clearly non-standard usage, using a customized parameter scheme.

Upvotes: 4

Related Questions