今天工作不忙,想起几年前一个同事提起的一个关于MessageBox的问题,其实你们可以理解成是模式对话框的问题或者说是对话框消息处理机制的问题,问题描述如下:1、MessageBox并不会创建新的线程(可以用任务管理器证实)
2、调用MessageBox会阻挡程序进一步执行,从代码上看是起到堵塞的作用(写过程序的人都知道)
3、MessageBox并不会影响消息循环(程序代码上虽然“堵塞”,但窗口并没有失去响应)
4、MessageBox并不会释放CPU时间(如Sleep之类)(程序没失去响应)
5、MessageBox可以同时弹出多个(使用一些手段就很容易做到)那么:
1、MessageBox如何实现对代码的堵塞?
2、如果弹出多个MessageBox,是不是可以算多重堵塞?而这个堵塞明显和WaitForSingleObject是不同的。(并没有释放CPU资源)
3、如果说模式对话框接管了父窗口的消息处理权,那么我可以强制Enable父窗口,父窗口其实还是有响应的,那这个“堵塞”究竟堵塞的是什么?
4、windows内部如何实现这个机制?恳请大家用心思考,用心回答。BTW:对csdn.net没有专门的Windows编程讨论专区表示抗议,对csdn.net把VC和MFC混为一体表示抗议。
2、调用MessageBox会阻挡程序进一步执行,从代码上看是起到堵塞的作用(写过程序的人都知道)
3、MessageBox并不会影响消息循环(程序代码上虽然“堵塞”,但窗口并没有失去响应)
4、MessageBox并不会释放CPU时间(如Sleep之类)(程序没失去响应)
5、MessageBox可以同时弹出多个(使用一些手段就很容易做到)那么:
1、MessageBox如何实现对代码的堵塞?
2、如果弹出多个MessageBox,是不是可以算多重堵塞?而这个堵塞明显和WaitForSingleObject是不同的。(并没有释放CPU资源)
3、如果说模式对话框接管了父窗口的消息处理权,那么我可以强制Enable父窗口,父窗口其实还是有响应的,那这个“堵塞”究竟堵塞的是什么?
4、windows内部如何实现这个机制?恳请大家用心思考,用心回答。BTW:对csdn.net没有专门的Windows编程讨论专区表示抗议,对csdn.net把VC和MFC混为一体表示抗议。
你会发现一点问题都没有,界面的“模式”,只是把父窗口Disable掉。
debehe 说的对。
楼主说的EnableWindow(false)掉主窗口也对,因为windows确实就是这么做的,不过这个和主线程的消息循环被阻塞掉没有冲突。
从代码上看,就是调用messagebox的函数没有返回,主线程还在等待该函数的返回。
先只是禁父窗口 , 进入自己的消息循环, 鼠标的输入消息 是被发送到具有光标的窗口中的,当然了键盘也是(键盘输入焦点),
如果, EnableWindow(hwndParent, TRUE)了, 只是不再禁用父窗口了,就成了一种 非模态窗口
先只是禁父窗口 , 进入自己的消息循环, 鼠标的输入消息 是被发送到具有光标的窗口中的,当然了键盘也是(键盘输入焦点),
如果, EnableWindow(hwndParent, TRUE)了, 只是不再禁用父窗口了,就成了一种 非模态窗口每个窗口都有自己的消息循环 ,(由于禁父窗口 键盘和鼠标的捕获),是我们以为 “阻塞的是原始的消息循环,但是被对话框的消息循环接替"其实, 你是你 , 他是他,
我对胡柏华说的有点疑问。函数在同一个线程中是无法“重入”的,因为在没有从函数返回之前无法进行下一次调用。正因为如此,如果线程在某个点上停住后(调用SleepEx,MsgWaitForMultipleObjectsEx等把控制权交还给内核不算停住),该线程会阻塞无法响应消息,看起来就是“死掉了”。这也是MsgWaitForMultipleObjectsEx等函数存在的原因,当线程运行时,你是无法调用该线程另一个函数的,MsgWaitForMultipleObjectsEx等函数就是给系统机会在本线程中运行一个回调函数。
对这个问题我的理解是这样的:
windows的消息是在各个窗口间流动的,父窗口和子窗口在同一个线程中,系统发给线程的消息它们都可以选择处理或者放弃。但是一旦进行了处理,在处理未结束时是不能接受新的消息的。另一个帖子所说的Timer问题,其实Timer仅仅是另一种消息而已,跟OnCommand(ID_MYMENU)没什么不同。当弹出对话框后,大部分消息是由对话框处理了,而父窗口选择丢弃消息,所以父窗口表现为"disabled"。但是一旦遇到Timer消息,父窗口不传递给对话框,而是自行处理。程序就再这样的接收消息-〉分发消息-〉处理消息-〉返回控制权给系统的循环中进行。
我没做过试验,所以我说的不是100%可靠,不过试验很简单,set一个Timer,在Timer中不断向一个文件写入当前时间。弹出一个对话框,你应该能发现时间还是不断更新的。然后再试试让对话框的一个消息响应函数进入死循环,你会发现时间不再更新。等我有空的时候再试试看吧。
递归函数调用就是一个最典型的函数重入,在函数体内再次调用本函数。只要函数堆栈不溢出,你可以一直递归下去。消息循环跟这个原理是一样的。可以这样做试验:不停向主窗口发送同一个消息,每个消息弹出一个模式对话框,当积累到一定次数时,会发生堆栈溢出报错。Sleep/Wait...之类的函数导致的是线程的阻塞,但是消息循环并未阻塞线程执行,而是一直在运行代码,当然GetMessage调用会阻塞线程,但PeekMessage不会,但是只要有消息存在,就能假设线程阻塞是不存在的。
1主线程调用getmessage()接收消息wm_user1,并调用窗口函数,窗口函数根据消息调用处理函数on_dealuser1();
2该消息wm_user1的处理函数on_dealuser1()引发了一个messagebox(),由于messagebox没有返回,所以on_dealuser1()不会返回,所以窗口函数不会返回,所以主线程的getmessage()不会返回!
3messagebox又有一个getmessage(),负责接收消息;
4如果这时又来了一个wm_user1消息给主窗口,那么:messagebox的getmessage()会负责接收这个消息,并派发给主线程的窗口函数,这时on_dealuser1()又会被调用!
那么on_dealuser1()就被重入了!
等有空做一下实验看看