java-native-access/jna · error · Win32Exception

Win32Exception from native GetLastError after GetPrivateProf

Error message

Win32Exception from native GetLastError after GetPrivateProfileSection returned 0

What it means

getPrivateProfileSection reads all key=value entries of one INI section via the Win32 GetPrivateProfileSection API. If the native call reports a returned size of 0, the wrapper calls GetLastError; ERROR_SUCCESS means a genuinely empty section (returned as an empty array), but any other error code is wrapped in a Win32Exception and thrown. This means Windows itself reported a concrete failure reading the section, not merely an empty result.

Source

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

     * <p>
     * This operation is atomic; no updates to the specified initialization file are allowed while this method is executed.
     * </p>
     *
     * @param appName
     *            The name of the section in the initialization file.
     * @param fileName
     *            The name of the initialization 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 key name and value pairs associated with the named section.
     */
    public static final String[] getPrivateProfileSection(final String appName, final String fileName) {
        final char buffer[] = new char[32768]; // Maximum section size according to MSDN (http://msdn.microsoft.com/en-us/library/windows/desktop/ms724348(v=vs.85).aspx)
        if (Kernel32.INSTANCE.GetPrivateProfileSection(appName, buffer, new DWORD(buffer.length), fileName).intValue() == 0) {
            final int lastError = Kernel32.INSTANCE.GetLastError();
            if (lastError == Kernel32.ERROR_SUCCESS) {
                return EMPTY_STRING_ARRAY;
            } else {
                throw new Win32Exception(lastError);
            }
        }
        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)

View on GitHub (pinned to d036ad9781)

Solutions

  1. Verify the fileName path is absolute and the INI file actually exists (File.exists()/canRead()) before calling.
  2. Confirm the exact section (appName) exists in the file; remember missing sections are also reported as error by some Windows versions.
  3. Catch Win32Exception and inspect its ErrorCode (e.g. ERROR_FILE_NOT_FOUND=2) to branch on the real cause instead of guessing.
  4. If the INI exceeds 32768 chars, split it or read via a different mechanism.

Example fix

// before
String[] entries = Kernel32Util.getPrivateProfileSection("Settings", "config.ini");

// after
File ini = new File("C:/app/config.ini");
if (!ini.isFile()) {
    throw new FileNotFoundException("Missing INI: " + ini);
}
try {
    String[] entries = Kernel32Util.getPrivateProfileSection("Settings", ini.getAbsolutePath());
} catch (Win32Exception e) {
    if (e.getErrorCode() == WinError.ERROR_FILE_NOT_FOUND) {
        entries = new String[0]; // default config
    } else {
        throw e;
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

File ini = new File(fileName);
if (!ini.isFile() || !ini.canRead()) {
    throw new FileNotFoundException(fileName);
}

Try / catch

try {
    return Kernel32Util.getPrivateProfileSection(appName, fileName);
} catch (Win32Exception e) {
    if (e.getErrorCode() == WinError.ERROR_FILE_NOT_FOUND) {
        return new String[0];
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling Kernel32Util.getPrivateProfileSection(appName, fileName) when GetPrivateProfileSection returns 0 and GetLastError is not ERROR_SUCCESS — typically the INI file does not exist or is unreadable, the appName section is missing, the file exceeds the 32768-char buffer, or access to the file/Windows directory is denied.

Common situations: Deploying an app whose .ini config file was never copied to the expected path; using a relative path that resolves against the Windows directory instead of the app directory; section name typo (names are case-insensitive but must exist); running under an account lacking read access to the file; INI files >32KB truncated by the fixed buffer.

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/234b937597432c5c. Report an issue: GitHub.