I have a very strange problem with JNA.
I am checking if a process exists by using GetExitCodeProcess().
So for example, I know notepad is PID 2084. When I use my method to check if PID 2084 exists, it returns true for PIDs between 2084 and 2087 (even though I am completely sure that PIDs 2085-2087 don’t exist). It returns false for other PIDs, like 2083 and 2088.
It’s almost as if there is some kind of impossible rounding error, and OpenProcess() is opening a handle on a PID that doesn’t exist!
This is happening with all processes. If I enumerate all the processes and call isRunning(PID), it returns true when PID + 1,2 or 3 exist. It returns false otherwise, so at least it’s working partially.
The pattern is always the same, it returns true between PID and PID + 3.
Example output:
[Notepad PID = 2084, cmd.exe PID = 2100]
isRunning(2083)=False
isRunning(2084)=true
isRunning(2085)=true
isRunning(2086)=true
isRunning(2087)=true
isRunning(2088)=false
.... false .....
isRunning(2100)=true
etc..
Interface code:
protected interface Kernel32 extends StdCallLibrary {
Kernel32 INSTANCE = (Kernel32)Native.loadLibrary("kernel32", Kernel32.class);
public Pointer OpenProcess(int dwDesiredAccess, boolean bInheritHandle, int dwProcessId);
int GetLastError();
boolean GetExitCodeProcess(Pointer hProcess, IntByReference lpExitCode);
};
Function code:
public static boolean isRunning(int pid)
{
final int PROCESS_QUERY_INFORMATION = 0x0400;
final int STILL_ALIVE = 259;
final int INVALID_PARAM = 87;
Pointer hProcess = kernel32.OpenProcess(PROCESS_QUERY_INFORMATION, false, pid);
int error = kernel32.GetLastError();
if (error == INVALID_PARAM)
return false; //Invalid parameter.
IntByReference exitCode = new IntByReference();
kernel32.GetExitCodeProcess(hProcess, exitCode);
if (exitCode.getValue() != STILL_ALIVE)
return false;
else
return true;
}
public static void main(String[] args) {
System.out.println(isRunning(2083)); //Proceses with PID 2083, 2085 to 2088 do not exist.
System.out.println(isRunning(2084)); //2084 is notepad
System.out.println(isRunning(2085));
System.out.println(isRunning(2086));
System.out.println(isRunning(2087));
System.out.println(isRunning(2088));
}
That’s a Windows implementation detail. The 2 least significant bits of the PID are ignored. So in your example, 2084-2087 all refer to the same process.
Raymond Chen wrote about this already: Why does OpenProcess succeed even when I add three to the process ID?
You would do well to heed the following caveat: