CxxxDlg::OnTimer(UINT nIDEvent)
{
static int i = 0,j;
j = i++;
if (i==2) KillTimer(nIDEvent);
MessageBox("!");
i++;
CString str;
str.Format("%d,%d ",j,i);
::OutputDebugString(str);
}
以上代码在执行的时候,会弹出2个messagebox。很多人都有1个疑问,那就是当第一个消息框弹出的时候,应该相当于是模态对话框,怎么还会第二次进入OnTimer,并且再次弹出messagebox?
首先,让我们来了解一下计时器的原理。计时器可以响应事件,而用户界面也可以响应。但是程序却只有一个线程。CPU不得不分配一个时间片给应用程序专门处理定时器事件,应用程序不能在外面操作定时器。因为定时器处理是由CPU统一处理。
让我们再来看看常见模态对话框的domodal到底干了些什么。MSDN解释如下:
The function displays the dialog box , disables the owner window, and starts its own message loop to retrieve and dispatch messages for the dialog box.
When the dialog box procedure calls the EndDialog function, DialogBoxParam destroys the dialog box, ends the message loop, enables the owner window 。
所以这里只是【Disables the owner window】,所以主窗口中的定时器等都可以正常运行,只是无法响应用户的操作了。
好,以上就解释了OnTimer还是定时响应的,问题的另一个关键是怎么第二个messagebox还能弹出来?
原来,当你在主消息循环的消息处理函数中弹出一个模态对话框,他阻塞了主消息循环,理论上,这时可以把主窗口关闭了!但是因为这个弹出的模态对话框还在,它阻塞了winmain这个主消息循环,实际上你是关不掉的。注意,阻塞的实际意思是说:消息被模态对话框处理了,而没有传到后面的父窗口。而每次弹出对话框,都是由最上层的那个消息框掌握着消息循环,其他的消息循环被阻塞了。
所以,上面代码运行的情况是:
(1)弹出第一个messagebox,然后后续代码暂停执行。
(2)第二次进入OnTimer
(3)弹出第二个messagebox接替消息循环,第一个messagebox禁用。后续代码暂停执行。
(4)用户点击第二个messagebox。此时显示结果,i = 3,j=1;再次,点击第一个messagebox,此时显示结果,i=4 ; j=0