我对JNA有一个非常奇怪的问题。 我正在使用GetExitCodeProcess()检查进程是否存在。
所以例如,我知道记事本是PID 2084.当我使用我的方法检查PID 2084是否存在时,它对于2084和2087之间的PID返回true(尽管我完全确定PID 2085-2087不存在)。它为其他PID返回false,如2083和2088.
这几乎就像是存在某种不可能的舍入错误,OpenProcess()
正在打开一个不存在的PID句柄!
所有流程都会发生这种情况。如果我枚举所有进程并调用isRunning(PID),则在PID + 1,2 or 3
存在时返回true。否则返回false,所以至少它部分工作。
模式始终相同,它在PID和PID + 3之间返回true。
示例输出:
[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
等。
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));
}
答案 0 :(得分:2)
这是一个Windows实现细节。 PID的2个最低有效位被忽略。所以在你的例子中,2084-2087都引用了相同的过程。
Raymond Chen已经写过这个:Why does OpenProcess succeed even when I add three to the process ID?
你应该注意以下警告:
同样,我想强调一下,您在基于Windows NT的内核中看到的行为只是一个可以随时更改的实现工件。
答案 1 :(得分:0)
回答你实际上没有问过的问题,但这里是大象:
我正在使用GetExitCodeProcess()检查进程是否存在。
糟糕的策略 - 进程ID被重用/回收,因此一旦PID 2084的记事本消失,PID将被回收到其他一些随机进程中,而且GetExitCodeProcess可能会给你错误的印象,记事本仍然存在(当它实际上是其他一些过程恰好具有相同的PID,现在还活着)。因此,当您在计算机上测试代码时,一切都可能正常工作 - 但偶尔会在现实世界中随机而神秘地失败。
如果你节省的不仅仅是PID,你可能能够让它更好[更好] - 例如同时保存exe名称(GetModuleFileNameEx),但即使这样,如果同一个应用程序的新实例也会遇到麻烦得到了。保存主要HWND以获得良好的测量; HWND也被回收,但速度远低于PID。