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
|