了解 SendMessage wparam

Understanding SendMessage wparam

我正在开发一个 MFC 项目,它有以下代码:

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

请帮助我理解 (EN_CHANGE << 16) | GetDlgCtrlID() 的作用。

根据标准 EDIT 控件的 EN_CHANGE 文档:

wParam

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

因此,代码采用常量 EN_CHANGE,将其位向左移动 16 位,然后对控件 ID 的位进行“或”运算。因此,EN_CHANGE 以位 16-31 结束,控制 ID 以位 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  

但是,代码 应该 使用 MAKEWPARAM() 宏而不是手动移位 + OR'ing 位,例如:

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

话虽如此,标准的 EDIT 控件通过 WM_COMMAND 而不是 WM_NOTIFY 发送 EN_CHANGE。但是标准的 windowless RICHEDIT 控件通过 WM_NOTIFY 发送 EN_CHANGE,它在 wParam 参数中仅携带控件 ID。命令ID携带在lParam参数指向的NMHDR结构中(除了RICHEDIT使用CHANGENOTIFY结构,与NMHDR无关)。

所以,这段代码对EN_CHANGE的使用显然是non-standard用法,使用自定义的参数方案。