java-native-access/jna · warning · IllegalStateException
Device context did not release properly.
Error message
Device context did not release properly.
What it means
GDI32Util.getScreenshot throws this IllegalStateException when ReleaseDC returns 0, i.e. the device context obtained with GetDC could not be released. This indicates a GDI resource leak risk since each process has a limited DC quota.
Source
Thrown at contrib/platform/src/com/sun/jna/platform/win32/GDI32Util.java:187
}
we = ex;
}
}
if (hdcTargetMem != null) {
// get rid of the device context when done
if (!GDI32.INSTANCE.DeleteDC(hdcTargetMem)) {
Win32Exception ex = new Win32Exception(Native.getLastError());
if (we != null) {
ex.addSuppressedReflected(we);
}
we = ex;
}
}
if (hdcTarget != null) {
if (0 == User32.INSTANCE.ReleaseDC(target, hdcTarget)) {
throw new IllegalStateException("Device context did not release properly.");
}
}
}
if (we != null) {
throw we;
}
return image;
}
}
View on GitHub (pinned to d036ad9781)
Solutions
- Check for and fix double-release of the same HDC in surrounding code
- Ensure the window remains valid for the duration of the capture (keep references, avoid destroying it concurrently)
- Monitor GDI object count (Task Manager > GDI objects); if exhausted, release leaked DCs/bitmaps elsewhere in the app
- Catch the IllegalStateException and log rather than masking an original screenshot failure — note the code rethrows the original Win32Exception afterwards if one occurred
Example fix
// before
HDC hdc = User32.INSTANCE.GetDC(target);
User32.INSTANCE.ReleaseDC(target, hdc);
User32.INSTANCE.ReleaseDC(target, hdc); // second release -> fails
// after
HDC hdc = User32.INSTANCE.GetDC(target);
if (hdc != null) {
User32.INSTANCE.ReleaseDC(target, hdc);
} Defensive patterns
Strategy: try-catch
Try / catch
try {
BufferedImage img = GDI32Util.getScreenshot(hwnd);
} catch (IllegalStateException e) {
if (e.getMessage().contains("Device context")) {
log.warn("ReleaseDC failed; check GDI handle usage", e);
} else {
throw e;
}
} Prevention
- Do not release the same HDC twice in surrounding code
- Keep the target window alive for the whole capture (no concurrent destroy)
- Monitor process GDI object counts in long-running automation; leaks elsewhere can make ReleaseDC misbehave
When it happens
Trigger: ReleaseDC failing because the HDC was already released, was not obtained via GetDC on that window, or the target HWND became invalid during the screenshot.
Common situations: Long-running automation taking many screenshots and hitting GDI handle exhaustion; double-release paths in custom code wrapped around getScreenshot; window destroyed between GetDC and ReleaseDC.
Related errors
- Window width and/or height were 0 even though GetWindowRect
- Invalid data length:
- Invalid guid length:
- Missing variable value separator in
- FileMonitor not implemented for " + os
AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12).
Data as JSON: /api/errors/3ad94295ee691800.
Report an issue: GitHub.