代码改变世界

噢,我的第一个基于SDK的窗口(续)

2004-09-10 23:59  FantasySoft  阅读(...)  评论(...编辑  收藏

        首先,我要自我检讨一下,在学习的过程对于细节问题没有足够的重视,以致于忽视了问题产生的根源,同时也对自己解决问题的方法感到惭愧。期待自己能够尽快改正这些缺点,取得更大的进步。
        我想,通常一个问题存在的原因不仅仅是单个方面的,它有可能是多个因素共同影响产生的结果。在面对问题的时候,应该冷静下来列举出导致问题发生的几种可能性,接着逐个排除,如果可能性都排除之后,就接着再列举可能性,如此反复,直至发现根本原因为止。
        举一个最近的例子吧,今天大半天的时间都在学习如何利用Windows SDK的API去创建一个窗口,遇到了不少的问题,最后需要解决的就是在点击了关闭按钮之后,窗口消失了但是进程中仍然存在该应用程序的问题。上一篇blog中给出了解答,而这个解答对于那篇blog中的代码而言是正确的,因为那里的代码是第二个版本。然而,这个解答对于我的第一个版本的代码是不起作用的,大家可以先看一下第一个版本代码的关键部分:

for (;;)
{
 
if  (PeekMessage( & msg,hwnd, 0 , 0
,PM_REMOVE))
    

       
if  (msg.message  ==
 WM_QUIT)
           
break
;   
    TranslateMessage(
&
msg);  
    DispatchMessage(
&
msg);
    }
 
}


在这样消息处理的基础上,虽然我在处理消息的回调函数中,增加了处理WM_DESTROY消息的代码,仍然是没有将问题解决的。当时我查阅了很多资料,都没有找到答案,后来找到了一个与自己代码十分相近的例子,然后在其基础上进行修改,结果就成为了我的第二版本的代码。而第二版本的代码则是可以工作得很好。尽管我写下了创建一个基于SDK窗口的体会,但是这个问题依然让我觉得如梗在喉。由于两个版本的代码在结构上都是类似的,我几乎找不到代码的问题出在哪里。最后只能祭出每行代码对比的法宝了,真丢脸啊!还好代码比较短,我很快就发现了差别所在,问题的所在。
        问题就出在PeekMessage函数的第二个参数上。第一个版本是hwnd,就是被创建的窗体的句柄,而第二个版本则是NULL。这个参数如果指定了某个窗口的句柄,函数就只会在消息队列中取出发送至该句柄对应的窗体的消息,如果指定为NULL,则没有这个限制。当发现了这个差别之后,问题的原因也就很明显了。如果是在其他的消息处理过程中,两者的区别并不大,但是如果在点击了关闭按钮之后, 在DestroyWindow函数被调用了之后,窗口句柄hwnd就不复存在了。如果PeekMessage函数指定了窗口句柄,又如何能够得到由DestroyWindow方法发送至消息队列的WM_DESTROY消息呢?因此,只有将第二个参数设为NULL,才能得到WM_DESTROY消息并在回调函数中进行处理了。
        最后回头总结一下,其实自己在看API的时候,也有注意到PeekMessage方法的参数,却没有放在心上,以致于在解决问题的时候出此下策,真是惭愧啊!Anyway,问题解决了,就是好事。我会继续努力的,不仅是技术积累,更加重要的是思维方式的提高。