2011-09-30 98 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。