📄 thrdcore.cpp
字号:
// CWinThread default implementation
BOOL CWinThread::InitInstance()
{
ASSERT_VALID(this);
return FALSE; // by default don't enter run loop
}
// main running routine until thread exits
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;
}
int CWinThread::ExitInstance()
{
ASSERT_VALID(this);
ASSERT(AfxGetApp() != this);
int nResult = m_msgCur.wParam; // returns the value from PostQuitMessage
return nResult;
}
BOOL CWinThread::OnIdle(LONG lCount)
{
ASSERT_VALID(this);
#if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)
// check MFC's allocator (before idle)
if (_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) & _CRTDBG_CHECK_ALWAYS_DF)
ASSERT(AfxCheckMemory());
#endif
if (lCount <= 0)
{
// send WM_IDLEUPDATECMDUI to the main window
CWnd* pMainWnd = m_pMainWnd;
if (pMainWnd != NULL && pMainWnd->m_hWnd != NULL &&
pMainWnd->IsWindowVisible())
{
AfxCallWndProc(pMainWnd, pMainWnd->m_hWnd,
WM_IDLEUPDATECMDUI, (WPARAM)TRUE, 0);
pMainWnd->SendMessageToDescendants(WM_IDLEUPDATECMDUI,
(WPARAM)TRUE, 0, TRUE, TRUE);
}
// send WM_IDLEUPDATECMDUI to all frame windows
AFX_MODULE_THREAD_STATE* pState = _AFX_CMDTARGET_GETSTATE()->m_thread;
CFrameWnd* pFrameWnd = pState->m_frameList;
while (pFrameWnd != NULL)
{
if (pFrameWnd->m_hWnd != NULL && pFrameWnd != pMainWnd)
{
if (pFrameWnd->m_nShowDelay == SW_HIDE)
pFrameWnd->ShowWindow(pFrameWnd->m_nShowDelay);
if (pFrameWnd->IsWindowVisible() ||
pFrameWnd->m_nShowDelay >= 0)
{
AfxCallWndProc(pFrameWnd, pFrameWnd->m_hWnd,
WM_IDLEUPDATECMDUI, (WPARAM)TRUE, 0);
pFrameWnd->SendMessageToDescendants(WM_IDLEUPDATECMDUI,
(WPARAM)TRUE, 0, TRUE, TRUE);
}
if (pFrameWnd->m_nShowDelay > SW_HIDE)
pFrameWnd->ShowWindow(pFrameWnd->m_nShowDelay);
pFrameWnd->m_nShowDelay = -1;
}
pFrameWnd = pFrameWnd->m_pNextFrameWnd;
}
}
else if (lCount >= 0)
{
AFX_MODULE_THREAD_STATE* pState = _AFX_CMDTARGET_GETSTATE()->m_thread;
if (pState->m_nTempMapLock == 0)
{
// free temp maps, OLE DLLs, etc.
AfxLockTempMaps();
AfxUnlockTempMaps();
}
}
#if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)
// check MFC's allocator (after idle)
if (_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) & _CRTDBG_CHECK_ALWAYS_DF)
ASSERT(AfxCheckMemory());
#endif
return lCount < 0; // nothing more to do if lCount >= 0
}
void CWinThread::DispatchThreadMessage(MSG* pMsg)
{
DispatchThreadMessageEx(pMsg);
}
BOOL CWinThread::DispatchThreadMessageEx(MSG* pMsg)
{
const AFX_MSGMAP* pMessageMap; pMessageMap = GetMessageMap();
const AFX_MSGMAP_ENTRY* lpEntry;
#ifdef _AFXDLL
for (/* pMessageMap already init'ed */; pMessageMap != NULL;
pMessageMap = (*pMessageMap->pfnGetBaseMap)())
#else
for (/* pMessageMap already init'ed */; pMessageMap != NULL;
pMessageMap = pMessageMap->pBaseMap)
#endif
{
// Note: catch not so common but fatal mistake!!
// BEGIN_MESSAGE_MAP(CMyThread, CMyThread)
#ifdef _AFXDLL
ASSERT(pMessageMap != (*pMessageMap->pfnGetBaseMap)());
#else
ASSERT(pMessageMap != pMessageMap->pBaseMap);
#endif
if (pMsg->message < 0xC000)
{
// constant window message
if ((lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries,
pMsg->message, 0, 0)) != NULL)
goto LDispatch;
}
else
{
// registered windows message
lpEntry = pMessageMap->lpEntries;
while ((lpEntry = AfxFindMessageEntry(lpEntry, 0xC000, 0, 0)) != NULL)
{
UINT* pnID = (UINT*)(lpEntry->nSig);
ASSERT(*pnID >= 0xC000);
// must be successfully registered
if (*pnID == pMsg->message)
goto LDispatch;
lpEntry++; // keep looking past this one
}
}
}
return FALSE;
LDispatch:
union MessageMapFunctions mmf;
mmf.pfn = lpEntry->pfn;
// always posted, so return value is meaningless
(this->*mmf.pfn_THREAD)(pMsg->wParam, pMsg->lParam);
return TRUE;
}
BOOL CWinThread::PreTranslateMessage(MSG* pMsg)
{
ASSERT_VALID(this);
// if this is a thread-message, short-circuit this function
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
}
LRESULT CWinThread::ProcessWndProcException(CException*, const MSG* pMsg)
{
if (pMsg->message == WM_CREATE)
{
return -1; // just fail
}
else if (pMsg->message == WM_PAINT)
{
// force validation of window to prevent getting WM_PAINT again
ValidateRect(pMsg->hwnd, NULL);
return 0;
}
return 0; // sensible default for rest of commands
}
/////////////////////////////////////////////////////////////////////////////
// Message Filter processing (WH_MSGFILTER)
LRESULT CALLBACK _AfxMsgFilterHook(int code, WPARAM wParam, LPARAM lParam)
{
CWinThread* pThread;
if (afxContextIsDLL || (code < 0 && code != MSGF_DDEMGR) ||
(pThread = AfxGetThread()) == NULL)
{
return ::CallNextHookEx(_afxThreadState->m_hHookOldMsgFilter,
code, wParam, lParam);
}
ASSERT(pThread != NULL);
return (LRESULT)pThread->ProcessMessageFilter(code, (LPMSG)lParam);
}
AFX_STATIC BOOL AFXAPI IsHelpKey(LPMSG lpMsg)
// return TRUE only for non-repeat F1 keydowns.
{
return lpMsg->message == WM_KEYDOWN &&
lpMsg->wParam == VK_F1 &&
!(HIWORD(lpMsg->lParam) & KF_REPEAT) &&
GetKeyState(VK_SHIFT) >= 0 &&
GetKeyState(VK_CONTROL) >= 0 &&
GetKeyState(VK_MENU) >= 0;
}
AFX_STATIC inline BOOL IsEnterKey(LPMSG lpMsg)
{ return lpMsg->message == WM_KEYDOWN && lpMsg->wParam == VK_RETURN; }
AFX_STATIC inline BOOL IsButtonUp(LPMSG lpMsg)
{ return lpMsg->message == WM_LBUTTONUP; }
BOOL CWinThread::ProcessMessageFilter(int code, LPMSG lpMsg)
{
if (lpMsg == NULL)
return FALSE; // not handled
CFrameWnd* pTopFrameWnd;
CWnd* pMainWnd;
CWnd* pMsgWnd;
switch (code)
{
case MSGF_DDEMGR:
// Unlike other WH_MSGFILTER codes, MSGF_DDEMGR should
// never call the next hook.
// By returning FALSE, the message will be dispatched
// instead (the default behavior).
return FALSE;
case MSGF_MENU:
pMsgWnd = CWnd::FromHandle(lpMsg->hwnd);
if (pMsgWnd != NULL)
{
pTopFrameWnd = pMsgWnd->GetTopLevelFrame();
if (pTopFrameWnd != NULL && pTopFrameWnd->IsTracking() &&
pTopFrameWnd->m_bHelpMode)
{
pMainWnd = AfxGetMainWnd();
if ((m_pMainWnd != NULL) && (IsEnterKey(lpMsg) || IsButtonUp(lpMsg)))
{
pMainWnd->SendMessage(WM_COMMAND, ID_HELP);
return TRUE;
}
}
}
// fall through...
case MSGF_DIALOGBOX: // handles message boxes as well.
pMainWnd = AfxGetMainWnd();
if (afxData.nWinVer < 0x333 && pMainWnd != NULL && IsHelpKey(lpMsg))
{
pMainWnd->SendMessage(WM_COMMAND, ID_HELP);
return TRUE;
}
if (code == MSGF_DIALOGBOX && m_pActiveWnd != NULL &&
lpMsg->message >= WM_KEYFIRST && lpMsg->message <= WM_KEYLAST)
{
// need to translate messages for the in-place container
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
if (pThreadState->m_bInMsgFilter)
return FALSE;
pThreadState->m_bInMsgFilter = TRUE; // avoid reentering this code
MSG msg = *lpMsg;
if (m_pActiveWnd->IsWindowEnabled() && PreTranslateMessage(&msg))
{
pThreadState->m_bInMsgFilter = FALSE;
return TRUE;
}
pThreadState->m_bInMsgFilter = FALSE; // ok again
}
break;
}
return FALSE; // default to not handled
}
/////////////////////////////////////////////////////////////////////////////
// Access to m_pMainWnd & m_pActiveWnd
CWnd* CWinThread::GetMainWnd()
{
if (m_pActiveWnd != NULL)
return m_pActiveWnd; // probably in-place active
// when not inplace active, just return main window
if (m_pMainWnd != NULL)
return m_pMainWnd;
return CWnd::GetActiveWindow();
}
/////////////////////////////////////////////////////////////////////////////
// CWinThread implementation helpers
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;
}
/////////////////////////////////////////////////////////////////////////////
// CWinThread diagnostics
#ifdef _DEBUG
void CWinThread::AssertValid() const
{
CCmdTarget::AssertValid();
}
void CWinThread::Dump(CDumpContext& dc) const
{
CCmdTarget::Dump(dc);
dc << "m_pThreadParams = " << m_pThreadParams;
dc << "\nm_pfnThreadProc = " << (void*)m_pfnThreadProc;
dc << "\nm_bAutoDelete = " << m_bAutoDelete;
dc << "\nm_hThread = " << (void*)m_hThread;
dc << "\nm_nThreadID = " << m_nThreadID;
dc << "\nm_nDisablePumpCount = " << m_nDisablePumpCount;
if (AfxGetThread() == this)
dc << "\nm_pMainWnd = " << m_pMainWnd;
dc << "\nm_msgCur = {";
dc << "\n\thwnd = " << (UINT)m_msgCur.hwnd;
dc << "\n\tmessage = " << (UINT)m_msgCur.message;
dc << "\n\twParam = " << (UINT)m_msgCur.wParam;
dc << "\n\tlParam = " << (void*)m_msgCur.lParam;
dc << "\n\ttime = " << m_msgCur.time;
dc << "\n\tpt = " << CPoint(m_msgCur.pt);
dc << "\n}";
dc << "\nm_pThreadParams = " << m_pThreadParams;
dc << "\nm_pfnThreadProc = " << (void*)m_pfnThreadProc;
dc << "\nm_ptCursorLast = " << m_ptCursorLast;
dc << "\nm_nMsgLast = " << m_nMsgLast;
dc << "\n";
}
#endif
#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif
IMPLEMENT_DYNAMIC(CWinThread, CCmdTarget)
/////////////////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -