Chinaunix首页 | 论坛 | 博客
  • 博客访问: 642937
  • 博文数量: 133
  • 博客积分: 1566
  • 博客等级: 上尉
  • 技术积分: 1230
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-01 09:31
文章分类

全部博文(133)

文章存档

2019年(1)

2018年(1)

2017年(8)

2016年(9)

2015年(17)

2014年(4)

2013年(31)

2012年(25)

2011年(36)

2010年(1)

我的朋友

分类: C/C++

2012-12-06 15:07:27

   消息映射是MFC应用程序的运行核心,Windows系统以消息的形式输入传递给应用程序的窗口过程,窗口通过窗口过程来接收和处理消息,并把控制返回Windows系统。
 
1. 消息结构
   消息是一个将事件和数据结合起来的集合。MSG结构含有来自windows应用程序消息队列的消息信息。
typedef struct tagMSG {
    HWND        hwnd;
    UINT        message;
    WPARAM      wParam;
    LPARAM      lParam;
    DWORD       time;
    POINT       pt;
#ifdef _MAC
    DWORD       lPrivate;
#endif
} MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;
1)hwnd---接收该消息的窗口句柄,用以检索消息队列中的消息。如果hwnd = 0,则应用程序检索所有消息队列中的消息。窗口可以是任何类型的屏幕对象(能在屏幕显示的对象),比如主窗口,按钮等。
2)message---消息标示符,该值由windows.h内的宏识别,它是用于区别其他消息的常量。
3)wParam和lParam---分别表示消息的第一和第二参数,确切的含义依赖与消息本身。wParam通常是一个于消息有关的常数量,也可能是窗口或控件的句柄;lParam通常是一个指向内存中数据的指针。
4)time---表示消息创建的时间
5)pt---消息创建时屏幕的光标坐标
 
2. 消息的种类
1)系统定义消息和应用程序定义消息
   根据消息的来源可以把消息分为系统定义消息和应用程序定义消息。
   消息标示符定义规则:前缀_后缀,前缀表示处理消息的窗体类型,后缀表示消息的具体内容
---WM:通用窗口消息
---BM:按钮空控制框
---DM:默认按钮控制框
---CB:组合框控制框
---EM:编辑控制框
---LB:列表控制框
---SBM:滚动控制框
   系统定义消息的标示符号常量范围:0~WM_USER-1或者0x80000~0xBFFFF
应用程序定义消息---应用程序创建的消息,用在自己的窗口中或与其他应用程序交互的消息。
   应用程序定义消息的标示符号常量范围:WM_USER(0x0400)~0x7FFF或者0xC000~0xFFFF。其中WM_USER(0x0400)~0x7FFF范围的消息由应用程序自己使用。0xC000~0xFFFF范围的消息用来和其他应用程序通讯。为了确保消息标示符唯一性,使用::RegisterWindowMessage为消息注册。
                系统定义消息及其对应的标示符号的范围
2)队列消息和非队列消息
   根据消息发送的目的地,消息分为队列消息和非队列消息。
   Windows系统有两类消息队列,一个是Windows系统维护的系统消息队列(System message queue),另一个是每个GUI线程有一个线程消息队列(Thread message queue)。
   队列消息都被发送到系统消息队列,Windows每次从系统消息队列中取出一个消息,确定其送往那个窗口和这个窗口是由那个线程创建,之后把消息放进创建窗口的线程的消息队列。并由线程从线程消息队列中取出消息送到适当的窗口过程进行处理。
                        鼠标消息WM_LBUTTONDOWN的产生及传递流程
   非队列消息将会绕过系统队列和消息队列,直接被送到目的窗口过程进行处理。
   除鼠标消息,键盘消息,和队列消息WM_PAINT, WM_TIMER和WM_QUIT外,绝大多数消息都是非队列消息。
3)窗口消息,命令消息和控制通知消息
   根据MFC消息处理函数和处理过程的不同,可分为窗口消息,命令消息和控制通知消息。
   A. 窗口消息由窗口对象处理,窗口消息被直接发送给MFC窗口过程,窗口过程调用相应的消息处理函数处理消息,消息处理函数就是MFC窗口类的成员函数。比如WM_CREATE,MoveWindow,DestroyWindow等消息。
   B. 命令消息,一种特殊的窗口消息,用来处理从一个窗口发送到另一窗口的用户请求。命令消息属于应用程序自定义消息。比如来自菜单,工具栏按钮,加速键等用户接口对象的WM_COMMAND消息。
   C. 控制通知消息,控制子窗口送给父窗口的WM_COMMAND通知消息,窗口过程调用相应的消息处理函数处理消息。控制通知消息只适用于标准的窗口控件,比如按钮,列表框,组合框,编辑框,以及Windows公共控件包括树状视图,列表视图等。控制通知消息和命令消息的区别:命令消息主要是来自用户请求,处理用户命令,而控制通知消息为了使控件发生改变。比如:单纯的单击鼠标,Windows发出命令消息;而单击按钮控件,鼠标动作就使得按钮向其父窗口发送控制通知消息,父窗口处理此消息,再将其交给按钮控件处理。
    窗口消息和控制通知消息,主要由窗口类处理,即由类CWnd及其派生类处理。而命令消息能够处理从CCmdTarget类派生的类的消息。
4)常用消息
   A. 鼠标消息:反应鼠标的各种动作
   B. 键盘消息
   C. WM_COMMAND:既包括控制通知消息,也包括命令消息
   D. WM_PAINT:用来通知窗口需要重新绘制
   E. WM_CREATE:通知生成窗口,完成初始化
   F. WM_CLOSE:通知关闭窗口
   G. WM_QUIT:通知应用程序结束
 
3. 消息的发送和接收
1)消息发送
   发送方式                       使用的函数
     发送                       SendMessage
                               | SendNotifyMessage
                               | SendMessageTimeout
                               | SendMessageCallback
     投递                       PostMessage
                               | PostQuitMessage
                               | PostThreadMessage
     广播                       BroadcastSystemMessage
A. 发送消息
   代表函数SendMessage:
LRESULT SendMessage(
    HWND hWnd,
    UINT Msg,
    WPARAM wParam,
    LPARAM lParam);
   调用此函数向一个或者多个窗口发送一条消息,函数在消息被处理之后才返回。如果消息的目标窗口是应用程序的一部分,那么该窗口的窗口函数就被直接调用;如果接收消息的窗口是由其他线程创建的,那么系统就切换到相应的线程,并调用相应的窗口函数。
   函数的返回值由接收函数的窗口的窗口函数返回,取决于发送的消息。
B. 投递消息
   代表函数是PostMessage:
BOOL PostMessage(
    __in_opt HWND hWnd,
    __in UINT Msg,
    __in WPARAM wParam,
    __in LPARAM lParam);
   调用此函数把一条消息投递到创建窗口的线程的消息队列的最后,并不等消息被处理就马上返回
C. 广播消息
   代表函数BroadcastSystemMessage:
long BroadcastSystemMessage(
    __in DWORD flags,
    __inout_opt LPDWORD lpInfo,
    __in UINT Msg,
    __in WPARAM wParam,
    __in LPARAM lParam);
    调用该函数可以向指定接收者发送一条消息,该消息可以是应用程序,可安装的驱动程序,网络驱动程序,系统级别的设备驱动消息或者他们的任意组合。广播消息成功返回一个正值,消息广播失败则返回-1。
如果flags = BSF_QUERY且至少有一个接收者返回了BROADCAST_QUERY_DENY,则返回值为0,如果flags != BSF_QUERY,则函数把消息发送给所有的接收者,并忽略其返回值。
2)消息接收
   有三个主要的接收函数:GetMessage,PeekMessage,WaitMessage
BOOL GetMessage(
    __out LPMSG lpMsg,
    __in_opt HWND hWnd,
    __in UINT wMsgFilterMin,
    __in UINT wMsgFilterMax);
   该函数用于获取与hWnd参数所指定的窗口相关联且在wMsgFilterMin/wMsgFilterMax参数所给消息值范围内的消息。如果hWnd = NULL,GetMessage获取属于调用该函数应用程序的任一窗口的消息。如果wMsgFilterMin = 0/wMsgFilterMax = 0,GetMessage返回所有可得到的消息。函数获取的如果不是消息WM_QUIT,则返回非零,否则返回零。
 
BOOL PeekMessage(
    __out LPMSG lpMsg,
    __in_opt HWND hWnd,
    __in UINT wMsgFilterMin,
    __in UINT wMsgFilterMax,
    __in UINT wRemoveMsg);
   该函数用于查看消息队列,如果其中有消息就将其放入到lpMsg所指的结构中。PeekMessage与GetMessage不同的是,函数GetMessage只有队列有消息时才返回,PeekMessage无论队列中是否有消息都会返回。函数获取到消息返回非零,否则返回零。
 
BOOL WaitMessage(VOID);
   该函数使应用程序挂起,直到一个新的消息被放入应用程序的消息队列之中才返回,函数执行成功返回非0,执行失败返回0
 
4. 消息循环
   消息循环---从线程的消息队列中检索出消息,并将其发送到相应的窗口过程进行消息处理的机制。
MSG msg;
while (GetMessage(&msg, (HWND)NULL, 0, 0)) // 接收消息
{
  if(TranslateAccelerator(hwndMain, haccel, &msg))
  {
   TranslateMessage(&msg);    // 转换消息
   DispatchMessage(&msg);    // 分发消息
  }
}
   函数GetMessage从线程消息队列中获取一个消息并将他复制到MSG结构。TranslateAccelerator判断该消息是否为一个按键消息且为一个加速键消息,(如果是,则该函数把几个按键消息转换成一个加速键消息传递给窗口的回调函数)。消息处理完成后,函数DispatchMessage把消息发送给该消息指定窗口中的回调函数。
   如果得到的消息是WM_QUIT,则GetMessage返回0,应用程序退出消息循环。
 
5. 消息映射---消息处理机制,把消息和消息处理函数相互关联起来
1)消息映射的实现方法
   A. 在类声明中,通过宏DECLARE_MESSAGE_MAP声明消息映射的关联方法,将消息和消息处理函数连接起来。
   B. 在类实现的文件中,通过宏BEGIN_MESSAGE_MAP/END_MESSAGE_MAP来定义在宏DECLARE_MESSAGE_MAP中声明的方法。
   C. 添加消息处理函数,并在里面添加相关的处理代码,实现需要的响应。
2)消息映射的宏
   A. 用于窗口映射的宏---此类宏前缀为“ON_WM_”,如ON_WM_PAINT(),此类宏不带参数
   B. 用于命令消息的宏---此类宏只有一种形式ON_COMMAND。命令ID/处理函数,分两类一对一:ON_COMMAND,多对一ON_COMMAND_RANGE。
   C. 用于控制通知消息的宏---此类宏的形式由消息具体决定,也支持多对一:ON_CONTROL_RANGE/ON_NOTIFY_RANGE
   D. 自定义消息映射的宏---此类前缀是“ON_”,后缀由用户自行命名,附带参数:命令ID/消息处理函数
 
6. 自定义消息的消息映射
   一种利用ON_MESSAGE宏,另一种就是创建自己的消息映射宏
   自定义消息的定义形式:WM_USER + X(X是一个非负整数)。
例如:
1)类声明文件中,声明一个消息命令ID,并在类声明体内声明一个响应函数
//自定义消息映射宏的命令ID
#define WM_MY_MESSAGE (WM_USER + 100)
//自定义消息映射宏的相应函数
afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
 
2)在类实现文件中,实现OnMyMessage函数
LRESULT CExMyMessageView::OnMyMessage(WPARAM wParam, LPARAM lParam)
{
 MessageBox(L"       Hello!");
 return NULL;
}
 
3)在BEGIN_MESSAGE_MAP/END_MESSAGE_MAP中,添加命令ID和响应函数的连接,实现消息映射
BEGIN_MESSAGE_MAP(CExMyMessageView, CView)
 // the message is added by user
 ON_MESSAGE(WM_MY_MESSAGE, OnMyMessage) //自定义消息映射宏
 // 标准打印命令
 ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
 ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
 ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview)
 ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()
 
 
  
 
  
 
 
 
   
阅读(3541) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~