java-native-access/jna · error · Win32Exception
Win32Exception (error code from GetLastError after…
Error message
Win32Exception (error code from GetLastError after GetPrinter)
What it means
WinspoolUtil.getPrinterInfo2() opens a printer and calls the Win32 GetPrinter API with level 2. If GetPrinter returns FALSE, the native error code from GetLastError is wrapped in a Win32Exception and thrown. This means the printer handle/level/buffer combination was rejected by the spooler.
Solutions
- Check the Win32Exception's errorCode (e.g. 5 = access denied, 87 = invalid parameter, 1801 = invalid printer name) and fix the underlying cause.
- Verify the printer name passed to OpenPrinter is valid and the printer exists (use getPrinterNames/EnumPrinters first).
- Run the process under an account with permissions on the target printer; for network printers ensure the spooler is reachable.
- Re-check that the printer still exists between the size-query and data call; retry getPrinterInfo2 if the error is transient.
Example fix
// before
PRINTER_INFO_2 info = WinspoolUtil.getPrinterInfo2(printerName);
// after
if (!WinspoolUtil.getPrinterNames().contains(printerName)) {
throw new IllegalArgumentException("Printer not found: " + printerName);
}
try {
PRINTER_INFO_2 info = WinspoolUtil.getPrinterInfo2(printerName);
} catch (Win32Exception e) {
if (e.getErrorCode() == W32Errors.ERROR_ACCESS_DENIED) {
throw new IllegalStateException("No permission for printer " + printerName, e);
}
throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
boolean printerExists(String name) {
return WinspoolUtil.getPrinterNames().stream().anyMatch(n -> n.equalsIgnoreCase(name));
} Try / catch
try {
PRINTER_INFO_2 info = WinspoolUtil.getPrinterInfo2(name);
} catch (Win32Exception e) {
switch (e.getErrorCode()) {
case 5: throw new SecurityException("Access denied for printer " + name, e);
case 1801: throw new IllegalArgumentException("Invalid printer name", e);
default: throw e;
}
} Prevention
- Validate the printer name against EnumPrinters output before querying.
- Check the spooler service status before printer operations.
- Run under an account with printer permissions.
- Inspect Win32Exception.getErrorCode() and map codes to concrete causes.
When it happens
Trigger: Calling getPrinterInfo2 with an invalid or closed printer handle, insufficient rights on the printer, or the spooler rejecting the level-2 GetPrinter call after the initial buffer-size call succeeded (e.g. printer deleted or access revoked between the two calls).
Common situations: Querying a network printer that has gone offline, running without printer-access privileges (e.g. service account lacking printer permissions), or a race where the printer is removed while the handle is open.
Related errors
- Win32Exception (error code from GetLastError after EnumJobs)
- Expected GetTokenInformation to fail with…
- Failed to access the print server
- Failed to find privilege
- Failed to get a change handle
AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12).
Data as JSON: /api/errors/b500332664230fd4.
Report an issue: GitHub.
Appendix: source
Thrown at contrib/platform/src/com/sun/jna/platform/win32/WinspoolUtil.java:119
IntByReference pcReturned = new IntByReference();
HANDLEByReference pHandle = new HANDLEByReference();
if (!Winspool.INSTANCE.OpenPrinter(printerName, pHandle, null)) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
Win32Exception we = null;
PRINTER_INFO_2 pinfo2 = null;
try {
Winspool.INSTANCE.GetPrinter(pHandle.getValue(), 2, null, 0, pcbNeeded);
if (pcbNeeded.getValue() <= 0) {
return new PRINTER_INFO_2();
}
pinfo2 = new PRINTER_INFO_2(pcbNeeded.getValue());
if (!Winspool.INSTANCE.GetPrinter(pHandle.getValue(), 2, pinfo2.getPointer(), pcbNeeded.getValue(), pcReturned)) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
pinfo2.read();
} catch (Win32Exception e) {
we = e;
} finally {
if (!Winspool.INSTANCE.ClosePrinter(pHandle.getValue())) {
Win32Exception ex = new Win32Exception(Kernel32.INSTANCE.GetLastError());
if (we != null) {
ex.addSuppressedReflected(we);
}
}
}
if (we != null) {
throw we;
}
View on GitHub (pinned to d036ad9781)