首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

MFC 核心原理深度解析:消息循環 (CWinThread::Run 與 PumpMessage)

     編輯:關於VC++

從 AfxWinMain 到消息循環

MFC 應用程式進入點 AfxWinMain 執行完初始化後,呼叫 pThread->Run() 進入消息循環。CWinThread::Run 定義於 THRDCORE.CPP。

CWinThread::Run 完整源碼解讀


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); // 不可到達
}

關鍵點

  1. 雙層循環:外層 for(;;) 維持生命週期;內層 while(bIdle...) 盡可能執行 OnIdle;do-while 盡可能抽乾訊息佇列
  2. PM_NOREMOVE:PeekMessage 僅檢查不移除,真正移除在 PumpMessage 內的 GetMessage
  3. OnIdle:lIdleCount 遞增,允許分優先級處理背景工作 (如 UI 更新、垃圾回收)
  4. IsIdleMessage:判定訊息是否為「閒置類」 (非鍵盤/滑鼠/定時器等),是的話重置 bIdle=TRUE 讓下一輪外層循環再跑 OnIdle

PumpMessage 核心邏輯


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 風格消息循環對比

特性SDK (WinMain)MFC (CWinThread::Run)
結構單層 while(GetMessage)雙層 + OnIdle 機制
閒置處理需自行實現 (PeekMessage + 處理)內建 OnIdle 虛函數 + 計數器
預處理無 (或自行 TranslateAccelerator)PreTranslateMessage 虛函數
多執行緒手動建立CWinThread 衍生類自動擁有獨立循環

實務啟示

  • 耗時操作 切勿 放在 OnIdle 或訊息處理中,應移至工作者執行緒
  • 需全域熱鍵/ToolTip/鍵盤導航 → 重寫 PreTranslateMessage
  • 需定期背景工作 (自動儲存、網路心跳) → 重寫 OnIdle 並善用 lIdleCount 分級
  • 次要 UI 執行緒 (Splash、模態對話框) 同樣走此循環

總結

MFC 消息循環以 雙層循環 + OnIdle + PreTranslateMessage 構建,在保留 SDK 核心 (GetMessage/TranslateMessage/DispatchMessage) 基礎上,提供了閒置處理、預處理、多執行緒支援等企業級框架能力。深入理解此源碼有助於診斷 UI 卡頓、熱鍵失效、背景工作調度等疑難雜症。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved