win32消息循环
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了win32消息循环相关的知识,希望对你有一定的参考价值。
整个循环不停的获取消息。不是太占资源了吗?
Windows系统是一个消息驱动的OS,什么是消息呢?我很难说得清楚,也很难下一个定义,我下面从不同的几个方面讲解一下,希望你看了后有一点了解。 (一些内容涉及C/C++编程知识)1、消息的组成:一个消息由一个消息名称(UINT),和两个参数(WPARAM,LPARAM)。当用户进行了输入或是窗口的状态发生改变时系统都会发送消息到某一个窗口。例如当菜单转中之后会有WM_COMMAND消息发送,WPARAM的高字中(HIWORD(wParam))是命令的ID号,对菜单来讲就是菜单ID。当然用户也可以定义自己的消息名称,也可以利用自定义消息来发送通知和传送数据。
2、谁将收到消息:一个消息必须由一个窗口接收。在窗口的过程(WNDPROC)中可以对消息进行分析,对自己感兴趣的消息进行处理。例如你希望对菜单选择进行处理那么你可以定义对WM_COMMAND进行处理的代码,如果希望在窗口中进行图形输出就必须对WM_PAINT进行处理。
3、未处理的消息到那里去了:M$为窗口编写了默认的窗口过程,这个窗口过程将负责处理那些你不处理消息。正因为有了这个默认窗口过程我们才可以利用Windows的窗口进行开发而不必过多关注窗口各种消息的处理。例如窗口在被拖动时会有很多消息发送,而我们都可以不予理睬让系统自己去处理。
4、窗口句柄:说到消息就不能不说窗口句柄,系统通过窗口句柄来在整个系统中唯一标识一个窗口,发送一个消息时必须指定一个窗口句柄表明该消息由那个窗口接收。而每个窗口都会有自己的窗口过程,所以用户的输入就会被正确的处理。例如有两个窗口共用一个窗口过程代码,你在窗口一上按下鼠标时消息就会通过窗口一的句柄被发送到窗口一而不是窗口二。
5、示例:下面有一段伪代码演示如何在窗口过程中处理消息
LONG yourWndProc(HWND hWnd,UINT uMessageType,WPARAM wP,LPARAM)
switch(uMessageType)
//使用SWITCH语句将各种消息分开
case(WM_PAINT):
doYourWindow(...);//在窗口需要重新绘制时进行输出
break;
case(WM_LBUTTONDOWN):
doYourWork(...);//在鼠标左键被按下时进行处理
break;
default:
callDefaultWndProc(...);//对于其它情况就让系统自己处理
break;
接下来谈谈什么是消息机制:系统将会维护一个或多个消息队列,所有产生的消息都回被放入或是插入队列中。系统会在队列中取出每一条消息,根据消息的接收句柄而将该消息发送给拥有该窗口的程序的消息循环。每一个运行的程序都有自己的消息循环,在循环中得到属于自己的消息并根据接收窗口的句柄调用相应的窗口过程。而在没有消息时消息循环就将控制权交给系统所以Windows可以同时进行多个任务。下面的伪代码演示了消息循环的用法:
while(1)
id=getMessage(...);
if(id == quit)
break;
translateMessage(...);
当该程序没有消息通知时getMessage就不会返回,也就不会占用系统的CPU时间。 图示消息投递模式
在16位的系统中系统中只有一个消息队列,所以系统必须等待当前任务处理消息后才可以发送下一消息到相应程序,如果一个程序陷如死循环或是耗时操作时系统就会得不到控制权。这种多任务系统也就称为协同式的多任务系统。Windows3.X就是这种系统。
而32位的系统中每一运行的程序都会有一个消息队列,所以系统可以在多个消息队列中转换而不必等待当前程序完成消息处理就可以得到控制权。这种多任务系统就称为抢先式的多任务系统。Windows95/Windows98/NT就是这种系统。 参考技术A 很通俗的讲,Win32是个多任务抢占式操作系统,每运行一个程序(可执行文件),操作系统就创建一个进程和主线程,把程序的代码和数据映射到该进程地址空间,并为每个线程分配了一个时间片,一个线程放弃CPU的处理权有、可以是时间片完了,I/O请求,还有就是程序自己要求放弃处理权,而GetMessage函数是一个阻塞函数,也就是你调用他就相当于主动放弃了CPU,引起线程上下文切换,从而其他线程可以得到CPU,但该函数会在有消息的时间激活而继续执行。如果你是获取消息用PeekMessage函数,那么你打开任务管理器,才知道什么叫做真正的浪费资源 参考技术B 还好吧,你用C++while语句写个普通的输出循环看看,我的CPU占用大概2%,内存占用200KB
MFC 中的消息循环
【中文标题】MFC 中的消息循环【英文标题】:Message loop in MFC 【发布时间】:2014-09-22 10:51:03 【问题描述】:我学过一点Win32 API,但现在想学MFC。在我的电子书中,他们说CWinApp
类管理应用程序的主线程,但我在此类中找不到类似GetMessage
、DispatchMessage
的函数。那么它如何开始消息循环呢?
请有人为我解释一下。抱歉,我是 MFC 的新手,我的英语很差。 在哪里可以找到一些关于 Visual Studio 中 MFC 的电子书/教程?
【问题讨论】:
【参考方案1】:这一切都在CWinApp:Run
部分完成。
InitInstance
返回 true 后,CWinApp:Run
启动,消息循环开始发挥作用。这个消息循环很棘手,因为它还会在应用程序无事可做时处理OnIdle
调用。
只需查看源代码。
【讨论】:
【参考方案2】:MFC 使用消息映射简化了消息处理,程序员大多不需要关心消息循环如何运行、消息如何传递以及映射消息如何映射到用户定义的函数。我建议您摆弄CWnd
派生类(如框架、对话框),并查看映射消息如何调用您的函数。
WM_MOUSEMOVE
正在调用您的 OnMouseMove,前提是您输入了一个条目 ON_WM_MOUSEMOVE
- 这很有趣,您应该会发现它是如何工作的。玩弄CWinApp
-派生类不是个好主意。
【讨论】:
【参考方案3】:MFC 有点像 Win32 上的包裹层。消息循环包含在名为 Run 的 CWinThread 成员中。应用程序类是从 CWinApp 派生的,而 CWinApp 又是从 CWinThread 派生的。此方法通常不会被覆盖。如果要读取消息循环代码,则应覆盖此方法,并且在调试时可以看到代码。它也处理空闲消息
int CWinThread::Run()
....
for (;;)
// phase1: check to see if we can do idle work
while (bIdle &&
!::PeekMessage(&(pState->m_msgCur), NULL, NULL, NULL, PM_NOREMOVE))
// call OnIdle while in bIdle state
if (!OnIdle(lIdleCount++))
bIdle = FALSE; // assume "no idle" state
// phase2: pump messages while available
do
// pump message, but quit on WM_QUIT
if (!PumpMessage())
return ExitInstance();
// reset "no idle" state after pumping "normal" message
//if (IsIdleMessage(&m_msgCur))
if (IsIdleMessage(&(pState->m_msgCur)))
bIdle = TRUE;
lIdleCount = 0;
while (::PeekMessage(&(pState->m_msgCur), NULL, NULL, NULL, PM_NOREMOVE));
【讨论】:
以上是关于win32消息循环的主要内容,如果未能解决你的问题,请参考以下文章
win32——消息循环 原理 函数 GetMessage PeekMessage TranslateMessage SendMessage PostMessage
Win32编程API 基础篇 -- 4.消息循环 根据英文教程翻译