| 1939 | //////////////////// |
| 1940 | |
| 1941 | DWORD ProcessExist(LPTSTR aProcess) |
| 1942 | { |
| 1943 | // Determine the PID if aProcess is a pure, non-negative integer (any negative number |
| 1944 | // is more likely to be the name of a process [with a leading dash], rather than the PID). |
| 1945 | DWORD specified_pid = IsNumeric(aProcess) ? ATOU(aProcess) : 0; |
| 1946 | if (specified_pid) |
| 1947 | { |
| 1948 | // Most of the time while a PID is being used, the process still exists. So try opening |
| 1949 | // the process directly, since doing so is much faster than enumerating all processes: |
| 1950 | if (HANDLE hproc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | SYNCHRONIZE, FALSE, specified_pid)) |
| 1951 | { |
| 1952 | DWORD wait_result = WAIT_FAILED; |
| 1953 | // OpenProcess can succeed for erroneous PID values; e.g. values of 1501 to 1503 can |
| 1954 | // open the process with ID 1500. This is likely due to the undocumented fact that |
| 1955 | // PIDs are a multiple of four: https://devblogs.microsoft.com/oldnewthing/20080228-00/?p=23283 |
| 1956 | DWORD actual_pid = GetProcessId(hproc); // Requires PROCESS_QUERY_LIMITED_INFORMATION access. |
| 1957 | if (actual_pid == specified_pid) |
| 1958 | { |
| 1959 | // OpenProcess can succeed for a process which has already exited if another process |
| 1960 | // still has an open handle to it. So check whether it's still running: |
| 1961 | wait_result = WaitForSingleObject(hproc, 0); // Requires SYNCHRONIZE access. |
| 1962 | } |
| 1963 | CloseHandle(hproc); |
| 1964 | if (wait_result == WAIT_OBJECT_0) |
| 1965 | return 0; // Process has exited. |
| 1966 | if (wait_result == WAIT_TIMEOUT) |
| 1967 | return specified_pid; // Process still running. |
| 1968 | // Otherwise, fall back to the slow but more reliable method to get a more conclusive result. |
| 1969 | } |
| 1970 | // If OpenProcess failed, some likely causes are ERROR_ACCESS_DENIED and ERROR_INVALID_PARAMETER. |
| 1971 | // The latter probably indicates the PID is invalid, but we continue anyway, for the unlikely |
| 1972 | // case of a process with a name composed of digits and no extension (verified possible). |
| 1973 | // If ERROR_ACCESS_DENIED was returned, we can't rule out the false-positive cases described |
| 1974 | // above without doing a thorough enumeration of processes, so continue in that case as well. |
| 1975 | } |
| 1976 | |
| 1977 | PROCESSENTRY32 proc; |
| 1978 | proc.dwSize = sizeof(proc); |
| 1979 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); |
| 1980 | Process32First(snapshot, &proc); |
| 1981 | |
| 1982 | while (Process32Next(snapshot, &proc)) |
| 1983 | { |
| 1984 | if (specified_pid && specified_pid == proc.th32ProcessID) |
| 1985 | { |
| 1986 | CloseHandle(snapshot); |
| 1987 | return specified_pid; |
| 1988 | } |
| 1989 | // Otherwise, check for matching name even if aProcess is purely numeric (i.e. a number might |
| 1990 | // also be a valid name?): |
| 1991 | // It seems that proc.szExeFile never contains a path, just the executable name. |
| 1992 | // But in case it ever does, ensure consistency by removing the path: |
| 1993 | LPCTSTR proc_name = _tcsrchr(proc.szExeFile, '\\'); |
| 1994 | proc_name = proc_name ? proc_name + 1 : proc.szExeFile; |
| 1995 | if (!_tcsicmp(proc_name, aProcess)) // lstrcmpi() is not used: 1) avoids breaking existing scripts; 2) provides consistent behavior across multiple locales; 3) performance. |
| 1996 | { |
| 1997 | CloseHandle(snapshot); |
| 1998 | return proc.th32ProcessID; |