I once found a nifty little library that used JNI to allow java applications on Windows to get the locations of various "special" directories on windows. I can't for the life of me find it again...
In particular, I need to get the location of the "All Users" (shared) "Application Data" directory.
So, anyone have a bullet proof way in Java to locate the "All Users" "Application Data" folder?
It needs to be bullet proof.
You might want to research Environment Variables:
http://en.wikipedia.org/wiki/Environment_variable#DOS_and_Windows
http://en.wikipedia.org/wiki/Environment_variable#System_path_variables
The System.getenv() method offers a list of the system's environment variables and it's included in the core library. Doesn't get much more bullet-proof than that.
You could use the following property in the environment:
ALLUSERSPROFILE=C:\Documents and Settings\All Users
Edit: This no longer works as of Windows Vista and newer.
Related
Could anyone please tell me how to make a symbolic link (in the same way MKLINK does) and/or remove a symbolic link with Java. I have found solutions that use Java as a wrapper and use a Windows native program to accomplish this, but I really want a pure Java solution. Thank you in advance!
Since Java 7 you can do this easily using the NIO package.
Path target = Paths.get("target");
Path link = Paths.get("link");
Files.createDirectory(target);
Files.createSymbolicLink(link, target);
Do remember that you do need the correct privileges for this. In my unit test I had to run eclipse as an administrator to make it work (same as that I couldn't create a link from a normal cmd.exe)
As far as I know window does not have real symbolic links like Unix-like system do.
However Windows has the following relevant tools:
You can map network drive, i.e. attach drive letter to specified network path. You can definitely do this using WMI. To access WMI from java take a look on tools like JaWin, Jinterop, Jintegra or write WMI script in JScript o VBScript and execute is from Java.
You can use command subst that assigns letter to local file system path. This is the closest approach to Unix soft link.
You can create desktop shortcut. Create one manually and take a look on it. Shortcut is actually regular text file (as far as I remember in INI format). You can easily create one using any language you want including java. This is not soft link but it is clickable.
In Linux, I'll usually put user configuration files in $HOME/.myapp and in Windows I'll use APPDATA. So far so good.
What about non-user specific configuration? In linux, I'd put it into /etc. Is there an equivalent in Windows? Please note I would like to have the service running before any user logs in. Also, in case it plays a role, I'm developing in Java.
Alternatively: I approaching this the wrong way?
You could use ALLUSERPROFILES as a base directory. This environment variable resolves to the C:\PROGRAMDATA folder in Windows7. Of course you need to add a specific folder for your applications
In summary, you should use the known folder: ProgramData.
To avoid hard coding of paths (and hence why I'm not providing them here) you should always retrieve the value via one of the following methods:
The %PROGRAMDATA% environment variable (you can also use %ALLUSERSPROFILE% but I consider %PROGRAMDATA% more meaningful)
For unmanaged code use SHGetKnownFolderPath, passing the FOLDERID_ProgramData.
For managed code use System.Environment.GetFolderPath, passing CommonApplicationData.
This folder is not writeable by non-admins, so depending on your requirements you'll want to create a directory for your program and set the ACLs you need at install time.
Some good information on this topic is provided in the blog post: "Where Should I Write Program Data Instead of Program Files".
For those interested in using other Known Folders, MSDN provides extensive documentation.
In Windows most "program files" for an app go in C:\Program Files\MyApp. The environment variable would be %ProgramFiles%\MyApp.
I have a program, written in Java, which originally used its directory in Program Files to write files accessible to all users of this program. This required our users to run as administrator all the time. In an effort to alleviate that, we decided to move files which needed to be written during regular usage to the ProgramData folder using the %ALLUSERSPROFILE% environment variable. Using a subfolder in this directory for our application works great if it is designated as writable during the installation process, which works fine using NSIS.
The problem comes with upgrading existing users. The Java File API provides setWritable but this does not appear to work after testing on development machines. It looks as though the new file API with Java 7 would solve this problem, but with no release date on the horizon I would rather not wait.
It seems the simplest solution would be to use JNA to call the appropriate Windows API call to set this directory writable. Since upgrading the software necessitates admin rights, similar to installing, it should let this change go through fine. However, I'm unsure where to start, having never used JNA before or the Windows API. Suggestions as to which Windows library to load and what functions to call would be appreciated, especially if someone has encountered a similar problem before.
Well, I'm glad you gave some background...You could use JNA, but the easier way would be to execute a call to the command-line utility cacls. It's included by default in Windows XP installations, I believe, so it should do the trick for you. Try Runtime.getRuntime().exec("C:\\Windows\\System32\\cacls.exe"+options)
Check out the documentation here -> http://technet.microsoft.com/en-us/library/bb490872.aspx
I use the follow line:
Runtime.getRuntime().exec( "C:\\Windows\\System32\\icacls.exe \"%ProgramData%\my application" /grant *S-1-5-32-545:(OI)(CI)(W,M)" );
S-1-5-32-545 is the SID for BUILTIN\Users because the name work only on English systems. https://support.microsoft.com/de-de/kb/163846
This give the BUILTIN\Users write access to all files in the given directory independent which user has create it.
I have a SWT Java app that runs on Windows XP / Vista / 7 and Mac OS X. I'm currently saving a config file to:
System.getProperty("user.home") + filename
With the changes in security in Windows Vista and Windows 7 this doesn't seem to be the best place to save it anymore.
This file saves information such as registration key info and it is annoying for my users if the file can't be saved or is deleted.
Is there a better path I should use?
Also, what's the preferred path for per user application data on Mac OS X?
macos path for application data to be kept is "~/Library/Application Support" as per Apple documentation
What changes in security? I understand they prohibited writing in Program Files, I didn't know they forbid to write in user home.
It would be a serious compatibility break, I have a number of applications writing there, either directly a file, or in a folder ("hidden" at the Unix mode, ie. prefixed with a dot).
Now, it seems to be more "friendly" to write in Application Data folder as do a number of other applications (but rarely cross-platform applications which seem to use the previous solution...) but the exact location seems hard to find in Java, and would need a platform detection to do something else on other platforms.
An alternative seems to be to use the Preferences API, ie. java.util.prefs.Preferences.
Sun itself, with its java control panel, had the very same problem (bug 6487334): their control panel, running at different integrity level, could not both read/write to their deployment directories.
They moved it to c:\users\<username>\appdata\local, but had to not rely on System.getProperty("user.home") because to this day, it uses a registry KEY that can be set to incorrect value if windows is "tweaked": bug 6519127
So the question How to get local application data folder in Java?, using HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\* is the right place to start looking for read/write access for your settings.
You can read it with, for instance, SWT Win32 Extension project.
The interest to keep your data within the user's homedir is that they will be part of the user's profile which can be a roaming profile, saved at logoff and restored at logon (used quite often on corporation's workstations)
Specifically getting on Windows the "..\Documents & Settings\All Users, basicaly any path that needs the front end to be dynamically derived based on the OS your software is running on. (Now I need the answer to this)
the current users My Documents dirctory (okay this has been answered)
and basicaly any path that needs the front end to be dynamically derived based on the OS your software is running on.
My docs would probably best be handled by accessing:
System.getProperty("user.home");
Look up the docs on System.getProperty.
Any information you can get about the user's environment can be fetched from
System.getProperty("...");
For a list of what you can get, take a look here.
I don't think you'll be able to get the path you require (the All Users path) in an OS dependent way. After all - do other operating systems have an equivalent? Your best bet is to probably inspect:
System.getProperty("os.name");
to see if you are running Windows and then if so use "C:\Documents & Settings\All Users\".
But you'll be better off just constantly using
System.getProperty("user.home");
(as mentioned by other people) throughout the application. Or alternatively, allow the user to specify the directory to store whatever it is you want to store.
Specifically getting on Windows the "..\Documents & Settings\All Users, basicaly any path that needs the front end to be dynamically derived based on the OS your software is running on. (Now I need the answer to this)
The folders below the All Users dir are variable directories in windows. Details can be found in the document about KNOWNFOLDERIDs (CSIDL in older versions).
Because this values are system dependent Java does not provide a way to access the values.
I think there is in general no equivalent on other operating systems to this windows specific folder. In addition the folder Documents & Settings\All Users is only present in latest windows versions and things are handled differently for e.g Windows 2000 or XP I think.
If you really need this information you should read the microsoft docs and impement a native library or some script invoked by Runtime.exec to provide the information to your java application.