⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 深入剖析mfc中windows消息处理、运行机制.htm

📁 深入剖析MFC中Windows消息处理、运行机制
💻 HTM
📖 第 1 页 / 共 4 页
字号:
                  <BR>我首先简要谈一下SDI,然后会花更多文字描述模式对话框。 
                  <BR>对于SDI窗口,你的应用程序类的InitInstance()大约如下: <BR>BOOL 
                  CEx06aApp::InitInstance() <BR>{ …………… <BR>CSingleDocTemplate* 
                  pDocTemplate; <BR>pDocTemplate = new CSingleDocTemplate( 
                  <BR>IDR_MAINFRAME, <BR>RUNTIME_CLASS(CEx06aDoc), 
                  <BR>RUNTIME_CLASS(CMainFrame), // main SDI frame window 
                  <BR>RUNTIME_CLASS(CEx06aView)); 
                  <BR>AddDocTemplate(pDocTemplate); <BR>CCommandLineInfo 
                  cmdInfo; <BR>ParseCommandLine(cmdInfo); <BR>if 
                  (!ProcessShellCommand(cmdInfo)) <BR>return FALSE; 
                  <BR>m_pMainWnd-&gt;ShowWindow(SW_SHOW); 
                  <BR>m_pMainWnd-&gt;UpdateWindow(); <BR>return TRUE; <BR>} 
                  <BR>完成一些如动态生成相关文档、视,显示主框架窗口、处理参数行信息等工作。这些都是显示在你工程中的“明码”。我们现在把断点设置到return 
                  TRUE;一句,跟入MFC源码中,看看到底MFC内部做了什么。 
                  <BR>程序进入SRC\WinMain.cpp,下一个大动作应是: <BR>nReturnCode = 
                  pThread-&gt;Run(); <BR>各位看官注意了,重点来了。F11进入 <BR>int 
                  CWinApp::Run() <BR>{ <BR>if (m_pMainWnd == NULL &amp;&amp; 
                  AfxOleGetUserCtrl()) <BR>{ <BR>// Not launched /Embedding or 
                  /Automation, but has no main window! <BR>TRACE0("Warning: 
                  m_pMainWnd is NULL in CWinApp::Run - quitting 
                  application.\n"); <BR>AfxPostQuitMessage(0); <BR>} <BR>return 
                  CWinThread::Run(); <BR>} <BR>再次F11进入: <BR>int 
                  CWinThread::Run() <BR>{ <BR>ASSERT_VALID(this); <BR><BR>// for 
                  tracking the idle time state <BR>BOOL bIdle = TRUE; <BR>LONG 
                  lIdleCount = 0; <BR><BR>// acquire and dispatch messages until 
                  a WM_QUIT message is received. <BR>for (;;) <BR>{ <BR>// 
                  phase1: check to see if we can do idle work <BR>while (bIdle 
                  &amp;&amp; <BR>!::PeekMessage(&amp;m_msgCur, NULL, NULL, NULL, 
                  PM_NOREMOVE)) <BR>{ <BR>// call OnIdle while in bIdle state 
                  <BR>if (!OnIdle(lIdleCount++)) <BR>bIdle = FALSE; // assume 
                  "no idle" state <BR>} <BR><BR>// phase2: pump messages while 
                  available <BR>do <BR>{ <BR>// pump message, but quit on 
                  WM_QUIT <BR>if (!PumpMessage()) <BR>return ExitInstance(); 
                  <BR><BR>// reset "no idle" state after pumping "normal" 
                  message <BR>if (IsIdleMessage(&amp;m_msgCur)) <BR>{ <BR>bIdle 
                  = TRUE; <BR>lIdleCount = 0; <BR>} <BR><BR>} while 
                  (::PeekMessage(&amp;m_msgCur, NULL, NULL, NULL, PM_NOREMOVE)); 
                  <BR>} <BR><BR>ASSERT(FALSE); // not reachable <BR>} 
                  <BR><BR>BOOL CWinThread::IsIdleMessage(MSG* pMsg) <BR>{ <BR>// 
                  Return FALSE if the message just dispatched should _not_ 
                  <BR>// cause OnIdle to be run. Messages which do not usually 
                  <BR>// affect the state of the user interface and happen very 
                  <BR>// often are checked for. <BR><BR>// redundant 
                  WM_MOUSEMOVE and WM_NCMOUSEMOVE <BR>if (pMsg-&gt;message == 
                  WM_MOUSEMOVE || pMsg-&gt;message == WM_NCMOUSEMOVE) <BR>{ 
                  <BR>// mouse move at same position as last mouse move? <BR>if 
                  (m_ptCursorLast == pMsg-&gt;pt &amp;&amp; pMsg-&gt;message == 
                  m_nMsgLast) <BR>return FALSE; <BR><BR>m_ptCursorLast = 
                  pMsg-&gt;pt; // remember for next time <BR>m_nMsgLast = 
                  pMsg-&gt;message; <BR>return TRUE; <BR>} <BR><BR>// WM_PAINT 
                  and WM_SYSTIMER (caret blink) <BR>return pMsg-&gt;message != 
                  WM_PAINT &amp;&amp; pMsg-&gt;message != 0x0118; <BR>} 
                  <BR>这是SDI处理消息的中心机构,但请注意,它觉对不是核心! 
                  <BR>分析一下,在无限循环FOR内部又出现一个WHILE循环 <BR>while (bIdle &amp;&amp; 
                  <BR>!::PeekMessage(&amp;m_msgCur, NULL, NULL, NULL, 
                  PM_NOREMOVE)) <BR>{ <BR>// call OnIdle while in bIdle state 
                  <BR>if (!OnIdle(lIdleCount++)) <BR>bIdle = FALSE; // assume 
                  "no idle" state <BR>} 
                  <BR>这段代码是当你程序进程的消息队列中没有消息时,会调用OnIdle做一些后备工作, 
                  <BR>临时对象在这里被删除。当然它是虚函数。其中的PeekMessage,是查看消息队列,如果有消息返回TRUE,如果没有消息返回FALSE,这里指定PM_NOREMOVE,是指查看过后不移走消息队列中刚刚被查看到的消息,也就是说这里的PeekMessage只起到一个检测作用,显然返回FALSE时[即没有消息],才会进入循环内部,执行OnIdle,当然了,你的OnIdle返回FLASE,会让程序不再执行OnIdle。你可能要问: 
                  <BR>当bidle=0或消息队例中有消息时,程序又执行到哪了呢? <BR>do <BR>{ <BR>// pump 
                  message, but quit on WM_QUIT <BR>if (!PumpMessage()) 
                  <BR>return ExitInstance(); <BR><BR>// reset "no idle" state 
                  after pumping "normal" message <BR>if 
                  (IsIdleMessage(&amp;m_msgCur)) <BR>{ <BR>bIdle = TRUE; 
                  <BR>lIdleCount = 0; <BR>} <BR><BR>} while 
                  (::PeekMessage(&amp;m_msgCur, NULL, NULL, NULL, PM_NOREMOVE)); 
                  <BR><BR>看啊,又进入一个循环! <BR>其中有个重要的函数,PumpMessage,内容如下: <BR>BOOL 
                  CWinThread::PumpMessage() <BR>{ <BR>ASSERT_VALID(this); 
                  <BR><BR>if (!::GetMessage(&amp;m_msgCur, NULL, NULL, NULL)) 
                  <BR>{ <BR>#ifdef _DEBUG <BR>if (afxTraceFlags &amp; 
                  traceAppMsg) <BR>TRACE0("CWinThread::PumpMessage - Received 
                  WM_QUIT.\n"); <BR>m_nDisablePumpCount++; // application must 
                  die <BR>// Note: prevents calling message loop things in 
                  ’ExitInstance’ <BR>// will never be decremented <BR>#endif 
                  <BR>return FALSE; <BR>} <BR><BR>#ifdef _DEBUG <BR>if 
                  (m_nDisablePumpCount != 0) <BR>{ <BR>TRACE0("Error: 
                  CWinThread::PumpMessage called when not permitted.\n"); 
                  <BR>ASSERT(FALSE); <BR>} <BR>#endif <BR><BR>#ifdef _DEBUG 
                  <BR>if (afxTraceFlags &amp; traceAppMsg) 
                  <BR>_AfxTraceMsg(_T("PumpMessage"), &amp;m_msgCur); <BR>#endif 
                  <BR><BR>// process this message <BR><BR>if (m_msgCur.message 
                  != WM_KICKIDLE &amp;&amp; !PreTranslateMessage(&amp;m_msgCur)) 
                  <BR>{ <BR>::TranslateMessage(&amp;m_msgCur); 
                  <BR>::DispatchMessage(&amp;m_msgCur); <BR>} <BR>return TRUE; 
                  <BR>} <BR>如你所想,这才是MFC消息处理的核心基地[也是我个人认为的]。 
                  <BR>GetMessage不同于PeekMessae,它是不得到消息不罢体,PeekMessage如果发现消息队列中没有消息会返回0,而GetMessage如果发现没有消息,等,直到有了消息,而且,GetMessage不同于PeekMessage,它会将消息移走[当然,PeekMessage也可以做到这点]。我想当你读了这个函数后,你应明白PreTranslateMessage函数的用法了吧[我比较喜欢在程序中充分利用这个函数]。 
                  <BR>::TranslateMessage(&amp;m_msgCur); 
                  <BR>::DispatchMessage(&amp;m_msgCur); 
                  <BR>将消息发送到窗口的处理函数[它是由窗口类指定的],之后的动作一直到你的程序做出反映的过程,你可以在《深入》一书中得到完美的解释。我们还是通过reurn 
                  TRUE;回到CWinThread::Run()中的Do{}while;循环。然后还是对IDLE的处理,即便刚才你的ONIDLE返回了FALSE,在这里你看到,你的程序还是有机会执行它的。然后又是利用PeekMessage检测消息队列: 
                  <BR>如果有消息[这个消息不被移动的原因是因为它要为PumpMessage内的GetMessage所利用。]再次进入PumpMessage[叫它“消息泵”吧]。 
                  <BR>如果没有消息,退出DO循环,但它还在FOR内部,所以又执行第一个While循环。 
                  <BR>这是CwinThread::Run的一个执行过程。 
                  <BR>不用担心退不出for(;;)如果你的消息队列中有一条WM_QUIT,会使GetMessage返回0,然后PumpMessage返回0而RUN()内部: 
                  <BR>if (!PumpMessage()) <BR>return ExitInstance();。 
                  <BR><BR>SDI就说到这,下面我来谈一下模式对话框。我分2种情况讨论: 
                  <BR>一当你的工程以模式对话框为基础时[没父窗口,或为桌面]。 
                  <BR>与SDI不同处在于,在应用程序类的InItInstance内部: <BR>BOOL 
                  CComboBoxApp::InitInstance() <BR>{ 
                  <BR>AfxEnableControlContainer(); <BR>// Standard 
                  initialization <BR>// If you are not using these features and 
                  wish to reduce the size <BR>// of your final executable, you 
                  should remove from the following <BR>// the specific 
                  initialization routines you do not need. <BR>#ifdef _AFXDLL 
                  <BR>Enable3dControls(); // Call this when using MFC in a 
                  shared DLL <BR>#else <BR>Enable3dControlsStatic(); // Call 
                  this when linking to MFC statically <BR>#endif 
                  <BR>this-&gt;m_nCmdShow = SW_HIDE; <BR>CComboBoxDlg dlg; 
                  <BR>m_pMainWnd = &amp;dlg; <BR>int nResponse = dlg.DoModal(); 
                  <BR>if (nResponse == IDOK) <BR>{ <BR>// TODO: Place code here 
                  to handle when the dialog is <BR>// dismissed with OK <BR>} 
                  <BR>else if (nResponse == IDCANCEL) <BR>{ <BR>// TODO: Place 
                  code here to handle when the dialog is <BR>// dismissed with 
                  Cancel <BR>} <BR>// Since the dialog has been closed, return 
                  FALSE so that we exit the <BR>// application, rather than 
                  start the application’s message pump. <BR>return FALSE; <BR>} 
                  <BR><BR>int nResponse = 
                  dlg.DoModal();一句使你的整个程序都在DoModal()内部进行。而且,你退出DoMal()时[你一定结束了你的对话框],InitInstance返回的是False,我们知道,这样,CwinThread::Run是不会执行的。 
                  <BR>但对话框程序是在哪里进行消息处理的呢。 
                  <BR>原来,dlg.DoModal()内部会调用CwinThread::RunModalLoop,它起到的作用和RUN()是一样的[当然内部有细小差别,请参考MSDN]!!! 
                  <BR><BR>第二种情况,你是在SDI[或其它]程序中调用Dlg.DoModal() 产生了一模式对话框[有父窗口]. 
                  <BR><BR>这又是如何运作的呢? <BR>建了这样一个工程做为例子。 
                  <BR>SDI,在View中处理LBUTTONDOWN: <BR>MyDLg.DoModal(); 
                  <BR>MyDLg内有按钮,以惫后用. 
                  <BR><BR>没有显示模式对话框前,消息处理一直在Cthread::Run()中进行. 
                  <BR>你单击后,程序执行点进入DoModal()内部的RunModalLoop,这又是一个消息处理机制. 
                  <BR>不过DoModal()中调用RunModalLoop,前会Disable掉它的父窗口.从RunModalLoop中出来后,再 
                  Enable它. 
                  <BR>模式对话框和非模式对话框都是通过调用CreateDialogIndirect()产生创建对话框.那它和非模式对话框区别是什么造成的呢? 
                  <BR>1 模式对话框将父窗口DISABLE掉. 
                  <BR>我原以为被Disable的窗口是不接收消息的.但后来我马上发现我是错的.但,为什么你对被Disable的窗口进行KeyBorad,Mouse动作时,窗口没反映呢,我想,这可能是操作系统从中搞的鬼.我在本文一开始,就写出操作系统向窗口发送消息的过程,我想当它发现目标窗口处理Disabled状态时,不会将消息发送给它,但这不能说窗口不接收消息,其它程序[或它本身]发送给它的消息还是可以接收并处理的. 
                  <BR>2 模式对话框本身有消息处理机制 RunModalLoop. <BR><BR>对以上两点加以实验. 
                  <BR>我在我的刚才建的项目中的模式对话框中加上一个BUTTON,其中加入如下代码: <BR>OnButton1() 
                  <BR>{ <BR>GetParaent()-&gt;EnableWindow(1); <BR>} 
                  <BR>单击,后我们发现,此时它已经不再表现为”模态”,我试着点击菜单,还是会作出正常反映. 
                  <BR>我想这此消息[对于父窗口的,如:菜单动作]的处理也应是在模式对话框中的RunModalLoop中进行处理的吧[这点我不能确定]. 
                  <BR><BR></TD></TR>
              <TR vAlign=center align=right>
                <TD vAlign=bottom bgColor=#ffffff><INPUT style="COLOR: #000000; BACKGROUND-COLOR: #ffffff" onclick=window.close() type=button value=关闭窗口><BR><BR></TD></TR>
              <TR vAlign=center align=right>
                <TD vAlign=center align=middle bgColor=#ffffff>
                  <TABLE id=AutoNumber20 style="BORDER-COLLAPSE: collapse" 
                  borderColor=#111111 cellSpacing=0 cellPadding=0 width="99%" 
                  align=center border=0>
                    <TBODY>
                    <TR>
                      <TD background=深入剖析MFC中Windows消息处理、运行机制.files/bg_dot.gif 
                      colSpan=10 height=1></TD></TR></TBODY></TABLE></TD></TR>
              <TR vAlign=center align=middle>
                <TD bgColor=#ffffff><BR><FONT 
                  color=red><B>特别声明:</B></FONT>文章版权归原作者所有, 未经允许请勿转载, 如有任何问题请<A 
                  href="mailto:webmaster@vczx.com">联系我们</A>. 
              <BR><BR></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></TD></TR><TR><TD 
align="center" valign="middle">
<CENTER>
<TABLE id=AutoNumber20 style="BORDER-COLLAPSE: collapse" borderColor=#111111 
cellSpacing=0 cellPadding=0 width="100%" align=center border=0>
  <TBODY>
  <TR>
    <TD bgColor=#666666 colSpan=10 height=1></TD></TR></TBODY></TABLE>
<TABLE id=AutoNumber20 style="BORDER-COLLAPSE: collapse" borderColor=#111111 
cellSpacing=0 cellPadding=0 width="100%" border=0>
  <TBODY>
  <TR>
    <TD width="100%"></TD></TR></TBODY></TABLE>
<TABLE borderColor=#799ccc cellSpacing=0 cellPadding=0 width="100%" align=center 
bgColor=#799ccc border=0>
  <TBODY>
  <TR bgColor=#dedede>
    <TD vAlign=center align=middle><BR>| <A class=d 
      href="http://www.vczx.com/"><FONT color=#000000>本站首页</FONT></A> | <A 
      class=d href="http://www.vczx.com/navigation.php" target=_blank><FONT 
      color=#000000>本站地图</FONT></A> | <A class=d 
      href="http://www.vczx.com/aboutus.php" target=_blank><FONT 
      color=#000000>关于本站</FONT></A> | <A class=d 
      href="http://www.vczx.com/copyright.php" target=_blank><FONT 
      color=#000000>版权声明</FONT></A> | <A class=d 
      href="http://www.vczx.com/link.php" target=_blank><FONT 
      color=#000000>友情链接</FONT></A> | <A class=d 
      href="http://www.vczx.com/ad.php" target=_blank><FONT 
      color=#000000>广告投放</FONT></A> | <A class=d 
      href="mailto:webmaster@vczx.com"><FONT color=#000000>联系我们</FONT></A> 
      |</FONT><BR><BR><B><FONT color=#ff0000>特别声明:</FONT><FONT 
      color=#636363></B>如本站所发布内容触犯了您的版权,请<A 
      href="mailto:webmaster@vczx.com"><B>来信</B></A>告诉我们,我们会立即删除。</FONT><BR><FONT 
      face=宋体 color=#636363>Copyright &copy; 2003-2004 <B><FONT face=Verdana 
      color=#000000>vczx</FONT><FONT face=Verdana color=#ce0000>.com</FONT></B> 
      Inc. All rights reserved.</FONT> </TD></TR>
  <TR bgColor=#dedede>
    <TD vAlign=center align=middle><FONT face=宋体 color=#636363>版权所有 &copy; 
      2003-2004 vc在线 本站由loose_went制作维护</FONT><BR>
      <SCRIPT language=JavaScript1.2>				<!--		var correctwidth=1024		var correctheight=768		if (screen.width!=correctwidth||screen.height!=correctheight)		document.write("<font color=#999999>本站最佳分辨率"+correctwidth+"*"+correctheight+",您当前的分辨率是"+screen.width+"*"+screen.height+".<br>设置合适的分辨率才能取得最佳的显示效果!</font>")		//-->		</SCRIPT>
    </TD></TR></TBODY></TABLE></CENTER></TD></TR></TABLE></BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -