MFC消息机制+UI线程和工作线程+模式对话框原理

本文详细探讨了MFC中的消息机制,包括队列消息和非队列消息的处理流程,以及UI线程和工作线程的区别。在UI线程中,PeekMessage()和OnIdle()函数在消息循环中的作用得以阐述。同时,文章讲解了MFC模式对话框的实现原理,指出模式对话框有自己的消息循环,并分析了其如何与父窗口交互,确保消息处理的正确性。
摘要由CSDN通过智能技术生成

消息机制

Windows程序是事件驱动,消息传递的,而消息分为队列消息和非队列消息。
1. 队列消息:
对于队列消息,最常见的是鼠标和键盘触发的消息,例如WM_MOUSERMOVE, WM_CHAR等消息,还有一些其它的消息,例如:WM_PAINT, WM_TIMER和WM_QUIT。当鼠标、键盘事件被触发后,相应的鼠标或键盘驱动程序就会把这些事件转换成相应的消息,然后输送到系统消息队列,由Windows系统去进行处理。Windows系统则在适当的时机,从系统消息队列中取出一个消息,根据前面我们所说的MSG消息结构确定消息是要被送往那个窗口,然后把取出的消息送往创建窗口的线程的相应队列,下面的事情就该由线程消息队列操心了,Windows开始忙自己的事情去了。线程看到自己的消息队列中有消息,就从队列中取出来,通过操作系统发送到合适的窗口过程去处理。
2. 非队列消息
非队列消息将会绕过系统队列和消息队列,直接将消息发送到窗口过程,。系统发送非队列消息通知窗口,系统发送消息通知窗口。 例如,当用户激活一个窗口系统发送WM_ACTIVATE, WM_SETFOCUS, and WM_SETCURSOR。这些消息通知窗口它被激活了。非队列消息也可以由当应用程序调用系统函数产生。例如,当程序调用SetWindowPos系统发送WM_WINDOWPOSCHANGED消息。

在讲消息的时候提到了系统消息队列和线程消息队列。系统中有一个系统消息队列,它由系统维护,队列消息会发到它那里,然后再发送到相应的线程消息队列里面。线程消息队列有相应的线程在维护,但并不是每个线程都有线程消息队列,仅当线程第一次调用GDI函数时系统给线程创建一个消息队列(例如MFC的UI线程)。还有消息队列是相对线程而言,而非进程。对于MFC的UI线程的线程消息队列有了消息之后,还会派送消息到消息对应窗口(消息结构体中有窗口句柄)。

参考博文:http://bbs.51cto.com/viewthread.php?tid=487054


MFC UI线程和工作线程

之前挺好奇,MFC程序的主线程一直在跑消息循环,一直在while里面,界面为什么不卡住还能响应?
这取决与PeekMessage(),OnIdle()等函数。
BOOL PeekMessage(…):该函数为一个消息检查线程消息队列,并将该消息(如果存在)放于指定的结构。和GetMessage()不一样的是,GetMessage()从线程消息队列获取消息,将消息从队列中移除,属于阻塞函数。当队列无消息时,GetMessage会等待下一条消息。而函数PeekMesssge是以查看的方式从队列中获取消息,可以不将消息从系统中移除,是非阻塞函数;当队列无消息时,返回FALSE,继续执行后续代码。
virtual BOOL OnIdle( LONG lCount ):执行空闲时间处理。不需要更多空闲时间返回0,否则返回非0。在这个空闲时间处理中将更新UI界面(比如工具栏按钮的enable和disable状态),删除临时对象(比如用FromHandle得到的对象指针。由于这个原因,在函数之间传递由FromHandle得到的对象指针是不安全的,因为他没有持久性)。在下面可以看到对传入参数lCount的处理。

后来找到下面这篇博文,主要讲MFC的UI线程和工作线程,个人感觉讲得很清晰,借助博主贴的代码,也更好地理解了消息机制。

内容转载自:http://www.cnblogs.com/carekee/articles/3160209.html

MFC的AfxBeginThread提供了两个版本:

CWinThread* AFXAPI AfxBeginThread(
    AFX_THREADPROC pfnThreadProc,
    LPVOID pParam,
    int nPriority =THREAD_PRIORITY_NORMAL,
    UINT nStackSize = 0,
    DWORD dwCreateFlags = 0,
    LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL);
CWinThread* AFXAPI AfxBeginThread(
    CRuntimeClass* pThreadClass,
    int nPriority = THREAD_PRIORITY_NORMAL, 
    UINT nStackSize = 0,
    DWORD dwCreateFlags = 0,
    LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL);

第一个版本用来让人创建“工作线程”,第二个版本让人用来创建“UI线程”。
1. UI线程
继承CWinThread->启动线程->进入CWinThread::Run()。
CWinThread::Run()的实现:

int CWinThread::Run()
{
    ASSERT_VALID(this);
    _AFX_THREAD_STATE*
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值