/* * Copyright (C) 2013 Laurent CLOUET * Author Laurent CLOUET <laurent.clouet@nopnop.net> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; version 2 * of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package com.sheepit.client.os.windows; import java.io.IOException; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import com.sun.jna.Native; import com.sun.jna.Pointer; import com.sun.jna.platform.win32.BaseTSD.DWORD_PTR; import com.sun.jna.platform.win32.Kernel32; import com.sun.jna.platform.win32.Kernel32Util; import com.sun.jna.platform.win32.WinDef.DWORD; import com.sun.jna.platform.win32.WinNT; public class WinProcess { public static final int PRIORITY_IDLE = 0x40; public static final int PRIORITY_BELOW_NORMAL = 0x4000; public static final int PRIORITY_NORMAL = 0x20; public static final int PRIORITY_ABOVE_NORMAL = 0x8000; public static final int PRIORITY_HIGH = 0x80; public static final int PRIORITY_REALTIME = 0x100; private WinNT.HANDLE handle; private int pid; Kernel32Lib kernel32lib; public WinProcess() { this.handle = null; this.pid = -1; this.kernel32lib = null; try { this.kernel32lib = (Kernel32Lib) Native.loadLibrary(Kernel32Lib.path, Kernel32Lib.class); } catch (java.lang.UnsatisfiedLinkError e) { System.out.println("WinProcess::construct " + e); } catch (java.lang.ExceptionInInitializerError e) { System.out.println("WinProcess::construct " + e); } catch (Exception e) { System.out.println("WinProcess::construct " + e); } } public WinProcess(Process process) { this(); try { Field f = process.getClass().getDeclaredField("handle"); f.setAccessible(true); long val = f.getLong(process); this.handle = new WinNT.HANDLE(); this.handle.setPointer(Pointer.createConstant(val)); this.pid = Kernel32.INSTANCE.GetProcessId(this.handle); } catch (NoSuchFieldException e) { } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } } public WinProcess(int pid_) throws IOException { this(); this.handle = Kernel32.INSTANCE.OpenProcess(0x0400 | // PROCESS_QUERY_INFORMATION 0x0800 | // PROCESS_SUSPEND_RESUME 0x0001 | // PROCESS_TERMINATE 0x0200 | // PROCESS_SET_INFORMATION 0x00100000, // SYNCHRONIZE false, pid_); if (this.handle == null) { throw new IOException("OpenProcess failed: " + Kernel32Util.formatMessageFromLastErrorCode(Kernel32.INSTANCE.GetLastError()) + " (pid: " + pid_ + ")"); } this.pid = pid_; } @Override protected void finalize() throws Throwable { if (this.handle != null) { // Kernel32.INSTANCE.CloseHandle(this.handle); // do not close the handle because the parent Process object might still be alive this.handle = null; } this.pid = -1; } public boolean kill() { try { List<WinProcess> children = this.getChildren(); this.terminate(); for (WinProcess child : children) { child.kill(); } } catch (IOException e) { e.printStackTrace(); } return false; } public boolean setPriority(int priority) { return this.kernel32lib.SetPriorityClass(this.handle, priority); } public boolean setAffinity(int numberCores) { // affects the process to a specific core/cpu, it will reduce the number of switch between core // that way the machine will look "less busy" since default behavior for windows is to put 4 cores // at 25% instead of 1 core at 100% but from the user point of view, it introduce lag. if (numberCores > 0) { long coreAffinity = 0; for (int i = 0; i < numberCores; i++) { coreAffinity |= 1L << i; } return this.kernel32lib.SetProcessAffinityMask(this.handle, new DWORD_PTR(coreAffinity)); } return false; } private void terminate() { Kernel32.INSTANCE.TerminateProcess(this.handle, 0); Kernel32.INSTANCE.CloseHandle(this.handle); // we are sure that the parent Process object is dead } private List<WinProcess> getChildren() throws IOException { ArrayList<WinProcess> result = new ArrayList<WinProcess>(); WinNT.HANDLE hSnap = this.kernel32lib.CreateToolhelp32Snapshot(Kernel32Lib.TH32CS_SNAPPROCESS, new DWORD(0)); Kernel32Lib.PROCESSENTRY32.ByReference ent = new Kernel32Lib.PROCESSENTRY32.ByReference(); if (!this.kernel32lib.Process32First(hSnap, ent)) { return result; } do { if (ent.th32ParentProcessID.intValue() == this.pid) { try { result.add(new WinProcess(ent.th32ProcessID.intValue())); } catch (IOException e) { System.err.println("WinProcess::getChildren, IOException " + e); } } } while (this.kernel32lib.Process32Next(hSnap, ent)); Kernel32.INSTANCE.CloseHandle(hSnap); return result; } public String toString() { return "WinProcess(pid: " + this.pid + ", handle " + this.handle + ")"; } }