【问题标题】:JNA GetExitCodeProcess() working strangelyJNA GetExitCodeProcess() 工作异常
【发布时间】:2011-09-30 17:40:45
【问题描述】:

我对 JNA 有一个非常奇怪的问题。 我正在使用 GetExitCodeProcess() 检查进程是否存在。

例如,我知道记事本是 PID 2084。当我使用我的方法检查 PID 2084 是否存在时,它会为 2084 到 2087 之间的 PID 返回 true(即使我完全确定 PID 2085-2087 不存在)存在)。对于其他 PID,如 2083 和 2088,它返回 false。

就好像存在某种不可能的舍入错误,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));
}

【问题讨论】:

    标签: java winapi jna


    【解决方案1】:

    这是一个 Windows 实现细节。 PID 的 2 个最低有效位被忽略。所以在你的例子中,2084-2087 都指的是同一个过程。

    Raymond Chen 已经写过这篇文章:Why does OpenProcess succeed even when I add three to the process ID?

    您最好注意以下警告:

    再次,我想强调的是,您在基于 Windows NT 的内核中看到的行为只是一个可以随时更改的实现工件。

    【讨论】:

    • 感谢您提供有用的文章。你有什么建议,我让方法保持原样,或者我还能做些什么?不幸的是,如果我进入 cmd 并输入 taskkill /PID 2084,它会告诉我该进程不存在。
    • 您的问题是关于为什么 PID+1、PID+2 和 PID+3 都指的是同一个进程。我这样回答。现在你似乎在问另一个问题。 taskkill /pid xxxx 对我来说很好。如果您想调试该问题,则可能是另一个问题。事实上,我现在看到您实际上并没有直接提出问题。我刚刚解释了你描述的行为。
    • 啊,不,我的意思是:Taskkill /pid 有效。 Taskkill /pid + 3 Taskkill /pid + 2 和 Taskkill /pid + 1 不起作用:(
    • @David 好的,对此不确定,但实际上 pid+1、+2、+3 发生的情况本质上是未定义的。您为什么还要考虑这些 PID?
    • 你是对的。因此,为了确保我正确阅读所有内容,PID 必须始终是四的倍数,对吧?
    【解决方案2】:

    回答你实际上并没有问的问题,但这里是房间里的大象:

    我正在使用 GetExitCodeProcess() 检查进程是否存在。

    错误的策略 - 进程 ID 被重用/回收,因此完全有可能一旦 PID 为 2084 的记事本死掉,PID 将被回收到其他随机进程中,而 GetExitCodeProcess 可能会给您留下记事本还活着的错误印象(当它实际上是某个其他进程恰好具有相同的 PID 时,它现在还活着)。因此,当您在机器上测试代码时,一切似乎都可以正常工作 - 但在现实世界中偶尔会随机且神秘地失败。

    如果您保存的不仅仅是 PID,您可能会 [更好] 使其工作 - 例如,还保存 exe 名称 (GetModuleFileNameEx),但即便如此,如果同一应用程序的新实例出现,您也会遇到麻烦被创建。也保存主要的 HWND 以进行良好的测量; HWND 也会被回收,但速度比 PID 慢得多。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-19
      • 2020-08-08
      相关资源
      最近更新 更多