java-native-access/jna · error · Win32Exception
Win32Exception from native GetLastError after WritePrivatePr
Error message
Win32Exception from native GetLastError after WritePrivateProfileSection failed
What it means
writePrivateProfileSection replaces the entire contents of one INI section with the supplied key=value strings via WritePrivateProfileSection. The Win32 call returns BOOL; FALSE means the write failed and the wrapper throws Win32Exception with the native GetLastError code. Common failure causes are a read-only/locked file, an invalid or unwritable path, or a missing section combined with an unwritable Windows directory.
Source
Thrown at contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java:836
return new String(buffer).split("\0");
}
/**
* @param appName
* The name of the section in which data is written. This section name is typically the name of the calling application.
* @param strings
* The new key names and associated values that are to be written to the named section. Each entry must be of the form {@code key=value}.
* @param fileName
* The name of the initialization file. If this parameter does not contain a full path for the file, the function searches the Windows directory
* for the file. If the file does not exist and lpFileName does not contain a full path, the function creates the file in the Windows directory.
*/
public static final void writePrivateProfileSection(final String appName, final String[] strings, final String fileName) {
final StringBuilder buffer = new StringBuilder();
for (final String string : strings)
buffer.append(string).append('\0');
buffer.append('\0');
if (! Kernel32.INSTANCE.WritePrivateProfileSection(appName, buffer.toString(), fileName)) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
}
/**
* Invokes the {@link Kernel32#QueryDosDevice(String, char[], int)} method
* and parses the result
* @param lpszDeviceName The device name
* @param maxTargetSize The work buffer size to use for the query
* @return The parsed result
*/
public static final List<String> queryDosDevice(String lpszDeviceName, int maxTargetSize) {
char[] lpTargetPath = new char[maxTargetSize];
int dwSize = Kernel32.INSTANCE.QueryDosDevice(lpszDeviceName, lpTargetPath, lpTargetPath.length);
if (dwSize == 0) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
return Native.toStringList(lpTargetPath, 0, dwSize);View on GitHub (pinned to d036ad9781)
Solutions
- Ensure the target INI file is writable (Files.isWritable) and the directory grants write access to the process user.
- Never pass null fileName unintentionally — it silently targets win.ini; always pass an absolute path.
- Run elevated or store user settings under %APPDATA% instead of protected locations.
- Retry after a short delay if a transient lock (AV scanner, another process) is suspected; inspect Win32Exception.getErrorCode() for ERROR_SHARING_VIOLATION/ERROR_ACCESS_DENIED.
Example fix
// before
Kernel32Util.writePrivateProfileSection("Settings", entries, "C:\\Program Files\\App\\config.ini");
// after
Path ini = Paths.get(System.getenv("APPDATA"), "App", "config.ini");
Files.createDirectories(ini.getParent());
if (!Files.isWritable(ini.getParent())) {
throw new AccessDeniedException(ini.toString());
}
Kernel32Util.writePrivateProfileSection("Settings", entries, ini.toString()); Defensive patterns
Strategy: validation
Validate before calling
Path ini = Paths.get(fileName).toAbsolutePath();
if (fileName == null) throw new IllegalArgumentException("fileName must not be null (would target win.ini)");
Files.createDirectories(ini.getParent());
if (Files.exists(ini) && !Files.isWritable(ini)) {
throw new AccessDeniedException(ini.toString());
} Try / catch
try {
Kernel32Util.writePrivateProfileSection(appName, strings, fileName);
} catch (Win32Exception e) {
if (e.getErrorCode() == WinError.ERROR_SHARING_VIOLATION) {
// retry after delay
} else {
throw e;
}
} Prevention
- Never pass null fileName — it silently writes to win.ini.
- Store settings under %APPDATA%, not Program Files or the Windows directory.
- Remove read-only flags from shipped INI files.
- Handle sharing violations with a short retry loop.
When it happens
Trigger: Calling Kernel32Util.writePrivateProfileSection(appName, strings, fileName) when WritePrivateProfileSection returns FALSE — target file is read-only, on read-only media, directory lacks write permission, path invalid, or another process holds the file with a conflicting lock.
Common situations: Writing to Program Files or the Windows directory under UAC without elevation; the INI shipped read-only from source control or installer; antivirus/another app locking the file; running from a read-only network share; passing null fileName which redirects writes into win.ini.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- Win32Exception from native GetLastError after GetPrivateProf
- Win32Exception from native GetLastError after GetPrivateProf
- LookupAccountNameW was expected to fail with ERROR_INSUFFICI
- Expected GetTokenInformation to fail with ERROR_INSUFFICIENT
- Failed to find privilege "{privilege}" - {GetLastError}
AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12).
Data as JSON: /api/errors/b9b204819ac0acc5.
Report an issue: GitHub.