From 6ff34ff5bee18c177c9d7573473c9fcf862d8636 Mon Sep 17 00:00:00 2001 From: helloJetBase-tech <178346048+marktech0813@users.noreply.github.com> Date: Tue, 11 Nov 2025 16:42:17 +0200 Subject: [PATCH 1/6] Improve error handling in OpenProcess method : Windows32Exception - The parameter is incorrect #1700 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I found the Windows code path that throws in getProcessFilePath(HWND) and implemented a defensive fix so your logs won’t fill with Win32Exceptions anymore. Now, when OpenProcess fails with ERROR_INVALID_PARAMETER (87), it is treated like ACCESS_DENIED: we either retry with PROCESS_QUERY_LIMITED_INFORMATION, or return an empty path if access still fails. This covers the race where a PID disappears between enumeration and open, or other transient/unsupported cases. --- .../src/com/sun/jna/platform/WindowUtils.java | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/WindowUtils.java b/contrib/platform/src/com/sun/jna/platform/WindowUtils.java index 78ea1fa2d..09b61b677 100644 --- a/contrib/platform/src/com/sun/jna/platform/WindowUtils.java +++ b/contrib/platform/src/com/sun/jna/platform/WindowUtils.java @@ -1298,23 +1298,25 @@ public String getProcessFilePath(final HWND hwnd) { pid.getValue()); if (process == null) { - if(Kernel32.INSTANCE.GetLastError() != WinNT.ERROR_ACCESS_DENIED) { - throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); - } else { - process = Kernel32.INSTANCE.OpenProcess( - WinNT.PROCESS_QUERY_LIMITED_INFORMATION, - false, + int lastError = Kernel32.INSTANCE.GetLastError(); + if (lastError == WinNT.ERROR_ACCESS_DENIED + || lastError == WinError.ERROR_INVALID_PARAMETER) { + process = Kernel32.INSTANCE.OpenProcess( + WinNT.PROCESS_QUERY_LIMITED_INFORMATION, + false, pid.getValue()); if (process == null) { - if (Kernel32.INSTANCE.GetLastError() != WinNT.ERROR_ACCESS_DENIED) { - throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); - } else { - // Ignore windows, that can't be accessed + lastError = Kernel32.INSTANCE.GetLastError(); + if (lastError == WinNT.ERROR_ACCESS_DENIED + || lastError == WinError.ERROR_INVALID_PARAMETER) { return ""; - } + } + throw new Win32Exception(lastError); } - } + } else { + throw new Win32Exception(lastError); + } } try { From 56131353836ca7af64b7297497986aa7d4f2a804 Mon Sep 17 00:00:00 2001 From: helloJetBase-tech <178346048+marktech0813@users.noreply.github.com> Date: Tue, 11 Nov 2025 17:48:21 +0200 Subject: [PATCH 2/6] Update CHANGES.md with bug fix details MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I added a bug-fix entry under “Next Release (5.19.0) → Bug Fixes” in CHANGES.md referencing #1700. --- CHANGES.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 34bdcca29..56667aea9 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,7 @@ Features Bug Fixes --------- +* [#1700](https://github.com/java-native-access/jna/issues/1700): Windows: treat `ERROR_INVALID_PARAMETER` from `OpenProcess` in `c.s.j.p.WindowUtils#getProcessFilePath` like `ERROR_ACCESS_DENIED` to avoid spurious `Win32Exception` when enumerating windows whose processes have exited or are otherwise inaccessible. Release 5.18.1 @@ -1465,4 +1466,4 @@ Bug Fixes * Ensure native libraries are only loaded once until released * Properly handle NULL when the return value is a Structure * Proper conversion to wchar_t on linux -* Copy full length of Java strings to C strings instead of stopping when a NUL character is encountered \ No newline at end of file +* Copy full length of Java strings to C strings instead of stopping when a NUL character is encountered From 2c6396d7f374122023109d9e2c2b519b8a2447a6 Mon Sep 17 00:00:00 2001 From: helloJetBase-tech <178346048+marktech0813@users.noreply.github.com> Date: Tue, 11 Nov 2025 17:49:22 +0200 Subject: [PATCH 3/6] Refactor error handling in OpenProcess method I replaced the local variable with a switch on GetLastError in getProcessFilePath(HWND) so we branch on ACCESS_DENIED and INVALID_PARAMETER without storing the error. --- .../src/com/sun/jna/platform/WindowUtils.java | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/WindowUtils.java b/contrib/platform/src/com/sun/jna/platform/WindowUtils.java index 09b61b677..2faa19480 100644 --- a/contrib/platform/src/com/sun/jna/platform/WindowUtils.java +++ b/contrib/platform/src/com/sun/jna/platform/WindowUtils.java @@ -1298,25 +1298,26 @@ public String getProcessFilePath(final HWND hwnd) { pid.getValue()); if (process == null) { - int lastError = Kernel32.INSTANCE.GetLastError(); - if (lastError == WinNT.ERROR_ACCESS_DENIED - || lastError == WinError.ERROR_INVALID_PARAMETER) { - process = Kernel32.INSTANCE.OpenProcess( - WinNT.PROCESS_QUERY_LIMITED_INFORMATION, - false, - pid.getValue()); - - if (process == null) { - lastError = Kernel32.INSTANCE.GetLastError(); - if (lastError == WinNT.ERROR_ACCESS_DENIED - || lastError == WinError.ERROR_INVALID_PARAMETER) { - return ""; - } - throw new Win32Exception(lastError); - } - } else { - throw new Win32Exception(lastError); - } + switch (Kernel32.INSTANCE.GetLastError()) { + case WinNT.ERROR_ACCESS_DENIED: + case WinError.ERROR_INVALID_PARAMETER: + process = Kernel32.INSTANCE.OpenProcess( + WinNT.PROCESS_QUERY_LIMITED_INFORMATION, + false, + pid.getValue()); + if (process == null) { + switch (Kernel32.INSTANCE.GetLastError()) { + case WinNT.ERROR_ACCESS_DENIED: + case WinError.ERROR_INVALID_PARAMETER: + return ""; + default: + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } + } + break; + default: + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } } try { From 05634ae170ec422b277b6a916528ab329fa4cf77 Mon Sep 17 00:00:00 2001 From: helloJetBase-tech <178346048+marktech0813@users.noreply.github.com> Date: Wed, 12 Nov 2025 20:04:46 +0200 Subject: [PATCH 4/6] Update WindowUtils.java Yes. Functionally identical, but cleaner: Less duplication and shallower nesting via early break and fall-through. No extraneous local state; logic is driven directly by GetLastError. Readability improved while preserving exact semantics (retry on ACCESS_DENIED/INVALID_PARAMETER, otherwise throw; return "" on second failure). Contribution by Gittensor, learn more at https://gittensor.io/ --- .../src/com/sun/jna/platform/WindowUtils.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/WindowUtils.java b/contrib/platform/src/com/sun/jna/platform/WindowUtils.java index 2faa19480..4c7f44904 100644 --- a/contrib/platform/src/com/sun/jna/platform/WindowUtils.java +++ b/contrib/platform/src/com/sun/jna/platform/WindowUtils.java @@ -1305,16 +1305,15 @@ public String getProcessFilePath(final HWND hwnd) { WinNT.PROCESS_QUERY_LIMITED_INFORMATION, false, pid.getValue()); - if (process == null) { - switch (Kernel32.INSTANCE.GetLastError()) { - case WinNT.ERROR_ACCESS_DENIED: - case WinError.ERROR_INVALID_PARAMETER: - return ""; - default: - throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); - } + if (process != null) { + break; + } + switch (Kernel32.INSTANCE.GetLastError()) { + case WinNT.ERROR_ACCESS_DENIED: + case WinError.ERROR_INVALID_PARAMETER: + return ""; } - break; + /* if above didn't already break or return, fall through to default */ default: throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); } From 12bdc9f9f98f84dc7f0833f1085f4d63c290ec64 Mon Sep 17 00:00:00 2001 From: helloJetBase-tech <178346048+marktech0813@users.noreply.github.com> Date: Thu, 13 Nov 2025 21:29:22 +0200 Subject: [PATCH 5/6] Update contrib/platform/src/com/sun/jna/platform/WindowUtils.java MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Bläsing --- contrib/platform/src/com/sun/jna/platform/WindowUtils.java | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/platform/src/com/sun/jna/platform/WindowUtils.java b/contrib/platform/src/com/sun/jna/platform/WindowUtils.java index 4c7f44904..9c4c24e3e 100644 --- a/contrib/platform/src/com/sun/jna/platform/WindowUtils.java +++ b/contrib/platform/src/com/sun/jna/platform/WindowUtils.java @@ -1311,6 +1311,7 @@ public String getProcessFilePath(final HWND hwnd) { switch (Kernel32.INSTANCE.GetLastError()) { case WinNT.ERROR_ACCESS_DENIED: case WinError.ERROR_INVALID_PARAMETER: + // Ignore windows, that can't be accessed return ""; } /* if above didn't already break or return, fall through to default */ From acc1ba9772641950233056f45655a4c06943c839 Mon Sep 17 00:00:00 2001 From: helloJetBase-tech <178346048+marktech0813@users.noreply.github.com> Date: Thu, 13 Nov 2025 21:29:29 +0200 Subject: [PATCH 6/6] Update CHANGES.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matthias Bläsing --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 56667aea9..40b1b09f5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,7 +11,7 @@ Features Bug Fixes --------- -* [#1700](https://github.com/java-native-access/jna/issues/1700): Windows: treat `ERROR_INVALID_PARAMETER` from `OpenProcess` in `c.s.j.p.WindowUtils#getProcessFilePath` like `ERROR_ACCESS_DENIED` to avoid spurious `Win32Exception` when enumerating windows whose processes have exited or are otherwise inaccessible. +* [#1700](https://github.com/java-native-access/jna/issues/1700): Windows: treat `ERROR_INVALID_PARAMETER` from `OpenProcess` in `c.s.j.p.WindowUtils#getProcessFilePath` like `ERROR_ACCESS_DENIED` to avoid spurious `Win32Exception` when enumerating windows whose processes have exited or are otherwise inaccessible - [marktech0813](https://github.com/marktech0813). Release 5.18.1