chHANDLE_DLGMSG(windows核心编程)讲解

看完《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获得此值并做妥善处理。

你可能感兴趣的:(chHANDLE_DLGMSG(windows核心编程)讲解)