JNA GetExitCodeProcess()工作奇怪

时间:2011-09-30 17:40:45

标签: java winapi jna

我对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));
}

2 个答案:

答案 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。