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. cocos2dx 3.x ccDrawLine一个坑

    ccDrawLine,如果传进去的坐标是INFINITY,画不出来.

  2. Windows Store Apps 开发转载

    懒得写了,就直接记录转载一下文章地址吧. 如何为应用定义全局默认字体:http://blogs.msdn.com/b/gautamdh/archive/2014/03/16/how-to-change ...

  3. 使用Frame控件设计Silverlight的导航

    这里所说的导航其实就是在Silverlight的页面之间前进后退以及跳转.通过Frame控件配合后台NavigationService类可以很容易的做到页面之间的导航. 这就是工具箱中的Frame控件 ...

  4. [转]如何使用Fiddler抓取指定浏览器的数据包

    参考资料:https://www.cnblogs.com/lauren1003/p/6519630.html 使用fiddler抓取不到浏览器的包时常用的解决办法: 1.必须先打开Fiddler,再打 ...

  5. 字符编码:ASCII,Unicode,UTF-8

    1.ASCII码美国制定的一套字符编码,对英语字符和二进制位之间的关系,做了统一规定.ASCII码一共规定了128个字符(包括32个不能打印出来的控制符号)的编码,占用一个字节,字节的最前面1位统一为 ...

  6. MySQL - 1093异常 - You can't specify target table 't' for update in FROM clause

    有一个表示地区的表,表结构与数据大概如下表. ID NAME PARENT_ID 1 中国 2 广东省 1 3 广州市 2 4 荔湾区 3 5 越秀区 3 6 番禺区 3 7 小谷围街道 6 现为了查 ...

  7. vue2.0的ajax

    Vue 原本有一个官方推荐的 ajax 插件 vue-resource,但是自从 Vue 更新到 2.0 之后,官方就不再更新 vue-resource 目前主流的 Vue 项目,都选择 axios ...

  8. js中作用域和闭包

    作用域链实例   (1) function example() { var age = 23; alert(age) } var age = 25; example(); alert(age); // ...

  9. JavaEE各种Javadoc的下载

    刚才突然发现,很多servlet的api都不熟悉,但是又没有给eclipse导入api,就google了一下 关键字,servlet api / doc 或者java ee api / doc 注意版 ...

  10. mysql too many max_connections

    debian 环境 mysql  MySQL Community Server 5.6.27 首先修改 my.cnf文件  全局查找  find / -name my.cnf* [mysqld] 配置 ...