Win32子窗口消息转发至父窗口时SendMessage返回值异常问题
问题原因分析
核心本质是对话框过程(DialogProc)与普通窗口过程(WndProc)的返回值规则不同
你创建的是对话框窗口,你编写的父窗口消息处理函数是DialogProc而非普通窗口的WndProc,二者返回值逻辑完全不一样:
- 普通窗口的
WndProc返回值会直接作为SendMessage的返回值传递给调用方 - 对话框的
DialogProc返回值仅为BOOL类型,仅用于标识当前消息是否被处理:- 返回
TRUE:当前消息已被处理,不需要系统默认逻辑介入 - 返回
FALSE:当前消息未被处理,交由系统默认对话框逻辑处理 - 如果你处理消息后需要给
SendMessage调用方返回特定值,必须先调用SetWindowLongPtr(hDlg, DWLP_MSGRESULT, 要返回的数值)设置返回结果,再返回TRUE即可。
- 返回
你遇到的返回值不一致问题,就是因为父对话框处理完WM_NOTIFY后只返回了TRUE,没有设置DWLP_MSGRESULT,系统默认会将这类消息的返回值设为0(也就是FALSE),所以ListView侧拿到的返回值不符合预期。之前自定义消息遇到的相同问题也是同一个原因导致的。
修复方案
修改父对话框的WM_NOTIFY处理逻辑即可,不需要调整ListView侧的转发代码:
case WM_NOTIFY: { if ((((LPNMHDR)lParam)->code == HDN_BEGINTRACKA) || (((LPNMHDR)lParam)->code == HDN_BEGINTRACKW)) { // 先设置需要返回给调用方的结果 SetWindowLongPtr(hDlg, DWLP_MSGRESULT, TRUE); // 再返回TRUE表示消息已处理 return TRUE; } // 其他未处理的消息返回FALSE交给系统处理 return FALSE; }
注意代码中的hDlg为当前对话框的句柄,也就是DialogProc的第一个入参。
跨窗口通信返回值的最优方案
分场景选择即可:
- 同进程内同步通信(也就是用
SendMessage发送消息):- 优先按Windows消息的标准规则处理:如果接收方是对话框就用
DWLP_MSGRESULT设置返回值,普通窗口直接返回结果即可,这是最规范的方案。 - 自定义消息场景下,你当前用的传栈变量地址作为
LPARAM、接收方直接修改该变量值的方案也是完全可行的,性能很高,只要注意不要把栈变量地址传给异步的PostMessage即可,SendMessage是同步调用,栈变量生命周期完全覆盖消息处理过程,不会有野指针问题。
- 优先按Windows消息的标准规则处理:如果接收方是对话框就用
- 跨进程通信:可选择
WM_COPYDATA、共享内存、命名管道等方案,你当前的父子窗口同进程场景不需要用到。
内容的提问来源于stack exchange,提问作者Vishal Chavda
相关产品推荐
相关产品推荐

