在windows程序中,消息是一个重要的概念,最常见的消息一般都是以WM_开头,WM就是window message,窗口消息的缩写,通过处理标准的windows消息,我们可以改变窗口的外观,如使用WM_ERASEBKGND消息可以改变窗口默认的窗口背景,窗口每次需要绘制窗口的背景的时候,就会发送一次这个消息,如果我们处理这个消息,我们就可以绘制我们自己的特性化的背景,如果不处理,默认窗口过程就会处理,绘制背景。通过处理标准的windows消息,我们可以对用户的输入做出响应,如WM_LBUTTONDOWN,当鼠标按下的时候,就可以对用户的操作作出响应,通过命令消息WM_COMMAND消息,可以获取来自菜单,按钮的命令。另外,控件还有自己的notification消息,当控件的状态发生改变的时候,如点击按钮,点击编辑框,选择一个列表框项目时,就会发送相应的消息,通过处理消息,就可以对获取控件的一些消息,做出一些处理。在sdk中还有一种消息,也是用于控件的,也是通过发送消息来控制控件的属性和操作,而这个在MFC中变成了成员函数,但是底层的原理还是一样的。消息的作用还有很多,我们不能单一的去理解消息这个概念,一方面,我们可以通过阅读msdn可以深入的学习消息,另一方面,我们可以通过在使用的过程中,加深对消息的理解。除了使用上面说的这些windows提供的预定义消息(系统消息)之外,我们也可以使用我们自定义的消息。

每个消息有一个ID,对于自定义消息,我们在定义的时候,也要定义一个ID,而这个ID的范围是有要求的,可以是WM_USER (0x0400) 到 0x7FFF,也可以是 WM_APP (0x8000) 到0xBFFF,别的ID范围呢,系统保留。在使用的时候,通常都是以WM_USER+X,WM_APP+X或是在定义消息ID的时候,有两种方法:

第一种方法是通过常量声明幅值的方法,也就是常量的使用方法,因为一个消息的ID就是一个常量,确定之后,就不能改变,因此,可以使用定义常量的方法来为一个消息附上ID,如下:

const UINT WM_MYMESSAGE1=WM_APP+1;

第二种方法是通过#define,如下:

#define WM_MYMESSAGE2 WM_APP+2

通过这两种方法,我们就可以在为一个消息指定ID。下面是要说说,上面这两句定义消息ID的表达式所放的位置的不同所产生的使用方法的不同。下面以实例来说明:

第一种情况,当我把定义消息ID的表达式放在了头文件MyView.h中

当我在SINView.cpp文件中接收和处理这两个消息时,必须事先包含声明两个消息ID的头文件,这里是MyView.h。否则,在cpp中处理的时候,就是出现语法错误,提示未声明的标示符。

第二种情况,如果我们由于一些原因,不能包含声明消息ID的头文件,例如,如果我们包含了,就会出现互相包含的情况,就会造成错误,或是,将在发送这个消息的cpp文件和接受处理这个消息的cpp文件中定义这两个消息的ID,那么这个时候,我们必须在两个地方声明和幅值消息ID,一个地方是发送的类的源文件或头文件中,另一个地方是接收和处理这个自定义消息的源文件中。例如,WM_MYMESSAGE3,我在MyView.h或是MyView.cpp中进行声明,因为我要从MyView.cpp中发送这个消息,如图:

在接收消息的地方,我再次定义一次,可以直接复制上次定义的,我要在SINView.cpp中接收和处理,于是在这个文件的开头,如下图:

现在已经定义好了消息的ID,接下来是发送消息,发送消息,一般是是用SendMessage和PostMessage,SendMessage必须要等到这个消息被处理并返回之后才会结束执行,否则会一直等待,如果消息一直得不到处理,函数一直等待,就会造成发送消息的线程阻塞。PostMessage是将消息发送之后,就立即返回,不管消息是否到达目的地,处理。如果在单线程程序中,我们最好是用PostMessage,用SendMessage容易造成线程锁死。另外,在MFC中使用这两个函数,如果直接使用,第一个参数就是要发送的消息,这样只能向本窗口发送消息,如果在MFC中使用::PostMessage,这样就是使用的是win32函数的api,第一个参数是目标窗口句柄,就可以向任意窗口发送消息。

下面说说如何处理发送的消息,首先介绍一种最为简单的处理方法,这种方法和在win32 sdk中的窗口过程一样,通过switch/case语句来处理.在MFC窗口类都有一个WindowProc虚函数,当这个窗口的消息进入这个窗口的消息映射之前,会首先通过这个虚函数,因此,我们在这里就可以拦截处理我们的自定义消息,甚至是别的任何消息,当然,标准窗口消息仍然是推荐使用MFC的消息映射的方法来处理。如下图:

使用这种方法,有一点很重要,那就是最后那一句return语句:return CView::WindowProc(message, wParam, lParam);这样保证别的消息可以正确处理。这种处理方式和win32 sdk中的窗口过程处理消息的方式是一样的。

接着介绍一种MFC标准的自定义消息处理的方式,也就是是用ON_MESSAGE宏。使用这种方式,就和我的博文"MFC-消息机制"中描述的消息处理方式一样,要使用这种处理方式,首先要声明一个消息响应函数原型,接着添加消息映射,最后实现消息响应函数。我们一步一步来看,首先看ON_MESSAGE宏的原型:

ON_MESSAGE(message, memberFxn)

第一个参数是消息ID,第二个参数消息响应函数。现在,针对WM_MYMESSAGE3消息,我们使用这种处理方式。首先在CSINView类中声明一个消息响应函数:

afx_msg LRESULT OnMyMessage3(WPARAM wParam, LPARAM lParam);

消息响应函数的名称由自己确定,这里我使用的是OnMyMessage3。在声明这个消息响应函数的时候,一般就是按照这个样式,而且一般声明为protected。

接着是消息添加消息映射,使用ON_MESSAGE,如下:

最后是实现消息响应函数,在SINView.cpp中,如下:

通过ON_MESSAGE宏,当窗口接收到消息的时候,就会自动调用我们的消息响应函数了。

以上就阐述了一下,在MFC自定义消息的使用方法,下面是效果图:

最后在说说消息过滤的问题,使用过win32 sdk编写程序的人都知道,可以在使用while从消息队列中获取消息的时候,在派发消息到窗口之前,可以做一个消息过滤,在MFC这里也可以,CWinApp有一个虚函数CWinApp::PreTranslateMessage,这个虚函数就是消息循环获取消息,派发之前,就调用这个虚函数,我们就可以在这个虚函数中,拦截过滤一些消息,主要是通过这个虚函数的参数,一个消息结构体,来判断要过滤的消息。一个是判断句柄,一个是判断消息id。

本文中涉及到的信息,如有疑问,请参考msdn。

author email:andyhl1987@126.com

本文代码:http://download.csdn.net/detail/xinzhiyounizhiyouni/6680781

windows7 vs2010环境下

MFC--自定义消息的更多相关文章

  1. MFC自定义消息

    本文地址:http://blog.163.com/strive_only/blog/static/893801682010101911467765/ 消息机制是windows的典型运行机制,在MFC中 ...

  2. MFC自定义消息的实现方法

    一.概述: 消息机制是windows程序的典型运行机制,在MFC中有很多已经封装好了的消息,如WM_BTN**等.但是在有些特殊情况下我们需要自定义一些消息去完成一些我们所需要的功能,这时候MFC的向 ...

  3. MFC在子线程中创建窗口(PostMessage方法)

    1.创建子线程 C++创建线程的方式比较多 1)最简单易用的<thread>头文件,但是这种方法创建的子线程中无法给主线程PostMessage消息(也可能是我操作有误,总之没成功) 2) ...

  4. MFC用户自定义消息

    之前做过佳能相机和位移平台的额二次开发,当时遇到一个棘手的问题,就是位移平台如何知道相机已经拍完照了,或者相机如何知道位移平台已经运行到指定位置,当时为了方便采用了定时器来定时检测位移平台的位置,结果 ...

  5. C#中自定义消息,与MFc对比

    在C#中采用的是事件驱动方式,但在我们使用的过程中,有时候通过调用系统原有的消息,处理起来会比较简单一些,特别是在处理与DLL文件的交互时,的确是非常的方便.    在C#中使用自定义消息      ...

  6. MFC发送自定义消息-PostMessage和SendMessage

    PostMessage:把消息投放到线程的消息队列,不能消息被处理就立即返回SendMessage:消息被处理完后才返回 几种发送消息的写法:   ::PostMessage(GetSafeHwnd( ...

  7. MFC添加自定义消息

    由于MFC中无法通过类向导来自定义消息,所以需要手动添加,主要过程如下: 本文基于vs2008下通过线程实现数据实时更新的对话框运用程序 1. 定义消息(Resource.h文件中): 由于很多新控件 ...

  8. MFC中创建自定义消息

    消息映射.循环机制是Windows程序运行的基本方式.VC++ MFC 中有许多现成的消息句柄,可当我们需要完成其它的任务,需要自定义消息,就遇到了一些困难.在MFC ClassWizard中不允许添 ...

  9. MFC消息-自定义消息

    转:http://blog.csdn.net/penpenandtongtong/article/details/18598907 像MFC的窗口发送消息,可以进行自定义的动作行为,因此很多时候非常有 ...

随机推荐

  1. 17.1 Replication Configuration

    17.1 Replication Configuration 17.1.1 How to Set Up Replication 17.1.2 Replication Formats 17.1.3 Re ...

  2. 基于visual Studio2013解决C语言竞赛题之0518回文数

     题目

  3. mongoose 数据库操作 - 分页

    使用mongoose 加入分页方法,临时还没发现什么更好的方法,我使用的方法是,直接在源代码中加入 找到 node_modules/mongoose/lib/model.js打开这个文件.里面加入这段 ...

  4. word2vec 中的数学原理具体解释(三)背景知识

      word2vec 是 Google 于 2013 年开源推出的一个用于获取 word vector 的工具包,它简单.高效,因此引起了非常多人的关注.因为 word2vec 的作者 Tomas M ...

  5. tomcat设置IP地址或者域名访问

    链接地址:http://jingyan.baidu.com/article/7e440953dc096e2fc0e2ef1a.html 本文介绍如何通过修改tomcat的配置,实现通过IP地址或者域名 ...

  6. linux i2c驱动架构-dm368 i2c驱动分析

      linux i2c驱动架构-dm368 i2c驱动分析   在阅读本文最好先熟悉一种i2c设备的驱动程序,并且浏览一下i2c-core.c以及芯片提供商的提供的i2c总线驱动(i2c-davinc ...

  7. android的四种加载模式

    在Android中每个界面都是一个Activity,切换界面操作其实是多个不同Activity之间的实例化操作.在Android中Activity的启动模式决定了Activity的启动运行方式. An ...

  8. 编译kernel:编译

    韦东山Linux视频第1期_裸板_UBoot_文件系统_驱动初步第10课第3节 内核启动流程分析之Makefile.WMV  1. 编译内核分三步: make xxx_defconfig [linux ...

  9. leetcode:Reverse Nodes in k-Group(以k为循环节反转链表)【面试算法题】

    题目: Given a linked list, reverse the nodes of a linked list k at a time and return its modified list ...

  10. 通过cmd命令安装、卸载、启动和停止Windows Service(InstallUtil.exe)-大壮他哥

    步骤: 1.运行--〉cmd:打开cmd命令框 2.在命令行里定位到InstallUtil.exe所在的位置 InstallUtil.exe 默认的安装位置是在C:/Windows/Microsoft ...