diff --git a/CHANGES.md b/CHANGES.md index 8df24df9a..ba3dacfc3 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,6 +8,7 @@ Next Release (5.14.0) Features -------- * [#1534](https://github.com/java-native-access/jna/pull/1534): Add `GetMethod`, `Put`, `SpawnInstance` to `c.s.j.p.win32.COM.WbemCli#IWbemClassObject` and `ExecMethod` to `c.s.j.p.win32.COM.WbemCli#IWbemServices` - [@faddom](https://github.com/faddom). +* [#1544](https://github.com/java-native-access/jna/pull/1544): Add `GetPriorityClass`, `SetPriorityClass`, `GetThreadPriority`, `SetThreadPriority` and associated constants to `c.s.j.p.win32.Kernel32` - [@dEajL3kA](https://github.com/dEajL3kA). Bug Fixes --------- diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java b/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java index 14a1bd772..c22fa5a52 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java @@ -68,6 +68,44 @@ public interface Kernel32 extends StdCallLibrary, WinNT, Wincon { */ int LOAD_LIBRARY_AS_DATAFILE = 0x2; + /** + * Process priority classes + */ + DWORD NORMAL_PRIORITY_CLASS = new DWORD(0x00000020L); + DWORD IDLE_PRIORITY_CLASS = new DWORD(0x00000040L); + DWORD HIGH_PRIORITY_CLASS = new DWORD(0x00000080L); + DWORD REALTIME_PRIORITY_CLASS = new DWORD(0x00000100L); + DWORD BELOW_NORMAL_PRIORITY_CLASS = new DWORD(0x00004000L); + DWORD ABOVE_NORMAL_PRIORITY_CLASS = new DWORD(0x00008000L); + + /** + * Process mode flags + */ + DWORD PROCESS_MODE_BACKGROUND_BEGIN = new DWORD(0x00100000L); + DWORD PROCESS_MODE_BACKGROUND_END = new DWORD(0x00200000L); + + /** + * Thread priorities + */ + int THREAD_PRIORITY_IDLE = -15; + int THREAD_PRIORITY_LOWEST = -2; + int THREAD_PRIORITY_BELOW_NORMAL = -1; + int THREAD_PRIORITY_NORMAL = 0; + int THREAD_PRIORITY_ABOVE_NORMAL = 1; + int THREAD_PRIORITY_HIGHEST = 2; + int THREAD_PRIORITY_TIME_CRITICAL = 15; + + /** + * Thread mode flags + */ + int THREAD_MODE_BACKGROUND_BEGIN = 0x10000; + int THREAD_MODE_BACKGROUND_END = 0x20000; + + /** + * Thread priority error code + */ + int THREAD_PRIORITY_ERROR_RETURN = 0x7FFFFFFF; + /** * Reads data from the specified file or input/output (I/O) device. Reads * occur at the position specified by the file pointer if supported by the @@ -4152,6 +4190,45 @@ Pointer VirtualAllocEx(HANDLE hProcess, Pointer lpAddress, SIZE_T dwSize, */ boolean GetExitCodeThread(HANDLE hThread, IntByReference exitCode); + /** + * Gets the priority class of the specified process. + * + * @param hProcess A handle to the process. + * @return If the function succeeds, the return value is the priority class of + * the specified process. + *
If the function fails, the return value is zero.
+ */ + DWORD GetPriorityClass(HANDLE hProcess); + + /** + * Sets the priority class for the specified process. + * + * @param hProcess A handle to the process. + * @param dwPriorityClass The priority class for the process. + * @return If the function succeeds, the return value is nonzero. + */ + boolean SetPriorityClass(HANDLE hProcess, DWORD dwPriorityClass); + + /** + * Gets the priority value of the specified thread. + * + * @param hProcess A handle to the process. + * @return If the function succeeds, the return value is the priority class of + * the specified thread. + *If the function fails, the return value is + * THREAD_PRIORITY_ERROR_RETURN.
+ */ + int GetThreadPriority(HANDLE hProcess); + + /** + * Sets the priority value for the specified thread. + * + * @param hThread A handle to the thread whose priority value is to be set. + * @param nPriority The priority value for the thread. + * @return If the function succeeds, the return value is nonzero. + */ + boolean SetThreadPriority(HANDLE hThread, int nPriority); + /** * Releases, decommits, or releases and decommits a region of memory within * the virtual address space of a specified process. diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java b/contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java index e34cb3647..27ecd88eb 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java @@ -392,23 +392,10 @@ public static int getFileType(String fileName) throws FileNotFoundException { default: return type; } - } catch(Win32Exception e) { - err = e; - throw err; // re-throw so finally block executed + } catch(final Win32Exception e) { + throw err = e; // re-throw to avoid return value! } finally { - try { - closeHandle(hFile); - } catch(Win32Exception e) { - if (err == null) { - err = e; - } else { - err.addSuppressedReflected(e); - } - } - - if (err != null) { - throw err; - } + cleanUp(hFile, err); } } @@ -944,22 +931,10 @@ public static final String QueryFullProcessImageName(int pid, int dwFlags) { throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); } return QueryFullProcessImageName(hProcess, dwFlags); - } catch (Win32Exception e) { - we = e; - throw we; // re-throw to invoke finally block + } catch (final Win32Exception e) { + throw we = e; // re-throw to avoid return value! } finally { - try { - closeHandle(hProcess); - } catch (Win32Exception e) { - if (we == null) { - we = e; - } else { - we.addSuppressedReflected(e); - } - } - if (we != null) { - throw we; - } + cleanUp(hProcess, we); } } @@ -1223,23 +1198,10 @@ public static ListIntentionally does not accept "background" processing mode flags!
+ * + * @param dwPriorityClass The priority value to test. + * @return Returns true, if and only if the given priority value was valid + */ + public static boolean isValidPriorityClass(final DWORD dwPriorityClass) { + return Kernel32.NORMAL_PRIORITY_CLASS.equals(dwPriorityClass) || + Kernel32.IDLE_PRIORITY_CLASS.equals(dwPriorityClass) || + Kernel32.HIGH_PRIORITY_CLASS.equals(dwPriorityClass) || + Kernel32.REALTIME_PRIORITY_CLASS.equals(dwPriorityClass) || + Kernel32.BELOW_NORMAL_PRIORITY_CLASS.equals(dwPriorityClass) || + Kernel32.ABOVE_NORMAL_PRIORITY_CLASS.equals(dwPriorityClass); + } + + /** + * Test whether the given thread priority is valid. + *Intentionally does not accept "background" processing mode flags!
+ * + * @param nPriority The priority value to test. + * @return Returns true, if and only if the given priority value was valid + */ + public static boolean isValidThreadPriority(final int nPriority) { + switch(nPriority) { + case Kernel32.THREAD_PRIORITY_IDLE: + case Kernel32.THREAD_PRIORITY_LOWEST: + case Kernel32.THREAD_PRIORITY_BELOW_NORMAL: + case Kernel32.THREAD_PRIORITY_NORMAL: + case Kernel32.THREAD_PRIORITY_ABOVE_NORMAL: + case Kernel32.THREAD_PRIORITY_HIGHEST: + case Kernel32.THREAD_PRIORITY_TIME_CRITICAL: + return true; + default: + return false; + } + } + + private static void cleanUp(final HANDLE h, Win32Exception we) { + try { + closeHandle(h); + } catch (final Win32Exception e) { + if (we == null) { + we = e; + } else { + we.addSuppressedReflected(e); + } + } + if (we != null) { + throw we; + } + } } diff --git a/contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java b/contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java index d964c70de..f8b6971c3 100644 --- a/contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java @@ -2099,4 +2099,24 @@ public void testVirtualLockUnlock() { // Unlocking an unlocked region should fail assertFalse(Kernel32.INSTANCE.VirtualUnlock(mem, new SIZE_T(4096))); } + + public void testGetPriorityClass() { + final HANDLE selfHandle = Kernel32.INSTANCE.GetCurrentProcess(); + assertTrue(Kernel32Util.isValidPriorityClass(Kernel32.INSTANCE.GetPriorityClass(selfHandle))); + } + + public void testSetPriorityClass() { + final HANDLE selfHandle = Kernel32.INSTANCE.GetCurrentProcess(); + assertTrue(Kernel32.INSTANCE.SetPriorityClass(selfHandle, Kernel32.HIGH_PRIORITY_CLASS)); + } + + public void testGetThreadPriority() { + final HANDLE selfHandle = Kernel32.INSTANCE.GetCurrentThread(); + assertTrue(Kernel32Util.isValidThreadPriority(Kernel32.INSTANCE.GetThreadPriority(selfHandle))); + } + + public void testSetThreadPriority() { + final HANDLE selfHandle = Kernel32.INSTANCE.GetCurrentThread(); + assertTrue(Kernel32.INSTANCE.SetThreadPriority(selfHandle, Kernel32.THREAD_PRIORITY_ABOVE_NORMAL)); + } } diff --git a/contrib/platform/test/com/sun/jna/platform/win32/Kernel32UtilTest.java b/contrib/platform/test/com/sun/jna/platform/win32/Kernel32UtilTest.java index cdb5c373f..ca57fce34 100644 --- a/contrib/platform/test/com/sun/jna/platform/win32/Kernel32UtilTest.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/Kernel32UtilTest.java @@ -37,6 +37,7 @@ import com.sun.jna.Pointer; import com.sun.jna.platform.win32.Tlhelp32.MODULEENTRY32W; +import com.sun.jna.platform.win32.WinDef.DWORD; import com.sun.jna.platform.win32.WinNT.CACHE_RELATIONSHIP; import com.sun.jna.platform.win32.WinNT.GROUP_RELATIONSHIP; import com.sun.jna.platform.win32.WinNT.HANDLE; @@ -513,4 +514,90 @@ public void testGetLogicalProcessorInformationEx() { assertTrue(cache.associativity == WinNT.CACHE_FULLY_ASSOCIATIVE || cache.associativity > 0); } } + + public void testGetCurrentProcessPriority() { + assertTrue(Kernel32Util.isValidPriorityClass(Kernel32Util.getCurrentProcessPriority())); + } + + public void testSetCurrentProcessPriority() { + Kernel32Util.setCurrentProcessPriority(Kernel32.HIGH_PRIORITY_CLASS); + } + + public void testSetCurrentProcessBackgroundMode() { + try { + Kernel32Util.setCurrentProcessBackgroundMode(true); + } finally { + try { + Kernel32Util.setCurrentProcessBackgroundMode(false); // Reset the "background" mode! + } catch (Exception e) { } + } + } + + public void testGetCurrentThreadPriority() { + assertTrue(Kernel32Util.isValidThreadPriority(Kernel32Util.getCurrentThreadPriority())); + } + + public void testSetCurrentThreadPriority() { + Kernel32Util.setCurrentThreadPriority(Kernel32.THREAD_PRIORITY_ABOVE_NORMAL); + } + + public void testSetCurrentThreadBackgroundMode() { + try { + Kernel32Util.setCurrentThreadBackgroundMode(true); + } finally { + try { + Kernel32Util.setCurrentThreadBackgroundMode(false); // Reset the "background" mode! + } catch (Exception e) { } + } + } + + public void testGetProcessPriority() { + final int pid = Kernel32.INSTANCE.GetCurrentProcessId(); + assertTrue(Kernel32Util.isValidPriorityClass(Kernel32Util.getProcessPriority(pid))); + } + + public void testSetProcessPriority() { + final int pid = Kernel32.INSTANCE.GetCurrentProcessId(); + Kernel32Util.setProcessPriority(pid, Kernel32.HIGH_PRIORITY_CLASS); + } + + public void testGetThreadPriority() { + final int tid = Kernel32.INSTANCE.GetCurrentThreadId(); + assertTrue(Kernel32Util.isValidThreadPriority(Kernel32Util.getThreadPriority(tid))); + } + + public void testSetThreadPriority() { + final int tid = Kernel32.INSTANCE.GetCurrentThreadId(); + Kernel32Util.setThreadPriority(tid, Kernel32.THREAD_PRIORITY_ABOVE_NORMAL); + } + + public void testIsValidPriorityClass() { + assertTrue(Kernel32Util.isValidPriorityClass(Kernel32.NORMAL_PRIORITY_CLASS)); + assertTrue(Kernel32Util.isValidPriorityClass(Kernel32.IDLE_PRIORITY_CLASS)); + assertTrue(Kernel32Util.isValidPriorityClass(Kernel32.HIGH_PRIORITY_CLASS)); + assertTrue(Kernel32Util.isValidPriorityClass(Kernel32.REALTIME_PRIORITY_CLASS)); + assertTrue(Kernel32Util.isValidPriorityClass(Kernel32.BELOW_NORMAL_PRIORITY_CLASS)); + assertTrue(Kernel32Util.isValidPriorityClass(Kernel32.ABOVE_NORMAL_PRIORITY_CLASS)); + assertFalse(Kernel32Util.isValidPriorityClass(new DWORD(0L))); + assertFalse(Kernel32Util.isValidPriorityClass(new DWORD(1L))); + assertFalse(Kernel32Util.isValidPriorityClass(new DWORD(0xFFFFFFFF))); + assertFalse(Kernel32Util.isValidPriorityClass(Kernel32.PROCESS_MODE_BACKGROUND_BEGIN)); + assertFalse(Kernel32Util.isValidPriorityClass(Kernel32.PROCESS_MODE_BACKGROUND_END)); + } + + public void testIsValidThreadPriority() { + assertTrue(Kernel32Util.isValidThreadPriority(Kernel32.THREAD_PRIORITY_IDLE)); + assertTrue(Kernel32Util.isValidThreadPriority(Kernel32.THREAD_PRIORITY_LOWEST)); + assertTrue(Kernel32Util.isValidThreadPriority(Kernel32.THREAD_PRIORITY_BELOW_NORMAL)); + assertTrue(Kernel32Util.isValidThreadPriority(Kernel32.THREAD_PRIORITY_NORMAL)); + assertTrue(Kernel32Util.isValidThreadPriority(Kernel32.THREAD_PRIORITY_ABOVE_NORMAL)); + assertTrue(Kernel32Util.isValidThreadPriority(Kernel32.THREAD_PRIORITY_HIGHEST)); + assertTrue(Kernel32Util.isValidThreadPriority(Kernel32.THREAD_PRIORITY_TIME_CRITICAL)); + assertFalse(Kernel32Util.isValidThreadPriority( 3)); + assertFalse(Kernel32Util.isValidThreadPriority( -3)); + assertFalse(Kernel32Util.isValidThreadPriority( 16)); + assertFalse(Kernel32Util.isValidThreadPriority(-16)); + assertFalse(Kernel32Util.isValidThreadPriority(Kernel32.THREAD_MODE_BACKGROUND_BEGIN)); + assertFalse(Kernel32Util.isValidThreadPriority(Kernel32.THREAD_MODE_BACKGROUND_END)); + } }