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
- Re-open the process handle and retry once — the target may have exited between calls.
- Check Win32Exception.getErrorCode(): ERROR_INVALID_HANDLE/ERROR_ACCESS_DENIED means retrying with a bigger buffer will not help.
- Skip failed PIDs in bulk enumeration instead of aborting the whole scan.
- 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
- Treat every enumerated process as possibly already dead; null-check results.
- Re-open handles rather than reusing them across long scans.
- Check error code before retrying with larger buffers — only ERROR_INSUFFICIENT_BUFFER benefits.
- Run with adequate privileges for protected processes.
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
- Win32Exception from native GetLastError after OpenProcess…
- Bad volume GUID path format:
- Expected GetTokenInformation to fail with…
- Failed to find privilege
- LookupAccountNameW was expected to fail with…
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)