Skip to content

Commit c7dcf61

Browse files
mkargdblock
authored andcommitted
Added com.sun.jna.platform.win32.Kernel32.GetPrivateProfileSection, GetPrivateProfileSectionNames and WritePrivateProfileSection and corresponding Kernel32Util helpers.
1 parent 438d131 commit c7dcf61

5 files changed

Lines changed: 259 additions & 0 deletions

File tree

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Features
1515
* [#101](https://github.com/twall/jna/issues/101): Modify `com.sun.jna.platform.win32.Advapi32Util.registryGet*` API to support `KEY_WOW64` option - [@falldog] (https://github.com/falldog).
1616
* [#271](https://github.com/twall/jna/pull/271): Added `com.sun.jna.platform.win32.Gdi32.ChoosePixelFormat` and `SetPixelFormat` - [@kc7bfi](https://github.com/kc7bfi).
1717
* [#271](https://github.com/twall/jna/pull/271): Added `com.sun.jna.platform.win32.OpenGL32`, `OpenGL32Util` and `WinOpenGL` - [@kc7bfi](https://github.com/kc7bfi).
18+
* [#250](https://github.com/twall/jna/pull/250): Added `com.sun.jna.platform.win32.Kernel32.GetPrivateProfileSection`, `GetPrivateProfileSectionNames` and `WritePrivateProfileSection` and corresponding `Kernel32Util` helpers - [@quipsy-karg](https://github.com/quipsy-karg).
1819

1920
Bug Fixes
2021
---------

contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1981,4 +1981,65 @@ DWORD GetPrivateProfileString(String lpAppName, String lpKeyName,
19811981
*/
19821982
boolean WritePrivateProfileString(String lpAppName, String lpKeyName,
19831983
String lpString, String lpFileName);
1984+
1985+
/**
1986+
* Retrieves all the keys and values for the specified section of an initialization file.
1987+
*
1988+
* <p>
1989+
* Each string has the following format: {@code key=string}.
1990+
* </p>
1991+
* <p>
1992+
* This operation is atomic; no updates to the specified initialization file are allowed while the key name and value pairs for the section are being copied
1993+
* to the buffer pointed to by the {@code lpReturnedString} parameter.
1994+
* </p>
1995+
*
1996+
* @param lpAppName
1997+
* The name of the section in the initialization file.
1998+
* @param lpReturnedString
1999+
* A buffer that receives the key name and value pairs associated with the named section. The buffer is filled with one or more {@code null}
2000+
* -terminated strings; the last string is followed by a second {@code null} character.
2001+
* @param nSize
2002+
* The size of the buffer pointed to by the {@code lpReturnedString} parameter, in characters. The maximum profile section size is 32,767
2003+
* characters.
2004+
* @param lpFileName
2005+
* 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
2006+
* Windows directory.
2007+
* @return The number of characters copied to the buffer, not including the terminating null character. If the buffer is not large enough to contain all the
2008+
* key name and value pairs associated with the named section, the return value is equal to {@code nSize} minus two.
2009+
*/
2010+
DWORD GetPrivateProfileSection(String lpAppName, char[] lpReturnedString, DWORD nSize, String lpFileName);
2011+
2012+
/**
2013+
* Retrieves the names of all sections in an initialization file.
2014+
* <p>
2015+
* This operation is atomic; no updates to the initialization file are allowed while the section names are being copied to the buffer.
2016+
* </p>
2017+
*
2018+
* @param lpszReturnBuffer
2019+
* A pointer to a buffer that receives the section names associated with the named file. The buffer is filled with one or more {@code null}
2020+
* -terminated strings; the last string is followed by a second {@code null} character.
2021+
* @param nSize
2022+
* size of the buffer pointed to by the {@code lpszReturnBuffer} parameter, in characters.
2023+
* @param lpFileName
2024+
* The name of the initialization file. If this parameter is {@code NULL}, the function searches the Win.ini file. If this parameter does not
2025+
* contain a full path to the file, the system searches for the file in the Windows directory.
2026+
* @return The return value specifies the number of characters copied to the specified buffer, not including the terminating {@code null} character. If the
2027+
* buffer is not large enough to contain all the section names associated with the specified initialization file, the return value is equal to the
2028+
* size specified by {@code nSize} minus two.
2029+
*/
2030+
DWORD GetPrivateProfileSectionNames(char[] lpszReturnBuffer, DWORD nSize, String lpFileName);
2031+
2032+
/**
2033+
* @param lpAppName
2034+
* The name of the section in which data is written. This section name is typically the name of the calling application.
2035+
* @param lpString
2036+
* The new key names and associated values that are to be written to the named section. This string is limited to 65,535 bytes. Must be filled
2037+
* with zero or many {@code null}-terminated strings of the form {@code key=value}, appended by an additional {@code null} byte to terminate the
2038+
* list.
2039+
* @param lpFileName
2040+
* The name of the initialization file. If this parameter does not contain a full path for the file, the function searches the Windows directory
2041+
* 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.
2042+
* @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero.
2043+
*/
2044+
boolean WritePrivateProfileSection(String lpAppName, String lpString, String lpFileName);
19842045
}

contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,4 +362,67 @@ public static final WinNT.SYSTEM_LOGICAL_PROCESSOR_INFORMATION[] getLogicalProce
362362
return (WinNT.SYSTEM_LOGICAL_PROCESSOR_INFORMATION[]) firstInformation
363363
.toArray(new WinNT.SYSTEM_LOGICAL_PROCESSOR_INFORMATION[returnedStructCount]);
364364
}
365+
366+
/**
367+
* Retrieves all the keys and values for the specified section of an initialization file.
368+
*
369+
* <p>
370+
* Each string has the following format: {@code key=string}.
371+
* </p>
372+
* <p>
373+
* This operation is atomic; no updates to the specified initialization file are allowed while this method is executed.
374+
* </p>
375+
*
376+
* @param appName
377+
* The name of the section in the initialization file.
378+
* @param fileName
379+
* 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
380+
* Windows directory.
381+
* @return The key name and value pairs associated with the named section.
382+
*/
383+
public static final String[] getPrivateProfileSection(final String appName, final String fileName) {
384+
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)
385+
if (Kernel32.INSTANCE.GetPrivateProfileSection(appName, buffer, new DWORD(buffer.length), fileName).intValue() == 0) {
386+
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
387+
}
388+
return new String(buffer).split("\0");
389+
}
390+
391+
/**
392+
* Retrieves the names of all sections in an initialization file.
393+
* <p>
394+
* This operation is atomic; no updates to the initialization file are allowed while this method is executed.
395+
* </p>
396+
*
397+
* @param fileName
398+
* The name of the initialization file. If this parameter is {@code NULL}, the function searches the Win.ini file. If this parameter does not
399+
* contain a full path to the file, the system searches for the file in the Windows directory.
400+
* @return the section names associated with the named file.
401+
*/
402+
public static final String[] getPrivateProfileSectionNames(final String fileName) {
403+
final char buffer[] = new char[65536]; // Maximum INI file size according to MSDN (http://support.microsoft.com/kb/78346)
404+
if (Kernel32.INSTANCE.GetPrivateProfileSectionNames(buffer, new DWORD(buffer.length), fileName).intValue() == 0) {
405+
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
406+
}
407+
return new String(buffer).split("\0");
408+
}
409+
410+
/**
411+
* @param appName
412+
* The name of the section in which data is written. This section name is typically the name of the calling application.
413+
* @param strings
414+
* 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}.
415+
* @param fileName
416+
* The name of the initialization file. If this parameter does not contain a full path for the file, the function searches the Windows directory
417+
* 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.
418+
*/
419+
public static final void writePrivateProfileSection(final String appName, final String[] strings, final String fileName) {
420+
final StringBuilder buffer = new StringBuilder();
421+
for (final String string : strings)
422+
buffer.append(string).append('\0');
423+
buffer.append('\0');
424+
if (! Kernel32.INSTANCE.WritePrivateProfileSection(appName, buffer.toString(), fileName)) {
425+
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
426+
}
427+
}
365428
}

contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,4 +531,66 @@ public final void testWritePrivateProfileString() throws IOException {
531531
assertEquals(reader.readLine(), null);
532532
reader.close();
533533
}
534+
535+
public final void testGetPrivateProfileSection() throws IOException {
536+
final File tmp = File.createTempFile("testGetPrivateProfileSection", ".ini");
537+
tmp.deleteOnExit();
538+
539+
final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(tmp)));
540+
try {
541+
writer.println("[X]");
542+
writer.println("A=1");
543+
writer.println("B=X");
544+
} finally {
545+
writer.close();
546+
}
547+
548+
final char[] buffer = new char[9];
549+
final DWORD len = Kernel32.INSTANCE.GetPrivateProfileSection("X", buffer, new DWORD(buffer.length), tmp.getCanonicalPath());
550+
551+
assertEquals(len.intValue(), 7);
552+
assertEquals(new String(buffer), "A=1\0B=X\0\0");
553+
}
554+
555+
public final void testGetPrivateProfileSectionNames() throws IOException {
556+
final File tmp = File.createTempFile("testGetPrivateProfileSectionNames", ".ini");
557+
tmp.deleteOnExit();
558+
559+
final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(tmp)));
560+
try {
561+
writer.println("[S1]");
562+
writer.println("[S2]");
563+
} finally {
564+
writer.close();
565+
}
566+
567+
final char[] buffer = new char[7];
568+
final DWORD len = Kernel32.INSTANCE.GetPrivateProfileSectionNames(buffer, new DWORD(buffer.length), tmp.getCanonicalPath());
569+
assertEquals(len.intValue(), 5);
570+
assertEquals(new String(buffer), "S1\0S2\0\0");
571+
}
572+
573+
public final void testWritePrivateProfileSection() throws IOException {
574+
final File tmp = File.createTempFile("testWritePrivateProfileSection", ".ini");
575+
tmp.deleteOnExit();
576+
577+
final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(tmp)));
578+
try {
579+
writer.println("[S1]");
580+
writer.println("A=1");
581+
writer.println("B=X");
582+
} finally {
583+
writer.close();
584+
}
585+
586+
final boolean result = Kernel32.INSTANCE.WritePrivateProfileSection("S1", "A=3\0E=Z\0\0", tmp.getCanonicalPath());
587+
assertTrue(result);
588+
589+
final BufferedReader reader = new BufferedReader(new FileReader(tmp));
590+
assertEquals(reader.readLine(), "[S1]");
591+
assertTrue(reader.readLine().matches("A\\s*=\\s*3"));
592+
assertTrue(reader.readLine().matches("E\\s*=\\s*Z"));
593+
reader.close();
594+
}
595+
534596
}

contrib/platform/test/com/sun/jna/platform/win32/Kernel32UtilTest.java

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,4 +180,76 @@ public final void testWritePrivateProfileString() throws IOException {
180180
assertEquals(reader.readLine(), null);
181181
reader.close();
182182
}
183+
184+
public final void testGetPrivateProfileSection() throws IOException {
185+
final File tmp = File.createTempFile("testGetPrivateProfileSection", ".ini");
186+
tmp.deleteOnExit();
187+
188+
final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(tmp)));
189+
try {
190+
writer.println("[X]");
191+
writer.println("A=1");
192+
writer.println("foo=bar");
193+
} finally {
194+
writer.close();
195+
}
196+
197+
final String[] lines = Kernel32Util.getPrivateProfileSection("X", tmp.getCanonicalPath());
198+
assertEquals(lines.length, 2);
199+
assertEquals(lines[0], "A=1");
200+
assertEquals(lines[1], "foo=bar");
201+
}
202+
203+
public final void testGetPrivateProfileSectionNames() throws IOException {
204+
final File tmp = File.createTempFile("testGetPrivateProfileSectionNames", "ini");
205+
tmp.deleteOnExit();
206+
207+
final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(tmp)));
208+
try {
209+
writer.println("[S1]");
210+
writer.println("A=1");
211+
writer.println("B=X");
212+
writer.println("[S2]");
213+
writer.println("C=2");
214+
writer.println("D=Y");
215+
} finally {
216+
writer.close();
217+
}
218+
219+
String[] sectionNames = Kernel32Util.getPrivateProfileSectionNames(tmp.getCanonicalPath());
220+
assertEquals(sectionNames.length, 2);
221+
assertEquals(sectionNames[0], "S1");
222+
assertEquals(sectionNames[1], "S2");
223+
}
224+
225+
public final void testWritePrivateProfileSection() throws IOException {
226+
final File tmp = File.createTempFile("testWritePrivateProfileSecion", "ini");
227+
tmp.deleteOnExit();
228+
229+
final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(tmp)));
230+
try {
231+
writer.println("[S1]");
232+
writer.println("A=1");
233+
writer.println("B=X");
234+
writer.println("[S2]");
235+
writer.println("C=2");
236+
writer.println("foo=bar");
237+
} finally {
238+
writer.close();
239+
}
240+
241+
Kernel32Util.writePrivateProfileSection("S1", new String[] { "A=3", "E=Z" }, tmp.getCanonicalPath());
242+
243+
final BufferedReader reader = new BufferedReader(new FileReader(tmp));
244+
try {
245+
assertEquals(reader.readLine(), "[S1]");
246+
assertEquals(reader.readLine(), "A=3");
247+
assertEquals(reader.readLine(), "E=Z");
248+
assertEquals(reader.readLine(), "[S2]");
249+
assertEquals(reader.readLine(), "C=2");
250+
assertEquals(reader.readLine(), "foo=bar");
251+
} finally {
252+
reader.close();
253+
}
254+
}
183255
}

0 commit comments

Comments
 (0)