如果你决定显示一个模态化界面,则要当心了:一定要设置正确的所有者窗口(Owner Window)。如果你不注意这个规则,你发发现自己一直被一些非常奇怪的Bug所困扰。
让我们回到我们的例子程序,并故意设置错误的所有者窗口,看看将会发生什么。
运行这个程序,按空格键,这个时候会显示一个模态对话框,然后单击主窗口右上角的的关闭按钮。 请注意,在程序退出之前你会听到扬声器的声音。
为什么会这样?
扬声器的声音来自我们对 MessageBeep 函数的调用,它反过来告诉我们我们的窗口句柄不再有效。 在一个将其状态保存在每个窗口实例变量中(而不是像我们那样保存在全局变量中)的实际程序中,程序更有可能崩溃,因为当窗口被销毁时所有实例变量都会消失。 在这种情况下,窗口在嵌套模式循环中被**。 结果,当控制权返回给调用者时,它现在是一个在已被销毁的对象内运行的方法。 对实例变量的任何访问都将访问已释放的内存,从而导致内存损坏或彻底崩溃。
下面我看看程序的调用堆栈:
清理窗口时,通常会**与窗口关联的所有数据结构。 但请注意,你正在释放堆栈深处的 OnChar 处理程序仍在使用的数据结构。 最终,控制回到 OnChar,它现在使用无效的实例指针运行。 (如果你相信 C++ 对象,你会发现它的“this”指针已经失效。)
问题的原因在于:没有正确的为模态化的 MessageBox 调用设置正确的所有者窗口,从而允许用户在框架窗口不希望其状态发生更改时与框架窗口进行交互。
更糟糕的是,用户可以切换回框架窗口并再次按下空格键。 结果:另一个消息框。 再重复一次,你最终会**一个看起来像这样的堆栈:
现在有四个顶级窗口,都处于活动状态。 如果用户以与创建它们相反的顺序以外的任何顺序关闭它们,那么就会遇到问题。 例如,如果用户首先关闭了第二个消息框,则当第三个消息框最终关闭时,对应于该嵌套级别的堆栈部分将最终返回到已销毁的窗口。
总结
问题出现了,该如何解决。请听下回分解。
最后
Raymond Chen的《The Old New Thing》是我非常喜欢的博客之一,里面有很多关于Windows的小知识,对于广大Windows平台**者来说,确实十分有帮助。本文来自:《Modality, part 4: The importance of setting the correct owner for modal UI》