chHANDLE_DLGMSG(windows核心编程)讲解

简介: 看完《Windows程序设计》后开始看《windows核心编程》, 结果看第一个案例的时候就很惊人的发现,Jeffery大牛的代码很深奥。乍一看好像没有包含《windows.h》。

看完《Windows程序设计》后开始看《windows核心编程》,

结果看第一个案例的时候就很惊人的发现,Jeffery大牛的代码很深奥。乍一看好像没有包含《windows.h》。

看看包含的头文件发现,CmnHdr.h中已经包含了《windows.h》。而CmnHdr.h中的代码更吓人,如果没有讲解,不知道怎么看才好。后来才知道原来书的最后有专门的搭建环境的介绍,基本上全面的讲解了CmnHdr.h的东西。

 

CmnHdr.h中包含了大牛的很多自己的东西。在看到chHANDLE_DLGMSG这个宏的时候,才知道有消息分流器这么个东西。后来到处查找信息,才发现很多以前不知道的东西。具体的消息分流器我不介绍,只是想屡一下大牛写chHANDLE_DLGMSG的动机。书中介绍很简短,只是说HANDLE_MSG对处理消息对话框过程不能返回TRUE或FALSE来告诉对话框过程我们到底有没有处理消息。为什么HANDLE_MSG不能正确返回呢?

 

原因在于HANDLE_MSG只是针对HANDLE_##message的简单封转。##message是指将HANDLE与具体的消息连接起来,而且是消息的宏定义方式(如WM_INITDIALOG而不是0x0110)。例如:

HANDLE_##WM_INITDIALOG就得到HANDLE_WM_INITDIALOG,但你可不能把WM_INITDIALOG的具体的数字写进去。

 

HANDLE_MSG宏定义如下:

 

#define HANDLE_MSG(hwnd, message, fn)    /
    case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn))

 

可以看到只是加上case和return语句。所以HANDLE_MSG只是考虑到了形式上正确,却无法应对所有的消息处理的返回值。HANDLE_MSG的消息返回完全靠HANDLE_##message的宏处理。

 

假如:HANDLE_##message的message是WM_INITDIALOG,那么HANDLE_##message就是HANDLE_WM_INITIDALOG。

 

HANDLE_WM_INITDIALOG宏定义如下:

 

#define HANDLE_WM_INITDIALOG(hwnd, wParam, lParam, fn) /
    (LRESULT)(DWORD)(UINT)(BOOL)(fn)((hwnd), (HWND)(wParam), lParam)

 

可以看到如果在消息对话框过程中使用HANDLE_MSG(hwnd,WM_INITDIALOG,Dlg_InitDialog);是没有问题的。是啊,我只说了对WM_INITDIALOG没有问题,windows里面那么多消息,其他消息就很有问题。看WM_COMMAND消息吧!

 

HANDLE_WM_COMMAND宏定义如下:

 

#define HANDLE_WM_COMMAND(hwnd, wParam, lParam, fn) /
    ((fn)((hwnd), (int)(LOWORD(wParam)), (HWND)(lParam), (UINT)HIWORD(wParam)), 0L)

 

可以看出HANDLE_WM_COMMAND根本没有返回值,因为fn的形式根本有没指明返回值。没有返回值那为什么HANDLE_MSG要返回呢?

这就是HANDLE_MSG的问题了,设计HANDLE_WM_COMMAND的只是想做case WM_COMMAND和return TRUE之间的过程。而HANDLE_MSG却只是做的了简单形式的封装,所以这就是HANDLE_MSG的问题。

 

对于对话框消息处理过程我们应该使用SetDlgMsgResult宏,来正确返回。这就是大牛chHANDLE_DLGMSG用到的宏,chHANDLE_DLGMSG中封装了SetDlgMsgResult。

 

这是大牛的chHANDLE_DLGMSG的宏定义:

 

#define chHANDLE_DLGMSG(hWnd, message, fn)                 /
   case (message): return (SetDlgMsgResult(hWnd, uMsg,     /
      HANDLE_##message((hWnd), (wParam), (lParam), (fn))))

 

这是SetDlgMsgResult宏定义:

 

#define     SetDlgMsgResult(hwnd, msg, result) (( /
        (msg) == WM_CTLCOLORMSGBOX      || /
        (msg) == WM_CTLCOLOREDIT        || /
        (msg) == WM_CTLCOLORLISTBOX     || /
        (msg) == WM_CTLCOLORBTN         || /
        (msg) == WM_CTLCOLORDLG         || /
        (msg) == WM_CTLCOLORSCROLLBAR   || /
        (msg) == WM_CTLCOLORSTATIC      || /
        (msg) == WM_COMPAREITEM         || /
        (msg) == WM_VKEYTOITEM          || /
        (msg) == WM_CHARTOITEM          || /
        (msg) == WM_QUERYDRAGICON       || /
        (msg) == WM_INITDIALOG             /
    ) ? (BOOL)(result) : (SetWindowLongPtr((hwnd), DWLP_MSGRESULT, (LPARAM)(LRESULT)(result)), TRUE))

 

chHANDLE_DLGMSG中,return返回的值即使SetDlgMsgResult返回的值。那么SetDlgMsgResult返回什么值呢?

让我们看看,如果消息是

(msg) == WM_CTLCOLORMSGBOX      || /
        (msg) == WM_CTLCOLOREDIT        || /
        (msg) == WM_CTLCOLORLISTBOX     || /
        (msg) == WM_CTLCOLORBTN         || /
        (msg) == WM_CTLCOLORDLG         || /
        (msg) == WM_CTLCOLORSCROLLBAR   || /
        (msg) == WM_CTLCOLORSTATIC      || /
        (msg) == WM_COMPAREITEM         || /
        (msg) == WM_VKEYTOITEM          || /
        (msg) == WM_CHARTOITEM          || /
        (msg) == WM_QUERYDRAGICON       || /
        (msg) == WM_INITDIALOG             /
中的一个,那么返回值就是我们写的函数的返回值,result在chHANDLE_DLGMSG中被替换成对应的消息处理函数fn。如果消息不是其中的,那么那么我们先执行SetWindowLongPtr(稍后讲),最后返回TRUE(根据逗号操作符特性)。注意执行SetWindowLongPtr的时候调用的消息处理函数result(其实就是fn)。

 

但为什么要这么做呢?这些WM_CTLCOLORMSGBOX     WM_CTLCOLOREDIT 。。。有什么特殊的吗? 这些消息的返回值都是有已知的且有自己含义的,对于这些消息只需要返回它们函数处理的返回值就让程序正常运行。但对于消息WM_COMMAND就很难说了,很有可能是某个控件的通知消息,需要一个值,这个值可能是零也可能不是零,所以不能像WM_CTLCOLORMSGBOX那样处理了,因为对话框过程中TRUE大部分时候代表用户处理此消息,FALSE或0代表用户没处理此消息,那么对话框的父消息处理过程会进行默认处理。这样的话,如果一个WM_COMMAND的处理消息需要返回0,怎么办?这样办,先返回TRUE,然后用SetWindowLongPtr设置需要返回的返回值,返回TRUE是向父窗口表明你已经处理了,但返回值最后被代替成了SetWindowlongPtr的值,这样才能正常工作。就这样了!

 

其实这么绕人的根本原因是因为:

 

windows内的对话框消息过程是这样处理的.

LRESULT CALLBACK DefDlgProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)  
{  
  DLGPROC dp = (DLGPROC)GetWindowLongPtr(hdlg, DWLP_DLGPROC);  
  SetWindowLongPtr(hdlg, DWLP_MSGRESULT, 0);  
  INT_PTR fResult = dp(hdlg, uMsg, wParam, lParam);  
 if (fResult) return GetWindowLongPtr(hdlg, DWLP_MSGRESULT);  
  else ...做默认的事...  

 

 

上述代码转载了以为csdn朋友的内容,我稍加解释:
就是因为对话框真正的消息处理过程是这样的。通过对话框过程(对话框窗口过程和对话框过程要分清)返回值表明对话框过程是否处理此消息,通过SetWindowlongPtr(...,DLG_MSGRESULT)设置对话框的返回值,因为对话框窗口过程用GetWindowLongPtr获得此值并做妥善处理。

 

继续努力!

相关文章
|
消息中间件 C++ Windows
02 MFC - Windows 编程模型
02 MFC - Windows 编程模型
86 0
|
5月前
|
网络协议 API Windows
MASM32编程调用 API函数RtlIpv6AddressToString,windows 10 容易,Windows 7 折腾
MASM32编程调用 API函数RtlIpv6AddressToString,windows 10 容易,Windows 7 折腾
|
5月前
|
Windows
[原创]用MASM32编程获取windows类型
[原创]用MASM32编程获取windows类型
|
5月前
|
JavaScript 前端开发 API
MASM32编程通过WMI获取Windows计划任务
MASM32编程通过WMI获取Windows计划任务
|
5月前
|
API Windows
MASM32编程获取Windows当前桌面主题名
MASM32编程获取Windows当前桌面主题名
|
6月前
|
编译器 开发工具 C语言
解锁QtCreator跨界神技!Windows下轻松驾驭OpenCV动态库,让你的跨平台开发如虎添翼,秒变视觉编程大师!
【8月更文挑战第4天】QtCreator是一款强大的跨平台IDE,便于创建多平台应用。本教程教你如何在Windows环境下集成OpenCV库至Qt项目。首先,下载匹配MinGW的OpenCV预编译版并解压。接着,在QtCreator中新建或打开项目,并在.pro文件中添加OpenCV的头文件和库文件路径。确保编译器设置正确。随后编写测试代码,例如加载和显示图片,并进行编译运行。完成这些步骤后,你就能在QtCreator中利用OpenCV进行图像处理开发了。
325 6
|
6月前
|
数据库 Windows
超详细步骤解析:从零开始,手把手教你使用 Visual Studio 打造你的第一个 Windows Forms 应用程序,菜鸟也能轻松上手的编程入门指南来了!
【8月更文挑战第31天】创建你的第一个Windows Forms (WinForms) 应用程序是一个激动人心的过程,尤其适合编程新手。本指南将带你逐步完成一个简单WinForms 应用的开发。首先,在Visual Studio 中创建一个“Windows Forms App (.NET)”项目,命名为“我的第一个WinForms 应用”。接着,在空白窗体中添加一个按钮和一个标签控件,并设置按钮文本为“点击我”。然后,为按钮添加点击事件处理程序`button1_Click`,实现点击按钮后更新标签文本为“你好,你刚刚点击了按钮!”。
530 0
|
8月前
|
Java C++
jni编程(windows+JDK11+clion)
jni编程(windows+JDK11+clion)
129 1
|
9月前
|
API C++ Windows
windows编程入门_链接错误的配置
windows编程入门_链接错误的配置
72 0
|
9月前
|
Windows
火山中文编程 -- 第一个windows程序
火山中文编程 -- 第一个windows程序
50 0