{"record":{"id":"b9b204819ac0acc5","repo":"java-native-access/jna","slug":"win32exception-from-native-getlasterror-after-b9b204","errorCode":null,"errorMessage":"Win32Exception from native GetLastError after WritePrivateProfileSection failed","messagePattern":"Win32Exception from native GetLastError after WritePrivateProfileSection failed","errorType":"error_code","errorClass":"Win32Exception","httpStatus":null,"severity":"error","filePath":"contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java","lineNumber":836,"sourceCode":"        return new String(buffer).split(\"\\0\");\n    }\n\n    /**\n     * @param appName\n     *            The name of the section in which data is written. This section name is typically the name of the calling application.\n     * @param strings\n     *            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}.\n     * @param fileName\n     *            The name of the initialization file. If this parameter does not contain a full path for the file, the function searches the Windows directory\n     *            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.\n     */\n    public static final void writePrivateProfileSection(final String appName, final String[] strings, final String fileName) {\n        final StringBuilder buffer = new StringBuilder();\n        for (final String string : strings)\n            buffer.append(string).append('\\0');\n        buffer.append('\\0');\n        if (! Kernel32.INSTANCE.WritePrivateProfileSection(appName, buffer.toString(), fileName)) {\n            throw new Win32Exception(Kernel32.INSTANCE.GetLastError());\n        }\n    }\n\n    /**\n     * Invokes the {@link Kernel32#QueryDosDevice(String, char[], int)} method\n     * and parses the result\n     * @param lpszDeviceName The device name\n     * @param maxTargetSize The work buffer size to use for the query\n     * @return The parsed result\n     */\n    public static final List<String> queryDosDevice(String lpszDeviceName, int maxTargetSize) {\n        char[] lpTargetPath = new char[maxTargetSize];\n        int dwSize = Kernel32.INSTANCE.QueryDosDevice(lpszDeviceName, lpTargetPath, lpTargetPath.length);\n        if (dwSize == 0) {\n            throw new Win32Exception(Kernel32.INSTANCE.GetLastError());\n        }\n\n        return Native.toStringList(lpTargetPath, 0, dwSize);","sourceCodeStart":818,"sourceCodeEnd":854,"githubUrl":"https://github.com/java-native-access/jna/blob/d036ad9781adad4b66693e8fa7098e4ac665e0a3/contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java#L818-L854","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nKernel32Util.writePrivateProfileSection(\"Settings\", entries, \"C:\\\\Program Files\\\\App\\\\config.ini\");\n\n// after\nPath ini = Paths.get(System.getenv(\"APPDATA\"), \"App\", \"config.ini\");\nFiles.createDirectories(ini.getParent());\nif (!Files.isWritable(ini.getParent())) {\n    throw new AccessDeniedException(ini.toString());\n}\nKernel32Util.writePrivateProfileSection(\"Settings\", entries, ini.toString());","handlingStrategy":"validation","validationCode":"Path ini = Paths.get(fileName).toAbsolutePath();\nif (fileName == null) throw new IllegalArgumentException(\"fileName must not be null (would target win.ini)\");\nFiles.createDirectories(ini.getParent());\nif (Files.exists(ini) && !Files.isWritable(ini)) {\n    throw new AccessDeniedException(ini.toString());\n}","typeGuard":null,"tryCatchPattern":"try {\n    Kernel32Util.writePrivateProfileSection(appName, strings, fileName);\n} catch (Win32Exception e) {\n    if (e.getErrorCode() == WinError.ERROR_SHARING_VIOLATION) {\n        // retry after delay\n    } else {\n        throw e;\n    }\n}","preventionTips":["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."],"tags":["win32","ini","file-write","jna"],"backgroundTag":"file-write-failed","analyzedSha":"d036ad9781adad4b66693e8fa7098e4ac665e0a3","analyzedAt":"2026-09-12T06:50:59.239Z","contentChangedAt":"2026-09-12T06:50:59.239Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}