C ++, How to determine if a Windows process is working?

This applies to Windows XP processes.

I have a process, let it handle Process1. Process1 creates a new process Process2 and saves its identifier.

Now, at some point, Process1 wants Process2 to do something, so first you need to make sure that Process2 is still alive and that the user has not killed him.

How can I verify that this process is still running? Since I created it, I have a process identifier, I would think that there is some library function line by line IsProcessIDValid (id), but I can not find it on MSDN

+56
c ++ windows process
Oct 19 '09 at 21:52
source share
12 answers

You can use GetExitCodeProcess . It will return STILL_ACTIVE (259) if the process is still running (or if it STILL_ACTIVE with this exit code :().

+66
Oct 19 '09 at 21:58
source share

A process handler will be signaled if it exits.

So, the following will be done (error handling removed for brevity):

 BOOL IsProcessRunning(DWORD pid) { HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, pid); DWORD ret = WaitForSingleObject(process, 0); CloseHandle(process); return ret == WAIT_TIMEOUT; } 

Please note that the process identifier can be reworked - it is better to cache the handle that is returned from the CreateProcess call.

You can also use the threadpool API (SetThreadpoolWait in Vista +, RegisterWaitForSingleObject on older platforms) to receive a callback when the process terminates.

EDIT: I missed part of the original β€œI want to do something” question. You can use this technique if it is normal to have potentially outdated data for a small window or if you want to perform an operation without even trying to complete it. You still have to handle the case when an action fails because the process has completed.

+34
Oct 19 '09 at 21:57
source share
 #include <cstdio> #include <windows.h> #include <tlhelp32.h> /*! \brief Check if a process is running \param [in] processName Name of process to check if is running \returns \c True if the process is running, or \c False if the process is not running */ bool IsProcessRunning(const wchar_t *processName) { bool exists = false; PROCESSENTRY32 entry; entry.dwSize = sizeof(PROCESSENTRY32); HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); if (Process32First(snapshot, &entry)) while (Process32Next(snapshot, &entry)) if (!wcsicmp(entry.szExeFile, processName)) exists = true; CloseHandle(snapshot); return exists; } 
+20
Feb 07 '13 at 12:37
source share

Another way to monitor a child process is to create a workflow that will:

  • call CreateProcess ()
  • call WaitForSingleObject () // the worker thread is now waiting for the child process to complete. it is also possible to get a return code (from the main () function).
+6
Oct 19 '09 at 10:30
source share

I found this today, this is from 2003. It finds a process by name, you don’t even need a pid.

 \#include windows.h \#include tlhelp32.h \#include iostream.h int FIND_PROC_BY_NAME(const char *); int main(int argc, char *argv[]) { // Check whether a process is currently running, or not char szName[100]="notepad.exe"; // Name of process to find int isRunning; isRunning=FIND_PROC_BY_NAME(szName); // Note: isRunning=0 means process not found, =1 means yes, it is found in memor return isRunning; } int FIND_PROC_BY_NAME(const char *szToFind) // Created: 12/29/2000 (RK) // Last modified: 6/16/2003 (RK) // Please report any problems or bugs to kochhar@physiology.wisc.edu // The latest version of this routine can be found at: // http://www.neurophys.wisc.edu/ravi/software/killproc/ // Check whether the process "szToFind" is currently running in memory // This works for Win/95/98/ME and also Win/NT/2000/XP // The process name is case-insensitive, ie "notepad.exe" and "NOTEPAD.EXE" // will both work (for szToFind) // Return codes are as follows: // 0 = Process was not found // 1 = Process was found // 605 = Unable to search for process // 606 = Unable to identify system type // 607 = Unsupported OS // 632 = Process name is invalid // Change history: // 3/10/2002 - Fixed memory leak in some cases (hSnapShot and // and hSnapShotm were not being closed sometimes) // 6/13/2003 - Removed iFound (was not being used, as pointed out // by John Emmas) { BOOL bResult,bResultm; DWORD aiPID[1000],iCb=1000,iNumProc,iV2000=0; DWORD iCbneeded,i; char szName[MAX_PATH],szToFindUpper[MAX_PATH]; HANDLE hProc,hSnapShot,hSnapShotm; OSVERSIONINFO osvi; HINSTANCE hInstLib; int iLen,iLenP,indx; HMODULE hMod; PROCESSENTRY32 procentry; MODULEENTRY32 modentry; // PSAPI Function Pointers. BOOL (WINAPI *lpfEnumProcesses)( DWORD *, DWORD cb, DWORD * ); BOOL (WINAPI *lpfEnumProcessModules)( HANDLE, HMODULE *, DWORD, LPDWORD ); DWORD (WINAPI *lpfGetModuleBaseName)( HANDLE, HMODULE, LPTSTR, DWORD ); // ToolHelp Function Pointers. HANDLE (WINAPI *lpfCreateToolhelp32Snapshot)(DWORD,DWORD) ; BOOL (WINAPI *lpfProcess32First)(HANDLE,LPPROCESSENTRY32) ; BOOL (WINAPI *lpfProcess32Next)(HANDLE,LPPROCESSENTRY32) ; BOOL (WINAPI *lpfModule32First)(HANDLE,LPMODULEENTRY32) ; BOOL (WINAPI *lpfModule32Next)(HANDLE,LPMODULEENTRY32) ; // Transfer Process name into "szToFindUpper" and // convert it to upper case iLenP=strlen(szToFind); if(iLenP<1 || iLenP>MAX_PATH) return 632; for(indx=0;indx<iLenP;indx++) szToFindUpper[indx]=toupper(szToFind[indx]); szToFindUpper[iLenP]=0; // First check what version of Windows we're in osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); bResult=GetVersionEx(&osvi); if(!bResult) // Unable to identify system version return 606; // At Present we only support Win/NT/2000 or Win/9x/ME if((osvi.dwPlatformId != VER_PLATFORM_WIN32_NT) && (osvi.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)) return 607; if(osvi.dwPlatformId==VER_PLATFORM_WIN32_NT) { // Win/NT or 2000 or XP // Load library and get the procedures explicitly. We do // this so that we don't have to worry about modules using // this code failing to load under Windows 95, because // it can't resolve references to the PSAPI.DLL. hInstLib = LoadLibraryA("PSAPI.DLL"); if(hInstLib == NULL) return 605; // Get procedure addresses. lpfEnumProcesses = (BOOL(WINAPI *)(DWORD *,DWORD,DWORD*)) GetProcAddress( hInstLib, "EnumProcesses" ) ; lpfEnumProcessModules = (BOOL(WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) GetProcAddress( hInstLib, "EnumProcessModules" ) ; lpfGetModuleBaseName =(DWORD (WINAPI *)(HANDLE, HMODULE, LPTSTR, DWORD )) GetProcAddress( hInstLib, "GetModuleBaseNameA" ) ; if( lpfEnumProcesses == NULL || lpfEnumProcessModules == NULL || lpfGetModuleBaseName == NULL) { FreeLibrary(hInstLib); return 605; } bResult=lpfEnumProcesses(aiPID,iCb,&iCbneeded); if(!bResult) { // Unable to get process list, EnumProcesses failed FreeLibrary(hInstLib); return 605; } // How many processes are there? iNumProc=iCbneeded/sizeof(DWORD); // Get and match the name of each process for(i=0;i<iNumProc;i++) { // Get the (module) name for this process strcpy(szName,"Unknown"); // First, get a handle to the process hProc=OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,FALSE, aiPID[i]); // Now, get the process name if(hProc) { if(lpfEnumProcessModules(hProc,&hMod,sizeof(hMod),&iCbneeded) ) { iLen=lpfGetModuleBaseName(hProc,hMod,szName,MAX_PATH); } } CloseHandle(hProc); // Match regardless of lower or upper case if(strcmp(_strupr(szName),szToFindUpper)==0) { // Process found FreeLibrary(hInstLib); return 1; } } } if(osvi.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS) { // Win/95 or 98 or ME hInstLib = LoadLibraryA("Kernel32.DLL"); if( hInstLib == NULL ) return FALSE ; // Get procedure addresses. // We are linking to these functions of Kernel32 // explicitly, because otherwise a module using // this code would fail to load under Windows NT, // which does not have the Toolhelp32 // functions in the Kernel 32. lpfCreateToolhelp32Snapshot= (HANDLE(WINAPI *)(DWORD,DWORD)) GetProcAddress( hInstLib, "CreateToolhelp32Snapshot" ) ; lpfProcess32First= (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32)) GetProcAddress( hInstLib, "Process32First" ) ; lpfProcess32Next= (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32)) GetProcAddress( hInstLib, "Process32Next" ) ; lpfModule32First= (BOOL(WINAPI *)(HANDLE,LPMODULEENTRY32)) GetProcAddress( hInstLib, "Module32First" ) ; lpfModule32Next= (BOOL(WINAPI *)(HANDLE,LPMODULEENTRY32)) GetProcAddress( hInstLib, "Module32Next" ) ; if( lpfProcess32Next == NULL || lpfProcess32First == NULL || lpfModule32Next == NULL || lpfModule32First == NULL || lpfCreateToolhelp32Snapshot == NULL ) { FreeLibrary(hInstLib); return 605; } // The Process32.. and Module32.. routines return names in all uppercase // Get a handle to a Toolhelp snapshot of all the systems processes. hSnapShot = lpfCreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ) ; if( hSnapShot == INVALID_HANDLE_VALUE ) { FreeLibrary(hInstLib); return 605; } // Get the first process' information. procentry.dwSize = sizeof(PROCESSENTRY32); bResult=lpfProcess32First(hSnapShot,&procentry); // While there are processes, keep looping and checking. while(bResult) { // Get a handle to a Toolhelp snapshot of this process. hSnapShotm = lpfCreateToolhelp32Snapshot( TH32CS_SNAPMODULE, procentry.th32ProcessID) ; if( hSnapShotm == INVALID_HANDLE_VALUE ) { CloseHandle(hSnapShot); FreeLibrary(hInstLib); return 605; } // Get the module list for this process modentry.dwSize=sizeof(MODULEENTRY32); bResultm=lpfModule32First(hSnapShotm,&modentry); // While there are modules, keep looping and checking while(bResultm) { if(strcmp(modentry.szModule,szToFindUpper)==0) { // Process found CloseHandle(hSnapShotm); CloseHandle(hSnapShot); FreeLibrary(hInstLib); return 1; } else { // Look for next modules for this process modentry.dwSize=sizeof(MODULEENTRY32); bResultm=lpfModule32Next(hSnapShotm,&modentry); } } //Keep looking CloseHandle(hSnapShotm); procentry.dwSize = sizeof(PROCESSENTRY32); bResult = lpfProcess32Next(hSnapShot,&procentry); } CloseHandle(hSnapShot); } FreeLibrary(hInstLib); return 0; } 
+5
Mar 14 2018-11-11T00:
source share

You can never check and check if a process is running, you can check if a process is running at some point in the recent past. A process is an object that is not controlled by your application and can exit at any time. It is impossible to guarantee that the process will not exit between checks to verify that it is running and the corresponding action.

The best approach is to simply perform the required action and catch the exception that will be thrown if the process has not been started.

+3
Oct 19 '09 at 21:57
source share

call EnumProcesses() and check if the PID is in the list.

http://msdn.microsoft.com/en-us/library/ms682629%28VS.85%29.aspx

+1
19 Oct '09 at 21:59
source share

JaredPar is right because you cannot know if the process is running. You can only know if the process was running at the time of the check. Perhaps he died on average.

You should also know that PIDs can be processed quite quickly. Therefore, simply because there is a process with your PID there, this does not mean that it is your process.

Processes have a common GUID. (Process 1 can generate a GUID and pass it to process 2 on the command line.) Process 2 must create a named mutex with this GUID. When Process 1 wants to check, it can make WaitForSingleObject in the mutex with a timeout of 0. If process 2 is gone, the return code will tell you that the mutex was left, otherwise you will get a timeout.

+1
Oct 19 '09 at 22:14
source share

When writing a monitoring tool, I took a slightly different approach.

It was a little wasteful to deploy an extra thread to use WaitForSingleObject or even RegisterWaitForSingleObject (which does this for you). Since in my case I do not need to know the exact moment that the process closed, it just really closed.

Instead, I use GetProcessTimes ():

https://msdn.microsoft.com/en-us/library/windows/desktop/ms683223(v=vs.85).aspx

GetProcessTimes () will return a FILETIME structure for an ExitTime process only if the process really exited. So just check if the ExitTime structure is full, and if the time is not 0;

This solution SHOULD be considered when the process was killed, but it was reused by another process. GetProcessTimes needs a process descriptor, not a PID. Therefore, the OS should know that the descriptor refers to a process that was running at some point, but no more, and gives you exit time.

Relying on ExitCode, it was dirty: /

+1
Mar 28 '16 at 7:42 on
source share

You can find out if a process is working (with its name or PID), iterating over running processes, simply taking a snapshot of running processes through CreateToolhelp32Snapshot , and using the Process32First and Process32Next calls for this snapshot.

Then you can use the th32ProcessID or szExeFile field in the resulting PROCESSENTRY32 structure, depending on whether you want to search by PID or executable name. A simple implementation can be found here .

0
Jan 22 '13 at 21:45
source share

This is the solution I have used in the past. Although the example here is in VB.net - I used this technique with c and C ++. It bypasses all problems with process identifiers and process handlers, and also returns codes. Windows is very faithful in issuing a mutex no matter how the process ends. I hope this helps someone ...

 **PROCESS1 :-** Randomize() mutexname = "myprocess" & Mid(Format(CDbl(Long.MaxValue) * Rnd(), "00000000000000000000"), 1, 16) hnd = CreateMutex(0, False, mutexname) ' pass this name to Process2 File.WriteAllText("mutexname.txt", mutexname) <start Process2> <wait for Process2 to start> pr = WaitForSingleObject(hnd, 0) ReleaseMutex(hnd) If pr = WAIT_OBJECT_0 Then <Process2 not running> Else <Process2 is running> End If ... CloseHandle(hnd) EXIT **PROCESS2 :-** mutexname = File.ReadAllText("mutexname.txt") hnd = OpenMutex(MUTEX_ALL_ACCESS Or SYNCHRONIZE, True, mutexname) ... ReleaseMutex(hnd) CloseHandle(hnd) EXIT 
0
Apr 28 '17 at 3:32
source share

The solution provided by @ user152949 , as noted in the comments, skips the first process and does not interrupt when the value "true" is set to "exist". Let me provide the corrected version:

 #include <windows.h> #include <tlhelp32.h> bool IsProcessRunning(const wchar_t* const processName) { PROCESSENTRY32 entry; entry.dwSize = sizeof(PROCESSENTRY32); const auto snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); if (!Process32First(snapshot, &entry)) { CloseHandle(snapshot); return false; } do { if (!_wcsicmp(entry.szExeFile, processName)) { CloseHandle(snapshot); return true; } } while (Process32Next(snapshot, &entry)); CloseHandle(snapshot); return false; } 
0
Jul 23 '19 at 12:53 on
source share



All Articles