Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Windows Shell API mapping: SHGetSpecialFolderPath #192

Merged
merged 3 commits into from
Feb 22, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
====================
Expand Down
82 changes: 81 additions & 1 deletion contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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 ""}.
* <p>
* 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.
* </p>
* @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.
* <p>
* 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.
* </p>
* <p>
* 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.
* </p>
* <p>
* 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}.
* </p>
*/
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}.
* <p>
* 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}.
* </p>
*/
boolean WritePrivateProfileString(String lpAppName, String lpKeyName, String lpString, String lpFileName);
}
69 changes: 66 additions & 3 deletions contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -28,6 +28,7 @@
/**
* Kernel32 utility API.
* @author dblock[at]dblock.org
* @author markus[at]headcrashing[dot]eu
*/
public abstract class Kernel32Util implements WinDef {

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 ""}.
* <p>
* 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.
* </p>
* @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 <p>
* 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.
* </p>
* <p>
* 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.
* </p>
* <p>
* 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}.
* </p>
*/
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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be checking error here and raising an exception.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, reading its description it looks like it cannot fail. Oh it comes from 16-bit times :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually this function will never fail but simply return the default! If the buffer is too small, the result is simply truncated. If the file is not found, the default is applied. Both are not necessarily failures but most likely are accepted by people used to this function. Typically, it is wanted behaviour that the default is returned if the file, the appname, or the key is missing -- instead of getting an exception. I think nobody ever checked for GetLatestError after this function, as the default's job is to get in place in case of any problem. Users would be scared if there is an exception thrown instead of getting the default. So if you insist for sake of OOP, I can throw an exception. But my advise would be in this particular function not to throw, for the sake of "expected behaviour". :-)

BTW, yes, this comes from 16 bit times, but in fact is still in use in lots of 32 bit software. ;-)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're correct. This is all good.

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());
}
}
19 changes: 18 additions & 1 deletion contrib/platform/src/com/sun/jna/platform/win32/Shell32.java
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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);
}
20 changes: 19 additions & 1 deletion contrib/platform/src/com/sun/jna/platform/win32/Shell32Util.java
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -20,6 +20,7 @@
/**
* Shell32 Utility API.
* @author dblock[at]dblock.org
* @author markus[at]headcrashing[dot]eu
*/
public abstract class Shell32Util {

Expand Down Expand Up @@ -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);
}
}
Loading