遭遇Windows消息循环

今天跟同事联调一段代码,被一个问题郁闷了很久。

调用过程其实并不复杂,就是他提供一个Dll,并输出一个函数(姑且叫做Foo()吧),我调用他的函数Foo,其内部产生一个窗口。但是,我每次调用,窗口总是一闪而过!我们于是怀疑,是不是因为主程序是console,不支持MFC的缘故?要不然一定是因为不是在主线程里调用的缘故?!又是多线程,真是麻烦!

反复测试,结果如下

                 MFC对话框Win32      MFC Console
多线程             失败                         失败
单线程             成功                         失败

为什么?难道就不能在普通线程里创建窗口吗?什么是主线程(UI线程),什么又是工作线程?以前认为理所当然的事情,现在突然变得很模糊!

开始把目光锁定到消息队列上!是不是因为主线程有消息队列?比如MFC对话框程序就有消息队列,而Console没有。但是,同样是线程,为什么你有而我没有?难道是WinMain函数和普通的main函数不一样?到底消息队列是什么时候产生的?

草草浏览了CWinApp的代码,也没有找到答案。这时候,隐约想起了《Windows核心编程》里说的,系统在你第一次调用相关函数的时候,自动为线程创建消息队列!但是,到底是什么函数呢?

带着这个郁闷回到了家,打开那本Windows编程宝典,翻到消息队列一章。原来,每个窗口归属于创建它的线程。一旦线程退出,窗口也将自行销毁!另外,线程还要进行消息循环,以分发窗口的消息!注意,消息循环是由线程负责的!线程刚开始创建的时候是不带消息队列的,当线程第一次调用窗口相关的函数时,操作系统自动为其创建消息队列!原来,窗口的消息队列是归属于线程的!

问题终于搞清楚了,在普通的工作线程里,我们没有消息循环,所以创建出来的窗口还没有没有机会显示出来,线程就结束退出了!即使在console程序里,通过cin.get()让程序等待,窗口还是没有机会刷新(依赖消息循环分发并调用消息处理函数)而一直处于忙碌等待状态!而前面的Foo函数,恰恰要依赖于消息循环!

知道问题的真正原因后,就很容易解决了!在调用同事的函数产生窗口后(函数返回了),在同一个线程里进行消息循环!如下

...in a working thread...

Foo();   //call some function

while (GetMessage(&msg, NULL, 0, 0))
{
    if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

...working thread exit...

问题迎刃而解!你看不是MFC的问题,也不是不能在工作线程里创建窗口。本来,我一开始就怀疑,这么依赖MFC,总不能让主程序都是MFC程序吧!作为一个DLL组件,不能对调用者有太多的限制!而多线程,太寻常了,如果都在主线程里做,那也太难模块化了吧!当然了,现在说这些都是马后炮,当时郁闷的时候,什么古怪的理由都用上了!

其实,这个问题本来可以解决得更快点的。如果同事事先说明他的Foo函数何时返回(我一直以为它要一直阻塞到其产生的窗口关闭才返回的,结果并不是这样的,窗口一产生它就返回了),以及是否需要依赖外部的消息循环(他是有提过,但也很模糊,搞不清具体为什么)。当然,最大的原因还是因为大家对Windows的消息循环机制理解得不是很深入!

现在你搞明白Windows的消息循环到底是如何进行的了么?
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值