Java Native Access (JNA) provides Java programs easy access to native shared libraries without writing anything but Java code - no JNI or native code is required.
—
This document covers JNA's Windows-specific functionality including stdcall calling convention support, Win32 API integration, and Windows-specific utilities.
import com.sun.jna.win32.StdCall;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;
import com.sun.jna.win32.StdCallFunctionMapper;
import com.sun.jna.win32.W32APIFunctionMapper;
import com.sun.jna.win32.W32APITypeMapper;/**
* Marker interface for stdcall calling convention
* Used by Windows API functions
*/
public interface StdCall extends AltCallingConvention {
// Marker interface - no methods
}
/**
* Base interface for Windows stdcall libraries
*/
public interface StdCallLibrary extends Library, StdCall {
/** Stdcall calling convention constant */
int STDCALL_CONVENTION = Function.ALT_CONVENTION;
/** Auto-lookup of stdcall-decorated names */
FunctionMapper FUNCTION_MAPPER = new StdCallFunctionMapper();
/**
* Callback interface using stdcall convention
*/
public interface StdCallCallback extends Callback, StdCall {
// Marker interface for stdcall callbacks
}
}/**
* Standard options for Win32 API usage
*/
public interface W32APIOptions extends StdCallLibrary {
/** Options for Unicode (wide character) Win32 APIs */
Map<String, Object> UNICODE_OPTIONS = Collections.unmodifiableMap(new HashMap<String, Object>() {{
put(OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);
put(OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE);
}});
/** Options for ASCII/MBCS Win32 APIs */
Map<String, Object> ASCII_OPTIONS = Collections.unmodifiableMap(new HashMap<String, Object>() {{
put(OPTION_TYPE_MAPPER, W32APITypeMapper.ASCII);
put(OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.ASCII);
}});
/** Default options based on w32.ascii system property */
Map<String, Object> DEFAULT_OPTIONS = Boolean.getBoolean("w32.ascii")
? ASCII_OPTIONS : UNICODE_OPTIONS;
}// Simple Windows library interface
public interface Kernel32 extends StdCallLibrary {
Kernel32 INSTANCE = Native.loadLibrary("kernel32", Kernel32.class);
/**
* Get current process ID
* DWORD GetCurrentProcessId(void);
*/
int GetCurrentProcessId();
/**
* Get handle to current process
* HANDLE GetCurrentProcess(void);
*/
Pointer GetCurrentProcess();
/**
* Sleep for specified milliseconds
* void Sleep(DWORD dwMilliseconds);
*/
void Sleep(int dwMilliseconds);
/**
* Get last Win32 error code
* DWORD GetLastError(void);
*/
int GetLastError();
/**
* Set last error code
* void SetLastError(DWORD dwErrCode);
*/
void SetLastError(int dwErrCode);
}
// Usage
int processId = Kernel32.INSTANCE.GetCurrentProcessId();
Pointer processHandle = Kernel32.INSTANCE.GetCurrentProcess();
Kernel32.INSTANCE.Sleep(1000); // Sleep for 1 second// Library supporting both ASCII and Unicode variants
public interface User32 extends StdCallLibrary {
User32 INSTANCE = Native.loadLibrary("user32", User32.class,
W32APIOptions.DEFAULT_OPTIONS);
/**
* Find window by class and window name
* Maps to FindWindowA or FindWindowW based on options
*/
Pointer FindWindow(String lpClassName, String lpWindowName);
/**
* Get window text
* Maps to GetWindowTextA or GetWindowTextW
*/
int GetWindowText(Pointer hWnd, char[] lpString, int nMaxCount);
/**
* Set window text
* Maps to SetWindowTextA or SetWindowTextW
*/
boolean SetWindowText(Pointer hWnd, String lpString);
/**
* Show message box
* Maps to MessageBoxA or MessageBoxW
*/
int MessageBox(Pointer hWnd, String lpText, String lpCaption, int uType);
}
// Explicit Unicode library
public interface User32W extends StdCallLibrary {
User32W INSTANCE = Native.loadLibrary("user32", User32W.class,
W32APIOptions.UNICODE_OPTIONS);
Pointer FindWindowW(WString lpClassName, WString lpWindowName);
int GetWindowTextW(Pointer hWnd, char[] lpString, int nMaxCount);
boolean SetWindowTextW(Pointer hWnd, WString lpString);
int MessageBoxW(Pointer hWnd, WString lpText, WString lpCaption, int uType);
}
// Explicit ASCII library
public interface User32A extends StdCallLibrary {
User32A INSTANCE = Native.loadLibrary("user32", User32A.class,
W32APIOptions.ASCII_OPTIONS);
Pointer FindWindowA(String lpClassName, String lpWindowName);
int GetWindowTextA(Pointer hWnd, byte[] lpString, int nMaxCount);
boolean SetWindowTextA(Pointer hWnd, String lpString);
int MessageBoxA(Pointer hWnd, String lpText, String lpCaption, int uType);
}/**
* Maps function names to stdcall-decorated names
*/
public class StdCallFunctionMapper implements FunctionMapper {
/**
* Get decorated function name for stdcall convention
* @param library Native library
* @param method Java method
* @return Decorated name (e.g., "_function@12")
*/
public String getFunctionName(NativeLibrary library, Method method);
}
/**
* Function mapper for Win32 API with ASCII/Unicode variants
*/
public class W32APIFunctionMapper implements FunctionMapper {
/** Mapper for Unicode APIs (adds W suffix) */
public static final FunctionMapper UNICODE = new W32APIFunctionMapper(true);
/** Mapper for ASCII APIs (adds A suffix) */
public static final FunctionMapper ASCII = new W32APIFunctionMapper(false);
/**
* Get function name with A or W suffix
* @param library Native library
* @param method Java method
* @return Function name with suffix
*/
public String getFunctionName(NativeLibrary library, Method method);
}/**
* Type mapper for Win32 API types (strings and BOOLs)
*/
public class W32APITypeMapper extends DefaultTypeMapper {
/** TypeMapper for Unicode Win32 APIs */
public static final TypeMapper UNICODE;
/** TypeMapper for ASCII/MBCS Win32 APIs */
public static final TypeMapper ASCII;
/** Default TypeMapper based on w32.ascii system property */
public static final TypeMapper DEFAULT;
static {
UNICODE = new W32APITypeMapper(true);
ASCII = new W32APITypeMapper(false);
DEFAULT = Boolean.getBoolean("w32.ascii") ? ASCII : UNICODE;
}
}// Windows handle types
public static class HANDLE extends PointerType {
public HANDLE() { }
public HANDLE(Pointer p) { setPointer(p); }
}
public static class HWND extends HANDLE {
public HWND() { }
public HWND(Pointer p) { super(p); }
}
public static class HMODULE extends HANDLE {
public HMODULE() { }
public HMODULE(Pointer p) { super(p); }
}
// Windows integer types
public static class DWORD extends IntegerType {
public DWORD() { super(4, true); } // 4-byte unsigned
public DWORD(long value) { super(4, value, true); }
}
public static class WORD extends IntegerType {
public WORD() { super(2, true); } // 2-byte unsigned
public WORD(long value) { super(2, value, true); }
}
public static class BYTE extends IntegerType {
public BYTE() { super(1, true); } // 1-byte unsigned
public BYTE(long value) { super(1, value, true); }
}
// BOOL type (maps to int)
public static class BOOL implements NativeMapped {
private final boolean value;
public BOOL() { this.value = false; }
public BOOL(boolean value) { this.value = value; }
public boolean booleanValue() { return value; }
@Override
public Object fromNative(Object nativeValue, FromNativeContext context) {
return new BOOL(((Integer) nativeValue) != 0);
}
@Override
public Object toNative() {
return value ? 1 : 0;
}
@Override
public Class<?> nativeType() {
return Integer.class;
}
}// RECT structure
public static class RECT extends Structure {
public int left;
public int top;
public int right;
public int bottom;
public RECT() { }
public RECT(int left, int top, int right, int bottom) {
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
write();
}
@Override
protected List<String> getFieldOrder() {
return Arrays.asList("left", "top", "right", "bottom");
}
}
// POINT structure
public static class POINT extends Structure {
public int x;
public int y;
public POINT() { }
public POINT(int x, int y) {
this.x = x;
this.y = y;
write();
}
@Override
protected List<String> getFieldOrder() {
return Arrays.asList("x", "y");
}
}
// SYSTEMTIME structure
public static class SYSTEMTIME extends Structure {
public short wYear;
public short wMonth;
public short wDayOfWeek;
public short wDay;
public short wHour;
public short wMinute;
public short wSecond;
public short wMilliseconds;
@Override
protected List<String> getFieldOrder() {
return Arrays.asList("wYear", "wMonth", "wDayOfWeek", "wDay",
"wHour", "wMinute", "wSecond", "wMilliseconds");
}
}// Extended Kernel32 interface
public interface Kernel32 extends StdCallLibrary {
Kernel32 INSTANCE = Native.loadLibrary("kernel32", Kernel32.class,
W32APIOptions.DEFAULT_OPTIONS);
// Process functions
int GetCurrentProcessId();
Pointer GetCurrentProcess();
Pointer OpenProcess(int dwDesiredAccess, boolean bInheritHandle, int dwProcessId);
boolean CloseHandle(Pointer hObject);
boolean TerminateProcess(Pointer hProcess, int uExitCode);
// Memory functions
Pointer VirtualAlloc(Pointer lpAddress, int dwSize, int flAllocationType, int flProtect);
boolean VirtualFree(Pointer lpAddress, int dwSize, int dwFreeType);
// Module functions
Pointer GetModuleHandle(String lpModuleName);
Pointer LoadLibrary(String lpFileName);
boolean FreeLibrary(Pointer hModule);
Pointer GetProcAddress(Pointer hModule, String lpProcName);
// System info
void GetSystemTime(SYSTEMTIME lpSystemTime);
void GetLocalTime(SYSTEMTIME lpSystemTime);
int GetTickCount();
// File functions
Pointer CreateFile(String lpFileName, int dwDesiredAccess, int dwShareMode,
Pointer lpSecurityAttributes, int dwCreationDisposition,
int dwFlagsAndAttributes, Pointer hTemplateFile);
boolean ReadFile(Pointer hFile, Pointer lpBuffer, int nNumberOfBytesToRead,
IntByReference lpNumberOfBytesRead, Pointer lpOverlapped);
boolean WriteFile(Pointer hFile, Pointer lpBuffer, int nNumberOfBytesToWrite,
IntByReference lpNumberOfBytesWritten, Pointer lpOverlapped);
// Constants
int PROCESS_ALL_ACCESS = 0x1F0FFF;
int MEM_COMMIT = 0x1000;
int MEM_RESERVE = 0x2000;
int MEM_RELEASE = 0x8000;
int PAGE_READWRITE = 0x04;
int GENERIC_READ = 0x80000000;
int GENERIC_WRITE = 0x40000000;
int CREATE_ALWAYS = 2;
int OPEN_EXISTING = 3;
}
// Extended User32 interface
public interface User32 extends StdCallLibrary {
User32 INSTANCE = Native.loadLibrary("user32", User32.class,
W32APIOptions.DEFAULT_OPTIONS);
// Window functions
Pointer FindWindow(String lpClassName, String lpWindowName);
Pointer GetForegroundWindow();
boolean SetForegroundWindow(Pointer hWnd);
boolean ShowWindow(Pointer hWnd, int nCmdShow);
boolean IsWindowVisible(Pointer hWnd);
// Window properties
int GetWindowText(Pointer hWnd, char[] lpString, int nMaxCount);
boolean SetWindowText(Pointer hWnd, String lpString);
boolean GetWindowRect(Pointer hWnd, RECT lpRect);
boolean SetWindowPos(Pointer hWnd, Pointer hWndInsertAfter,
int X, int Y, int cx, int cy, int uFlags);
// Input functions
boolean GetCursorPos(POINT lpPoint);
boolean SetCursorPos(int X, int Y);
short GetKeyState(int nVirtKey);
// Message functions
int MessageBox(Pointer hWnd, String lpText, String lpCaption, int uType);
boolean PostMessage(Pointer hWnd, int Msg, Pointer wParam, Pointer lParam);
int SendMessage(Pointer hWnd, int Msg, Pointer wParam, Pointer lParam);
// Constants
int SW_HIDE = 0;
int SW_NORMAL = 1;
int SW_MAXIMIZE = 3;
int SW_MINIMIZE = 6;
int MB_OK = 0x00000000;
int MB_YESNO = 0x00000004;
int WM_CLOSE = 0x0010;
int VK_RETURN = 0x0D;
int VK_ESCAPE = 0x1B;
}/**
* Callback that can be used in DLL context on Windows
*/
public interface DLLCallback extends Callback {
// Marker interface for DLL-compatible callbacks
}
// Windows callback examples
public interface WindowEnumProc extends StdCallLibrary.StdCallCallback {
boolean callback(Pointer hWnd, Pointer lParam);
}
public interface HookProc extends StdCallLibrary.StdCallCallback {
int callback(int nCode, Pointer wParam, Pointer lParam);
}
// Usage with Win32 APIs
public interface User32Extended extends StdCallLibrary {
User32Extended INSTANCE = Native.loadLibrary("user32", User32Extended.class);
/**
* Enumerate all top-level windows
* BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam);
*/
boolean EnumWindows(WindowEnumProc lpEnumFunc, Pointer lParam);
/**
* Install hook procedure
* HHOOK SetWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId);
*/
Pointer SetWindowsHookEx(int idHook, HookProc lpfn, Pointer hMod, int dwThreadId);
/**
* Remove hook procedure
* BOOL UnhookWindowsHookEx(HHOOK hhk);
*/
boolean UnhookWindowsHookEx(Pointer hhk);
}
// Callback implementations
WindowEnumProc windowEnumerator = new WindowEnumProc() {
@Override
public boolean callback(Pointer hWnd, Pointer lParam) {
char[] windowText = new char[512];
User32.INSTANCE.GetWindowText(hWnd, windowText, windowText.length);
String title = new String(windowText).trim();
if (!title.isEmpty()) {
System.out.println("Window: " + title);
}
return true; // Continue enumeration
}
};
// Enumerate all windows
User32Extended.INSTANCE.EnumWindows(windowEnumerator, Pointer.NULL);// Get current window information
public class WindowInfo {
public static void main(String[] args) {
// Get foreground window
Pointer hwnd = User32.INSTANCE.GetForegroundWindow();
if (hwnd != null) {
// Get window title
char[] titleBuffer = new char[512];
int titleLength = User32.INSTANCE.GetWindowText(hwnd, titleBuffer, titleBuffer.length);
String title = new String(titleBuffer, 0, titleLength);
// Get window position
RECT rect = new RECT();
User32.INSTANCE.GetWindowRect(hwnd, rect);
System.out.println("Active window: " + title);
System.out.println("Position: (" + rect.left + ", " + rect.top +
") - (" + rect.right + ", " + rect.bottom + ")");
}
}
}
// System information
public class SystemInfo {
public static void main(String[] args) {
// Get current time
SYSTEMTIME time = new SYSTEMTIME();
Kernel32.INSTANCE.GetSystemTime(time);
System.out.printf("Current UTC time: %04d-%02d-%02d %02d:%02d:%02d.%03d%n",
time.wYear, time.wMonth, time.wDay,
time.wHour, time.wMinute, time.wSecond, time.wMilliseconds);
// Get process info
int processId = Kernel32.INSTANCE.GetCurrentProcessId();
Pointer processHandle = Kernel32.INSTANCE.GetCurrentProcess();
System.out.println("Process ID: " + processId);
System.out.println("Process handle: " + processHandle);
}
}
// File operations
public class FileOperations {
public static void writeFile(String filename, String content) {
Pointer hFile = Kernel32.INSTANCE.CreateFile(
filename,
Kernel32.GENERIC_WRITE,
0, // No sharing
null, // Default security
Kernel32.CREATE_ALWAYS,
0, // Normal attributes
null // No template
);
if (hFile == null || hFile.equals(Pointer.createConstant(-1))) {
throw new RuntimeException("Failed to create file: " +
Kernel32.INSTANCE.GetLastError());
}
try {
byte[] data = content.getBytes("UTF-8");
Memory buffer = new Memory(data.length);
buffer.write(0, data, 0, data.length);
IntByReference bytesWritten = new IntByReference();
boolean success = Kernel32.INSTANCE.WriteFile(
hFile, buffer, data.length, bytesWritten, null);
if (!success) {
throw new RuntimeException("Failed to write file: " +
Kernel32.INSTANCE.GetLastError());
}
System.out.println("Wrote " + bytesWritten.getValue() + " bytes");
} catch (Exception e) {
throw new RuntimeException("Error writing file", e);
} finally {
Kernel32.INSTANCE.CloseHandle(hFile);
}
}
}// Error handling pattern
public class Win32ErrorHandler {
public static void checkResult(boolean success, String operation) {
if (!success) {
int errorCode = Kernel32.INSTANCE.GetLastError();
throw new Win32Exception(errorCode, operation + " failed");
}
}
public static void checkHandle(Pointer handle, String operation) {
if (handle == null || handle.equals(Pointer.createConstant(-1))) {
int errorCode = Kernel32.INSTANCE.GetLastError();
throw new Win32Exception(errorCode, operation + " failed");
}
}
}
// Custom exception for Win32 errors
public class Win32Exception extends RuntimeException {
private final int errorCode;
public Win32Exception(int errorCode, String message) {
super(message + " (error code: " + errorCode + ")");
this.errorCode = errorCode;
}
public int getErrorCode() {
return errorCode;
}
}
// Usage
try {
Pointer handle = Kernel32.INSTANCE.CreateFile(filename, access, share, null, disposition, flags, null);
Win32ErrorHandler.checkHandle(handle, "CreateFile");
boolean success = Kernel32.INSTANCE.WriteFile(handle, buffer, size, bytesWritten, null);
Win32ErrorHandler.checkResult(success, "WriteFile");
} catch (Win32Exception e) {
System.err.println("Win32 operation failed: " + e.getMessage());
System.err.println("Error code: " + e.getErrorCode());
}// Registry access
public interface Advapi32 extends StdCallLibrary {
Advapi32 INSTANCE = Native.loadLibrary("advapi32", Advapi32.class);
int RegOpenKeyEx(Pointer hKey, String lpSubKey, int ulOptions, int samDesired, PointerByReference phkResult);
int RegQueryValueEx(Pointer hKey, String lpValueName, Pointer lpReserved, IntByReference lpType,
Pointer lpData, IntByReference lpcbData);
int RegCloseKey(Pointer hKey);
// Registry constants
Pointer HKEY_CURRENT_USER = Pointer.createConstant(0x80000001L);
Pointer HKEY_LOCAL_MACHINE = Pointer.createConstant(0x80000002L);
int KEY_READ = 0x20019;
}
// Performance counters
public interface Pdh extends StdCallLibrary {
Pdh INSTANCE = Native.loadLibrary("pdh", Pdh.class);
int PdhOpenQuery(Pointer szDataSource, Pointer dwUserData, PointerByReference phQuery);
int PdhAddCounter(Pointer hQuery, String szFullCounterPath, Pointer dwUserData, PointerByReference phCounter);
int PdhCollectQueryData(Pointer hQuery);
int PdhGetFormattedCounterValue(Pointer hCounter, int dwFormat, Pointer lpdwType, Pointer pValue);
int PdhCloseQuery(Pointer hQuery);
}This comprehensive Windows integration provides full access to Win32 APIs with proper calling convention support, automatic function name resolution, type mapping, and error handling for robust Windows application development.
Install with Tessl CLI
npx tessl i tessl/maven-net-java-dev-jna--jna