再次F11进入:
int CWinThread::Run()
{
ASSERT_VALID(this); // for tracking the idle time state
BOOL bIdle = TRUE;
LONG lIdleCount = 0; // acquire and dispatch messages until a WM_QUIT message is received.
for (;;)
{
// phase1: check to see if we can do idle work
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
} // phase2: pump messages while available
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));
} ASSERT(FALSE);  // not reachable
}BOOL CWinThread::IsIdleMessage(MSG* pMsg)
{
// Return FALSE if the message just dispatched should _not_
// cause OnIdle to be run.  Messages which do not usually
// affect the state of the user interface and happen very
// often are checked for. // redundant WM_MOUSEMOVE and WM_NCMOUSEMOVE
if (pMsg->message == WM_MOUSEMOVE || pMsg->message == WM_NCMOUSEMOVE)
{
// mouse move at same position as last mouse move?
if (m_ptCursorLast == pMsg->pt && pMsg->message == m_nMsgLast)
return FALSE; m_ptCursorLast = pMsg->pt;  // remember for next time
m_nMsgLast = pMsg->message;
return TRUE;
} // WM_PAINT and WM_SYSTIMER (caret blink)
return pMsg->message != WM_PAINT && pMsg->message != 0x0118;
}
这是SDI处理消息的中心机构,但请注意,它觉对不是核心!
分析一下,在无限循环FOR内部又出现一个WHILE循环
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
}
这段代码是当你程序进程的消息队列中没有消息时,会调用OnIdle做一些后备工作,
临时对象在这里被删除。当然它是虚函数。其中的PeekMessage,是查看消息队列,如果有消息返回TRUE,如果没有消息返回FALSE,这里指定PM_NOREMOVE,是指查看过后不移走消息队列中刚刚被查看到的消息,也就是说这里的PeekMessage只起到一个检测作用,显然返回FALSE时[即没有消息],才会进入循环内部,执行OnIdle,当然了,你的OnIdle返回FLASE,会让程序不再执行OnIdle。你可能要问:
当bidle=0或消息队例中有消息时,程序又执行到哪了呢? 
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));看啊,又进入一个循环!
其中有个重要的函数,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中进行处理的吧[这点我不能确定].先写到这里吧,一点浊见.请大家批评.
CSDN烤鸡翅膀
2002-4-24

解决方案 »

  1.   

    另外,文章有个技术专区,专门处理这些技术文章:一般这样的文章都在那里:
    http://www.csdn.net/develop/那边对文章的限制更少。可以贴图。
      

  2.   

    还有待深入!----------------------------*****------------------------------------
    没讲清楚原来SDK下的窗口过过程函数与MFC消息路由及映射之间的关系,或者说是联系!
      

  3.   

    to  cline(营营) :
    我想《深入浅出》一书已经有了相关内容。
      

  4.   

    TO mahongxi(烤鸡翅膀)(色摸):它只提了用一个全局函数来摸拟消息引发。但这在MFC中对应于何物,好像没提到过!
      

  5.   

    正准备学VC++~书都买好了~侯老师的三本书~Effictive、Essential、深入浅出~
    从"我首先简要谈一下SDI,然后会花更多文字描述模式对话框"里开始就看不懂了~
    不过要收藏~
      

  6.   

    TO rivershan(笨猫)
    我再向你疯狂推荐:
    <深度探索C++对象模型>
      

  7.   

    我想问一下,如果我创建一个非模态对话框后,他的父窗口是disable还是able,我此时发到父窗口的消息,会不会及时得到响应,比如单击右键这样的动作。
    我试验的结果是我单击许多此右键后,他才响应一次,很随机,不能说他不相应,但响应很迟钝。
    能帮我解释一下为什么吗,怎样解决这个问题呢?
      

  8.   

    to cyh_enigma:
    如果显示非模式对话框,那么它的父窗口是Enabled的。
    会得到及时响应。
    实现:
    void CEx07aView::OnRButtonDown(UINT nFlags, CPoint point) 
    {
    // TODO: Add your message handler code here and/or call default
    static int i = 0;
    CClientDC dc(this);
    CString str;
    str.Format("%d",i++);
    dc.TextOut(0,0,str);
    }随机性是由于产生RBUTTONDBCLICK造成的。
    你可以:
    void CEx07aView::OnRButtonDblClk(UINT nFlags, CPoint point) 
    {
    // TODO: Add your message handler code here and/or call default
    this->OnRButtonDown(nFlags,point);
    }
    再试试。
      

  9.   

    怎么让Static text的文字可以连接到WEB页?诚心求教,呵呵
      

  10.   

    nie173(〖拒绝〗)
    一般的做法是派生出自己的CYouStatic
      

  11.   

    to mahongxi:
    谢谢,明白了。你的文章对我非常有启示,希望今后还能看到类似的文章。
    再问一下
    窗口是否disable是不是模态对话框与非模态对话框的主要区别?
      

  12.   

    To: mahongxi (烤鸡翅膀)(色摸) 在这里看到很多人讲学习VC++要弄懂win api/c++/mfc
    现在我已经看过的书有:一本大学里C++的教程,几要VC方面的入门书,正在看<深入浅出mfc>。
    C++的教程好象只教给我最基本的C++知识,在我使用VC的时候有一点帮助,但我觉得它讲得浅了,有没有更深入一点的书?还有就是win api 该如何入手呢?请帮助推荐几本好书在windows系统里编程我应该具备怎样的基础?
      

  13.   

    To  meinmei(军军) :
    如果你已经对C++有了一定的认识,
    想更深入的了解其内部细节,
    我推荐《深度探索C++ 对象模型》至于API我也没有专门的学习过,但这方面的资料很多。你在Message中说主要想进行数据库软件开发,
    虽然VC对有强大的数据库支持但我更倾向于推荐你学习Delphi.
      

  14.   

    to  cyh_enigma(迷) :
    窗口是否disable是模态对话框与非模态对话框的区别之一,
    之所以表现出的“模式”也是由它决定的。但是不是主要区别,
    这个我不敢下定论。
      

  15.   

    To: mahongxi (烤鸡翅膀)(色摸)    我建议你出书,你写的鄙夷胁破书强多了!!希望你多写一些!!!
      :)
      

  16.   

    To: mahongxi (烤鸡翅膀)(色摸)    我建议你出书,你写的比有些破书强多了!!希望你多写一些!!!
      :)  刚刚打错了,不好意思
      

  17.   

    同意  woxiangyao(我想) 的见意
      

  18.   

    TO woxiangyao(我想) , hzfxjun(飞天) :
    出书?
    这我倒没想过,
    不过我现在最大的任务是看书,要不然周二的考试又要挂了....
      

  19.   

    To: mahongxi (烤鸡翅膀)(色摸)      哈哈,那就先祝你考试成功,完事儿了,就想想出书的事儿!
      如果你懒得写太多,那就先把这篇的”续集”写出来。
        我们都等着呢。
      

  20.   

    mahongxi(烤鸡翅膀)(色摸): 合作如何?下面是我的帖子。
    http://www.csdn.net/expert/topic/680/680626.xml?temp=.318844
      

  21.   

    对于在SDI中打开一个Dialog
    我想进入哪个消息循环都不重要吧
    补充说明一点
    应用程序是由消息驱动的,在消息循环中得到消息后会调用API
    DispatchMessage,接着是由操作系统开栈执行窗口过程,
    如果在在该窗口过程中,又需要打开一个模式Dialog,进入另一个消息循环
    的话都无所谓,这时由这个消息泵负责向SDI窗口发送消息(其实是操作系统调用窗口过程,别忘了窗口过程叫CALLBACK函数:))
      

  22.   

    hollysky(爱神) :
    我这里不太理解,能不能讲得更细些?
      

  23.   

    cline(营营) :
    乐意!已经在你贴子里回了.
      

  24.   

    不错,不错,写得比较有深度,可以看看,不过,还是建议大家先去读读,侯sir的《深入浅出MFC》得好。
      

  25.   

    这东西并不神秘,我觉得看看mfc和微软的源程序就能明白.
      

  26.   

    To mahongxi (烤鸡翅膀)(色摸):我觉得你的一些观点对初学Windows程序设计的人会有所误导,或者是你本身对“模态对话框”的认识就止于此!
    其实,我觉得从MFC的CDialog派生出来的对话框类,所完成的对话框,严格来讲都是“非模态的”,(都是MFC搞的鬼!),只是MFC的实现机制把它做得同Windows的“模态”对话框表现的一模样!
    不知道你是否以纯API的方式写过Windows程序没有,尤其是对话框类的应用。
    我学MFC的时候,远没有现在那么幸运,一直没有读过《深》,我总觉得我现在再去读它,是一种时间的浪费。
    时间久了,也许是我记错了,很高兴能与你交流!
      

  27.   

    woxiangyao(我想):
    他这, 你让他出书, 你不是在害他吗!
      

  28.   

    很厉害!不过把MFC弄的这么透的程序员不多!象我就还的学习了?!