海东信息港

当前位置:

深入剖析MFC中Windows消息处理机

2019/06/19 来源:海东信息港

导读

当bidle=0或消息队例中有消息时,程序又执行到哪了呢?do{// pump message, but quit on WM_

  当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_ssage != 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 = Modal();

  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 = Modal();一句使你的整个程序都在DoModal()内部进行。而且,你退出DoMal()时[你一定结束了你的对话框],InitInstance返回的是False,我们知道,这样,CwinThread::Run是不会执行的。

  但对话框程序是在哪里进行消息处理的呢。

  原来,Modal()内部会调用CwinThread::RunModalLoop,它起到的作用和RUN()是一样的[当然内部有细小差别,请参考MSDN]!!!

  第二种情况,你是在SDI[或其它]程序中调用Modal() 产生了一模式对话框[有父窗口].

  这又是如何运作的呢?

  建了这样一个工程做为例子。

  SDI,在View中处理LBUTTONDOWN:

  Modal();

  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中进行处理的吧[这点我不能确定].

  查看本文来源

月经不调吃什么好补血
月经不调的原因是什么
月经不调都有哪些药
标签