[转载]关于chHANDLE_DLGMSG

===========================================

原文地址:点击打开链接

最近读到windows核心编程 作者制作的chHANDLE_DLGMSG 对话框消息处理宏

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

这个宏直接调用的windowsx.h里的另一个宏:

  1. #define     SetDlgMsgResult(hwnd, msg, result) (( /
  2. (msg) == WM_CTLCOLORMSGBOX      || /
  3. (msg) == WM_CTLCOLOREDIT        || /
  4. (msg) == WM_CTLCOLORLISTBOX     || /
  5. (msg) == WM_CTLCOLORBTN         || /
  6. (msg) == WM_CTLCOLORDLG         || /
  7. (msg) == WM_CTLCOLORSCROLLBAR   || /
  8. (msg) == WM_CTLCOLORSTATIC      || /
  9. (msg) == WM_COMPAREITEM         || /
  10. (msg) == WM_VKEYTOITEM          || /
  11. (msg) == WM_CHARTOITEM          || /
  12. (msg) == WM_QUERYDRAGICON       || /
  13. (msg) == WM_INITDIALOG             /
  14. ) ? (BOOL)(result) : (SetWindowLongPtr((hwnd), DWLP_MSGRESULT, (LPARAM)(LRESULT)(result)), TRUE))

可以看到,如果消息是以上列出的消息之一,这些是对话框需要特定返回值的消息,则直接返回"result" 的结果,

如果是其他消息,则返回TRUE表示已经处理过此消息,返回FALSE表示没有处理,没有处理的消息将交由系统的"对话框管理器处理"

从第二个宏可以看到,如果是其他消息,则必然返回TRUE

既然返回了TRUE,那为什么还要在返回之前调用SetWindowLongPtr函数呢.

原来是这样:

对话框回调函数的返回值跟消息的返回值是两码事,

对话框消息函数的返回值 是BOOL值 表示 是否处理了这条消息. TRUE表示已经处理

而消息的返回值是指处理的结果,一般用0表示处理成功

比如在窗口处理WM_CREATE消息的时候,申请内存失败,就有可能返回-1,windows就不会继续窗口的创建过程.

由第一个宏所知 result 其实就是 HANDLE_WM_**** 一系列宏,这些宏都是返回0.

因此,这里调用SetWindowLongPtr的目的是表示该消息处理成功.

=========================================================

原文地址:点击打开链接

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

继续努力!

时间: 2024-11-01 10:44:35

[转载]关于chHANDLE_DLGMSG的相关文章

【转载】C++拷贝构造函数(深拷贝,浅拷贝)

对于普通类型的对象来说,它们之间的复制是很简单的,例如:int a=88;int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量.下面看一个类对象拷贝的简单例子. #include <iostream>using namespace std;class CExample {private:     int a;public:     CExample(int b)     { a=b;}     void Show ()     {        cout<

门控时钟-理论分析 ---- 转载

转载自:http://www.chipsbank.com/news_detail/newsId=123.html 门控的基本要求: 1. 所需要的沿(对于正沿触发的寄存器是正沿,对于负沿触发的寄存器是负沿)不增加,不减少: 1. 不会产生毛刺: 1. 使用后功耗要能够降低: 1. 最好面积还会减小. 1. 上升沿触发的门控时钟的结构研究:应用与上升沿触发的寄存器的门控. 1. 直接与门结构: 1. 高电平使能Latch + 与门结构: 1. 低电平使能Latch + 与门结构: 1. 波形研究:

浅谈Java中的equals和==(转载)

在初学Java时,可能会经常碰到下面的代码: 1 String str1 = new String("hello"); 2 String str2 = new String("hello"); 3 4 System.out.println(str1==str2); 5 System.out.println(str1.equals(str2)); 为什么第4行和第5行的输出结果不一样?==和equals方法之间的区别是什么?如果在初学Java的时候这个问题不弄清楚,就

JVM学习(2)——技术文章里常说的堆,栈,堆栈到底是什么,从os的角度总结--转载http://www.cnblogs.com/kubixuesheng/p/5202561.html

转载自---http://www.cnblogs.com/kubixuesheng/p/5202561.html 俗话说,自己写的代码,6个月后也是别人的代码--复习!复习!复习!涉及到的知识点总结如下: 堆栈是栈 JVM栈和本地方法栈划分 Java中的堆,栈和c/c++中的堆,栈 数据结构层面的堆,栈 os层面的堆,栈 JVM的堆,栈和os如何对应 为啥方法的调用需要栈 属于月经问题了,正好碰上有人问我这类比较基础的知识,无奈我自觉回答不是有效果,现在深入浅出的总结下: 前一篇文章总结了:JV

GitHub超详细图文攻略 - Git客户端下载安装 GitHub提交修改源码工作流程 Git分支 标签 过滤 Git版本工作流(转载)

最近听同事说他都在使用GitHub,GitHub是程序员的社区,在里面可以学到很多书上学不到的东西,所以最近在准备入手这方面的知识去尝试学习,正好碰到这么详细完整的文章,就转载了,希望对自己和大家有帮助. GitHub操作总结 : 总结看不明白就看下面的详细讲解. GitHub操作流程 : 第一次提交 : 方案一 : 本地创建项目根目录, 然后与远程GitHub关联, 之后的操作一样; -- 初始化Git仓库 :git init ; -- 提交改变到缓存 :git commit -m 'desc

2.EasyUI学习总结(二)——easyloader分析与使用(转载)

本文转载自:http://www.cnblogs.com/haogj/archive/2013/04/22/3036685.html 使用脚本库总要加载一大堆的样式表和脚本文件,在easyui 中,除了可以使用通常的方式加载之外,还提供了使用 easyloader 加载的方式.这个组件主要是为了按需加载组件而诞生.什么情况下使用它呢? 你觉得一次性导入 easyui 的核心 min js 和 css 太大 你只用到 easyui 的其中几个组件 你想使用其中的一个组件,但是你又不知道这个组件依赖

Data guard概念篇一(转载)

本文转载至以下链接,感谢作者分享! http://tech.it168.com/db/2008-02-14/200802141545840_1.shtml 一.Data Guard配置(Data Guard Configurations) Data Guard是一个集合,由一个primary数据库(生产数据库)及一个或多个standby数据库(最多9个)组成.组成Data Guard的数据库通过Oracle Net连接,并且有可能分布于不同地域.只要各库之间可以相互通信,它们的物理位置并没有什么

【转载】GBDT(MART) 迭代决策树入门教程 | 简介

      转载地址:http://blog.csdn.net/w28971023/article/details/8240756        GBDT(Gradient Boosting Decision Tree) 又叫 MART(Multiple Additive Regression Tree),是一种迭代的决策树算法,该算法由多棵决策树组成,所有树的结论累加起来做最终答案.它在被提出之初就和SVM一起被认为是泛化能力(generalization)较强的算法.近些年更因为被用于搜索排

LIB和DLL的区别与使用(转载)

转载自:http://www.cppblog.com/amazon/archive/2009/09/04/95318.html 共有两种库:一种是LIB包含了函数所在的DLL文件和文件中函数位置的信息(入口),代码由运行时加载在进程空间中的DLL提供,称为动态链接库dynamic link library.一种是LIB包含函数代码本身,在编译时直接将代码加入程序当中,称为静态链接库static link library.共有两种链接方式:动态链接使用动态链接库,允许可执行模块(.dll文件或.e