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

應用程式忙碌時偵測使用者按鍵 (ESC) 終止作業:PeekMessage 輪詢訊息佇列技巧

     編輯:關於VC++

問題背景

長時間運算 (如大量資料匯入、複雜演算法) 時,UI 執行緒被阻塞,使用者無法透過一般訊息迴路接收按鍵。需在計算迴圈中主動輪詢訊息佇列,偵測 Esc 鍵終止作業。

Windows 訊息機制差異

  • DOS:程式主動向 OS 詢問輸入
  • Windows:OS 將事件封裝為訊息放入應用程式佇列,應用程式必須主動 GetMessage/PeekMessage 取出處理

解決方案:PeekMessage 非阻塞輪詢


void CMyClass::LongRunningTask()
{
    MSG msg;
    for (int i = 0; i < TotalSteps; ++i) {
        // 執行單一計算步驟
        DoOneStep(i);

        // 每 N 步或固定時間輪詢一次,避免過度消耗 CPU
        if (i % 100 == 0) {
            // 檢查鍵盤訊息範圍 WM_KEYFIRST ~ WM_KEYLAST
            if (::PeekMessage(&msg, m_hWnd, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)) {
                if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE) {
                    // 使用者按下 ESC,中斷作業
                    AfxMessageBox(_T("作業已由使用者取消"));
                    break;
                }
                // 非 ESC 鍵可選擇 DispatchMessage 讓系統處理
                ::DispatchMessage(&msg);
            }
        }
    }
}

關鍵參數說明

參數值說明
hwndm_hWnd僅檢查屬於本視窗的訊息
wMsgFilterMinWM_KEYFIRST (0x0100)鍵盤訊息範圍起始
wMsgFilterMaxWM_KEYLAST (0x0109)鍵盤訊息範圍結束
wRemoveMsgPM_REMOVE取出後從佇列移除;若用 PM_NOREMOVE 則僅檢查不移除

進階建議

  1. 頻率控制:每 100~1000 次迴圈或 50~100ms 輪詢一次,平衡回應速度與 CPU 佔用
  2. 處理其他訊息:若需保持視窗重繪/移動回應,可在輪詢時呼叫 PumpMessage() 或完整訊息迴圈
  3. 多執行緒替代方案:將長時間工作移至 Worker Thread,UI Thread 保持訊息迴圈暢通,透過 PostMessage/Event 通訊,架構更乾淨

適用場景

  • 舊版單執行緒 MFC 應用快速加入取消功能
  • 無法輕易重構為多執行緒的舊程式碼
  • 主控台應用程式模擬 kbhit() 行為

原始碼下載

包含 MFC Dialog 專案示範:進度條模擬長時間作業、ESC 取消、訊息泵處理 WM_PAINT 保持介面不凍結。

本文配套源碼

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