蜗牛的家
男儿当自强
posts - 48,  comments - 21,  trackbacks - 0
int CWnd::RunModalLoop(DWORD dwFlags)
{
 ASSERT(::IsWindow(m_hWnd)); 
// window must be created
 ASSERT(!(m_nFlags & WF_MODALLOOP)); // window must not already be in modal state

 
// for tracking the idle time state
 BOOL bIdle = TRUE;
 LONG lIdleCount 
= 0;
 BOOL bShowIdle 
= (dwFlags & MLF_SHOWONIDLE) && !(GetStyle() & WS_VISIBLE);
 HWND hWndParent 
= ::GetParent(m_hWnd);
 m_nFlags 
|= (WF_MODALLOOP|WF_CONTINUEMODAL);
 MSG
* pMsg = &AfxGetThread()->m_msgCur;

 
// acquire and dispatch messages until the modal state is done
 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;
   }

  }


  
// phase2: pump messages while available
  do
  
{
   ASSERT(ContinueModal());

   
// pump message, but quit on WM_QUIT
   
//PumpMessage(消息泵)的实现和上面讲的差不多。都是派送消息到窗口。
   if (!AfxGetThread()->PumpMessage())
   
{
    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);
   消息分为队列消息(进入线程的消息队列)和非队列消息(不进入线程的消息队列)。对于队列消息,最常见的是鼠标和键盘触发的消息,例如 WM_MOUSERMOVE,WM_CHAR等消息;还有例如:WM_PAINT、WM_TIMER和WM_QUIT。当鼠标、键盘事件被触发后,相应的鼠标或键盘驱动程序就会把这些事件转换成相应的消息,然后输送到系统消息队列,由Windows系统负责把消息加入到相应线程的消息队列中,于是就有了消息循环(从消息队列中读取并派送消息)。还有一种是非队列消息,他绕过系统队列和消息队列,直接将消息发送到窗口过程。例如,当用户激活一个窗口系统发送 WM_ACTIVATE, WM_SETFOCUS, and WM_SETCURSOR。创建窗口时发送WM_CREATE消息。
BOOL CWinThread::PumpMessage()
{
 ASSERT_VALID(
this);
 
 
//如果是WM_QUIT就退出函数(return FALSE),这将导致程序结束.
 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;
}
BOOL CWinThread::PreTranslateMessage(MSG* pMsg)
{
 ASSERT_VALID(
this);

 
// 如果是线程消息,那么将会在消息映射表中找到消息入口,调用线程消息的处理函数
 if (pMsg->hwnd == NULL && DispatchThreadMessageEx(pMsg))
  
return TRUE;

 
// walk from target to main window
 CWnd* pMainWnd = AfxGetMainWnd();
 
if (CWnd::WalkPreTranslateTree(pMainWnd->GetSafeHwnd(), pMsg))
  
return TRUE;

 
// in case of modeless dialogs, last chance route through main
 
//   window's accelerator table
 if (pMainWnd != NULL)
 
{
   CWnd
* pWnd = CWnd::FromHandle(pMsg->hwnd);
   
if (pWnd->GetTopLevelParent() != pMainWnd)
   
return pMainWnd->PreTranslateMessage(pMsg);
 }


 
return FALSE;   // no special processing
}
注:1.一般用PostThreadMessage函数发送线程之间的消息,他和窗口消息不同,需要指定线程id,消息激被系统放入到目标线程的消息队列中;用 ON_THREAD_MESSAGE( message, memberFxn )宏可以映射线程消息和他的处理函数。这个宏必须在应用程序类(从CWinThread继承)中,因为只有应用程序类才处理线程消息。如果你在别的类(比如视图类)中用这个宏,线程消息的消息处理函数将得不到线程消息。
   2.消息的目标窗口的PreTranslateMessage函数首先得到消息处理权,如果函数返回FALSE,那么他的父窗口将得到消息的处理权,直到主窗口;如果函数返回TRUE(表示消息已经被处理了),那么就不需要调用父类的PreTranslateMessage函数。这样,保证了消息的目标窗口以及他的父窗口都可以有机会调用PreTranslateMessage,如果你想要消息不传递给父类进行处理的话,返回TRUE就行了
 
   //对话框程序的消息循环
int CWnd::RunModalLoop(DWORD dwFlags)
{
 ASSERT(::IsWindow(m_hWnd)); 
// window must be created
 ASSERT(!(m_nFlags & WF_MODALLOOP)); // window must not already be in modal state

 
// for tracking the idle time state
 BOOL bIdle = TRUE;
 LONG lIdleCount 
= 0;
 BOOL bShowIdle 
= (dwFlags & MLF_SHOWONIDLE) && !(GetStyle() & WS_VISIBLE);
 HWND hWndParent 
= ::GetParent(m_hWnd);
 m_nFlags 
|= (WF_MODALLOOP|WF_CONTINUEMODAL);
 MSG
* pMsg = &AfxGetThread()->m_msgCur;

 
// acquire and dispatch messages until the modal state is done
 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++)) 
         //发送WM_KICKIDLE消息,如果对话框中有状态栏或是工具栏等,靠这个消息更新状态,相当于OnIdle
   
{
    
// stop idle processing next time
    bIdle = FALSE;
   }

  }


  
// phase2: pump messages while available
  do
  
{
   ASSERT(ContinueModal());

   
// pump message, but quit on WM_QUIT
   
//PumpMessage(消息泵)的实现和上面讲的差不多。都是派送消息到窗口。
   if (!AfxGetThread()->PumpMessage())
   
{
    AfxPostQuitMessage(
0);
    
return -1;
   }


   
// 消息为WM_SYSTIMER或者WM_SYSKEYDOWN,并且空闲显示标志为真的话,就显示窗口并通知窗口立刻重绘。
   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 (AfxGetThread()->IsIdleMessage(pMsg))
   
{
    bIdle 
= TRUE;
    lIdleCount 
= 0;
   }


  }
 while (::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE));
 }
 //无限循环

ExitModal:
 m_nFlags 
&= ~(WF_MODALLOOP|WF_CONTINUEMODAL);
 
return m_nModalResult;
}
posted on 2008-09-02 23:16 黑色天使 阅读(612) 评论(0)  编辑 收藏 引用 所属分类: VC&MFC

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理



<2009年7月>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

常用链接

留言簿(2)

随笔分类

随笔档案

文章档案

搜索

  •  

最新评论

阅读排行榜

评论排行榜