菜鸟关于Windows消息循环的疑问

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了菜鸟关于Windows消息循环的疑问相关的知识,希望对你有一定的参考价值。

我最近刚起步学WinAPI,想利用 GDI 做一个窗口中绘制动画的程序。具体思路就是在一个死循环中先按照需求绘图,再 Sleep(100) ,实现帧频为10的动画。用代码表述如下:
while(1)
//绘制

Sleep(100);


这样子实现在控制台程序中是没有问题的,但由于Windows窗口程序有用到消息循环,机制与控制台程序不同,且这一种机制又与面向对象语言中的事件侦听有所区别,因而我不知道如何进行上述绘制。更清晰地说,就是,在
while(GetMessage(&messages, NULL, 0, 0))
TranslateMessage(&messages);
DispatchMessage(&messages);

的消息循环中,如何实现每隔100ms进行绘制?
请说明思路,最好附上源码(只是相关部分,不必复制整个程序),谢谢!
百度知道里的问题都翻遍了,没有类似的奇葩问题,因此不必多费事儿复制粘贴了

如何你在窗口函数case不返回的话这个窗口就会没响应的,你可以试试看在一个case里写Sleep(5000)

有些人已经说对了,GetMessage只负责从消息队列里面取出一条消息,TranslateMessage将键盘敲键的消息转换成WM_CHAR消息,DispatchMessage就负责调用你的窗口函数,其实相当于
... DispatchMessage(...)

....
WinSunProc(...): //事实上这里是通过你注册窗口类时候给Windows的函数指针来实现的,但是效果和直接调用一样。

现在整个流程就很清楚了,GetMessage -> DispatchMessage -> WinSunProc 然后再返回到主循环进行下一条消息的操作,如果你在WinSunProc里面一直不返回,那么程序是无法处理下条消息的。
处理消息的时候如果又有其他消息过来是没关系的,Windows的GetMessage是从消息“队列”里面去消息的,没来得处理的消息是会排队在消息队列里面的,微软说了Windows的消息队列足够长,一般不会出现消息丢失的情况,具体没说多长,可能根据操作系统版本不同有不同的长度限制。
另外GetMessage还有个特性,如果程序的消息队列是空的,也就是没有消息了,那么GetMessage就不会返回,直到等到下一条消息来再返回,Windows会将处于等待的程序转入Idle模式,所以那个while循环是不会出现CPU100%的占用率的。如果你希望在程序没有消息的时候在后台做点什么事情,那么就可以利用PeekMessage,典型的MFC就是利用了PeekMessage来运作消息循环的,PeekMessage在队列中有消息的时候则把消息取回,没消息的时候也会立刻返回,这样你就可以在没消息的时候做点别的事情。MFC的CWinApp类在Run这个函数中包含了消息循环,在没有消息的时候,Run会去调用CWinApp::OnIdle,默认的OnIdle会负责释放不需要再使用的动态连接库文件。如果Run里面的PeekMessage取到消息,他则调用CWinApp::PumpMessage函数,PumpMessage就负责调用DispatchMessage把消息转交给窗口函数。

贴下CWinApp::Run的代码:
int CWinThread::Run()

ASSERT_VALID(this);
_AFX_THREAD_STATE* pState = AfxGetThreadState();

// for tracking the idle time state
BOOL bIdle = TRUE;
LONG lIdleCount = 0;

// acquire and dispatch messages until a WM_QUIT message is received.
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));

参考技术A 定时器 、WM_TIMER消息 、SetTimer、KillTimer、
CALLBACK TimerProc 先去学会追问

我试过了,可以实现,谢谢!不过有一个问题,API 中有特定的函数清除窗口内容吗(类似于控制台的 system("cls") 与 as3.0 的 Graphics.clear())?还是说只能重新画一个窗口那么大的矩形进行覆盖呢?

本回答被提问者采纳

关于虚拟机与宿主机同网段主机互ping的一点疑问

宿主机win10(192.168.1.0/24)虚拟机win2008r2(192.168.159.0/24)使用NAT模式,宿主机和虚拟机能够互ping通,虚拟机能够ping通与宿主机同一网段的任何计算机,但与宿主机同网段的计算机却不能ping通虚拟机,不知道是为何?我是菜鸟,请各位老师能给我解释下为什么不?

本文出自 “我是菜鸟我怕谁” 博客,请务必保留此出处http://daihl1987.blog.51cto.com/8825614/1869237

以上是关于菜鸟关于Windows消息循环的疑问的主要内容,如果未能解决你的问题,请参考以下文章

Windows 消息循环 - WPF中的消息循环

windows程序消息循环机制

Windows 线程何时需要消息循环,为啥?

理解Windows消息循环机制

qt卡在消息循环

事件循环和线程没有必然关系(就像Windows子线程默认没有消息循环一样),模态对话框和事件循环也没有必然关系(QWidget直接就可以)