Skip to content

Conversation

@marktech0813
Copy link

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.

In contrib/platform/src/com/sun/jna/platform/WindowUtils.java, updated W32WindowUtils.getProcessFilePath:
On first OpenProcess failure, if GetLastError() is ACCESS_DENIED or INVALID_PARAMETER, we attempt PROCESS_QUERY_LIMITED_INFORMATION.
If the second OpenProcess also fails with ACCESS_DENIED or INVALID_PARAMETER, we return an empty string instead of throwing.
Only other error codes still throw a Win32Exception.

…he parameter is incorrect java-native-access#1700

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.
@JaredDavis22
Copy link

Hi,
I believe CHANGES.MD needs an update as well.

Is your email valid? From: helloJetBase-tech 178346048+marktech0813@users.noreply.github.com That seems to be a frequent comment from @matthiasblaesing.

What about using a switch instead of adding a local variable?

@marktech0813
Copy link
Author

hi,

I added a bug-fix entry under “Next Release (5.19.0) → Bug Fixes” in CHANGES.md referencing java-native-access#1700.
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.
@marktech0813
Copy link
Author

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.
I added a bug-fix entry under “Next Release (5.19.0) → Bug Fixes” in CHANGES.md referencing #1700.

Copy link
Author

@marktech0813 marktech0813 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me know if you’d prefer we still cache the error once per branch to be extra defensive, but functionally it’s now switch-based and CHANGES is updated.

@BugsBeGone
Copy link
Contributor

BugsBeGone commented Nov 12, 2025

While we're finessing, how about an early break and fall-through to reduce duplicate code? Within the first switch, rather than checking for null, just break out early if process is assigned. Then the nested switch can just check for the 2 cases, else fall through to the outer switch's default. Maybe better if I just show the code:

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) {
            break;
        }
        switch (Kernel32.INSTANCE.GetLastError()) {
            case WinNT.ERROR_ACCESS_DENIED:
            case WinError.ERROR_INVALID_PARAMETER:
                return "";
        }
        /* if above didn't already break or return, fall through to default */
    default:
        throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}

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/
@marktech0813
Copy link
Author

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).

Copy link
Member

@matthiasblaesing matthiasblaesing left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is real and this stack overflow post gives some possible reasons: https://stackoverflow.com/questions/4988082/openprocess-error-87-invalid-parameter

The use the correct parameter to fetch the PID, but the other to reasons (window from system process or different user/terminal services) sounds reasonable.

So I agree with the general idea here.

Nitpicks:

Please squash the commits into a single commit.

@marktech0813
Copy link
Author

okay.

marktech0813 and others added 2 commits November 13, 2025 21:29
Co-authored-by: Matthias Bläsing <mblaesing@doppel-helix.eu>
Co-authored-by: Matthias Bläsing <mblaesing@doppel-helix.eu>
@matthiasblaesing
Copy link
Member

Please squash and update the author information.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants