《Windows程序设计》第三章学习心得(1)|图解消息机制

注释:文章转载自如鹏网论坛,版权归原作者所有。

为了绘制下面那张所谓“Windows消息循环流程图”,忙活了一下午!先给表扬一下自己(吼吼~画得还蛮好看的嘛!),再泼桶冷水(呃~乱七八糟地塞了一堆条条框框,没被消息循环搞昏就先被这图搞晕了!)


        OK,不说废话,慢慢切入正题!


    最近读完《Windows程序设计》第三章,把书上的“HelloWin”代码敲了两遍,又查阅了一些参考资料,前后改了4个版本。这一来二去的,算是对Windows程序的运行机制(主要是消息处理)有了一点点小小的认识。为了对所学知识进行巩固,为了与各位鹏友互通有无,为了维护世界的和平,为了&@#$(不好意思,突然想到《宠物小精灵》),特地写了这篇学习心得,也算是对上一篇的延续吧!

    正如书中所讲,“Windows编程的难点”在于“Windows程序所做的一切都是响应发送给窗口过程的消息”。对于我们这些刚从单纯的控制台出来,一跃进入WIN32多彩世界的孩子们来说,未免让人眼花缭乱,以至于头冒金星,乱了方寸。

    学习这一章中最为重要的,我想莫过于理解消息处理机制。为此我双眼死盯着书中第61页最后一段话。猛查找了不少资料,做了不少试验,还特地绘了张“Windows消息循环流程图”。下面同各位鹏友分享一下这张花了我一下午功夫的流程图。

 

《Windows程序设计》第三章学习心得(1)|图解消息机制_第1张图片


注:这是小图版,大图版在文章下方可以下载!

    此前在网上找到了几张老外绘制的流程图,由于过于简洁,以至于很多细节没有体现。这么一来这些流程图很难解决我的一堆疑问。小小的失望之后我又振奋了起来!于是继续猛搜资料,跟随做了一系列试验。哈哈,皇天不负有心人,终于让我得到了较为满意的答案。


    然而,仅仅仅停留于这些答案之上并不能让我满足。我想,我需要再做点什么事情,以使我今后的人生更有意义(扯远了)。继而又突发奇想,结合了几张流程图的特点,再加上从这些参考资料上得到的答案,另外绘制出了这张“Windows消息循环流程图”。

    这图画得可能些许花哨,咋一看可能有点晕乎。别怕,我画它的目的不是让大家精神恍惚的。先别纠结,让我结合这张流程图同各位鹏友分享一下我对消息处理的一点小小的认识。

    有Charles Pezold的《Windows程序设计》这本书的鹏友可以翻开第61页,看到最后一段。只有电子版的鹏友可以在“窗口和消息”-“Windows程序设计的难点”里的“别呼叫我,我会呼叫你”的最后一段找到。

    下面把这段话给贴出来:


“有时候,DefWindowProc处理完消息后会产生其它的消息。例如,假设使用者执行HELLOWIN,并且使用者最终单击了 Close按钮,或者假设用键盘或鼠标从系统菜单中选择了 Close, DefWindowProc处理这一键盘或者鼠标输入,在检测到使用者选择了Close选项之后,它给窗口消息处理程序发送一条WM_SYSCOMMAND消息。WndProc将这个消息传给DefWindowProc。DefWindowProc给窗口消息处理程序发送一条WM_CLOSE消息来响应之。WndProc再次将它传给DefWindowProc。DestroyWindow呼叫DestroyWindow来响应这条WM_CLOSE消息。DestroyWindow导致Windows给窗口消息处理程序发送一条WM_DESTROY消息。WndProc再呼叫PostQuitMessage,将一条WM_QUIT消息放入消息队列中,以此来响应此消息。这个消息导致WinMain中的消息循环终止,然后程序结束。”
(订正:“DestroyWindow呼叫DestroyWindow”改为“DefWindowProc呼叫DestroyWindow”。)


    我的流程图便是根据文中关闭窗口这个操作绘制的。下面详谈一下我对这段话的理解。




    首先,用鼠标左键点击窗口的关闭按钮。于是我们看到窗口在桌面上消失了。仅仅停留于这层认识当然不是我们这些Windows程序设计学习者所能容许的。至少还需要了解在这个短暂的瞬间都发生了什么微妙的变化!让我们一起体验“第一次亲密接触”吧!

    在此瞬间,Windows检测到鼠标左键的点击事件。从书本第62页“3.2.2进队消息与不进队消息”第四段获悉,Windows将鼠标左键点击产生的消息(WM_LBUTTONDOWN)送入了消息队列。

    接着,应用程序的消息循环利用GetMessage函数,将msg消息结构的指针传递给Windows,让Windows对msg这个结构进行数据填充。而这个“数据填充”的过程就是所谓“从消息队列中取出消息”的过程。(是不是有点像山里用竹子做成的“自动引水”设备。想象一下,水流啊流,水车转啊转,水一瓢接着一瓢往山下送。)

    接到消息后,TranslateMessage函数对这个消息进行一些处理。从书上得知进行一些键盘转换处理。咱们暂且不管它都干了些什么勾当,这不是第三章要告诉我们的。(下一篇心得会讲到我改造的HelloWin,里面有稍微涉及到这个知识。)

    TranslateMessage函数干完活回家后(返回),DispatchMessage函数又将这个msg结构传给Windows。然后就要进行一步很有意义的动作啦。Windows把这个msg结构传给适当的窗口过程进行处理。也就是传递WM_LBUTTONDOWN消息给窗口过程。而msg结构里存储着WM_LBUTTONDOWN消息及其相关参数。同咱日常生活一样,信不能乱送,得放到信封里,填上姓名、地址、邮编等等,还要贴上邮票。

    瞧瞧,Windows是不是像个勤劳尽职的杂工:负责把咱们写好的信收拾好(放入消息队列),等邮递员(GetMessage)来了,得把信纸装成一封一封的信件交给他。当邮局对信件进行审核盖章(TranslateMessage的工作)并分发(DispatchMessage也是个邮递员)到各个私人信箱后,Windows还得挨家挨户去帮人家取信件,并转交给各户的管家(窗口过程WndProc)。真是尽职尽责,佩服,在此向Windows鞠个躬。

    在流程图中并没有提到WM_LBUTTONDOWN消息,其中有两个原因:一个是第三章里没有提到这个消息的处理。HelloWin的窗口过程WndProc中没有处理这个消息的代码。(WndProc不处理这个消息,而是把它交给DefWindowProc来处理。)另外,WM_LBUTTONDOWN并不是关闭窗口的特定消息。DefWindowProc只是通过从该消息的msg结构的POINT成员结构中获取鼠标焦点,来判断鼠标是否在关闭按钮上点击。

    DefWindowProc对这一鼠标点击进行处理。在检测到我们点击了关闭按钮后,它给WndProc发送一条WM_SYSCOMMAND消息。

1

    其实DefWindowProc并没有把消息直接发送给WndProc。我们知道很多事情都是由我们勤劳的Windows来做,这边也不例外,WM_SYSCOMMAND消息是通过Windows间接发送给WndProc的。(再次鞠躬)

    同上面处理WM_LBUTTONDOWN消息大同小异。Windows将WM_SYSCOMMAND消息(流程图——消息①)放入消息队列中。(终于可以一边看文字一边参照流程图了!由于流程图中有标注,因此有些细节在后面不再详谈。)

    GetMessage从消息队列中取出WM_SYSCOMMAND消息。经过TranslateMessage和DispatchMessage后,再由Windows将其发送给WndProc。WndProc不处理,又将其传给DefWindowProc。DefWindowProc接收到WM_SYSCOMMAND消息后,同样通过Windows间接发送一条WM_CLOSE消息(流程图——消息②)给WndProc。

    实际上DefWindowProc接收到WM_SYSCOMMAND消息后还需判断是否为关闭窗口。即做类似“wParam & 0xFFF0 == SC_CLOSE”这样的判断,条件成立才发送WM_CLOSE消息。(参考资料:在WM_SYSCOMMAND消息中,wParam参数的4个低位是Windows内部实用的。当应用程序检测到wParam的值时,它必须通过AND操作来将0xFFF0与wParam值相与,以便得到正确结果。)这个我们暂且不去理会,保留一些脑细胞继续往下看。我会在下一篇学习心得里涉及到一点点这个知识。

2

    WndProc还是不处理WM_CLOSE消息,再次将它传给DefWindowProc。DefWindowProc调用DestroyWindow函数来响应这条WM_CLOSE消息。在此期间,DestroyWindow对窗口进行一系列的销毁工作,并通过Windows给WndProc发送一条WM_DESTROY消息(流程图——消息③)。于是我们发现桌面上的那个窗口消失了,而在这弹指一挥间,该应用程序其实还没有结束。(下篇学习心得会演示出来。)

3、处理WM_DESTROY消息

    WndProc中终于有WM_DESTROY消息的处理代码了。WndProc调用PostQuitMessage函数,将一条WM_QUIT消息(流程图——消息④)放入消息队列中。此刻PostQuitMessage不等WM_QUIT消息是否被处理便立即返回。(嘿嘿,它忙着逃命去啦,因为我们的应用程序要完蛋了!)

4

    GetMessage从消息队列中取出WM_QUIT消息并返回0值,导致消息循环终止。紧接着整个应用程序结束运行并返回Windows。由于此前取出消息后GetMessage返回的都是非0值,故一直执行消息循环。

    OK,汇报完毕!

    看完了汇报是不是对消息处理机制有了进一步的认识?是不是开始蠢蠢欲动,想从中做些手脚来满足一下未脱的搞怪心理?
、终止消息循环,结束程序,返回Windows
、处理WM_CLOSE消息
、处理WM_SYSCOMMAND消息
0、鼠标左键点击窗口关闭按钮

消息处理

 

你可能感兴趣的:(windows,程序设计,机制,图解,学习心得)