参看:http://wenku.baidu.com/link?url=Z9UcZPaN0lf9u4MwtkSvt4do3kCPuHISedW3CLyzXsr2uDvhZauc0ziwsYTOK_F2r_ffbnI6myevV7WxaD1WKzD8u1QYTOjh7H86rXdtkQy
在windows中一个线程只有一个消息队列(PostMessage消息队列),非模态对话框的消息在主线程的消息循环中处理,对于模态对话框,其先禁止主窗口,然后自己建立一个消息循环进行消息处理,对话框结束后,停止对话框自己的消息循环,然后enable主窗口。
所以,一个线程中只有一个消息队列(PostMessage消息队列),但是可能存在主线程消息循环外的其他局部消息循环,但是他们不会并行执行。
模态对话框与非模态对话框的内部机制区别:
非模态对话框与APP共用消息循环,不会独占用户 ;模态对话框独占用户输入,其他界面无法响应,有自己的消息循环;
模态对话框的具体实现有以下步骤:
1.让父窗口失效EnableWindow(parentWindow, FALSE);
2.建立模态对话框自己的消息循环(RunModalLoop);
3.直至接收关闭消息,消息循环终止,并销毁窗口。
具体代码:
INT_PTR CDialog::DoModal() { //对话框资源加载 ...... //在创建模态窗口之前先让父窗口失效,不响应键盘、鼠标产生的消息 HWND hWndParent = PreModal(); AfxUnhookWindowCreate(); BOOL bEnableParent = FALSE; if (hWndParent && hWndParent != ::GetDesktopWindow() && ::IsWindowEnabled(hWndParent)) { ::EnableWindow(hWndParent, FALSE); bEnableParent = TRUE; ....... } //创建模态窗口,并进行消息循环,若窗口不关闭,则循环不退出 AfxHookWindowCreate(this); VERIFY(RunModalLoop(dwFlags) == m_nModalResult); //窗口关闭,销毁窗口 DestroyWindow(); PostModal(); //释放资源,并让父窗口有效 pMainWnd->EnableWindow(TRUE); //返回 return m_nModalResult; }
int CWnd::RunModalLoop(DWORD dwFlags) { //要检查窗口状态是否是模态窗口 //若状态一直为模态,则一直进行消息循环 for (;;) { ASSERT(ContinueModal()); // phase1: check to see if we can do idle work while (bIdle &&!::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE)) { ASSERT(ContinueModal()); // show the dialog when the message queue goes idle if (bShowIdle) { ShowWindow(SW_SHOWNORMAL); UpdateWindow(); bShowIdle = FALSE; } // call OnIdle while in bIdle state if (!(dwFlags & MLF_NOIDLEMSG) && hWndParent != NULL && lIdleCount == 0) { // send WM_ENTERIDLE to the parent ::SendMessage(hWndParent, WM_ENTERIDLE, MSGF_DIALOGBOX, (LPARAM)m_hWnd); } if ((dwFlags & MLF_NOKICKIDLE) ||!SendMessage(WM_KICKIDLE, MSGF_DIALOGBOX, lIdleCount++)) { // stop idle processing next time bIdle = FALSE; } } //在有消息的情况下取消息处理 do { ASSERT(ContinueModal()); // pump message, but quit on WM_QUIT if (!AfxPumpMessage()) { AfxPostQuitMessage(0); return -1; } // show the window when certain special messages rec'd if (bShowIdle &&(pMsg->message == 0x118 || pMsg->message == WM_SYSKEYDOWN)) { ShowWindow(SW_SHOWNORMAL); UpdateWindow(); bShowIdle = FALSE; } if (!ContinueModal()) goto ExitModal; // reset "no idle" state after pumping "normal" message if (AfxIsIdleMessage(pMsg)) { bIdle = TRUE; lIdleCount = 0; } } while (::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE)); } ExitModal: m_nFlags &= ~(WF_MODALLOOP | WF_CONTINUEMODAL); return m_nModalResult; }
//thrdcore.cpp // main running routine until thread exits int CWinThread::Run() { // for tracking the idle time state BOOL bIdle = TRUE; LONG lIdleCount = 0; //消息读取乃至分发 当为WM_QUIT时,退出循环 for (;;) { //检查是否为空闲时刻 while (bIdle &&!::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE)) { // call OnIdle while in bIdle state if (!OnIdle(lIdleCount++)) bIdle = FALSE; // assume "no idle" state } //有消息,读消息并分发 do { // pump message, but quit on WM_QUIT if (!PumpMessage()) return ExitInstance(); // reset "no idle" state after pumping "normal" message if (IsIdleMessage(&m_msgCur)) { bIdle = TRUE; lIdleCount = 0; } } while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE)); } }
当模态对话框显示时,进入模态对话框的消息循环,除非将模态对话框关闭,否则APP的DispatchMessage函数一直出不来。