2011-09-30 57 views
0

JNA有一个很奇怪的问题。 我正在使用GetExitCodeProcess()检查进程是否存在。因此,例如,我知道记事本是PID 2084.当我使用我的方法来检查PID 2084是否存在时,它在2084和2087之间的PID中返回true(尽管我完全确定PID 2085-2087不会“ t存在)。它对于其他PID(如2083和2088)返回false。JNA GetExitCodeProcess()奇怪地工作

这几乎就好像存在某种不可能的舍入误差,而OpenProcess()正在打开一个不存在的PID句柄!

这发生在所有进程中。如果我列举所有进程并调用isRunning(PID),则当存在PID + 1,2 or 3时,它将返回true。否则它返回false,所以至少它是部分工作的。

的图案总是一样的,它返回PID和PID + 3.

实施例输出之间真:

[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

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

雷蒙德陈写了关于这个已经:Why does OpenProcess succeed even when I add three to the process ID?

你会很好地注意以下警告:

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

+0

谢谢你的有用的文章。你有什么建议,我保留原来的方法,还是有什么我可以做的?不幸的是,如果我进入cmd并键入taskkill/PID 2084,它会告诉我该进程不存在。 – David

+0

你的问题是关于为什么PID + 1,PID + 2和PID + 3都指向相同的过程。我回答说。现在你似乎在提出另一个问题。 'taskkill/pid xxxx'对我来说工作正常。如果你想调试这个问题,这可能是一个不同的问题。事实上,我现在看到你实际上没有提出直接的问题。我只是解释了你描述的行为。 –

+0

啊不,我的意思是: Taskkill/pid作品。 Taskkill/pid + 3 Taskkill/pid + 2和Taskkill/pid + 1不起作用:( – David

0

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

我检查,如果一个进程使用GetExitCodeProcess存在()。

糟糕的战略 - 进程ID得到重用/循环使用,所以它是完全可能的,一旦与PID记事本2084米的模具中,PID会被回收到一些其他的随机过程,并GetExitCodeProcess可以给你的虚假印象的记事本是仍然活着(当它实际上是一些其他进程,恰好有相同的PID现在活着)。所以当你在你的机器上测试你的代码时,所有的东西看起来都可以正常工作,但偶尔会在现实世界中随机而神秘地失败。

如果您保存的不仅仅是PID,例如保存exe名称(GetModuleFileNameEx),也许可以使其工作[更好],但即使如此,如果同一个新实例也会遇到问题应用程序被创建。保存主要HWND以获得更好的效果; HWND也被回收,但速度远远低于PID。