java-native-access/jna · error · Win32Exception

Win32Exception from native GetLastError after OpenProcess fa

Error message

Win32Exception from native GetLastError after OpenProcess failed

What it means

QueryFullProcessImageName(pid, dwFlags) first opens the target process with PROCESS_QUERY_INFORMATION | PROCESS_VM_READ via OpenProcess. If OpenProcess returns null (failure), the wrapper throws Win32Exception with the native GetLastError code — classically ERROR_ACCESS_DENIED for protected/system processes. The handle is cleaned up in a finally block; the exception is re-thrown after cleanup.

Source

Thrown at contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java:931

     * This function retrieves the full path of the executable file of a given process identifier.
     *
     * @param pid
     *          Identifier for the running process
     * @param dwFlags
     *          0 - The name should use the Win32 path format.
     *          1(WinNT.PROCESS_NAME_NATIVE) - The name should use the native system path format.
     *
     * @return the full path of the process's executable file of null if failed. To get extended error information,
     *         call GetLastError.
     */
    public static final String QueryFullProcessImageName(int pid, int dwFlags) {
        HANDLE hProcess = null;
        Win32Exception we = null;

        try {
            hProcess = Kernel32.INSTANCE.OpenProcess(WinNT.PROCESS_QUERY_INFORMATION | WinNT.PROCESS_VM_READ, false, pid);
            if (hProcess == null) {
                throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
            }
            return QueryFullProcessImageName(hProcess, dwFlags);
        } catch (final Win32Exception e) {
            throw we = e; // re-throw to avoid return value!
        } finally {
            cleanUp(hProcess, we);
        }
    }

    /**
     *
     * This function retrieves the full path of the executable file of a given process.
     *
     * @param hProcess
     *          Handle for the running process
     * @param dwFlags
     *          0 - The name should use the Win32 path format.
     *          1(WinNT.PROCESS_NAME_NATIVE) - The name should use the native system path format.

View on GitHub (pinned to d036ad9781)

Solutions

  1. Check the process still exists before opening (Kernel32.INSTANCE.OpenProcess failure with ERROR_INVALID_PARAMETER means it exited).
  2. Run the JVM elevated or grant SeDebugPrivilege when querying other users'/system processes.
  3. Catch Win32Exception and skip processes returning ERROR_ACCESS_DENIED instead of failing the whole enumeration.
  4. Request only needed access; consider PROCESS_QUERY_LIMITED_INFORMATION (supported by the dwFlags variant) which succeeds on more processes.

Example fix

// before
String name = Kernel32Util.QueryFullProcessImageName(pid, 0); // throws for System PIDs

// after
String name;
try {
    name = Kernel32Util.QueryFullProcessImageName(pid, 0);
} catch (Win32Exception e) {
    if (e.getErrorCode() == WinError.ERROR_ACCESS_DENIED) {
        name = "<access denied>"; // skip protected process
    } else {
        throw e;
    }
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
    return Kernel32Util.QueryFullProcessImageName(pid, 0);
} catch (Win32Exception e) {
    if (e.getErrorCode() == WinError.ERROR_ACCESS_DENIED
            || e.getErrorCode() == WinError.ERROR_INVALID_PARAMETER) {
        return "<unavailable>"; // protected or exited process
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling Kernel32Util.QueryFullProcessImageName(int pid, int dwFlags) when OpenProcess fails — the PID does not exist (ERROR_INVALID_PARAMETER), the process is a protected/system process (ERROR_ACCESS_DENIED), or the caller lacks SeDebugPrivilege and is not on the same user session.

Common situations: Enumerating all PIDs (e.g. from tasklist or ProcessHandle.allProcesses) and hitting PID 4/System or antivirus processes; process exited between listing and opening; running as a normal user while targeting another user's process; sandboxed services without debug privileges.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12). Data as JSON: /api/errors/ac05d6d468e81ab6. Report an issue: GitHub.