diff --git a/CHANGES.md b/CHANGES.md index 8568f6d639..9a77eeda9d 100755 --- a/CHANGES.md +++ b/CHANGES.md @@ -17,6 +17,7 @@ Features * [#180](https://github.com/twall/jna/pull/180): Fix: added missing fields in `XEvents.getFieldOrder()` - [@xwizard](https://github.com/xwizard). * [#183](https://github.com/twall/jna/pull/183): Added StructureFieldOrderInspector unit test utility to scan for Structure field issues. See: com.sun.jna.platform.StructureFieldOrderTest.testMethodGetFieldOrder() - [@bhamail](https://github.com/bhamail). * [#187](https://github.com/twall/jna/pull/187): Allow StructureFieldOrderTest unit test in platform project to run on Linux. - [@bhamail](https://github.com/bhamail). +* [#192](https://github.com/twall/jna/pull/192): SHGetSpecialFolderPath() and initialization file (.ini) API function. - [@headcrashing](https://github.com/headcrashing). Release 3.5.1 ==================== diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java b/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java index 146dcf5f94..c1ebe1b59b 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2007 Timothy Wall, All Rights Reserved +/* Copyright (c) 2007, 2013 Timothy Wall, Markus Karg, All Rights Reserved * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -1727,4 +1727,84 @@ boolean Process32Next(HANDLE hSnapshot, * value. */ LCID GetUserDefaultLCID(); + + /** + * Retrieves an integer associated with a key in the specified section of an initialization file. + * + * @param appName + * The name of the section in the initialization file. + * @param keyName + * The name of the key whose value is to be retrieved. This value is in the form of a string; the {@link GetPrivateProfileInt} function converts + * the string into an integer and returns the integer. + * @param defaultValue + * The default value to return if the key name cannot be found 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 return value is the integer equivalent of the string following the specified key name in the specified initialization file. If the key is not + * found, the return value is the specified default value. + */ + int GetPrivateProfileInt(String appName, String keyName, int defaultValue, String fileName); + + /** + * Retrieves a string from the specified section in an initialization file. + * + * @param lpAppName + * The name of the section containing the key name. If this parameter is {@code null}, the {@link GetPrivateProfileString} function copies all + * section names in the file to the supplied buffer. + * @param lpKeyName + * The name of the key whose associated string is to be retrieved. If this parameter is {@code null}, all key names in the section specified by + * the {@code lpAppName} parameter are copied to the buffer specified by the {@code lpReturnedString} parameter. + * @param lpDefault + * A default string. If the {@code lpKeyName} key cannot be found in the initialization file, {@link GetPrivateProfileString} copies the default + * string to the {@code lpReturnedString} buffer. If this parameter is {@code null}, the default is an empty string, {@code ""}. + *

+ * Avoid specifying a default string with trailing blank characters. The function inserts a {@code null} character in the + * {@code lpReturnedString} buffer to strip any trailing blanks. + *

+ * @param lpReturnedString + * A pointer to the buffer that receives the retrieved string. + * @param nSize + * The size of the buffer pointed to by the {@code lpReturnedString} parameter, in characters. + * @param lpFileName + * 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 return value is the number of characters copied to the buffer, not including the terminating {@code null} character. + *

+ * If neither {@code lpAppName} nor {@code lpKeyName} is {@code null} and the supplied destination buffer is too small to hold the requested string, + * the string is truncated and followed by a {@code null} character, and the return value is equal to {@code nSize} minus one. + *

+ *

+ * If either {@code lpAppName} or {@code lpKeyName} is {@code null} and the supplied destination buffer is too small to hold all the strings, the + * last string is truncated and followed by two {@code null} characters. In this case, the return value is equal to {@code nSize} minus two. + *

+ *

+ * In the event the initialization file specified by {@code lpFileName} is not found, or contains invalid values, this function will set errorno + * with a value of '0x2' (File Not Found). To retrieve extended error information, call {@link #GetLastError}. + *

+ */ + DWORD GetPrivateProfileString(String lpAppName, String lpKeyName, String lpDefault, char[] lpReturnedString, DWORD nSize, String lpFileName); + + /** + * Copies a string into the specified section of an initialization file. + * + * If the file was created using Unicode characters, the function writes Unicode characters to the file. Otherwise, the function writes ANSI characters. + * + * @param lpAppName + * The name of the section to which the string will be copied. If the section does not exist, it is created. The name of the section is + * case-independent; the string can be any combination of uppercase and lowercase letters. + * @param lpKeyName + * The name of the key to be associated with a string. If the key does not exist in the specified section, it is created. If this parameter is + * {@code null}, the entire section, including all entries within the section, is deleted. + * @param lpString + * A string to be written to the file. If this parameter is {@code null}, the key pointed to by the {@code lpKeyName} parameter is deleted. + * @param lpFileName + * The name of the initialization file. + * @return If the function successfully copies the string to the initialization file, the return value is {@code true}. + *

+ * If the function fails, or if it flushes the cached version of the most recently accessed initialization file, the return value is {@code false}. + * To get extended error information, call {@link #GetLastError}. + *

+ */ + boolean WritePrivateProfileString(String lpAppName, String lpKeyName, String lpString, String lpFileName); } diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java b/contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java index 142e5c5535..964e81d5bf 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2010 Daniel Doubrovkine, All Rights Reserved +/* Copyright (c) 2010, 2013 Daniel Doubrovkine, Markus Karg, All Rights Reserved * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -28,6 +28,7 @@ /** * Kernel32 utility API. * @author dblock[at]dblock.org + * @author markus[at]headcrashing[dot]eu */ public abstract class Kernel32Util implements WinDef { @@ -176,7 +177,7 @@ public static int getFileType(String fileName) throws FileNotFoundException { case WinNT.FILE_TYPE_UNKNOWN: int err = Kernel32.INSTANCE.GetLastError(); switch(err) { - case W32Errors.NO_ERROR: + case WinError.NO_ERROR: break; default: throw new Win32Exception(err); @@ -224,5 +225,67 @@ public static String getEnvironmentVariable(String name) { throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); } return Native.toString(buffer); - } + } + + /** + * Retrieves an integer associated with a key in the specified section of an initialization file. + * + * @param appName + * The name of the section in the initialization file. + * @param keyName + * The name of the key whose value is to be retrieved. This value is in the form of a string; the {@link #GetPrivateProfileInt} function converts + * the string into an integer and returns the integer. + * @param defaultValue + * The default value to return if the key name cannot be found 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 retrieved integer, or the default if not found. + */ + public static final int getPrivateProfileInt(final String appName, final String keyName, final int defaultValue, final String fileName) { + return Kernel32.INSTANCE.GetPrivateProfileInt(appName, keyName, defaultValue, fileName); + } + + /** + * Retrieves a string from the specified section in an initialization file. + * + * @param lpAppName + * The name of the section containing the key name. If this parameter is {@code null}, the {@link GetPrivateProfileString} function copies all + * section names in the file to the supplied buffer. + * @param lpKeyName + * The name of the key whose associated string is to be retrieved. If this parameter is {@code null}, all key names in the section specified by + * the {@code lpAppName} parameter are returned. + * @param lpDefault + * A default string. If the {@code lpKeyName} key cannot be found in the initialization file, {@link GetPrivateProfileString} returns the + * default. If this parameter is {@code null}, the default is an empty string, {@code ""}. + *

+ * Avoid specifying a default string with trailing blank characters. The function inserts a {@code null} character in the + * {@code lpReturnedString} buffer to strip any trailing blanks. + *

+ * @param lpFileName + * 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

+ * If neither {@code lpAppName} nor {@code lpKeyName} is {@code null} and the destination buffer is too small to hold the requested string, the + * string is truncated. + *

+ *

+ * If either {@code lpAppName} or {@code lpKeyName} is {@code null} and the destination buffer is too small to hold all the strings, the last string + * is truncated and followed by two {@code null} characters. + *

+ *

+ * In the event the initialization file specified by {@code lpFileName} is not found, or contains invalid values, this function will set errorno + * with a value of '0x2' (File Not Found). To retrieve extended error information, call {@link #GetLastError}. + *

+ */ + public static final String getPrivateProfileString(final String appName, final String keyName, final String defaultValue, final String fileName) { + final char buffer[] = new char[1024]; + Kernel32.INSTANCE.GetPrivateProfileString(appName, keyName, defaultValue, buffer, new DWORD(buffer.length), fileName); + return Native.toString(buffer); + } + + public static final void writePrivateProfileString(final String appName, final String keyName, final String string, final String fileName) { + if (!Kernel32.INSTANCE.WritePrivateProfileString(appName, keyName, string, fileName)) + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + } } diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Shell32.java b/contrib/platform/src/com/sun/jna/platform/win32/Shell32.java index 4d96331b95..321a20c416 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Shell32.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Shell32.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2007 Timothy Wall, All Rights Reserved +/* Copyright (c) 2007, 2013 Timothy Wall, Markus Karg, All Rights Reserved * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -151,4 +151,21 @@ HRESULT SHGetFolderPath(HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlag */ INT_PTR ShellExecute(HWND hwnd, String lpOperation, String lpFile, String lpParameters, String lpDirectory, int nShowCmd); + + /** + * Retrieves the path of a special folder, identified by its CSIDL. + * + * @param owner + * Reserved. + * @param path + * A pointer to a null-terminated string that receives the drive and path of the specified folder. This buffer must be at least MAX_PATH + * characters in size. + * @param csidl + * A CSIDL that identifies the folder of interest. If a virtual folder is specified, this function will fail. + * @param create + * Indicates whether the folder should be created if it does not already exist. If this value is nonzero, the folder is created. If this value is + * zero, the folder is not created. + * @return {@code true} if successful; otherwise, {@code false}. + */ + boolean SHGetSpecialFolderPath(HWND owner, char[] path, int csidl, boolean create); } diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Shell32Util.java b/contrib/platform/src/com/sun/jna/platform/win32/Shell32Util.java index 5c1c964e2d..dd85003afa 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/Shell32Util.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/Shell32Util.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2010 Daniel Doubrovkine, All Rights Reserved +/* Copyright (c) 2010, 2013 Daniel Doubrovkine, Markus Karg, All Rights Reserved * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,6 +20,7 @@ /** * Shell32 Utility API. * @author dblock[at]dblock.org + * @author markus[at]headcrashing[dot]eu */ public abstract class Shell32Util { @@ -55,4 +56,21 @@ public static String getFolderPath(HWND hwnd, int nFolder, DWORD dwFlags) { public static String getFolderPath(int nFolder) { return getFolderPath(null, nFolder, ShlObj.SHGFP_TYPE_CURRENT); } + + /** + * Retrieves the path of a special folder, identified by its CSIDL. + * + * @param csidl + * A CSIDL that identifies the folder of interest. If a virtual folder is specified, this function will fail. + * @param create + * Indicates whether the folder should be created if it does not already exist. If this value is nonzero, the folder is created. If this value is + * zero, the folder is not created. + * @return The drive and path of the specified folder + */ + public static final String getSpecialFolderPath(final int csidl, final boolean create) { + final char[] pszPath = new char[WinDef.MAX_PATH]; + if (!Shell32.INSTANCE.SHGetSpecialFolderPath(null, pszPath, csidl, create)) + throw new Win32Exception(Kernel32.INSTANCE.GetLastError()); + return Native.toString(pszPath); + } } \ No newline at end of file diff --git a/contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java b/contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java index 8a66c9ed9a..d7851cd444 100644 --- a/contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/Kernel32Test.java @@ -1,20 +1,24 @@ /* Copyright (c) 2007 Timothy Wall, All Rights Reserved - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. + * Lesser General Public License for more details. */ package com.sun.jna.platform.win32; +import java.io.BufferedReader; +import java.io.BufferedWriter; import java.io.File; +import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; @@ -24,11 +28,11 @@ import junit.framework.TestCase; +import com.sun.jna.Memory; import com.sun.jna.Native; import com.sun.jna.NativeMappedConverter; import com.sun.jna.Platform; import com.sun.jna.Pointer; -import com.sun.jna.Memory; import com.sun.jna.platform.win32.WinBase.MEMORYSTATUSEX; import com.sun.jna.platform.win32.WinBase.SYSTEM_INFO; import com.sun.jna.platform.win32.WinDef.DWORD; @@ -41,24 +45,24 @@ import com.sun.jna.ptr.IntByReference; public class Kernel32Test extends TestCase { - + public static void main(String[] args) { - OSVERSIONINFO lpVersionInfo = new OSVERSIONINFO(); + OSVERSIONINFO lpVersionInfo = new OSVERSIONINFO(); assertTrue(Kernel32.INSTANCE.GetVersionEx(lpVersionInfo)); - System.out.println("Operating system: " + System.out.println("Operating system: " + lpVersionInfo.dwMajorVersion.longValue() + "." + lpVersionInfo.dwMinorVersion.longValue() + " (" + lpVersionInfo.dwBuildNumber + ")" + " [" + Native.toString(lpVersionInfo.szCSDVersion) + "]"); junit.textui.TestRunner.run(Kernel32Test.class); } - + public void testGetDriveType() { if (!Platform.isWindows()) return; - + Kernel32 kernel = Kernel32.INSTANCE; assertEquals("Wrong drive type.", WinBase.DRIVE_FIXED, kernel.GetDriveType("c:")); } - + public void testStructureOutArgument() { Kernel32 kernel = Kernel32.INSTANCE; WinBase.SYSTEMTIME time = new WinBase.SYSTEMTIME(); @@ -69,18 +73,18 @@ public void testStructureOutArgument() { assertEquals("Day not properly set", cal.get(Calendar.DAY_OF_WEEK)-1, time.wDayOfWeek); - assertEquals("Year not properly set", + assertEquals("Year not properly set", cal.get(Calendar.YEAR), time.wYear); } - + public void testGetLastError() { Kernel32 kernel = Kernel32.INSTANCE; int ERRCODE = 8; - + kernel.SetLastError(ERRCODE); int code = kernel.GetLastError(); assertEquals("Wrong error value after SetLastError", ERRCODE, code); - + if (kernel.GetProcessVersion(-1) == 0) { final int INVALID_PARAMETER = 87; code = kernel.GetLastError(); @@ -90,16 +94,16 @@ public void testGetLastError() { fail("GetProcessId(NULL) should fail"); } } - + public void testConvertHWND_BROADCAST() { HWND hwnd = WinUser.HWND_BROADCAST; NativeMappedConverter.getInstance(hwnd.getClass()).toNative(hwnd, null); } - + public void testGetComputerName() { IntByReference lpnSize = new IntByReference(0); assertFalse(Kernel32.INSTANCE.GetComputerName(null, lpnSize)); - assertEquals(W32Errors.ERROR_BUFFER_OVERFLOW, Kernel32.INSTANCE.GetLastError()); + assertEquals(WinError.ERROR_BUFFER_OVERFLOW, Kernel32.INSTANCE.GetLastError()); char buffer[] = new char[WinBase.MAX_COMPUTERNAME_LENGTH + 1]; lpnSize.setValue(buffer.length); assertTrue(Kernel32.INSTANCE.GetComputerName(buffer, lpnSize)); @@ -107,87 +111,87 @@ public void testGetComputerName() { public void testWaitForSingleObject() { HANDLE handle = Kernel32.INSTANCE.CreateEvent(null, false, false, null); - + // handle runs into timeout since it is not triggered - // WAIT_TIMEOUT = 0x00000102 - assertEquals(W32Errors.WAIT_TIMEOUT, Kernel32.INSTANCE.WaitForSingleObject( + // WAIT_TIMEOUT = 0x00000102 + assertEquals(WinError.WAIT_TIMEOUT, Kernel32.INSTANCE.WaitForSingleObject( handle, 1000)); - + Kernel32.INSTANCE.CloseHandle(handle); } - - public void testWaitForMultipleObjects(){ + + public void testWaitForMultipleObjects(){ HANDLE[] handles = new HANDLE[2]; - + handles[0] = Kernel32.INSTANCE.CreateEvent(null, false, false, null); handles[1] = Kernel32.INSTANCE.CreateEvent(null, false, false, null); - + // handle runs into timeout since it is not triggered // WAIT_TIMEOUT = 0x00000102 - assertEquals(W32Errors.WAIT_TIMEOUT, Kernel32.INSTANCE.WaitForMultipleObjects( + assertEquals(WinError.WAIT_TIMEOUT, Kernel32.INSTANCE.WaitForMultipleObjects( handles.length, handles, false, 1000)); - + Kernel32.INSTANCE.CloseHandle(handles[0]); Kernel32.INSTANCE.CloseHandle(handles[1]); - + // invalid Handle handles[0] = WinBase.INVALID_HANDLE_VALUE; handles[1] = Kernel32.INSTANCE.CreateEvent(null, false, false, null); - + // returns WAIT_FAILED since handle is invalid assertEquals(WinBase.WAIT_FAILED, Kernel32.INSTANCE.WaitForMultipleObjects( handles.length, handles, false, 5000)); Kernel32.INSTANCE.CloseHandle(handles[1]); - } - + } + public void testGetCurrentThreadId() { assertTrue(Kernel32.INSTANCE.GetCurrentThreadId() > 0); } - + public void testGetCurrentThread() { HANDLE h = Kernel32.INSTANCE.GetCurrentThread(); assertNotNull(h); assertFalse(h.equals(0)); // CloseHandle does not need to be called for a thread handle assertFalse(Kernel32.INSTANCE.CloseHandle(h)); - assertEquals(W32Errors.ERROR_INVALID_HANDLE, Kernel32.INSTANCE.GetLastError()); + assertEquals(WinError.ERROR_INVALID_HANDLE, Kernel32.INSTANCE.GetLastError()); } public void testOpenThread() { - HANDLE h = Kernel32.INSTANCE.OpenThread(WinNT.THREAD_ALL_ACCESS, false, + HANDLE h = Kernel32.INSTANCE.OpenThread(WinNT.THREAD_ALL_ACCESS, false, Kernel32.INSTANCE.GetCurrentThreadId()); assertNotNull(h); assertFalse(h.equals(0)); assertTrue(Kernel32.INSTANCE.CloseHandle(h)); } - + public void testGetCurrentProcessId() { assertTrue(Kernel32.INSTANCE.GetCurrentProcessId() > 0); } - + public void testGetCurrentProcess() { HANDLE h = Kernel32.INSTANCE.GetCurrentProcess(); assertNotNull(h); assertFalse(h.equals(0)); // CloseHandle does not need to be called for a process handle assertFalse(Kernel32.INSTANCE.CloseHandle(h)); - assertEquals(W32Errors.ERROR_INVALID_HANDLE, Kernel32.INSTANCE.GetLastError()); - } - + assertEquals(WinError.ERROR_INVALID_HANDLE, Kernel32.INSTANCE.GetLastError()); + } + public void testOpenProcess() { - HANDLE h = Kernel32.INSTANCE.OpenProcess(0, false, + HANDLE h = Kernel32.INSTANCE.OpenProcess(0, false, Kernel32.INSTANCE.GetCurrentProcessId()); assertNull(h); // opening your own process fails with access denied - assertEquals(W32Errors.ERROR_ACCESS_DENIED, Kernel32.INSTANCE.GetLastError()); + assertEquals(WinError.ERROR_ACCESS_DENIED, Kernel32.INSTANCE.GetLastError()); } - + public void testGetTempPath() { - char[] buffer = new char[WinDef.MAX_PATH]; - assertTrue(Kernel32.INSTANCE.GetTempPath(new DWORD(WinDef.MAX_PATH), buffer).intValue() > 0); + char[] buffer = new char[WinDef.MAX_PATH]; + assertTrue(Kernel32.INSTANCE.GetTempPath(new DWORD(WinDef.MAX_PATH), buffer).intValue() > 0); } - + public void testGetTickCount() throws InterruptedException { // Tick count rolls over every 49.7 days, so to safeguard from // roll-over, we will get two time spans. At least one should @@ -200,15 +204,15 @@ public void testGetTickCount() throws InterruptedException { assertTrue(tick2 > tick1 || tick3 > tick2); } - + public void testGetVersion() { DWORD version = Kernel32.INSTANCE.GetVersion(); assertTrue("Version high should be non-zero: 0x" + Integer.toHexString(version.getHigh().intValue()), version.getHigh().intValue() != 0); assertTrue("Version low should be >= 0: 0x" + Integer.toHexString(version.getLow().intValue()), version.getLow().intValue() >= 0); } - + public void testGetVersionEx_OSVERSIONINFO() { - OSVERSIONINFO lpVersionInfo = new OSVERSIONINFO(); + OSVERSIONINFO lpVersionInfo = new OSVERSIONINFO(); assertEquals(lpVersionInfo.size(), lpVersionInfo.dwOSVersionInfoSize.longValue()); assertTrue(Kernel32.INSTANCE.GetVersionEx(lpVersionInfo)); assertTrue(lpVersionInfo.dwMajorVersion.longValue() > 0); @@ -216,11 +220,11 @@ public void testGetVersionEx_OSVERSIONINFO() { assertEquals(lpVersionInfo.size(), lpVersionInfo.dwOSVersionInfoSize.longValue()); assertTrue(lpVersionInfo.dwPlatformId.longValue() > 0); assertTrue(lpVersionInfo.dwBuildNumber.longValue() > 0); - assertTrue(Native.toString(lpVersionInfo.szCSDVersion).length() >= 0); + assertTrue(Native.toString(lpVersionInfo.szCSDVersion).length() >= 0); } - + public void testGetVersionEx_OSVERSIONINFOEX() { - OSVERSIONINFOEX lpVersionInfo = new OSVERSIONINFOEX(); + OSVERSIONINFOEX lpVersionInfo = new OSVERSIONINFOEX(); assertEquals(lpVersionInfo.size(), lpVersionInfo.dwOSVersionInfoSize.longValue()); assertTrue(Kernel32.INSTANCE.GetVersionEx(lpVersionInfo)); assertTrue(lpVersionInfo.dwMajorVersion.longValue() > 0); @@ -228,16 +232,16 @@ public void testGetVersionEx_OSVERSIONINFOEX() { assertEquals(lpVersionInfo.size(), lpVersionInfo.dwOSVersionInfoSize.longValue()); assertTrue(lpVersionInfo.dwPlatformId.longValue() > 0); assertTrue(lpVersionInfo.dwBuildNumber.longValue() > 0); - assertTrue(Native.toString(lpVersionInfo.szCSDVersion).length() >= 0); + assertTrue(Native.toString(lpVersionInfo.szCSDVersion).length() >= 0); assertTrue(lpVersionInfo.wProductType >= 0); } - + public void testGetSystemInfo() { SYSTEM_INFO lpSystemInfo = new SYSTEM_INFO(); Kernel32.INSTANCE.GetSystemInfo(lpSystemInfo); assertTrue(lpSystemInfo.dwNumberOfProcessors.intValue() > 0); } - + public void testIsWow64Process() { try { IntByReference isWow64 = new IntByReference(42); @@ -248,7 +252,7 @@ public void testIsWow64Process() { // IsWow64Process is not available on this OS } } - + public void testGetNativeSystemInfo() { try { SYSTEM_INFO lpSystemInfo = new SYSTEM_INFO(); @@ -258,7 +262,7 @@ public void testGetNativeSystemInfo() { // only available under WOW64 } } - + public void testGlobalMemoryStatusEx() { MEMORYSTATUSEX lpBuffer = new MEMORYSTATUSEX(); assertTrue(Kernel32.INSTANCE.GlobalMemoryStatusEx(lpBuffer)); @@ -273,46 +277,46 @@ public void testGetLogicalDriveStrings() { char buf[] = new char[dwSize.intValue()]; assertTrue(Kernel32.INSTANCE.GetLogicalDriveStrings(dwSize, buf).intValue() > 0); } - + public void testGetDiskFreeSpaceEx() { - LARGE_INTEGER.ByReference lpFreeBytesAvailable = new LARGE_INTEGER.ByReference(); - LARGE_INTEGER.ByReference lpTotalNumberOfBytes = new LARGE_INTEGER.ByReference(); - LARGE_INTEGER.ByReference lpTotalNumberOfFreeBytes = new LARGE_INTEGER.ByReference(); - assertTrue(Kernel32.INSTANCE.GetDiskFreeSpaceEx(null, + LARGE_INTEGER.ByReference lpFreeBytesAvailable = new LARGE_INTEGER.ByReference(); + LARGE_INTEGER.ByReference lpTotalNumberOfBytes = new LARGE_INTEGER.ByReference(); + LARGE_INTEGER.ByReference lpTotalNumberOfFreeBytes = new LARGE_INTEGER.ByReference(); + assertTrue(Kernel32.INSTANCE.GetDiskFreeSpaceEx(null, lpFreeBytesAvailable, lpTotalNumberOfBytes, lpTotalNumberOfFreeBytes)); assertTrue(lpTotalNumberOfFreeBytes.getValue() > 0); assertTrue(lpTotalNumberOfFreeBytes.getValue() < lpTotalNumberOfBytes.getValue()); } - + public void testDeleteFile() { String filename = Kernel32Util.getTempPath() + "\\FileDoesNotExist.jna"; assertFalse(Kernel32.INSTANCE.DeleteFile(filename)); - assertEquals(W32Errors.ERROR_FILE_NOT_FOUND, Kernel32.INSTANCE.GetLastError()); + assertEquals(WinError.ERROR_FILE_NOT_FOUND, Kernel32.INSTANCE.GetLastError()); } - + public void testReadFile() throws IOException { String expected = "jna - testReadFile"; File tmp = File.createTempFile("testReadFile", "jna"); tmp.deleteOnExit(); - + FileWriter fw = new FileWriter(tmp); fw.append(expected); fw.close(); - + HANDLE hFile = Kernel32.INSTANCE.CreateFile(tmp.getAbsolutePath(), WinNT.GENERIC_READ, WinNT.FILE_SHARE_READ, new WinBase.SECURITY_ATTRIBUTES(), WinNT.OPEN_EXISTING, WinNT.FILE_ATTRIBUTE_NORMAL, null); assertFalse(hFile == WinBase.INVALID_HANDLE_VALUE); - + Memory m = new Memory(2048); IntByReference lpNumberOfBytesRead = new IntByReference(0); assertTrue(Kernel32.INSTANCE.ReadFile(hFile, m, (int) m.size(), lpNumberOfBytesRead, null)); int read = lpNumberOfBytesRead.getValue(); assertEquals(expected.length(), read); assertEquals(expected, new String(m.getByteArray(0, read))); - - assertTrue(Kernel32.INSTANCE.CloseHandle(hFile)); + + assertTrue(Kernel32.INSTANCE.CloseHandle(hFile)); } - + public void testSetHandleInformation() throws IOException { File tmp = File.createTempFile("testSetHandleInformation", "jna"); tmp.deleteOnExit(); @@ -320,39 +324,39 @@ public void testSetHandleInformation() throws IOException { HANDLE hFile = Kernel32.INSTANCE.CreateFile(tmp.getAbsolutePath(), WinNT.GENERIC_READ, WinNT.FILE_SHARE_READ, new WinBase.SECURITY_ATTRIBUTES(), WinNT.OPEN_EXISTING, WinNT.FILE_ATTRIBUTE_NORMAL, null); assertFalse(hFile == WinBase.INVALID_HANDLE_VALUE); - + assertTrue(Kernel32.INSTANCE.SetHandleInformation(hFile, WinBase.HANDLE_FLAG_PROTECT_FROM_CLOSE, 0)); assertTrue(Kernel32.INSTANCE.CloseHandle(hFile)); } - + public void testCreatePipe() { HANDLEByReference hReadPipe = new HANDLEByReference(); HANDLEByReference hWritePipe = new HANDLEByReference(); - + assertTrue(Kernel32.INSTANCE.CreatePipe(hReadPipe, hWritePipe, null, 0)); assertTrue(Kernel32.INSTANCE.CloseHandle(hReadPipe.getValue())); assertTrue(Kernel32.INSTANCE.CloseHandle(hWritePipe.getValue())); } - + public void testGetExitCodeProcess() { IntByReference lpExitCode = new IntByReference(0); assertTrue(Kernel32.INSTANCE.GetExitCodeProcess(Kernel32.INSTANCE.GetCurrentProcess(), lpExitCode)); assertEquals(WinBase.STILL_ACTIVE, lpExitCode.getValue()); } - + public void testTerminateProcess() throws IOException { File tmp = File.createTempFile("testTerminateProcess", "jna"); tmp.deleteOnExit(); HANDLE hFile = Kernel32.INSTANCE.CreateFile(tmp.getAbsolutePath(), WinNT.GENERIC_READ, WinNT.FILE_SHARE_READ, new WinBase.SECURITY_ATTRIBUTES(), WinNT.OPEN_EXISTING, WinNT.FILE_ATTRIBUTE_NORMAL, null); - + assertFalse(Kernel32.INSTANCE.TerminateProcess(hFile, 1)); - assertEquals(W32Errors.ERROR_INVALID_HANDLE, Kernel32.INSTANCE.GetLastError()); + assertEquals(WinError.ERROR_INVALID_HANDLE, Kernel32.INSTANCE.GetLastError()); assertTrue(Kernel32.INSTANCE.CloseHandle(hFile)); } - + public void testGetFileAttributes() { - assertTrue(WinBase.INVALID_FILE_ATTRIBUTES != Kernel32.INSTANCE.GetFileAttributes(".")); + assertTrue(WinBase.INVALID_FILE_ATTRIBUTES != Kernel32.INSTANCE.GetFileAttributes(".")); } public void testCopyFile() throws IOException { @@ -406,7 +410,7 @@ public void testCreateProcess() { assertTrue(status); assertTrue(processInformation.dwProcessId.longValue() > 0); } - + public void testGetEnvironmentVariable() { assertTrue(Kernel32.INSTANCE.SetEnvironmentVariable("jna-getenvironment-test", "42")); int size = Kernel32.INSTANCE.GetEnvironmentVariable("jna-getenvironment-test", null, 0); @@ -475,4 +479,50 @@ public void testGetProcessList() throws IOException { assertTrue(Kernel32.INSTANCE.CloseHandle(processEnumHandle)); assertTrue(processIdList.size() > 4); } + + public final void testGetPrivateProfileInt() throws IOException { + final File tmp = File.createTempFile("testGetPrivateProfileInt", "ini"); + tmp.deleteOnExit(); + final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(tmp))); + writer.println("[Section]"); + writer.println("existingKey = 123"); + writer.close(); + + assertEquals(123, Kernel32.INSTANCE.GetPrivateProfileInt("Section", "existingKey", 456, tmp.getCanonicalPath())); + assertEquals(456, Kernel32.INSTANCE.GetPrivateProfileInt("Section", "missingKey", 456, tmp.getCanonicalPath())); + } + + public final void testGetPrivateProfileString() throws IOException { + final File tmp = File.createTempFile("testGetPrivateProfileString", "ini"); + tmp.deleteOnExit(); + final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(tmp))); + writer.println("[Section]"); + writer.println("existingKey = ABC"); + writer.close(); + + final char[] buffer = new char[8]; + assertEquals("ABC", Kernel32.INSTANCE.GetPrivateProfileString("Section", "existingKey", "DEF", buffer, new DWORD(buffer.length), tmp.getCanonicalPath())); + assertEquals("DEF", Kernel32.INSTANCE.GetPrivateProfileString("Section", "missingKey", "DEF", buffer, new DWORD(buffer.length), tmp.getCanonicalPath())); + } + + public final void testWritePrivateProfileString() throws IOException { + final File tmp = File.createTempFile("testWritePrivateProfileString", "ini"); + tmp.deleteOnExit(); + final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(tmp))); + writer.println("[Section]"); + writer.println("existingKey = ABC"); + writer.println("removedKey = JKL"); + writer.close(); + + assertTrue(Kernel32.INSTANCE.WritePrivateProfileString("Section", "existingKey", "DEF", tmp.getCanonicalPath())); + assertTrue(Kernel32.INSTANCE.WritePrivateProfileString("Section", "addedKey", "GHI", tmp.getCanonicalPath())); + assertTrue(Kernel32.INSTANCE.WritePrivateProfileString("Section", "removedKey", null, tmp.getCanonicalPath())); + + final BufferedReader reader = new BufferedReader(new FileReader(tmp)); + assertEquals(reader.readLine(), "[Section]"); + assertTrue(reader.readLine().matches("existingKey\\s*=\\s*DEF")); + assertTrue(reader.readLine().matches("addedKey\\s*=\\s*GHI")); + assertEquals(reader.readLine(), null); + reader.close(); + } } diff --git a/contrib/platform/test/com/sun/jna/platform/win32/Kernel32UtilTest.java b/contrib/platform/test/com/sun/jna/platform/win32/Kernel32UtilTest.java index 62034fb8a3..eb540e431d 100644 --- a/contrib/platform/test/com/sun/jna/platform/win32/Kernel32UtilTest.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/Kernel32UtilTest.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2010 Daniel Doubrovkine, All Rights Reserved +/* Copyright (c) 2010, 2013 Daniel Doubrovkine, Markus Karg, All Rights Reserved * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -12,15 +12,21 @@ */ package com.sun.jna.platform.win32; +import java.io.BufferedReader; +import java.io.BufferedWriter; import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; import java.io.IOException; - -import com.sun.jna.platform.win32.WinNT.LARGE_INTEGER; +import java.io.PrintWriter; import junit.framework.TestCase; +import com.sun.jna.platform.win32.WinNT.LARGE_INTEGER; + /** * @author dblock[at]dblock[dot]org + * @author markus[at]headcrashing[dot]eu */ public class Kernel32UtilTest extends TestCase { @@ -129,4 +135,49 @@ public void testGetEnvironmentVariable() { Kernel32.INSTANCE.SetEnvironmentVariable("jna-getenvironment-test", "42"); assertEquals("42", Kernel32Util.getEnvironmentVariable("jna-getenvironment-test")); } + + public final void testGetPrivateProfileInt() throws IOException { + final File tmp = File.createTempFile("testGetPrivateProfileInt", "ini"); + tmp.deleteOnExit(); + final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(tmp))); + writer.println("[Section]"); + writer.println("existingKey = 123"); + writer.close(); + + assertEquals(123, Kernel32Util.getPrivateProfileInt("Section", "existingKey", 456, tmp.getCanonicalPath())); + assertEquals(456, Kernel32Util.getPrivateProfileInt("Section", "missingKey", 456, tmp.getCanonicalPath())); + } + + public final void testGetPrivateProfileString() throws IOException { + final File tmp = File.createTempFile("testGetPrivateProfileString", "ini"); + tmp.deleteOnExit(); + final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(tmp))); + writer.println("[Section]"); + writer.println("existingKey = ABC"); + writer.close(); + + assertEquals("ABC", Kernel32Util.getPrivateProfileString("Section", "existingKey", "DEF", tmp.getCanonicalPath())); + assertEquals("DEF", Kernel32Util.getPrivateProfileString("Section", "missingKey", "DEF", tmp.getCanonicalPath())); + } + + public final void testWritePrivateProfileString() throws IOException { + final File tmp = File.createTempFile("testWritePrivateProfileString", "ini"); + tmp.deleteOnExit(); + final PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(tmp))); + writer.println("[Section]"); + writer.println("existingKey = ABC"); + writer.println("removedKey = JKL"); + writer.close(); + + Kernel32Util.writePrivateProfileString("Section", "existingKey", "DEF", tmp.getCanonicalPath()); + Kernel32Util.writePrivateProfileString("Section", "addedKey", "GHI", tmp.getCanonicalPath()); + Kernel32Util.writePrivateProfileString("Section", "removedKey", null, tmp.getCanonicalPath()); + + final BufferedReader reader = new BufferedReader(new FileReader(tmp)); + assertEquals(reader.readLine(), "[Section]"); + assertTrue(reader.readLine().matches("existingKey\\s*=\\s*DEF")); + assertTrue(reader.readLine().matches("addedKey\\s*=\\s*GHI")); + assertEquals(reader.readLine(), null); + reader.close(); + } } diff --git a/contrib/platform/test/com/sun/jna/platform/win32/Shell32Test.java b/contrib/platform/test/com/sun/jna/platform/win32/Shell32Test.java index 8eeb7a1b49..00d855a10d 100644 --- a/contrib/platform/test/com/sun/jna/platform/win32/Shell32Test.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/Shell32Test.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2010 Daniel Doubrovkine, All Rights Reserved +/* Copyright (c) 2010, 2013 Daniel Doubrovkine, Markus Karg, All Rights Reserved * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,6 +19,7 @@ /** * @author dblock[at]dblock[dot]org + * @author markus[at]headcrashing[dot]eu */ public class Shell32Test extends TestCase { @@ -42,4 +43,9 @@ public void testSHGetDesktopFolder() { // should release the interface, but we need Com4JNA to do that. } + public final void testSHGetSpecialFolderPath() { + final char[] pszPath = new char[WinDef.MAX_PATH]; + assertTrue(Shell32.INSTANCE.SHGetSpecialFolderPath(null, pszPath, ShlObj.CSIDL_APPDATA, false)); + assertFalse(Native.toString(pszPath).isEmpty()); + } } diff --git a/contrib/platform/test/com/sun/jna/platform/win32/Shell32UtilTest.java b/contrib/platform/test/com/sun/jna/platform/win32/Shell32UtilTest.java index 1a40d31d87..733a7ccf39 100644 --- a/contrib/platform/test/com/sun/jna/platform/win32/Shell32UtilTest.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/Shell32UtilTest.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2010 Daniel Doubrovkine, All Rights Reserved +/* Copyright (c) 2010, 2013 Daniel Doubrovkine, Markus Karg, All Rights Reserved * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,6 +16,7 @@ /** * @author dblock[at]dblock[dot]org + * @author markus[at]headcrashing[dot]eu */ public class Shell32UtilTest extends TestCase { @@ -24,9 +25,14 @@ public static void main(String[] args) { System.out.println("Windows: " + Shell32Util.getFolderPath(ShlObj.CSIDL_WINDOWS)); System.out.println(" System: " + Shell32Util.getFolderPath(ShlObj.CSIDL_SYSTEM)); System.out.println("AppData: " + Shell32Util.getFolderPath(ShlObj.CSIDL_APPDATA)); + System.out.println("AppData: " + Shell32Util.getSpecialFolderPath(ShlObj.CSIDL_APPDATA, false)); } public void testGetFolderPath() { assertTrue(Shell32Util.getFolderPath(ShlObj.CSIDL_WINDOWS).length() > 0); } + + public final void testGetSpecialFolderPath() { + assertFalse(Shell32Util.getSpecialFolderPath(ShlObj.CSIDL_APPDATA, false).isEmpty()); + } }