PreTranslateMessage作用和使用方法

 PreTranslateMessage是消息在送给TranslateMessage函数之前被调用的,绝大多数本窗口的消息都要通过这里,比较常用,当需要在MFC之前处理某些消息时,常常要在这里添加代码.  
       MFC消息控制流最具特色的地方是CWnd类的虚拟函数PreTranslateMessage(),通过重载这个函数,可以改变MFC的消息控制流程,甚至可以作一个全新的控制流出来。只有穿过消息队列的消息才受PreTranslateMessage()影响,采用SendMessage()或其他类似的方式向窗口直接发送的而不经过消息队列的消息根本不会理睬PreTranslateMessage()的存在。 
         是否调用TranslateMessage()和DispatchMessage()是由一个名称为PreTranslateMessage()函数的返回值决定的,如果该函数返回TRUE,则不会把该消息分发给窗口函数处理。      传给PreTranslateMessage()的消息是未经翻译过的消息,它没有经过TranslateMessage()处理。可以在该函数中使用(pMsg->wParam==VK_RETURN)来拦截回车键。wParam中存放的是键盘上字符的虚拟码。 
PeekMessage和GetMessage的区别:

GetMessage在没有消息的时候等待消息,cpu当然低

PeekMessage没有消息的时候立刻返回,所以cpu占用率高。

因为游戏不能靠windows消息驱动,所以要用PeekMessage();

PretranslateMessage的实现,不得不谈到MFC消息循环的实现。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也就不会被调用。   [Page] 如果用PostMessage,则消息进入消息队列,由GetMessage取得,PreTranslateMessage就有机会进行处理。
 
windows消息处理机制是这样的:          
首先系统(也就是windows)把来自硬件(鼠标,键盘等消息)和来自应用程序的消息 放到一个系统消息队列中去. 而应用程序需要有自己的消息队列,也就是线程消息队列,每一个线程有自己的消息队列,对于多线程的应用程序就有和线程数目相等的线程消息队列.     
windows消息队列把得到的消息发送到线程消息队列,线程消息队列每次取出一条消息发送到指定窗口, 不断循环直到程序退出.这个循环就是靠消息环(while(GetMessage()) TranslateMessage();DispatchMessage();实现的.GetMessage()只是从线程消息中取出一条消息,TranslateMessage()把virtue key消息转化成character消息,如VK_F1会转化成WM_HELP,而DispatchMessage  则把取出的消息发送到目的窗口.如果收到WM_CLOSE消息则结束循环,发送postqiutmessage(0),处理WM_DESTROY销毁窗口!

 while (GetMessage(&msg, NULL, , ))          //C++ code
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

原文地址:http://blog.csdn.net/shengliz/article/details/4979286

【转】 PreTranslateMessage作用和使用方法的更多相关文章

  1. PreTranslateMessage作用和使用方法

    PreTranslateMessage作用和使用方法  PreTranslateMessage是消息在送给TranslateMessage函数之前被调用的,绝大多数本窗口的消息都要通过这里,比较常用, ...

  2. JAVA 注解的几大作用及使用方法详解

    JAVA 注解的几大作用及使用方法详解 (2013-01-22 15:13:04) 转载▼ 标签: java 注解 杂谈 分类: Java java 注解,从名字上看是注释,解释.但功能却不仅仅是注释 ...

  3. serialVersionUID的作用以及设置方法(转)

    声明:本篇文章是转载的 http://blog.csdn.net/kakaxi_77/article/details/8129070 http://snowlotus.iteye.com/blog/2 ...

  4. PreTranslateMessage作用和用法

    PreTranslateMessage作用和用法  PreTranslateMessage是消息在送给TranslateMessage函数之前被调用的,绝大多数本窗体的消息都要通过这里,比較经常使用, ...

  5. 在Android开发中替换资源图片不起作用的解决方法

    现象 在android开发中,经常会需要替换res\drawable中的图片,打开res\layout下的文件预览布局页面发现图片已经被替换,但在模拟器或者真实机器上运行时发现该图片并没有被替换,还是 ...

  6. Linux中PATH环境变量的作用和使用方法

    关于PATH的作用:PATH说简单点就是一个字符串变量,当输入命令的时候LINUX会去查找PATH里面记录的路径.比如在根目录/下可以输入命令ls,在/usr目录下也可以输入ls,但其实ls这个命令根 ...

  7. PHP trim()函数的作用和使用方法

    PHP trim()函数一般是用来去除字符串首尾处的空白字符(或者其他字符),一般在用在服务端对接收的用户数据进行处理,以免把用户误输入的空格存储到数据库,下次对比数据时候出错. 该函数有两个参数,第 ...

  8. C++ "#"的作用和使用方法

    本系列文章由 @yhl_leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/48879093 1 #和##的作用和使用 ...

  9. header中Content-Disposition的作用与使用方法

    下载文件的时候会使用: Content-disposition 是 MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件.Content-disposition其实可以控制用 ...

随机推荐

  1. 基于Linux的USB 主/从设备之间通讯的三种方式

    转载:http://archive.eet-china.com/www.eet-china.com/ART_8800323770_617693_TA_eda530e7.HTM 随着简单易用的USB接口 ...

  2. TextBoxes 与 TextBoxes ++

    TextBoxes 论文关键idea 本文和SegLink一样,也是在SSD的基础上进行改进的.相比SSD做了以下的改进: 修改了default box的apect ratio,分别为[1 2 3 5 ...

  3. java Webservice(一)HttpClient远程调用

    我们将Web Service发布在Tomcat或者其他应用服务器上后,有很多方法可以调用该Web Service,常用的有两种: 1.通过浏览器HTTP调用,返回规范的XML文件内容      2.通 ...

  4. Xilinx之RAM使用指南

    一. RAM 分类XILINX 的 RAM 可分为三种,分别是:单口 RAM,简化双口 RAM 和真双口 RAM.如下 图所示: 图1 单口 RAM 图2 简化双口 RAM A 口写入数据,B 口读数 ...

  5. 【Android】8.2 动态选择和设置主题

    分类:C#.Android.VS2015: 创建日期:2016-02-17 一.简介 除了通过Theme指定主题外,还可以在程序运行时动态指定并应用主题. 二.示例-ch0802ThemeDemo 1 ...

  6. Ubantu 安装boost环境

    boost版本为: boost_1_61_0ubuntu版本为:ubuntu-14.04 这里有两种安装方法: ==============第一种:也是最简单的:进入linux系统后,输入   # a ...

  7. 每日英语:He Diets, She Diets: More Weight-Loss Plans Target Men

    Weight-loss companies are becoming savvier about getting men to go on a diet. savvier:更加精明 Men and w ...

  8. centos 手动编译 fcitx 各种问题大全

    yum install ncurses-devel   tinyxml-devel sqlite-devel wget http://downloads.sourceforge.net/project ...

  9. Spring Boot干货系列:(二)配置文件解析

    Spring Boot干货系列:(二)配置文件解析 2017-02-28 嘟嘟MD 嘟爷java超神学堂   前言 上一篇介绍了Spring Boot的入门,知道了Spring Boot使用“习惯优于 ...

  10. Android AlarmManager的一些问题

    我开始的代码是这样写的 alarmManager.set(AlarmManager.RTC_WAKEUP, (5*1000), sender); 我的本意是设定五秒后启动闹钟 但是每次都是我设置完闹钟 ...