看啊,又进入一个循环! 其中有个重要的函数,PumpMessage,内容如下: BOOL CWinThread::PumpMessage() { ASSERT_VALID(this);
if (!::GetMessage(&m_msgCur, NULL, NULL, NULL)) { #ifdef _DEBUG if (afxTraceFlags & traceAppMsg) TRACE0("CWinThread::PumpMessage - Received WM_QUIT./n"); m_nDisablePumpCount++; // application must die // Note: prevents calling message loop things in ’ExitInstance’ // will never be decremented #endif return FALSE; }
#ifdef _DEBUG if (m_nDisablePumpCount != 0) { TRACE0("Error: CWinThread::PumpMessage called when not permitted./n"); ASSERT(FALSE); } #endif
#ifdef _DEBUG if (afxTraceFlags & traceAppMsg) _AfxTraceMsg(_T("PumpMessage"), &m_msgCur); #endif
// process this message
if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur)) { ::TranslateMessage(&m_msgCur); ::DispatchMessage(&m_msgCur); } return TRUE; } 如你所想,这才是MFC消息处理的核心基地[也是我个人认为的]。 GetMessage不同于PeekMessae,它是不得到消息不罢体,PeekMessage如果发现消息队列中没有消息会返回0,而GetMessage如果发现没有消息,等,直到有了消息,而且,GetMessage不同于PeekMessage,它会将消息移走[当然,PeekMessage也可以做到这点]。我想当你读了这个函数后,你应明白PreTranslateMessage函数的用法了吧[我比较喜欢在程序中充分利用这个函数]。 ::TranslateMessage(&m_msgCur); ::DispatchMessage(&m_msgCur); 将消息发送到窗口的处理函数[它是由窗口类指定的],之后的动作一直到你的程序做出反映的过程,你可以在《深入》一书中得到完美的解释。我们还是通过reurn TRUE;回到CWinThread::Run()中的Do{}while;循环。然后还是对IDLE的处理,即便刚才你的ONIDLE返回了FALSE,在这里你看到,你的程序还是有机会执行它的。然后又是利用PeekMessage检测消息队列: 如果有消息[这个消息不被移动的原因是因为它要为PumpMessage内的GetMessage所利用。]再次进入PumpMessage[叫它“消息泵”吧]。 如果没有消息,退出DO循环,但它还在FOR内部,所以又执行第一个While循环。 这是CwinThread::Run的一个执行过程。 不用担心退不出for(;;)如果你的消息队列中有一条WM_QUIT,会使GetMessage返回0,然后PumpMessage返回0而RUN()内部: if (!PumpMessage()) return ExitInstance();。
SDI就说到这,下面我来谈一下模式对话框。我分2种情况讨论: 一当你的工程以模式对话框为基础时[没父窗口,或为桌面]。 与SDI不同处在于,在应用程序类的InItInstance内部: BOOL CComboBoxApp::InitInstance() { AfxEnableControlContainer(); // Standard initialization // If you are not using these features and wish to reduce the size // of your final executable, you should remove from the following // the specific initialization routines you do not need. #ifdef _AFXDLL Enable3dControls(); // Call this when using MFC in a shared DLL #else Enable3dControlsStatic(); // Call this when linking to MFC statically #endif this->m_nCmdShow = SW_HIDE; CComboBoxDlg dlg; m_pMainWnd = &dlg; int nResponse = dlg.DoModal(); if (nResponse == IDOK) { // TODO: Place code here to handle when the dialog is // dismissed with OK } else if (nResponse == IDCANCEL) { // TODO: Place code here to handle when the dialog is // dismissed with Cancel } // Since the dialog has been closed, return FALSE so that we exit the // application, rather than start the application’s message pump. return FALSE; }
int nResponse = dlg.DoModal();一句使你的整个程序都在DoModal()内部进行。而且,你退出DoMal()时[你一定结束了你的对话框],InitInstance返回的是False,我们知道,这样,CwinThread::Run是不会执行的。 但对话框程序是在哪里进行消息处理的呢。 原来,dlg.DoModal()内部会调用CwinThread::RunModalLoop,它起到的作用和RUN()是一样的[当然内部有细小差别,请参考MSDN]!!!
第二种情况,你是在SDI[或其它]程序中调用Dlg.DoModal() 产生了一模式对话框[有父窗口].
这又是如何运作的呢? 建了这样一个工程做为例子。 SDI,在View中处理LBUTTONDOWN: MyDLg.DoModal(); MyDLg内有按钮,以惫后用.
没有显示模式对话框前,消息处理一直在Cthread::Run()中进行. 你单击后,程序执行点进入DoModal()内部的RunModalLoop,这又是一个消息处理机制. 不过DoModal()中调用RunModalLoop,前会Disable掉它的父窗口.从RunModalLoop中出来后,再 Enable它. 模式对话框和非模式对话框都是通过调用CreateDialogIndirect()产生创建对话框.那它和非模式对话框区别是什么造成的呢? 1 模式对话框将父窗口DISABLE掉. 我原以为被Disable的窗口是不接收消息的.但后来我马上发现我是错的.但,为什么你对被Disable的窗口进行KeyBorad,Mouse动作时,窗口没反映呢,我想,这可能是操作系统从中搞的鬼.我在本文一开始,就写出操作系统向窗口发送消息的过程,我想当它发现目标窗口处理Disabled状态时,不会将消息发送给它,但这不能说窗口不接收消息,其它程序[或它本身]发送给它的消息还是可以接收并处理的. 2 模式对话框本身有消息处理机制 RunModalLoop.
对以上两点加以实验. 我在我的刚才建的项目中的模式对话框中加上一个BUTTON,其中加入如下代码: OnButton1() { GetParaent()->EnableWindow(1); } 单击,后我们发现,此时它已经不再表现为”模态”,我试着点击菜单,还是会作出正常反映. 我想这此消息[对于父窗口的,如:菜单动作]的处理也应是在模式对话框中的RunModalLoop中进行处理的吧[这点我不能确定].
先写到这里吧,一点浊见.请大家批评.
2002-4-24
这篇文章对于初学windows编程以及正在使用windows编程的人来说,可以算是一篇较好的文章,在这里站长把它发表出来,供大家学习! 
说明:本教程来源互联网或网友上传或出版商,仅为学习研究或媒体推广,wanshiok.com不保证资料的完整性。
2/2 首页 上一页 1 2 |