java-native-access/jna · error · Win32Exception

Win32Exception from native GetLastError after…

Error message

Win32Exception from native GetLastError after QueryFullProcessImageName retry loop exhausted

What it means

QueryFullProcessImageName(HANDLE, dwFlags) grows its name buffer by 1024 chars in a loop while the API fails with ERROR_INSUFFICIENT_BUFFER. Once the loop exits for any other failure, the wrapper throws Win32Exception with the current GetLastError code. This means the buffer-size path was exhausted by a different error — typically the process handle is no longer valid or access was revoked.

Solutions

  1. Re-open the process handle and retry once — the target may have exited between calls.
  2. Check Win32Exception.getErrorCode(): ERROR_INVALID_HANDLE/ERROR_ACCESS_DENIED means retrying with a bigger buffer will not help.
  3. Skip failed PIDs in bulk enumeration instead of aborting the whole scan.
  4. Run with sufficient privileges (elevated / SeDebugPrivilege) if access-denied errors dominate.

Example fix

// before
String name = Kernel32Util.QueryFullProcessImageName(hProcess, 0);

// after
String name;
try {
    name = Kernel32Util.QueryFullProcessImageName(hProcess, 0);
} catch (Win32Exception e) {
    if (e.getErrorCode() == WinError.ERROR_INVALID_HANDLE) {
        name = null; // process exited; skip
    } else {
        throw e;
    }
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
    return Kernel32Util.QueryFullProcessImageName(hProcess, 0);
} catch (Win32Exception e) {
    if (e.getErrorCode() == WinError.ERROR_INVALID_HANDLE) {
        return null; // process exited
    }
    throw e;
}

Prevention

When it happens

Trigger: The do/while retry loop ends because GetLastError != ERROR_INSUFFICIENT_BUFFER — e.g. ERROR_ACCESS_DENIED on a protected process, ERROR_INVALID_HANDLE because the process exited and its handle became stale, or an unexpected error with a full buffer (name longer than the loop's growth pattern under unusual conditions).

Common situations: Short-lived processes dying mid-query; protected processes (PPL) denying name queries even with a handle; enumerating many processes where some vanish between OpenProcess and the name query.

Related errors


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

Appendix: source

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

     * @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(HANDLE hProcess, int dwFlags) {
        int size = WinDef.MAX_PATH; // Start with MAX_PATH, then increment with 1024 each iteration
        IntByReference lpdwSize = new IntByReference();
        do {
            char[] lpExeName = new char[size];
            lpdwSize.setValue(size);
            if (Kernel32.INSTANCE.QueryFullProcessImageName(hProcess, dwFlags, lpExeName, lpdwSize)) {
                return new String(lpExeName, 0, lpdwSize.getValue());
            }
            size += 1024;
        } while (Kernel32.INSTANCE.GetLastError() == Kernel32.ERROR_INSUFFICIENT_BUFFER);
        throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
    }

    /**
     * Gets the specified resource out of the specified executable file
     *
     * @param path
     *            The path to the executable file
     * @param type
     *            The type of the resource (either a type name or type ID is
     *            allowed)
     * @param name
     *            The name or ID of the resource
     * @return The resource bytes, or null if no such resource exists.
     * @throws IllegalStateException if the call to LockResource fails
     */
    public static byte[] getResource(String path, String type, String name) {
        HMODULE target = Kernel32.INSTANCE.LoadLibraryEx(path, null, Kernel32.LOAD_LIBRARY_AS_DATAFILE);

View on GitHub (pinned to d036ad9781)