使用WaitForSingleObject函數,可以判斷進程是否退出。
WaitForSingleObject函數的作用是:等待直到指定的對象處於信號狀態(通知狀態)或到達指定的等待時間(超時時間)。
函數聲明如下:
1 DWORD WaitForSingleObject( 2 [in] HANDLE hHandle, 3 [in] DWORD dwMilliseconds 4 );
參數說明:
hHandle:需要等待的對象
dwMilliseconds:超時時間(毫秒),如果設置為INFINITE,則會一直等待下去,直到對象被通知。
WaitForSingleObject支持以下對象:
- Change notification
- Console input
- Event
- Memory resource notification
- Mutex
- Process
- Semaphore
- Thread
- Waitable timer
這里只是簡單介紹一下這個函數,如果需要了解更詳細的說明,可以參考:https://docs.microsoft.com/zh-cn/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject
監控新創建的進程退出:
這里我們創建一個MFC程序來進行演示,在界面上添加一個按鈕,創建記事本進程。
創建進程后創建一個線程等待進程退出,在線程處理函數中調用WaitForSingleObject,傳入進程對象進行等待
1 void CProcessMonitorDlg::OnBnClickedButton2() 2 { 3 LPTSTR szNotepad = _tcsdup(TEXT("notepad.exe")); 4 ::CreateProcess(NULL, szNotepad, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pi); 5 ::CreateThread(NULL, 0, MonitorThreadProc, NULL, 0, NULL); 6 free(szNotepad); 7 }
線程處理函數
1 DWORD __stdcall CProcessMonitorDlg::MonitorThreadProc(LPVOID lpThreadParameter) 2 { 3 ::WaitForSingleObject(pi.hProcess, INFINITE); 4 DWORD dwCode = 0; 5 GetExitCodeProcess(pi.hProcess, &dwCode); 6 TCHAR buf[260]{}; 7 wsprintf(buf, L"notepad.exe exit,exit code = %d", dwCode); 8 ::MessageBox(NULL, buf, L"tooltip", MB_OK); 9 return 0; 10 }
詳細的代碼可以參考文末的示例代碼。
監控已經存在的進程退出:
我們先調用CreateToolhelp32Snapshot、Process32First和Process32Next函數進行進程的枚舉,然后再調用WaitForSingleObject等待進程退出。
這里我們以cmd.exe為例
先枚舉進程,然后創建線程,等待進程退出。
1 PROCESSENTRY32 pe{}; 2 pe.dwSize = sizeof(PROCESSENTRY32); 3 HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 4 5 if (hSnapShot == NULL) 6 { 7 ::MessageBox(NULL, L"創建進程快照失敗", L"", MB_OK | MB_ICONINFORMATION); 8 return; 9 } 10 11 BOOL bNext = Process32First(hSnapShot, &pe); 12 13 while (bNext) 14 { 15 if (lstrcmp(pe.szExeFile,L"cmd.exe") == 0) 16 { 17 ::CreateThread(NULL, 0, MonitorCMDThreadProc, (PVOID)pe.th32ProcessID, 0, NULL); 18 CloseHandle(hSnapShot); 19 break; 20 } 21 22 bNext = Process32Next(hSnapShot, &pe); 23 } 24 25 26 CloseHandle(hSnapShot);
線程處理函數
1 DWORD dwCmdPid = (DWORD)lpThreadParameter; 2 HANDLE hProcessCmd =::OpenProcess(PROCESS_QUERY_INFORMATION| SYNCHRONIZE, FALSE, dwCmdPid); 3 4 if(hProcessCmd) 5 ::WaitForSingleObject(hProcessCmd, INFINITE); 6 7 DWORD dwCode = 0; 8 GetExitCodeProcess(hProcessCmd, &dwCode); 9 CloseHandle(hProcessCmd); 10 TCHAR buf[260]{}; 11 wsprintf(buf, L"cmd.exe exit,exit code = %d", dwCode); 12 ::MessageBox(NULL, buf, L"tooltip", MB_OK); 13 return 0;
其實這種方式挺簡單的,可以不用開線程一直去刷,然后判斷進程是否存在。
通過這種方式可以監測服務程序意外退出,並進行重啟操作。
示例代碼
https://github.com/zhaotianff/WindowsProgramming/tree/master/ProcessMonitor