{"record":{"id":"234b937597432c5c","repo":"java-native-access/jna","slug":"win32exception-from-native-getlasterror-after","errorCode":null,"errorMessage":"Win32Exception from native GetLastError after GetPrivateProfileSection returned 0","messagePattern":"Win32Exception from native GetLastError after GetPrivateProfileSection returned 0","errorType":"error_code","errorClass":"Win32Exception","httpStatus":null,"severity":"error","filePath":"contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java","lineNumber":796,"sourceCode":"     * <p>\n     * This operation is atomic; no updates to the specified initialization file are allowed while this method is executed.\n     * </p>\n     *\n     * @param appName\n     *            The name of the section in the initialization file.\n     * @param fileName\n     *            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\n     *            Windows directory.\n     * @return The key name and value pairs associated with the named section.\n     */\n    public static final String[] getPrivateProfileSection(final String appName, final String fileName) {\n        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)\n        if (Kernel32.INSTANCE.GetPrivateProfileSection(appName, buffer, new DWORD(buffer.length), fileName).intValue() == 0) {\n            final int lastError = Kernel32.INSTANCE.GetLastError();\n            if (lastError == Kernel32.ERROR_SUCCESS) {\n                return EMPTY_STRING_ARRAY;\n            } else {\n                throw new Win32Exception(lastError);\n            }\n        }\n        return new String(buffer).split(\"\\0\");\n    }\n\n    /**\n     * Retrieves the names of all sections in an initialization file.\n     * <p>\n     * This operation is atomic; no updates to the initialization file are allowed while this method is executed.\n     * </p>\n     *\n     * @param fileName\n     *            The name of the initialization file. If this parameter is {@code NULL}, the function searches the Win.ini file. If this parameter does not\n     *            contain a full path to the file, the system searches for the file in the Windows directory.\n     * @return the section names associated with the named file.\n     */\n    public static final String[] getPrivateProfileSectionNames(final String fileName) {\n        final char buffer[] = new char[65536]; // Maximum INI file size according to MSDN (http://support.microsoft.com/kb/78346)","sourceCodeStart":778,"sourceCodeEnd":814,"githubUrl":"https://github.com/java-native-access/jna/blob/d036ad9781adad4b66693e8fa7098e4ac665e0a3/contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java#L778-L814","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the fileName path is absolute and the INI file actually exists (File.exists()/canRead()) before calling.","Confirm the exact section (appName) exists in the file; remember missing sections are also reported as error by some Windows versions.","Catch Win32Exception and inspect its ErrorCode (e.g. ERROR_FILE_NOT_FOUND=2) to branch on the real cause instead of guessing.","If the INI exceeds 32768 chars, split it or read via a different mechanism."],"exampleFix":"// before\nString[] entries = Kernel32Util.getPrivateProfileSection(\"Settings\", \"config.ini\");\n\n// after\nFile ini = new File(\"C:/app/config.ini\");\nif (!ini.isFile()) {\n    throw new FileNotFoundException(\"Missing INI: \" + ini);\n}\ntry {\n    String[] entries = Kernel32Util.getPrivateProfileSection(\"Settings\", ini.getAbsolutePath());\n} catch (Win32Exception e) {\n    if (e.getErrorCode() == WinError.ERROR_FILE_NOT_FOUND) {\n        entries = new String[0]; // default config\n    } else {\n        throw e;\n    }\n}","handlingStrategy":"try-catch","validationCode":"File ini = new File(fileName);\nif (!ini.isFile() || !ini.canRead()) {\n    throw new FileNotFoundException(fileName);\n}","typeGuard":null,"tryCatchPattern":"try {\n    return Kernel32Util.getPrivateProfileSection(appName, fileName);\n} catch (Win32Exception e) {\n    if (e.getErrorCode() == WinError.ERROR_FILE_NOT_FOUND) {\n        return new String[0];\n    }\n    throw e;\n}","preventionTips":["Always pass an absolute path to the INI file.","Check File.exists()/canRead() before every call.","Log Win32Exception.getErrorCode() to identify the native cause.","Keep INI files under 32KB to fit the fixed buffer."],"tags":["win32","ini","file-read","jna"],"backgroundTag":"file-read-failed","analyzedSha":"d036ad9781adad4b66693e8fa7098e4ac665e0a3","analyzedAt":"2026-09-12T06:50:59.239Z","contentChangedAt":"2026-09-12T06:50:59.239Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}