先来看windows消息机制:

首先系统(也就是windows)把来自硬件(鼠标,键盘等消息)和来自应用程序的消息 放到一个系统消息队列中去. 而应用程序需要有自己的消息队列,也就是线程消息队列,每一个线程有自己的消息队列,对于多线程的应用程序就有和线程数目相等的线程消息队列.

   windows消息队列把得到的消息发送到线程消息队列,线程消息队列每次取出一条消息发送到指定窗口,不断循环直到程序退出.这个循环就是靠消息环

 while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

实现的
.GetMessage()
只是从线程消息中取出一条消息,TranslateMessage()把virtue key消息转化成character(键盘消息)息,如
VK_F1会转化成
WM_HELP,而
DispatchMessage  则把取出的消息发送到目的窗口.如果收到
WM_CLOSE消息则结束循环
,发送
postqiutmessage(0),处理
WM_DESTROY销毁窗口
!

PreTranslateMessage作用和使用方法:

先看一下translagemessage
BOOL TranslateMessage(  CONST MSG *lpMsg );

如果消息被转换(即,字符消息被送到线程的消息队列中),返回非零值。

 如果消息没有转换(即,字符消息没被送到线程的消息队列中),返回值是零。
TranslateMessage函数只能用于转换由GetMessage或PeekMessage函数接收到的消息。
             PreTranslateMessage是消息在送给TranslateMessage函数
之前被调用的,绝大多数本窗口的消息都要通过这里,比较常用,当需要在MFC之前处理某些消息时,常常要在这里添加代码.  

下面看看mfc中:

MFC消息控制流最具特色的地方是CWnd类的虚拟函数PreTranslateMessage(),通过重载这个函数,可以改变MFC的消息控制流程,甚至可以作一个全新的控制流出来。只有穿过消息队列的消息才受PreTranslateMessage()影响,采用SendMessage()或其他类似的方式向窗口直接发送的而不经过消息队列的消息根本不会理睬PreTranslateMessage()的存在。

是否调用TranslateMessage()和DispatchMessage()是由一个名称为PreTranslateMessage()函数的返回值决定的,如果该函数返回TRUE,则不会把该消息分发给窗口函数处理。

传给PreTranslateMessage()的消息是未经翻译过的消息,它没有经过TranslateMessage()处理。可以在该函数中使用              (pMsg->wParam==VK_RETURN)来拦截回车键。wParam中存放的是键盘上字符的虚拟码。

    下面看一下GetMessage和PeekMessage:

PeekMessage   返回   TRUE   的条件是有消息,如果没有消息返回   FALSE                 没有消息的时候立刻返回,所以cpu占用率高   非阻塞
GetMessage    返回   TRUE   的条件是有消息且该消息不为   WM_QUIT  
           返回   FALSE  的条件是有消息且该消息  为   WM_QUIT                              在没有消息的时候等待消息,cpu当然低  阻塞

GetMessage不将控制传回给程序,直到从程序的消息队列中取得消息,但是PeekMessage总是立刻传回,而不论一个消息是否出现。

while (TRUE)
{
if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break ;
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
else
{
// 完成某些工作的其它行程序
}
}
return msg.wParam ;

代码中为何对wm_quit消息检查?   如果GetMessage接收到一个WM_QUIT消息,它将传回0,但是PeekMessage用它的传回值来指示是否得到一个消息,所以需要对WM_QUIT进行检查。

(尽管Windows文件上说,您不能用PeekMessage从消息队列中删除WM_PAINT消息,但是这并不是什么大不了的问题。毕竟,GetMessage并不从消息队列中删除WM_PAINT消息。从队列中删除WM_PAINT消息的唯一方法是令窗口显示区域的失效区域变得有效,这可以用ValidateRect和ValidateRgn或者BeginPaint和EndPaint对来完成。如果您在使用PeekMessage从队列中取出WM_PAINT消息后,同平常一样处理它,那么就不会有问题了。所不能作的是使用如下所示的程序代码来清除消息队列中的所有消息:
while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) ;这行叙述从消息队列中删除WM_PAINT之外的所有消息。如果队列中有一个WM_PAINT消息,程序就会永远地陷在while循环中。)

MFC通过CWinApp类中的Pumpmessage函数实现消息循环,但是实际的消息循环代码位于CWinThread中,CWinApp只是从CWinThread继承过来。其简化后的代码大概如下:

BOOL CWinThread::PumpMessage()
  {
  _AFX_THREAD_STATE *pState = AfxGetThreadState();
  
  ::GetMessage(&(pState->m_msgCur), NULL, NULL, NULL))
  
  if (!AfxPreTranslateMessage(&(pState->m_msgCur)))
  {
  ::TranslateMessage(&(pState->m_msgCur));
  ::DispatchMessage(&(pState->m_msgCur));
  }
  return TRUE;
  }

可以看到,PumpMessage在实际的TranslateMessage和DispatchMessage发生之前会调用AfxPreTranslateMessage,AfxPreTranslateMessage又会调用CWnd::WalkPreTranslateTree(虽然也会调用其他函数,但是这个最为关键),其代码如下:

BOOL PASCAL CWnd::WalkPreTranslateTree(HWND hWndStop, MSG* pMsg)
  {
  ASSERT(hWndStop == NULL || ::IsWindow(hWndStop));
  ASSERT(pMsg != NULL);
  
  // walk from the target window up to the hWndStop window checking
  // if any window wants to translate this message
  
  for (HWND hWnd = pMsg->hwnd; hWnd != NULL; hWnd = ::GetParent(hWnd))
  {
  CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
  if (pWnd != NULL)
  {
  // target window is a C window
  if (pWnd->PreTranslateMessage(pMsg))
  return TRUE; // trapped by target window (eg: accelerators)
  }
  
  // got to hWndStop window without interest
  if (hWnd == hWndStop)
  break;
  }
  return FALSE; // no special processing
  }

可以看到,代码还是很直接的。从接受到消息的窗口层层往上遍历,并调用PretranslateMessage看是否返回TRUE,是则结束,否则继续。 


这里有一个地方非常关键:CWnd *pWnd = CWnd::FromHandlePermanent(hWnd) 这一句代码从当前AfxModuleThreadState拿到Permanent句柄表,从而找到hWnd对应的CWnd   ;

后续:

   MFC中PreTranslateMessage是GetMessage(...)函数的下一级操作,即GetMessage(...)从消息队列中获取消息后,交由PreTranslateMessage()处理,若其返回FALSE则再交给TranslateMessage和DispatchMessage处理(进入WindowProc);  
           如果用SendMessage,   则消息直接交到WindowProc处理,所以GetMessage不会取得SendMessage的消息,当然PreTranslateMessage也就不会被调用。  
           如果用PostMessage,则消息进入消息队列,由GetMessage取得,PreTranslateMessage就有机会进行处理。

2013,、7、24

jofranks 于南昌

【VC++积累】之八、PreTranslageMessage;TranslageMessage;GetMessage和PeekMessage的区别的更多相关文章

  1. 深入GetMessage和PeekMessage

    http://blog.csdn.net/fireseed/article/details/2176 http://www.cnblogs.com/sadier/articles/100948.htm ...

  2. 转:VC中WORD,DWORD,unsigned long,unsigned short的区别(转)

    typedef unsigned long       DWORD;typedef int                 BOOL;typedef unsigned char       BYTE; ...

  3. VC中编辑框更新SetDlgItemText()与UpdateData()的区别

    SetDlgItemText(IDC_EDIT_RXDATA,m_strREData);  //前一个是ID号,后一个是编辑框的成员变量 UpdateData(FALSE);   它们都能更新编辑框的 ...

  4. Win32消息循环机制等【转载】http://blog.csdn.net/u013777351/article/details/49522219

    Dos的过程驱动与Windows的事件驱动 在讲本程序的消息循环之前,我想先谈一下Dos与Windows驱动机制的区别: DOS程序主要使用顺序的,过程驱动的程序设计方法.顺序的,过程驱动的程序有一个 ...

  5. 最近面试遇到的Windows相关的题目

    上周准备在公司内部转岗,面了3个部门windows客户端相关的工作,最终拿到3个Offer,主要涉及C++和Windows两大块内容,C++的题目基本都答上了,Windows一直都是我的弱项,在这里记 ...

  6. 深度解析VC中的消息传递机制

    摘要:Windows编程和Dos编程,一个很大的区别就是,Windows编程是事件驱动,消息传递的.所以,要学好Windows编程,必须 对消息机制有一个清楚的认识,本文希望能够对消息的传递做一个全面 ...

  7. 深度解析VC中的消息

    消息是指什么? 消息系统对于一个win32程序来说十分重要,它是一个程序运行的动力源泉.一个消息,是系统定义的一个32位的值,他唯一的定义了一个事件,向Windows发出一个通知,告诉应用程序某个事情 ...

  8. 深度解析VC中的消息(转发)

    http://blog.csdn.net/chenlycly/article/details/7586067 这篇转发的文章总结的比较好,但是没有告诉我为什么ON_MESSAGE的返回值必须是LRES ...

  9. [C语言(VC)] 打造自己的键盘记录器 (zaroty)

    说起键盘记录,想必很多朋友都用过网上流传的一些键盘记录软件吧,但是有没有想过自己写一个呢?也许你会想:会不会很复杂啊?我可以很负责的告诉你,写键盘记录是很简单的.你所需要的仅仅是懂得一些C语言的DLL ...

随机推荐

  1. mini-css-extract-plugin简介

    将css单独打包成一个文件的插件,它为每个包含css的js文件都创建一个css文件.它支持css和sourceMaps的按需加载. 目前只有在webpack V4版本才支持使用该插件 和extract ...

  2. CSS3选择器01—CSS2.1部分选择器

    这篇文章主要用于存储CSS以及CSS3的选择器部分知识,以便日后查阅及记忆. 该内容分为两部分,第一部分为css选择器的一些基本知识.第二部分为CSS3新增加的选择器. 在开始之前,先简单介绍一下选择 ...

  3. Linux-C网络编程

    简介 基础是TCP/IP协议,网上资料很多不再赘述. 推荐<图解TCP/IP> socket编程 网络字节序 发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出, 接收主机把从网 ...

  4. VMware虚拟机中CentOS设置固定IP

    因为需要配置固定IP,在网上找了很久终于找到一个可行的例子,自己配置成功了. 1.首先获取你的GATEWAY 方便后面在cento系统配置里使用选取菜单栏:Edit->Virtual Netwo ...

  5. 【原】Spring整合Redis(第一篇)—SDR简述

    1.SDR说明 Spring Data Redis(SDR),是SpringFramework提供的一套简化访问Redis的API,是对Jedis的又一层封装. SDR集成了Jedis,JRedis, ...

  6. ant design的一些坑

    1.在本地修改ant design的某些样式可以生效,但在线上就失效了.比如collapse组件里的箭头图标在本地和在线上的类名有变化,本地类名,线上类名:箭头图标的svg样式在线上会自动添加一个内联 ...

  7. 让Win2008+IIS7+ASP.NET支持10万并发请求

    今天下午17点左右,博客园博客站点出现这样的错误信息: Error Summary: HTTP Error 503.2 - Service Unavailable The serverRuntime@ ...

  8. Android开发之解决APP启动白屏或者黑屏闪现的问题

    在做搜芽的过程中,发现那个外包人缘做的不行,由于启动的时候会停顿,然后白屏一会,联想到几个月前我在我的三僚企业通信软件里面拉起9K-Mail的时候也会黑屏,所以决定学习一下.解决一下.这不,万能的网络 ...

  9. 使用36-pin的STM32输出VGA, VGA output using a 36-pin STM32

    使用36-pin的STM32输出VGA 手头上有个项目需要通过单片机来控制将图像显示在LCD上,在网上搜了一阵子,发现都是使用的FPGA做的, 开始自己对FPGA不是很熟,一直在用的也是ARM系列的, ...

  10. 如何:声明、实例化和使用委托(C# 编程指南)

    委托的声明如下所示: C#   public delegate void Del<T>(T item); public void Notify(int i) { } C#   Del< ...