Home > OS >  Understanding SendMessage wparam
Understanding SendMessage wparam

Time:02-10

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.

CodePudding user response:

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.

  • Related