JDK-4787931 : System property "user.home" does not correspond to "USERPROFILE" (win)
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 1.3.0,1.4.1,1.4.2,6u5,6u24,7,7u1
  • Priority: P4
  • Status: Resolved
  • Resolution: Duplicate
  • OS:
    windows,windows_nt,windows_xp,windows_vista,windows_7 windows,windows_nt,windows_xp,windows_vista,windows_7
  • CPU: generic,x86
  • Submitted: 2002-12-03
  • Updated: 2014-03-04
  • Resolved: 2013-05-07
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Name: nt126004			Date: 12/03/2002

java version "1.4.1_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_01-b01)
Java HotSpot(TM) Client VM (build 1.4.1_01-b01, mixed mode)

Microsoft Windows XP [Version 5.1.2600]

All Windows

The Java runtime looks (as far as I can see) at the
n\Explorer\Shell Folders\Desktop]"
and strips the last directory of this value.
As this is a derived value from a Registry-key whose
purpose is *NOT* to point at the users home directory, this
behaviour is likely to fail.
We have seen some cases, where the mentioned registry entry
changed during a windows session or after a restart. So a
Java-program's behaviour depends on when the user has
started a programm (before or after the change to the
registry, which the user probably does not know about).
After all, its really difficult to track down the reason
for a java-programs malfunction, because the mentioned
registry entry is not easy to find, and the Environment-
variable "USERPROFILE" - which should be the source
of "user.home" (this is my opinion) - does not
influence "user.home" at all.

1.change the above windows registry value to an other value
(e.g. "c:\MyDesktopFolder")
2.run PropertyTest.java
3.type "set USERPROFILE" inside windows cmd-line (shell)

Expected Result:
PropertyTest returns what Windows thinks is the User Home
directory, which should be the same value as "set
USERPROFILE" returns, e.g. "C:\Dokumente und Einstellungen\TestUser1".

Actual Result:
PropertyTest returns "C:", whereas "set USERPROFILE" still
returns "C:\Dokumente und Einstellungen\TestUser1" !

This bug can be reproduced always.

---------- BEGIN SOURCE ----------
/* precondition:
alter "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shel
l Folders\Desktop" prior to running this test */

public class PropertyTest{
  public static void main(String[] args) {

---------- END SOURCE ----------

No simple workaround for us, since it depends on how our
customer deploys our application to his employees.

Reading the Environment-variable "USERPROFILE" on
Application startup is not that simple because of other
java-bugs (Exec for batch-files...).

If a customer has a problem (most often, our Application
won't start at some time (hopefully not during a
presentation to the management ;-(, because the "user.home"
is different, and the license-information file can not be
found anymore), we can tell him to manually edit the
registry, which is so awful and unprofessional for
a "professional application plattform" like java should be
(Review ID: 178403) 

Duplicate for JDK-6519127

Do we need the backport, http://cr.openjdk.java.net/~uta/openjdk-webrevs/JDK-6519127/webrev.03/ ? Fixed in JDK 8.

EVALUATION Will investigate fix for Tiger; problem has existed since 1.3. ###@###.### 2002-12-09 It is not at all obvious to me what the correct value for java.home should be. When I log in to my Windows machine using ssh, I see HOME=C:HOMEDRIVE=d: HOMEPATH=\martin USERPROFILE=C:\WINNT/Profiles/martin Three different values, and the directory C:\WINNT/Profiles/martin doesn't even exist! When I log in the traditional way on the console, I get HOME=C:HOMEDRIVE=C: HOMEPATH=USERPROFILE=C:\Documents and Settings\martin which is a little more consistent, and the latter directory actually exists. Given that HOME is what is used on Unix, and given that this variable exists on Windows, I would favor this algorithm: if HOME is defined, and names an actual directory, use that. if HOMEDRIVE and HOMEPATH are defined, and name an actual directory, use that. if USERPROFILE is defined, and names an actual directory, use that. else use the root directory of the drive where the windows system directory is located (typically C:\). But I am not a real windows user, and I am not familiar with the culture enough to know what most users would expected. An argument for HOME is that this variable appears to be used by "Command Prompt" for its initial directory. ###@###.### 2004-03-19 The registry approach used by the JDK is definitely wrong. The suggestion in the evaluation is also problematic because HOME/HOMEDRIVE/HOMEPATH don't exist in older Windows platforms, and there are many bugs documented in MSDN that these variables are not set properly by Microsoft in various situations. To determine the user profile correctly on Windows, there are really two ways to do it: 1. Use %USERPROFILE% environment This variable is normally set to the actual user profile location by Microsoft. The advantages is that it works on various Windows platforms with various types of user profile settings: http://www.microsoft.com/technet/prodtechnol/winxppro/maintain/xpusrdat.mspx However, older Windows (e.g. Windows 95/98) is more or less a single user system, so settings up user profile is not required for end users. In these OSes, %USERPROFILE% would not be set by Windows, but Windows itself would default the profile location internally to Windows directory. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/shlwapi/registry/shreggetpath.asp Thus, the correct algorithm in this case would be: if %USERPROFILE% is present { Set "user.home" to value of %USERPROFILE% } else { Set "user.home" to Windows directory } This scheme works in general, and it basically mirrors the internal algorithm used by Windows. There is still a catch - because the value is set in environment variables, if the user happens to change the user profile location on-the-fly through Windows Control Panel, %USERPROFILE% will reflect the new value only in new processes; %USERPROFILE% in all the running processes will still have the old value. Users could also override USERPROFILE in the shell which may cause unintentional side effect. 2. Use SHGetFolderLocation or SHGetFolderPath APIs These APIs are actually the recommended way from Microsoft to determine special folders in user profile on Windows: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/programmersguide/shell_new/fastuserswitching.asp These APIs generally return the special folder location under the user profile: C:\Documents and Settings\<username>\<special-folder> You could determine the user profile by looking up the parent directory of the returned path. Thus, the algorithm would be something like if shfolder.dll is present { SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, pszPath) } else if shell32.dll is present { SHGetSpecialFolderPath(NULL, pszPath, CSIDL_APPDATA, TRUE); } Set "user.home" to parent directory of pszPath The nice thing about using these APIs is that they could provide the user profile location programmatically without suffering the drawback of environment variable scheme in general. This scheme also works in most cases. The catch is that these APIs are from shfolder.dll and shell32.dll, and these DLLs only present if Internet Explorer 4 or later is installed. Although IE is almost pre-installed with every Windows OS, Windows 95 and Windows NT4 are the exception. Loading shfolder.dll and shell32.dll would also have minor footprint impact because additional Windows libraries are now required to run the Java apps. In general, the end result of using #1 and #2 would be pretty much the same, and it is simply a matter of choice. In plugin, we used #1 for determine the "user.home" settings for simplicity, and we used #2 to determine special folder location. Since JRE only cares about user profile location for "user.home", I would suggest #1, so it will be consistent with plugin. #1 was also suggested by many customers in early releases of plugin to workaround this particular "user.home" in the JRE, so this fix should be well-received by customers. The only potential issue for customers is backward compatibility of "user.home", but we should fix it anyway because it is really a bug. ###@###.### I have done some more investigation. The windows system I was using (Win 2003 Server 64-bit) has both the concept of a "User Profile" and a "Home Folder" (which I think is the same as the "Home Directory"), as can be seen from per-user properties in the menu tree Administrative Tools -> Computer Management -> Local Users & Groups -> Users If the Home Folder is unset, it defaults to the User Profile, which in turn defaults to %SYSTEMDRIVE%Documents and Settings\%USERNAME%. Windows (at least in the interactive session) will initialize %HOMEDRIVE% and %HOMEPATH% to point to the Home Folder, and will set HOME=%HOMEDRIVE%%HOMEPATH%. Intuitively, it seems clear we should set user.home to the same value as the Windows Home Folder, at least on modern Windows systems. Which means we should use %USERPROFILE% only as a fallback. There is a programmatic API to access the home directory. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/netmgmt/netmgmt/netusergetinfo.asp NetUserGetInfo returns in its USER_INFO_1 structure, the member LPWSTR usri1_home_dir; which seems to be exactly what we want. My current recommendation is: Check if HOMEDRIVE and HOMEPATH are defined, and name a directory. If not, use the NetUserGetInfo API to extract a valid home directory. If that doesn't work, try %USERPROFILE%. If that doesn't work, try the root directory of %SYSTEMDRIVE% This seems to be consistent with "Command Prompt". ###@###.### 2004-03-23

WORK AROUND J2SE 1.5 will have a working System.getenv(String), so users can simply do a System.getenv("USERPROFILE") directly. ###@###.### 2004-03-19