在响应一个按钮消息的时候,我用下面的代码等待一个线程的结束:while (true)
{
result_wait = ::MsgWaitForMultipleObjects(1, (HANDLE *)&_id, FALSE, INFINITE, QS_ALLINPUT); if (WAIT_OBJECT_0 + 1 == result_wait)
{
// Get next message in queue.
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
else //if ( ( dwRet >= WAIT_OBJECT_0) && ( dwRet < WAIT_OBJECT_0 + 1) )
{
// Thread just ended.
ajust_status();
break;
}
}但是这里的 ::TranslateMessage(&msg); ::DispatchMessage(&msg); 却相应不了消息循环中的PreTranslateMessage了,那么在PreTranslateMessage里处理消息就无法得到执行。怎么解决冲突啊?
{
result_wait = ::MsgWaitForMultipleObjects(1, (HANDLE *)&_id, FALSE, INFINITE, QS_ALLINPUT); if (WAIT_OBJECT_0 + 1 == result_wait)
{
// Get next message in queue.
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
else //if ( ( dwRet >= WAIT_OBJECT_0) && ( dwRet < WAIT_OBJECT_0 + 1) )
{
// Thread just ended.
ajust_status();
break;
}
}但是这里的 ::TranslateMessage(&msg); ::DispatchMessage(&msg); 却相应不了消息循环中的PreTranslateMessage了,那么在PreTranslateMessage里处理消息就无法得到执行。怎么解决冲突啊?
参考 http://blogs.msdn.com/b/oldnewthing/archive/2005/02/17/375307.aspx
谢谢给的参考,收益匪浅,但我用while循环把消息处理完之后再去等的,应该没问题吧。
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
你自己写的消息环根本没调用PreTranslateMessage,当然运行不了了。你去看看人家MFC的消息环怎么写的: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::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;
}
哦,一语惊醒梦中人啊。我总是想等到线程完全结束,其实没必要的,对吗? 只要这么做:
unsinged ThreadFun
{
...
::PostMessage(hWnd, WM_ThreadEnded, 0, 0);
_endthreadex(0);
}然后处理该消息的时候就认为线程已经结束了。是这意思吗?
是的,保险起见,消息处理线程收到WM_ThreadEnded消息后,最好再调用WaitForSingleObject(hThread),确保线程安全退出。
我发现PretranslateMessage只在当前模块中所有的窗口里Walk了一遍。如果我的线程在另外的某块。即便我:
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) && ! AfxGetThread()->PreTranslateMessage(&msg))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}也没用,因为这样也Walk不到主模块啊。