GetMessage以及消息循环说明

在创建窗口、显示窗口、更新窗口后,我们需要编写一个消息循环,不断地从消息队列中取出消息,并进行响应。要从消息队列中取出消息,我们需要调用GetMessage()函数,该函数的原型声明如下:在创建窗口、显示窗口、更新窗口后,我们需要编写一个消息循环,不断地从消息队列中取出消息,并进行响应。要从消息队列中取出消息,我们需要调用GetMessage()函数,该函数的原型声明如下:

BOOL GetMessage(LPMSG lpMsg,              // address of structure with messageHWND hWnd,                 // handle of windowUINT wMsgFilterMin,       // first messageUINT wMsgFilterMax        // last message);

参数lpMsg指向一个消息(MSG)结构体,GetMessage从线程的消息队列中取出的消息信息将保存在该结构体对象中。

参数hWnd指定接收属于哪一个窗口的消息。通常我们将其设置为NULL,用于接收属于调用线程的所有窗口的窗口消息。

参数wMsgFilterMin指定要获取的消息的最小值,通常设置为0。

参数wMsgFilterMax指定要获取的消息的最大值。如果wMsgFilterMin和wMsgFilter Max都设置为0,则接收所有消息。

GetMessage函数接收到除WM_QUIT外的消息均返回非零值。对于WM_QUIT消息,该函数返回零。如果出现了错误,该函数返回-1,例如,当参数hWnd是无效的窗口句柄或lpMsg是无效的指针时。

通常消息循环代码如下:

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

GetMessage函数只有在接收到WM_QUIT消息时,才返回0。此时while语句判断的条件为假,循环退出,程序才有可能结束运行。在没有接收到WM_QUIT消息时,Windows应用程序就通过这个while循环来保证程序始终处于运行状态。

TranslateMessage函数用于将虚拟键消息转换为字符消息。字符消息被投递到调用线程的消息队列中,当下一次调用GetMessage函数时被取出。当我们敲击键盘上的某个字符键时,系统将产生WM_KEYDOWN和WM_KEYUP消息。这两个消息的附加参数(wParam和lParam)包含的是虚拟键代码和扫描码等信息,而我们在程序中往往需要得到某个字符的ASCII码,TranslateMessage这个函数就可以将WM_KEYDOWN和WM_ KEYUP消息的组合转换为一条WM_CHAR消息(该消息的wParam附加参数包含了字符的ASCII码),并将转换后的新消息投递到调用线程的消息队列中。注意,TranslateMessage函数并不会修改原有的消息,它只是产生新的消息并投递到消息队列中。

DispatchMessage函数分派一个消息到窗口过程,由窗口过程函数对消息进行处理。DispachMessage实际上是将消息回传给操作系统,由操作系统调用窗口过程函数对消息进行处理(响应)。

(1)操作系统接收到应用程序的窗口消息,将消息投递到该应用程序的消息队列中。

(2)应用程序在消息循环中调用GetMessage函数从消息队列中取出一条一条的消息。取出消息后,应用程序可以对消息进行一些预处理,例如,放弃对某些消息的响应,或者调用TranslateMessage产生新的消息。

(3)应用程序调用DispatchMessage,将消息回传给操作系统。消息是由MSG结构体对象来表示的,其中就包含了接收消息的窗口的句柄。因此,DispatchMessage函数总能进行正确的传递。

(4)系统利用WNDCLASS结构体的lpfnWndProc成员保存的窗口过程函数的指针调用窗口过程,对消息进行处理(即“系统给应用程序发送了消息”)。

以上就是Windows应用程序的消息处理过程。

提示:

(1)从消息队列中获取消息还可以调用PeekMessage函数,该函数的原型声明如下所示:

BOOL PeekMessage(

LPMSG lpMsg,           // message information

HWND hWnd,              // handle to window

UINT wMsgFilterMin, // first message

UINT wMsgFilterMax,  // last message

UINT wRemoveMsg      // removal options

);

前4个参数和GetMessage函数的4个参数的作用相同。最后1个参数指定消息获取的方式,如果设为PM_NOREMOVE,那么消息将不会从消息队列中被移除;如果设为PM_REMOVE,那么消息将从消息队列中被移除(与GetMessage函数的行为一致)。关于PeekMessage函数的更多信息,请参见MSDN。

(2)发送消息可以使用SendMessage和PostMessage函数。SendMessage将消息直接发送给窗口,并调用该窗口的窗口过程进行处理。在窗口过程对消息处理完毕后,该函数才返回(SendMessage发送的消息为不进队消息)。PostMessage函数将消息放入与创建窗口的线程相关联的消息队列后立即返回。除了这两个函数外,还有一个PostThreadMessage函数,用于向线程发送消息,对于线程消息,MSG结构体中的hwnd成员为NULL。

消息循环错误分析

while(GetMessage(&msg,hwnd,0,0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

注意代码中以粗体显示的部分。这段代码基于这样一个想法:第1章的程序只有一个窗口,而我们前面说了GetMessage函数的hWnd参数是用于指定接收属于哪一个窗口的消息,于是不少人就在消息循环中为GetMessage函数的hWnd参数指定了CreateWindow函数返回的窗口句柄。

读者可以用上述代码中的消息循环部分替换1.5节代码中的消息循环部分,然后运行程序,关闭程序。你会发现你的机器变慢了,同时按下键盘上的Ctrl + Alt + Delete键,启动Windows的任务管理器,切换到“进程”选项卡,单击“CPU”项进行排序,你会发现如图1.7所示的情况。

从图1.7中可以看到,WinMain.exe的CPU占用率接近100,难怪机器“变慢了”。那么这是什么原因呢?实际上这个问题的答案在MSDN中就可以找到,并且就在GetMessage函数的说明文档中。不少初学者在遇到问题时,首先是头脑一片空白,接着就去找人求助,这种思想用在程序开发的学习中,没有什么好处。笔者经常遇到学员问问题,结果有不少问题的答案在MSDN关于某个函数的解释中就可看到(由于显示器的限制,有的答案需要滚动窗口才能看到 J)。所以在这里,笔者也建议读者遇到问题一定要记得查看MSDN,学会使用MSDN并从中汲取知识,将使你受用无穷。

图1.7   WinMain.exe的CPU占用率接近100

回到正题,在1.4.3节介绍GetMessage函数时,曾说过如果hWnd参数是无效的窗口句柄或lpMsg参数是无效的指针时,GetMessage函数将返回-1。当我们关闭窗口时,调用了DestroyWindow来销毁窗口,由于窗口被销毁了,窗口的句柄当然也就是无效的句柄了,那么GetMessage将返回-1。在C/C++语言中,非0即为真,由于窗口被销毁,句柄变为无效,GetMessage总是返回-1,循环条件总是为真,于是形成了一个死循环,机器当然就“变慢了”。J

在MSDN关于GetMessage函数的说明文档中给出了下面的代码:

BOOL bRet;

while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)

{

if (bRet == -1)

{

// handle the error and possibly exit

}

else

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

}

针对我们这个问题,可以修改上述代码如下:

HWND hwnd;

hwnd=CreateWindow(…);

MSG msg;

BOOL bRet;

while( (bRet = GetMessage( &msg, hwnd, 0, 0 )) != 0)

{

if (bRet == -1)

{

// handle the error and possibly exit

return -1;

}

else

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

}

GetMessage以及消息循环说明相关推荐

  1. win32——消息循环 原理 函数 GetMessage PeekMessage TranslateMessage SendMessage PostMessage...

    //消息循环 MSG 结构体 typedef struct tagMSG {HWND hwnd;UINT message; //消息ID WPARAM wParam;LPARAM lParam;DWO ...

  2. C++-Windows消息循环GetMessage/TranslateMessage/DispatchMessage

    1.windows消息循环 if (GetMessage(&msg, NULL, 0, 0)) {TranslateMessage(&msg); //消息转化DispatchMessa ...

  3. Windows 消息循环(1) - 概览

    本文从消息循环是如何驱动程序的这个角度,对 Windows 消息循环进行概览性介绍. 使用 EN5 课件获得更好的阅读体验: [希沃白板5]课件分享 : <Windows培训 - 消息循环> ...

  4. android 结束if循环_Android Handler 消息循环机制

    前言 一问起Android应用程序的入口,很多人会说是Activity中的onCreate方法,也有人说是ActivityThread中的静态main方法.因为Java虚拟机在运行的时候会自动加载指定 ...

  5. TApplication与主消息循环

    Windows应用程序的每一个窗口都有一个大的消息循环以及一个窗口函数(WndProc)用以分发和处理消息.VCL作为一个Framework,当然会将这些东西隐藏起来,而重新提供一种易用的.易理解的虚 ...

  6. 1.4 消息循环和回调函数

    ************************************************** * 本文由小鸟飞飞整理发表 <samboy@sohu.com> * * 首发网站:蓝丽 ...

  7. 模态对话框的消息循环原理及分析笔记

    简述: APP消息循环和模态对话框中局部消息循环的关系 根据上图可以看出,在APP的消息循环再派发ONOK消息后,调用ModalDlg的响应函数,pWnd->OnOk();在该消息中, 会 进入 ...

  8. 模态对话框和非模态对话框的消息循环分析

    1.非模态对话框和父窗口共享当前线程的消息循环 2.模态对话框新建一个新的消息循环,并由当前消息循环派发消息,而父窗口.模态对话框屏蔽了用户对它父窗口的操作,但是不是在消息循环里面屏蔽,所以给父窗口发 ...

  9. 深入理解MFC消息循环和消息泵的原理

    首先,应该清楚MFC的消息循环(::GetMessage,::PeekMessage),消息泵(CWinThread::PumpMessage)和MFC的消息在窗口之间的路由是两件不同的事情.在MFC ...

最新文章

  1. Online Learning场景下实时新闻热点机器学习训练实践
  2. grid布局浏览器兼容_CSS Grid布局尝试
  3. mysql data_add data_sub
  4. 响应式web(一):什么是响应式web,异步调用,callback的本质,servlet3的异步
  5. .NET MasterPage技术
  6. 从堆里找回“丢失”的代码相关命令简介
  7. [翻译]:怎样从C/C++代码中对C#进行回调
  8. 决策树会有哪些特性?
  9. 定了!网易CEO丁磊6月11日快手直播带货
  10. Jquery常用操作select篇
  11. FPGA的学习:TFT_LCD液晶屏字符显示
  12. php如何与微信公众平台连接失败,微信公众平台接入问题,配置失败不知道是哪的原因?...
  13. 一种简单、安全的Dota全图新思路
  14. 建立您的启动:自定义会议视图
  15. maven快速入门第十七讲——从私服下载jar包到本地仓库
  16. myeclipse+wtk环境配置
  17. [游戏开发]Unity Profiler真机调试
  18. 计蒜客 I小灰灰的笼外领地(计算多边形面积)
  19. Python 获取视频fps工具(附代码) | Python工具
  20. Item 8:析构函数不要抛出异常 Effective C++笔记

热门文章

  1. 系统学习----Linux网络管理
  2. Python基础教程(第2版)读书笔记
  3. C++生成dll及dll的调用
  4. bzoj 4398: 福慧双修(最短路建模/构造)
  5. linux内核崩溃+grub,Linux内核崩溃信息分析
  6. 计算机软件著作权法保护的内容不包括,计算机著作权保护法中的软件著作权包括哪些权限...
  7. 目录:吴恩达机器学习课后作业
  8. 利用python和Tushare自动更新A股每日数据
  9. Python量化入门(1)- 开发环境的准备
  10. 程序员就业和发展前景?