工作管理員如何判斷某程式「未回應」?核心邏輯是向目標視窗發送訊息並設定超時:若視窗程序在指定時間內未處理,即視為掛住。本文介紹標準做法與兩個未公開的高效替代方案。
DWORD dwResult;
BOOL bResponsive = SendMessageTimeout(
hWnd, // 目標視窗
WM_NULL, // 空訊息,不觸發任何動作
0, 0, // wParam, lParam
SMTO_ABORTIFHUNG | SMTO_BLOCK, // 旗標:遇掛住即中止、同步等待
5000, // 超時 5 秒
&dwResult // 接收回傳值
);
if (!bResponsive) {
// 視窗未在 5 秒內處理 WM_NULL -> 停止回應
}
WM_NULL (0x0000) 是最輕量的測試訊息,任何正常視窗程序都會立即返回 0。SMTO_ABORTIFHUNG 關鍵:若目標佇列已掛住,系統不等待直接返回 FALSE。Windows 內部提供兩個未匯出函數,位於 USER32.DLL,需用 GetProcAddress 取得:
BOOL (WINAPI *IsHungAppWindow)(HWND hWnd);
// 直接判斷視窗所屬執行緒是否掛住
BOOL (WINAPI *IsHungThread)(DWORD dwThreadId);
// 判斷指定執行緒是否掛住
HMODULE hUser32 = GetModuleHandle("user32.dll");
auto pIsHungAppWindow = (BOOL(WINAPI*)(HWND))GetProcAddress(hUser32, "IsHungAppWindow");
auto pIsHungThread = (BOOL(WINAPI*)(DWORD))GetProcAddress(hUser32, "IsHungThread");
bool IsAppHung(HWND hWnd) {
if (pIsHungAppWindow) return pIsHungAppWindow(hWnd); // NT
// Win9x 需先取得視窗執行緒 ID
DWORD dwThreadId = GetWindowThreadProcessId(hWnd, NULL);
if (pIsHungThread) return pIsHungThread(dwThreadId);
// 回退標準法
return !SendMessageTimeout(hWnd, WM_NULL, 0, 0, SMTO_ABORTIFHUNG, 5000, NULL);
}