使用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
这里只是简单介绍一下这个函数,如果需要了解更详细的说明,可以参考:waitForSingleObject 函数 (synchapi.h) - Win32 apps | Microsoft Learn
监控新创建的进程退出:
这里我们创建一个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 == INVALID_HANDLE_VALUE) 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;
其实这种方式挺简单的,可以不用开线程一直去刷,然后判断进程是否存在。
通过这种方式可以监测服务程序意外退出,并进行重启操作。
示例代码
WindowsProgramming/ProcessMonitor at master · zhaotianff/WindowsProgramming · GitHub