changeset 6420:01b36b400145

6519127: user.home property not set correctly Summary: Registry-based approach was changed to SHGetKnownFolderPath/SHGetFolderPathW Reviewed-by: alanb, anthony
author uta
date Wed, 23 Jan 2013 15:06:49 +0400
parents 71691b9d45ab
children bf2a14ebb6e9
files src/windows/native/java/lang/java_props_md.c
diffstat 1 files changed, 50 insertions(+), 79 deletions(-) [+]
line wrap: on
line diff
--- a/src/windows/native/java/lang/java_props_md.c	Wed Jan 23 09:49:10 2013 +0000
+++ b/src/windows/native/java/lang/java_props_md.c	Wed Jan 23 15:06:49 2013 +0400
@@ -23,6 +23,11 @@
  * questions.
  */
 
+/* Access APIs for Windows Vista and above */
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0601
+#endif
+
 #include <windows.h>
 #include <shlobj.h>
 #include <objidl.h>
@@ -49,8 +54,6 @@
 static void SetupI18nProps(LCID lcid, char** language, char** script, char** country,
                char** variant, char** encoding);
 
-#define SHELL_KEY "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"
-
 #define PROPSIZE 9      // eight-letter + null terminator
 #define SNAMESIZE 86    // max number of chars for LOCALE_SNAME is 85
 
@@ -174,75 +177,53 @@
 }
 
 /*
- * Code to figure out the user's home directory using the registry
-*/
-static WCHAR*
-getHomeFromRegistry()
-{
-    HKEY key;
-    int rc;
-    DWORD type;
-    WCHAR *p;
-    WCHAR path[MAX_PATH+1];
-    int size = MAX_PATH+1;
-
-    rc = RegOpenKeyEx(HKEY_CURRENT_USER, SHELL_KEY, 0, KEY_READ, &key);
-    if (rc != ERROR_SUCCESS) {
-        // Shell folder doesn't exist??!!
-        return NULL;
-    }
-
-    path[0] = 0;
-    rc = RegQueryValueExW(key, L"Desktop", 0, &type, (LPBYTE)path, &size);
-    if (rc != ERROR_SUCCESS || type != REG_SZ) {
-        return NULL;
-    }
-    RegCloseKey(key);
-    /* Get the parent of Desktop directory */
-    p = wcsrchr(path, L'\\');
-    if (p == NULL) {
-        return NULL;
-    }
-    *p = L'\0';
-    return _wcsdup(path);
-}
-
-/*
  * Code to figure out the user's home directory using shell32.dll
  */
 WCHAR*
 getHomeFromShell32()
 {
-    HRESULT rc;
-    LPITEMIDLIST item_list = 0;
-    WCHAR *p;
-    WCHAR path[MAX_PATH+1];
-    int size = MAX_PATH+1;
+    /*
+     * Note that we don't free the memory allocated
+     * by getHomeFromShell32.
+     */
+    static WCHAR *u_path = NULL;
+    if (u_path == NULL) {
+        HRESULT hr;
 
-    rc = SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOPDIRECTORY, &item_list);
-    if (!SUCCEEDED(rc)) {
-        // we can't find the shell folder.
-        return NULL;
+        /*
+         * SHELL32 DLL is delay load DLL and we can use the trick with
+         * __try/__except block.
+         */
+        __try {
+            /*
+             * For Windows Vista and later (or patched MS OS) we need to use
+             * [SHGetKnownFolderPath] call to avoid MAX_PATH length limitation.
+             * Shell32.dll (version 6.0.6000 or later)
+             */
+            hr = SHGetKnownFolderPath(&FOLDERID_Profile, KF_FLAG_DONT_VERIFY, NULL, &u_path);
+        } __except(EXCEPTION_EXECUTE_HANDLER) {
+            /* Exception: no [SHGetKnownFolderPath] entry */
+            hr = E_FAIL;
+        }
+
+        if (FAILED(hr)) {
+            WCHAR path[MAX_PATH+1];
+
+            /* fallback solution for WinXP and Windows 2000 */
+            hr = SHGetFolderPathW(NULL, CSIDL_FLAG_DONT_VERIFY | CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, path);
+            if (FAILED(hr)) {
+                /* we can't find the shell folder. */
+                u_path = NULL;
+            } else {
+                /* Just to be sure about the path length until Windows Vista approach.
+                 * [S_FALSE] could not be returned due to [CSIDL_FLAG_DONT_VERIFY] flag and UNICODE version.
+                 */
+                path[MAX_PATH] = 0;
+                u_path = _wcsdup(path);
+            }
+        }
     }
-
-    path[0] = 0;
-    SHGetPathFromIDListW(item_list, (LPWSTR)path);
-
-    /* Get the parent of Desktop directory */
-    p = wcsrchr(path, L'\\');
-    if (p) {
-        *p = 0;
-    }
-
-    /*
-     * We've been successful.  Note that we don't free the memory allocated
-     * by ShGetSpecialFolderLocation.  We only ever come through here once,
-     * and only if the registry lookup failed, so it's just not worth it.
-     *
-     * We also don't unload the SHELL32 DLL.  We've paid the hit for loading
-     * it and we may need it again later.
-     */
-    return _wcsdup(path);
+    return u_path;
 }
 
 static boolean
@@ -336,7 +317,7 @@
 
     OSVERSIONINFOEX ver;
 
-    if (sprops.user_dir) {
+    if (sprops.line_separator) {
         return &sprops;
     }
 
@@ -538,15 +519,7 @@
     }
 
     /*
-     * Home directory/
-     *
-     * We first look under a standard registry key.  If that fails we
-     * fall back on using a SHELL32.DLL API.  If that fails we use a
-     * default value.
-     *
-     * Note: To save space we want to avoid loading SHELL32.DLL
-     * unless really necessary.  However if we do load it, we leave it
-     * in memory, as it may be needed again later.
+     * Home directory
      *
      * The normal result is that for a given user name XXX:
      *     On multi-user NT, user.home gets set to c:\winnt\profiles\XXX.
@@ -554,13 +527,11 @@
      *     On single-user Win95, user.home gets set to c:\windows.
      */
     {
-        WCHAR *homep = getHomeFromRegistry();
+        WCHAR *homep = getHomeFromShell32();
         if (homep == NULL) {
-            homep = getHomeFromShell32();
-            if (homep == NULL)
-                homep = L"C:\\";
+            homep = L"C:\\";
         }
-        sprops.user_home = _wcsdup(homep);
+        sprops.user_home = homep;
     }
 
     /*