Search code examples
delphidelphi-10.4-sydney

Why does OpenProcess() return a non 0 value when the process ID is no longer running


I'm starting a new instance of another application using CreateProcess from Example and I end up saving the PID so that I can later check if that process is still running.

I'm using to following method to check if it's running or not:

procedure TfrmRSM.Button1Click(Sender: TObject);
begin
  var
  ahandle := OpenProcess(PROCESS_ALL_ACCESS, true, aPID);

  if ahandle = 0 then
    ShowMessage('is not running')
  else
    ShowMessage('is running');

  CloseHandle(ahandle);
end;

The code above should return 0 when the process is no longer running but it still returns a number greater than 0

I am closing the handle after using CreateProcess

Whats to propper way to check if a PID is running if the method I'm using is incorrect? I'm only able to find methods that use the application name.


Solution

  • I'm starting a new instance of another application using CreateProcess from Example and I end up saving the PID so that I can later check if that process is still running.

    The correct way to handle this is to keep open the HANDLE that CreateProcess() gives you, and then you can query it via WaitForSingleObject() or GetExitCodeProcess() to see if the process has terminated or not, and then close the HANDLE when you no longer need it.

    In comments, you mention that your launching app may terminate and be restarted separate from the target process. In that case, you could close the HANDLE if you still have it open, saving its PID and creation date/time somewhere you can get it back from, and then when your app restarts it can enumerate running processes (alternatively) to see if the target EXE is still running and has a matching PID and date/time, and if so then open a new HANDLE to that PID. Just be careful, because this does introduce a small race condition where the target process might terminate after you detect its presence and its PID could get recycled before you have a chance to open it. So you might need to re-validate the HANDLE's info again after opening it.

    Otherwise, during your app's shutdown (or even before), you can off-load the open HANDLE from CreateProcess() to a separate helper process that stays running in the background monitoring the HANDLE, and then your main app can get the HANDLE back from that helper after restarting. Or, perform the actual CreateProcess() call in the helper to begin with, so the HANDLE monitoring stays within a single process at all times, and let your main app query the helper for status when needed.

    I'm using to following method to check if it's running or not:

    That will not work, as you don't know whether the PID is still valid, or even still refers to the same process you are interested in. Once that process has terminated, its PID can be recycled at any time for use with a new process.

    The code above should return 0 when the process is no longer running but it still returns a number greater than 0

    The only way OpenProcess() can return non-zero is if the specified PID is actually running. But that does not guarantee it is the same process you are interested in. At the very least, after OpenProcess() returns a non-zero HANDLE, you can query that HANDLE for its info (EXE file path, creation date/time, etc) to see if it is the same process you are expecting. If the info does not match, the PID was recycled.