MFC 應用程式進入點 AfxWinMain 執行完初始化後,呼叫 pThread->Run() 進入消息循環。CWinThread::Run 定義於 THRDCORE.CPP。
int CWinThread::Run() {
ASSERT_VALID(this);
BOOL bIdle = TRUE;
LONG lIdleCount = 0;
for (;;) { // 無限循環,直到 WM_QUIT
// Phase 1: 執行閒置處理 (OnIdle)
while (bIdle && !::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE)) {
if (!OnIdle(lIdleCount++))
bIdle = FALSE; // 無閒置工作時退出內層循環
}
// Phase 2: 抽取並分發訊息
do {
if (!PumpMessage()) // 遇到 WM_QUIT 返回 FALSE
return ExitInstance();
// 重置閒置狀態 (非 WM_QUIT、非 WM_KICKIDLE 等)
if (IsIdleMessage(&m_msgCur)) {
bIdle = TRUE;
lIdleCount = 0;
}
} while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
}
ASSERT(FALSE); // 不可到達
}
for(;;) 維持生命週期;內層 while(bIdle...) 盡可能執行 OnIdle;do-while 盡可能抽乾訊息佇列PeekMessage 僅檢查不移除,真正移除在 PumpMessage 內的 GetMessagelIdleCount 遞增,允許分優先級處理背景工作 (如 UI 更新、垃圾回收)bIdle=TRUE 讓下一輪外層循環再跑 OnIdle
BOOL CWinThread::PumpMessage() {
ASSERT_VALID(this);
if (!::GetMessage(&m_msgCur, NULL, NULL, NULL)) {
// GetMessage 返回 FALSE = 收到 WM_QUIT
return FALSE;
}
// PreTranslateMessage: 加速鍵、ToolTip、鍵盤導航等預處理
if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur)) {
::TranslateMessage(&m_msgCur); // 虛擬鍵碼 → 字元訊息
::DispatchMessage(&m_msgCur); // 分發至 WindowProc
}
return TRUE;
}
| 特性 | SDK (WinMain) | MFC (CWinThread::Run) |
|---|---|---|
| 結構 | 單層 while(GetMessage) | 雙層 + OnIdle 機制 |
| 閒置處理 | 需自行實現 (PeekMessage + 處理) | 內建 OnIdle 虛函數 + 計數器 |
| 預處理 | 無 (或自行 TranslateAccelerator) | PreTranslateMessage 虛函數 |
| 多執行緒 | 手動建立 | CWinThread 衍生類自動擁有獨立循環 |
OnIdle 或訊息處理中,應移至工作者執行緒PreTranslateMessageOnIdle 並善用 lIdleCount 分級MFC 消息循環以 雙層循環 + OnIdle + PreTranslateMessage 構建,在保留 SDK 核心 (GetMessage/TranslateMessage/DispatchMessage) 基礎上,提供了閒置處理、預處理、多執行緒支援等企業級框架能力。深入理解此源碼有助於診斷 UI 卡頓、熱鍵失效、背景工作調度等疑難雜症。