Windows OS 消息泵(消息循环处理)


理解消息循环和整个消息传送机制对Windows编程来说非常重要。 

  什么是消息(Message) 

  每个消息是一个整型数值,如果查看头文件(查看头文件了解API的做法)可以发现如下一些宏定义: 

  #defineWM_INITDIALOG 0x0110 

  #define WM_COMMAND 0x0111 

  #defineWM_LBUTTONDOWN 0x0201 

  //... 

  消息机制的功能:在Windows通信中,至少一些基本Windows通信,几乎都要用到消息。如果你想让窗口或控件(实质上,控件是特殊的窗口)执行何种动作,你应该传送一个消息给它;如果另一个窗口想让你执行何种操作,它可以传送一个消息给你。如果一个事件,如敲击键盘、移动鼠标、点击按钮等,系统将消息传送给窗口,而这些窗口等控件接收到消息后执行相应的操作。 

  消息的机构:每个Windows消息共有两个参数,wParam和lParam。最初的wParam是16位(Win16时代)的,lParam是32位的。在 Win32中,两个参数都是32位的。并不是所有的消息都是用这两个参数,每个消息使用它们的方式也不尽相同。如WM_CLOSE消息会忽略上述两个参数;再如WM_COMMAND消息使用上述两个参数,wParam包含”两个”值,HIWORD(wParam)是通知信息(如果可用),LOWORD(wParam)是发送消息的控件或菜单的ID,lParam是发送消息的控件的HWND(窗口句柄),如果这个值为NULL,表示这个消息不是由控件发送的。 

  HIWORD()和LOWORD()是Windows定义的宏,分别取出一个32位整型值的高字和低字。在Win32中,一个”字”是一个16位整 型,DWORD(Double WORD)是32位整型。 

  消息发送方法:可以用PostMessage()或SendMessage()发送消息。PostMessage()把一个消息放入消息队列(MessageQueue)后立即返回,也就是当调用PostMessage(),函数执行完成返回时,很可能消息尚未处理,它是一个异步函数。 

  SendMessage()直接将消息发送到窗口,直到这个消息处理完成才返回。如果要关闭一个窗口,可以给它发送一个WM_CLOSE消息,像PostMessage(hwnd,M_CLOSE, 0, 0); 效果跟点击窗口右上角的 关闭按钮是一样的。注意这里的wParam和lParam的值都是0,因为前面提到过,WM_CLOSE消息会忽略上述两个参数,它是一个同步函数。 

  对话框(Dialogs)操作 

  如果使用对话框,为跟控件通信,你需要向控件发送消息。你或者可以使用GetDlgItem()函数根据控件的ID取得控件的句柄,然后调用 SendMessage()函数发送消息;或者使用SendDlgItemMessage()组合了上面的步骤。传入一个窗口句柄和子控件ID能够取得子控件的句柄,用这个句柄发送消息。跟SsendDlgItemMessage()类似的API如GetDlgItemText()能够对所有的窗口进行操作,而不仅仅是对话框。 

  什么是消息队列(Message Queue) 

  假设一个场景:系统正在处理WM_PAINT消息,就在这时用户在键盘上敲击了一些按键,这时会发生什么呢?系统应该中断绘图操作然后处理按键消息还是应该丢弃按键的消息?很明显这些都是不合理的,因此我们引入了消息队列,当消息发送过来,将消息加入消息队列,当一个消息被处理时,将其从消息队列移除。这样确保消息不会丢失,当你正在处理一个消息时,其它到来的消息可以加入到消息队列直到被处理。 

  什么是消息循环(Message Loop) 

  while(GetMessage(&Msg,NULL, 0, 0) > 0) 

  { 

  TranslateMessage(&Msg); 

  DispatchMessage(&Msg); 

  } 

  上面代码的执行过程为: 

  1. 消息循环调用GetMessage()从消息队列中查找消息进行处理,如果消息队列为空,程序将停止执行并等待(程序阻塞)。 

  2.事件发生时导致一个消息加入到消息队列(例如系统注册了一个鼠标点击事件),GetMessage()将返回一个正值,这表明有消息需要被处理,并且消息 已经填充到传入的MSG参数中;当传入WM_QUIT消息时返回0;如果返回值为负表明发生了错误。 

  3. 取出消息(在Msg变量中)并将其传递给TranslateMessage()函数,这个函数做一些额外的处理:将虚拟键值信息转换为字符信息。这一步实际上是可选的,但有些地方需要用到这一步。 

  4. 上面的步骤执行完后,将消息传递给DispatchMessage()函数。DispatchMessage()函数将消息分发到消息的目标窗口,并且查找目标窗口过程函数,给窗口过程函数传递窗口句柄、消息、wParam、lParam等参数然后调用该函数。 

  5. 在窗口过程函数中,检查消息和其他参数,你可以用它来实现你想要的操作。如果不想处理某些特殊的消息,你应该总是调用DefWindowProc()函 数,系统将按按默认的方式处理这些消息(通常认为是不做任何操作)。 

  6. 一旦一个消息处理完成,窗口过程函数返回,DispatchMessage()函数返回,继续循环处理下一个消息。 

  消息循环对Windows编程来说是一个非常重要的概念。窗口过程函数并不是系统自动调用的,而是由开发人员自己通过调用 DispatchMessage()间接的调用的。 

  HOOK:钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。其实挂入钩子的机制也正是利用了Windows消息循环处理的机制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值