java-native-access/jna · error · Win32Exception

Win32Exception from native GetLastError after GetPrivateProf

Error message

Win32Exception from native GetLastError after GetPrivateProfileSectionNames returned 0

What it means

getPrivateProfileSectionNames enumerates all section names in an INI file via GetPrivateProfileSectionNames into a 65536-char buffer. A return of 0 means the enumeration failed, and the wrapper throws Win32Exception carrying the native GetLastError code. Unlike getPrivateProfileSection, there is no empty-result path here: 0 always indicates failure per the API contract.

Source

Thrown at contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java:816

        }
        return new String(buffer).split("\0");
    }

    /**
     * Retrieves the names of all sections in an initialization file.
     * <p>
     * This operation is atomic; no updates to the initialization file are allowed while this method is executed.
     * </p>
     *
     * @param fileName
     *            The name of the initialization file. If this parameter is {@code NULL}, the function searches the Win.ini file. If this parameter does not
     *            contain a full path to the file, the system searches for the file in the Windows directory.
     * @return the section names associated with the named file.
     */
    public static final String[] getPrivateProfileSectionNames(final String fileName) {
        final char buffer[] = new char[65536]; // Maximum INI file size according to MSDN (http://support.microsoft.com/kb/78346)
        if (Kernel32.INSTANCE.GetPrivateProfileSectionNames(buffer, new DWORD(buffer.length), fileName).intValue() == 0) {
            throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
        }
        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');

View on GitHub (pinned to d036ad9781)

Solutions

  1. Check the INI file exists and is readable (absolute path) before calling.
  2. Catch Win32Exception and map its error code (ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND) to user-facing messages.
  3. Keep the INI under 64KB or split it; the fixed 65536-char buffer cannot grow.
  4. Fall back to parsing the file manually (e.g. IniEditor or hand-rolled reader) if the native call repeatedly fails.

Example fix

// before
String[] sections = Kernel32Util.getPrivateProfileSectionNames("app.ini");

// after
Path ini = Paths.get("app.ini").toAbsolutePath();
if (!Files.isReadable(ini)) {
    throw new FileNotFoundException("Cannot read INI: " + ini);
}
String[] sections;
try {
    sections = Kernel32Util.getPrivateProfileSectionNames(ini.toString());
} catch (Win32Exception e) {
    LOG.warn("Section enumeration failed (code " + e.getErrorCode() + ")", e);
    sections = new String[0];
}
Defensive patterns

Strategy: try-catch

Validate before calling

Path ini = Paths.get(fileName).toAbsolutePath();
if (!Files.isReadable(ini)) {
    throw new FileNotFoundException(ini.toString());
}

Try / catch

try {
    return Kernel32Util.getPrivateProfileSectionNames(fileName);
} catch (Win32Exception e) {
    LOG.warn("INI section enum failed: " + e.getErrorCode());
    return new String[0];
}

Prevention

When it happens

Trigger: Calling Kernel32Util.getPrivateProfileSectionNames(fileName) when GetPrivateProfileSectionNames returns 0 — the INI file does not exist, the path is invalid, the buffer is too small for files larger than 64KB, or the file cannot be opened by the calling process.

Common situations: INI file missing after deployment or renamed; UNC/network path inaccessible due to credentials; an INI larger than the 64KB maximum MSDN documents; typos in the file path; file locked by another process with exclusive access.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of java-native-access/jna@d036ad9781 (2026-09-12). Data as JSON: /api/errors/893578790f3e6189. Report an issue: GitHub.