- Implement reading user shell folders from registry
[reactos.git] / reactos / dll / win32 / shell32 / shellpath.c
index df17cba..76fc17c 100644 (file)
  *
  */
 
-#define symlink(A, B)
-#include "config.h"
-#include "wine/port.h"
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <ctype.h>
-#include "wine/debug.h"
-#include "windef.h"
-#include "winbase.h"
-#include "winnls.h"
-#include "winreg.h"
-#include "wingdi.h"
-#include "winuser.h"
-
-#include "shlobj.h"
-#include "shresdef.h"
-#include "shell32_main.h"
-#include "undocshell.h"
-#include "pidl.h"
-#include "wine/unicode.h"
-#include "shlwapi.h"
+#include <precomp.h>
 
 WINE_DEFAULT_DEBUG_CHANNEL(shell);
 
@@ -66,29 +44,6 @@ BOOL WINAPI PathAppendAW(
        return PathAppendA(lpszPath1, lpszPath2);
 }
 
-/*************************************************************************
- * PathCombine  [SHELL32.37]
- */
-LPVOID WINAPI PathCombineAW(
-       LPVOID szDest,
-       LPCVOID lpszDir,
-       LPCVOID lpszFile)
-{
-       if (SHELL_OsIsUnicode())
-         return PathCombineW( szDest, lpszDir, lpszFile );
-       return PathCombineA( szDest, lpszDir, lpszFile );
-}
-
-/*************************************************************************
- * PathAddBackslash            [SHELL32.32]
- */
-LPVOID WINAPI PathAddBackslashAW(LPVOID lpszPath)
-{
-       if(SHELL_OsIsUnicode())
-         return PathAddBackslashW(lpszPath);
-       return PathAddBackslashA(lpszPath);
-}
-
 /*************************************************************************
  * PathBuildRoot               [SHELL32.30]
  */
@@ -99,31 +54,6 @@ LPVOID WINAPI PathBuildRootAW(LPVOID lpszPath, int drive)
        return PathBuildRootA(lpszPath, drive);
 }
 
-/*
-       Extracting Component Parts
-*/
-
-/*************************************************************************
- * PathFindFileName    [SHELL32.34]
- */
-LPVOID WINAPI PathFindFileNameAW(LPCVOID lpszPath)
-{
-       if(SHELL_OsIsUnicode())
-         return PathFindFileNameW(lpszPath);
-       return PathFindFileNameA(lpszPath);
-}
-
-/*************************************************************************
- * PathFindExtension           [SHELL32.31]
- */
-LPVOID WINAPI PathFindExtensionAW(LPCVOID lpszPath)
-{
-       if (SHELL_OsIsUnicode())
-         return PathFindExtensionW(lpszPath);
-       return PathFindExtensionA(lpszPath);
-
-}
-
 /*************************************************************************
  * PathGetExtensionA           [internal]
  *
@@ -142,7 +72,7 @@ static LPSTR PathGetExtensionA(LPCSTR lpszPath)
 /*************************************************************************
  * PathGetExtensionW           [internal]
  */
-static LPWSTR PathGetExtensionW(LPCWSTR lpszPath)
+LPWSTR PathGetExtensionW(LPCWSTR lpszPath)
 {
        TRACE("(%s)\n",debugstr_w(lpszPath));
 
@@ -151,33 +81,11 @@ static LPWSTR PathGetExtensionW(LPCWSTR lpszPath)
 }
 
 /*************************************************************************
- * PathGetExtension            [SHELL32.158]
- */
-LPVOID WINAPI PathGetExtensionAW(LPCVOID lpszPath,DWORD void1, DWORD void2)
-{
-       if (SHELL_OsIsUnicode())
-         return PathGetExtensionW(lpszPath);
-       return PathGetExtensionA(lpszPath);
-}
-
-/*************************************************************************
- * PathGetArgs [SHELL32.52]
- */
-LPVOID WINAPI PathGetArgsAW(LPVOID lpszPath)
-{
-       if (SHELL_OsIsUnicode())
-         return PathGetArgsW(lpszPath);
-       return PathGetArgsA(lpszPath);
-}
-
-/*************************************************************************
- * PathGetDriveNumber  [SHELL32.57]
+ * SHPathGetExtension          [SHELL32.158]
  */
-int WINAPI PathGetDriveNumberAW(LPVOID lpszPath)
+LPVOID WINAPI SHPathGetExtensionW(LPCWSTR lpszPath, DWORD void1, DWORD void2)
 {
-       if (SHELL_OsIsUnicode())
-         return PathGetDriveNumberW(lpszPath);
-       return PathGetDriveNumberA(lpszPath);
+       return PathGetExtensionW(lpszPath);
 }
 
 /*************************************************************************
@@ -190,50 +98,6 @@ BOOL WINAPI PathRemoveFileSpecAW(LPVOID lpszPath)
        return PathRemoveFileSpecA(lpszPath);
 }
 
-/*************************************************************************
- * PathStripPath       [SHELL32.38]
- */
-void WINAPI PathStripPathAW(LPVOID lpszPath)
-{
-       if (SHELL_OsIsUnicode())
-            PathStripPathW(lpszPath);
-        else
-            PathStripPathA(lpszPath);
-}
-
-/*************************************************************************
- * PathStripToRoot     [SHELL32.50]
- */
-BOOL WINAPI PathStripToRootAW(LPVOID lpszPath)
-{
-       if (SHELL_OsIsUnicode())
-         return PathStripToRootW(lpszPath);
-       return PathStripToRootA(lpszPath);
-}
-
-/*************************************************************************
- * PathRemoveArgs      [SHELL32.251]
- */
-void WINAPI PathRemoveArgsAW(LPVOID lpszPath)
-{
-       if (SHELL_OsIsUnicode())
-            PathRemoveArgsW(lpszPath);
-        else
-            PathRemoveArgsA(lpszPath);
-}
-
-/*************************************************************************
- * PathRemoveExtension [SHELL32.250]
- */
-void WINAPI PathRemoveExtensionAW(LPVOID lpszPath)
-{
-       if (SHELL_OsIsUnicode())
-            PathRemoveExtensionW(lpszPath);
-        else
-            PathRemoveExtensionA(lpszPath);
-}
-
-
 /*
        Path Manipulations
 */
@@ -264,7 +128,7 @@ static void PathGetShortPathW(LPWSTR pszPath)
 
        if (GetShortPathNameW(pszPath, path, MAX_PATH))
        {
-         lstrcpyW(pszPath, path);
+         wcscpy(pszPath, path);
        }
 }
 
@@ -278,71 +142,9 @@ VOID WINAPI PathGetShortPathAW(LPVOID pszPath)
        PathGetShortPathA(pszPath);
 }
 
-/*************************************************************************
- * PathRemoveBlanks [SHELL32.33]
- */
-void WINAPI PathRemoveBlanksAW(LPVOID str)
-{
-       if(SHELL_OsIsUnicode())
-            PathRemoveBlanksW(str);
-        else
-            PathRemoveBlanksA(str);
-}
-
-/*************************************************************************
- * PathQuoteSpaces [SHELL32.55]
- */
-VOID WINAPI PathQuoteSpacesAW (LPVOID lpszPath)
-{
-       if(SHELL_OsIsUnicode())
-            PathQuoteSpacesW(lpszPath);
-        else
-            PathQuoteSpacesA(lpszPath);
-}
-
-/*************************************************************************
- * PathUnquoteSpaces [SHELL32.56]
- */
-VOID WINAPI PathUnquoteSpacesAW(LPVOID str)
-{
-       if(SHELL_OsIsUnicode())
-         PathUnquoteSpacesW(str);
-       else
-         PathUnquoteSpacesA(str);
-}
-
-/*************************************************************************
- * PathParseIconLocation       [SHELL32.249]
- */
-int WINAPI PathParseIconLocationAW (LPVOID lpszPath)
-{
-       if(SHELL_OsIsUnicode())
-         return PathParseIconLocationW(lpszPath);
-       return PathParseIconLocationA(lpszPath);
-}
-
 /*
        ########## Path Testing ##########
 */
-/*************************************************************************
- * PathIsUNC           [SHELL32.39]
- */
-BOOL WINAPI PathIsUNCAW (LPCVOID lpszPath)
-{
-       if (SHELL_OsIsUnicode())
-         return PathIsUNCW( lpszPath );
-       return PathIsUNCA( lpszPath );
-}
-
-/*************************************************************************
- *  PathIsRelative     [SHELL32.40]
- */
-BOOL WINAPI PathIsRelativeAW (LPCVOID lpszPath)
-{
-       if (SHELL_OsIsUnicode())
-         return PathIsRelativeW( lpszPath );
-       return PathIsRelativeA( lpszPath );
-}
 
 /*************************************************************************
  * PathIsRoot          [SHELL32.29]
@@ -402,16 +204,6 @@ BOOL WINAPI PathIsExeAW (LPCVOID path)
        return PathIsExeA(path);
 }
 
-/*************************************************************************
- * PathIsDirectory     [SHELL32.159]
- */
-BOOL WINAPI PathIsDirectoryAW (LPCVOID lpszPath)
-{
-       if (SHELL_OsIsUnicode())
-         return PathIsDirectoryW (lpszPath);
-       return PathIsDirectoryA (lpszPath);
-}
-
 /*************************************************************************
  * PathFileExists      [SHELL32.45]
  */
@@ -422,16 +214,6 @@ BOOL WINAPI PathFileExistsAW (LPCVOID lpszPath)
        return PathFileExistsA (lpszPath);
 }
 
-/*************************************************************************
- * PathMatchSpec       [SHELL32.46]
- */
-BOOL WINAPI PathMatchSpecAW(LPVOID name, LPVOID mask)
-{
-       if (SHELL_OsIsUnicode())
-         return PathMatchSpecW( name, mask );
-       return PathMatchSpecA( name, mask );
-}
-
 /*************************************************************************
  * PathIsSameRoot      [SHELL32.650]
  */
@@ -548,16 +330,6 @@ BOOL WINAPI PathYetAnotherMakeUniqueName(
        ########## cleaning and resolving paths ##########
  */
 
-/*************************************************************************
- * PathFindOnPath      [SHELL32.145]
- */
-BOOL WINAPI PathFindOnPathAW(LPVOID sFile, LPCVOID *sOtherDirs)
-{
-       if (SHELL_OsIsUnicode())
-         return PathFindOnPathW(sFile, (LPCWSTR *)sOtherDirs);
-       return PathFindOnPathA(sFile, (LPCSTR *)sOtherDirs);
-}
-
 /*************************************************************************
  * PathCleanupSpec     [SHELL32.171]
  *
@@ -576,7 +348,7 @@ int WINAPI PathCleanupSpec( LPCWSTR lpszPathW, LPWSTR lpszFileW )
         TRACE("Cleanup %s\n",debugstr_w(lpszFileW));
 
         if (lpszPathW)
-            length = strlenW(lpszPathW);
+            length = wcslen(lpszPathW);
 
         while (*p)
         {
@@ -727,8 +499,8 @@ LONG WINAPI PathProcessCommandW (
        FIXME("(%s, %p, 0x%04x, 0x%04x) stub\n",
        debugstr_w(lpszPath), lpszBuff, dwBuffSize, dwFlags);
        if(!lpszPath) return -1;
-       if(lpszBuff) strcpyW(lpszBuff, lpszPath);
-       return strlenW(lpszPath);
+       if(lpszBuff) wcscpy(lpszBuff, lpszPath);
+       return wcslen(lpszPath);
 }
 
 /*************************************************************************
@@ -749,17 +521,6 @@ LONG WINAPI PathProcessCommandAW (
        ########## special ##########
 */
 
-/*************************************************************************
- * PathSetDlgItemPath (SHELL32.48)
- */
-VOID WINAPI PathSetDlgItemPathAW(HWND hDlg, int id, LPCVOID pszPath)
-{
-       if (SHELL_OsIsUnicode())
-            PathSetDlgItemPathW(hDlg, id, pszPath);
-        else
-            PathSetDlgItemPathA(hDlg, id, pszPath);
-}
-
 static const WCHAR szCurrentVersion[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\0'};
 static const WCHAR Administrative_ToolsW[] = {'A','d','m','i','n','i','s','t','r','a','t','i','v','e',' ','T','o','o','l','s','\0'};
 static const WCHAR AppDataW[] = {'A','p','p','D','a','t','a','\0'};
@@ -1148,8 +909,6 @@ static const CSIDL_DATA CSIDL_Data[] =
     }
 };
 
-static HRESULT _SHExpandEnvironmentStrings(LPCWSTR szSrc, LPWSTR szDest);
-
 /* Gets the value named value from the registry key
  * rootKey\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders
  * (or from rootKey\userPrefix\... if userPrefix is not NULL) into path, which
@@ -1165,7 +924,7 @@ static HRESULT _SHGetUserShellFolderPath(HKEY rootKey, LPCWSTR userPrefix,
     HRESULT hr;
     WCHAR shellFolderPath[MAX_PATH], userShellFolderPath[MAX_PATH];
     LPCWSTR pShellFolderPath, pUserShellFolderPath;
-    DWORD dwDisp, dwType, dwPathLen = MAX_PATH;
+    DWORD dwDisp, dwType, dwPathLen;
     HKEY userShellFolderKey, shellFolderKey;
 
     TRACE("%p,%s,%s,%p\n",rootKey, debugstr_w(userPrefix), debugstr_w(value),
@@ -1173,13 +932,13 @@ static HRESULT _SHGetUserShellFolderPath(HKEY rootKey, LPCWSTR userPrefix,
 
     if (userPrefix)
     {
-        strcpyW(shellFolderPath, userPrefix);
+        wcscpy(shellFolderPath, userPrefix);
         PathAddBackslashW(shellFolderPath);
-        strcatW(shellFolderPath, szSHFolders);
+        wcscat(shellFolderPath, szSHFolders);
         pShellFolderPath = shellFolderPath;
-        strcpyW(userShellFolderPath, userPrefix);
+        wcscpy(userShellFolderPath, userPrefix);
         PathAddBackslashW(userShellFolderPath);
-        strcatW(userShellFolderPath, szSHUserFolders);
+        wcscat(userShellFolderPath, szSHUserFolders);
         pUserShellFolderPath = userShellFolderPath;
     }
     else
@@ -1188,14 +947,14 @@ static HRESULT _SHGetUserShellFolderPath(HKEY rootKey, LPCWSTR userPrefix,
         pShellFolderPath = szSHFolders;
     }
 
-    if (RegCreateKeyExW(rootKey, pShellFolderPath, 0, NULL, 0, KEY_ALL_ACCESS,
+    if (RegCreateKeyExW(rootKey, pShellFolderPath, 0, NULL, 0, KEY_SET_VALUE,
      NULL, &shellFolderKey, &dwDisp))
     {
         TRACE("Failed to create %s\n", debugstr_w(pShellFolderPath));
         return E_FAIL;
     }
     if (RegCreateKeyExW(rootKey, pUserShellFolderPath, 0, NULL, 0,
-     KEY_ALL_ACCESS, NULL, &userShellFolderKey, &dwDisp))
+     KEY_QUERY_VALUE, NULL, &userShellFolderKey, &dwDisp))
     {
         TRACE("Failed to create %s\n",
          debugstr_w(pUserShellFolderPath));
@@ -1203,21 +962,25 @@ static HRESULT _SHGetUserShellFolderPath(HKEY rootKey, LPCWSTR userPrefix,
         return E_FAIL;
     }
 
+    dwPathLen = MAX_PATH * sizeof(WCHAR);
+
     if (!RegQueryValueExW(userShellFolderKey, value, NULL, &dwType,
      (LPBYTE)path, &dwPathLen) && (dwType == REG_EXPAND_SZ || dwType == REG_SZ))
     {
         LONG ret;
 
-        path[dwPathLen / sizeof(WCHAR)] = '\0';
+        dwPathLen /= sizeof(WCHAR);
+
+        path[dwPathLen] = '\0';
         if (dwType == REG_EXPAND_SZ && path[0] == '%')
         {
             WCHAR szTemp[MAX_PATH];
 
-            _SHExpandEnvironmentStrings(path, szTemp);
-            lstrcpynW(path, szTemp, MAX_PATH);
+            dwPathLen = ExpandEnvironmentStringsW(path, szTemp, MAX_PATH);
+            lstrcpynW(path, szTemp, dwPathLen);
         }
-        ret = RegSetValueExW(shellFolderKey, value, 0, REG_SZ, (LPBYTE)path,
-         (strlenW(path) + 1) * sizeof(WCHAR));
+
+        ret = RegSetValueExW(shellFolderKey, value, 0, REG_SZ, (LPBYTE)path, dwPathLen * sizeof(WCHAR));
         if (ret != ERROR_SUCCESS)
             hr = HRESULT_FROM_WIN32(ret);
         else
@@ -1225,6 +988,7 @@ static HRESULT _SHGetUserShellFolderPath(HKEY rootKey, LPCWSTR userPrefix,
     }
     else
         hr = E_FAIL;
+
     RegCloseKey(shellFolderKey);
     RegCloseKey(userShellFolderKey);
     TRACE("returning 0x%08x\n", hr);
@@ -1247,7 +1011,9 @@ static HRESULT _SHGetUserShellFolderPath(HKEY rootKey, LPCWSTR userPrefix,
  */
 static HRESULT _SHGetDefaultValue(BYTE folder, LPWSTR pszPath)
 {
+    DWORD dwSize;
     HRESULT hr;
+    HKEY hKey;
     WCHAR resourcePath[MAX_PATH];
     LPCWSTR pDefaultPath = NULL;
 
@@ -1258,6 +1024,18 @@ static HRESULT _SHGetDefaultValue(BYTE folder, LPWSTR pszPath)
     if (!pszPath)
         return E_INVALIDARG;
 
+    if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
+    {
+        /* FIXME assume MAX_PATH size */
+        dwSize = MAX_PATH * sizeof(WCHAR);
+        if (RegQueryValueExW(hKey, CSIDL_Data[folder].szValueName, NULL, NULL, (LPBYTE)pszPath, &dwSize) == ERROR_SUCCESS)
+        {
+            RegCloseKey(hKey);
+            return S_OK;
+        }
+        RegCloseKey(hKey);
+    }
+
     if (CSIDL_Data[folder].szDefaultPath &&
      IS_INTRESOURCE(CSIDL_Data[folder].szDefaultPath))
     {
@@ -1284,13 +1062,13 @@ static HRESULT _SHGetDefaultValue(BYTE folder, LPWSTR pszPath)
         switch (CSIDL_Data[folder].type)
         {
             case CSIDL_Type_User:
-                strcpyW(pszPath, UserProfileW);
+                wcscpy(pszPath, UserProfileW);
                 break;
             case CSIDL_Type_AllUsers:
-                strcpyW(pszPath, AllUsersProfileW);
+                wcscpy(pszPath, AllUsersProfileW);
                 break;
             case CSIDL_Type_CurrVer:
-                strcpyW(pszPath, SystemDriveW);
+                wcscpy(pszPath, SystemDriveW);
                 break;
             default:
                 ; /* no corresponding env. var, do nothing */
@@ -1298,7 +1076,7 @@ static HRESULT _SHGetDefaultValue(BYTE folder, LPWSTR pszPath)
         if (pDefaultPath)
         {
             PathAddBackslashW(pszPath);
-            strcatW(pszPath, pDefaultPath);
+            wcscat(pszPath, pDefaultPath);
         }
     }
     TRACE("returning 0x%08x\n", hr);
@@ -1346,7 +1124,7 @@ static HRESULT _SHGetCurrentVersionPath(DWORD dwFlags, BYTE folder,
                 hr = _SHGetDefaultValue(folder, pszPath);
                 dwType = REG_EXPAND_SZ;
                 RegSetValueExW(hKey, CSIDL_Data[folder].szValueName, 0, dwType,
-                 (LPBYTE)pszPath, (strlenW(pszPath)+1)*sizeof(WCHAR));
+                 (LPBYTE)pszPath, (wcslen(pszPath)+1)*sizeof(WCHAR));
             }
             else
             {
@@ -1377,47 +1155,75 @@ static HRESULT _SHGetUserProfilePath(HANDLE hToken, DWORD dwFlags, BYTE folder,
 
     if (folder >= sizeof(CSIDL_Data) / sizeof(CSIDL_Data[0]))
         return E_INVALIDARG;
+
     if (CSIDL_Data[folder].type != CSIDL_Type_User)
         return E_INVALIDARG;
+
     if (!pszPath)
         return E_INVALIDARG;
 
-    /* Only the current user and the default user are supported right now
-     * I'm afraid.
-     * FIXME: should be able to call GetTokenInformation on the token,
-     * then call ConvertSidToStringSidW on it to get the user prefix.
-     * But Wine's registry doesn't store user info by sid, it stores it
-     * by user name (and I don't know how to convert from a token to a
-     * user name).
-     */
-    if (hToken != NULL && hToken != (HANDLE)-1)
-    {
-        FIXME("unsupported for user other than current or default\n");
-        return E_FAIL;
-    }
-
     if (dwFlags & SHGFP_TYPE_DEFAULT)
+    {
         hr = _SHGetDefaultValue(folder, pszPath);
+    }
     else
     {
-        LPCWSTR userPrefix = NULL;
+        LPWSTR userPrefix;
         HKEY hRootKey;
 
         if (hToken == (HANDLE)-1)
         {
+            /* Get the folder of the default user */
             hRootKey = HKEY_USERS;
-            userPrefix = DefaultW;
+            userPrefix = (LPWSTR)DefaultW;
         }
-        else /* hToken == NULL, other values disallowed above */
+        else if(!hToken)
+        {
+            /* Get the folder of the current user */
             hRootKey = HKEY_CURRENT_USER;
-        hr = _SHGetUserShellFolderPath(hRootKey, userPrefix,
-         CSIDL_Data[folder].szValueName, pszPath);
+            userPrefix = NULL;
+        }
+        else
+        {
+            /* Get the folder of the specified user */
+            DWORD InfoLength;
+            PTOKEN_USER UserInfo;
+
+            hRootKey = HKEY_USERS;
+
+            GetTokenInformation(hToken, TokenUser, NULL, 0, &InfoLength);
+            UserInfo = (PTOKEN_USER)HeapAlloc(GetProcessHeap(), 0, InfoLength);
+
+            if(!GetTokenInformation(hToken, TokenUser, UserInfo, InfoLength, &InfoLength))
+            {
+                WARN("GetTokenInformation failed for %x!\n", hToken);
+                HeapFree(GetProcessHeap(), 0, UserInfo);
+                return E_FAIL;
+            }
+
+            if(!ConvertSidToStringSidW(UserInfo->User.Sid, &userPrefix))
+            {
+                WARN("ConvertSidToStringSidW failed for %x!\n", hToken);
+                HeapFree(GetProcessHeap(), 0, UserInfo);
+                return E_FAIL;
+            }
+
+            HeapFree(GetProcessHeap(), 0, UserInfo);
+        }
+
+        hr = _SHGetUserShellFolderPath(hRootKey, userPrefix, CSIDL_Data[folder].szValueName, pszPath);
+
+        /* Free the memory allocated by ConvertSidToStringSidW */
+        if(hToken && hToken != (HANDLE)-1)
+            LocalFree(userPrefix);
+
         if (FAILED(hr) && hRootKey != HKEY_LOCAL_MACHINE)
-            hr = _SHGetUserShellFolderPath(HKEY_LOCAL_MACHINE, NULL,
-             CSIDL_Data[folder].szValueName, pszPath);
+            hr = _SHGetUserShellFolderPath(HKEY_LOCAL_MACHINE, NULL, CSIDL_Data[folder].szValueName, pszPath);
+
         if (FAILED(hr))
             hr = _SHGetDefaultValue(folder, pszPath);
     }
+
     TRACE("returning 0x%08x (output path is %s)\n", hr, debugstr_w(pszPath));
     return hr;
 }
@@ -1454,164 +1260,6 @@ static HRESULT _SHGetAllUsersProfilePath(DWORD dwFlags, BYTE folder,
     return hr;
 }
 
-static HRESULT _SHOpenProfilesKey(PHKEY pKey)
-{
-    LONG lRet;
-    DWORD disp;
-
-    lRet = RegCreateKeyExW(HKEY_LOCAL_MACHINE, ProfileListW, 0, NULL, 0,
-     KEY_ALL_ACCESS, NULL, pKey, &disp);
-    return HRESULT_FROM_WIN32(lRet);
-}
-
-/* Reads the value named szValueName from the key profilesKey (assumed to be
- * opened by _SHOpenProfilesKey) into szValue, which is assumed to be MAX_PATH
- * WCHARs in length.  If it doesn't exist, returns szDefault (and saves
- * szDefault to the registry).
- */
-static HRESULT _SHGetProfilesValue(HKEY profilesKey, LPCWSTR szValueName,
- LPWSTR szValue, LPCWSTR szDefault)
-{
-    HRESULT hr;
-    DWORD type, dwPathLen = MAX_PATH * sizeof(WCHAR);
-    LONG lRet;
-
-    TRACE("%p,%s,%p,%s\n", profilesKey, debugstr_w(szValueName), szValue,
-     debugstr_w(szDefault));
-    lRet = RegQueryValueExW(profilesKey, szValueName, NULL, &type,
-     (LPBYTE)szValue, &dwPathLen);
-    if (!lRet && (type == REG_SZ || type == REG_EXPAND_SZ) && dwPathLen
-     && *szValue)
-    {
-        dwPathLen /= sizeof(WCHAR);
-        szValue[dwPathLen] = '\0';
-        hr = S_OK;
-    }
-    else
-    {
-        /* Missing or invalid value, set a default */
-        lstrcpynW(szValue, szDefault, MAX_PATH);
-        TRACE("Setting missing value %s to %s\n", debugstr_w(szValueName),
-                                                  debugstr_w(szValue));
-        lRet = RegSetValueExW(profilesKey, szValueName, 0, REG_EXPAND_SZ,
-                              (LPBYTE)szValue,
-                              (strlenW(szValue) + 1) * sizeof(WCHAR));
-        if (lRet)
-            hr = HRESULT_FROM_WIN32(lRet);
-        else
-            hr = S_OK;
-    }
-    TRACE("returning 0x%08x (output value is %s)\n", hr, debugstr_w(szValue));
-    return hr;
-}
-
-/* Attempts to expand environment variables from szSrc into szDest, which is
- * assumed to be MAX_PATH characters in length.  Before referring to the
- * environment, handles a few variables directly, because the environment
- * variables may not be set when this is called (as during Wine's installation
- * when default values are being written to the registry).
- * The directly handled environment variables, and their source, are:
- * - ALLUSERSPROFILE, USERPROFILE: reads from the registry
- * - SystemDrive: uses GetSystemDirectoryW and uses the drive portion of its
- *   path
- * If one of the directly handled environment variables is expanded, only
- * expands a single variable, and only in the beginning of szSrc.
- */
-static HRESULT _SHExpandEnvironmentStrings(LPCWSTR szSrc, LPWSTR szDest)
-{
-    HRESULT hr;
-    WCHAR szTemp[MAX_PATH], szProfilesPrefix[MAX_PATH] = { 0 };
-    HKEY key = NULL;
-
-    TRACE("%s, %p\n", debugstr_w(szSrc), szDest);
-
-    if (!szSrc || !szDest) return E_INVALIDARG;
-
-    /* short-circuit if there's nothing to expand */
-    if (szSrc[0] != '%')
-    {
-        strcpyW(szDest, szSrc);
-        hr = S_OK;
-        goto end;
-    }
-    /* Get the profile prefix, we'll probably be needing it */
-    hr = _SHOpenProfilesKey(&key);
-    if (SUCCEEDED(hr))
-    {
-        WCHAR szDefaultProfilesPrefix[MAX_PATH];
-
-        GetWindowsDirectoryW(szDefaultProfilesPrefix, MAX_PATH);
-        PathAddBackslashW(szDefaultProfilesPrefix);
-        PathAppendW(szDefaultProfilesPrefix, szDefaultProfileDirW);
-        hr = _SHGetProfilesValue(key, ProfilesDirectoryW, szProfilesPrefix,
-         szDefaultProfilesPrefix);
-    }
-
-    *szDest = 0;
-    strcpyW(szTemp, szSrc);
-    while (SUCCEEDED(hr) && szTemp[0] == '%')
-    {
-        if (!strncmpiW(szTemp, AllUsersProfileW, strlenW(AllUsersProfileW)))
-        {
-            WCHAR szAllUsers[MAX_PATH];
-
-            strcpyW(szDest, szProfilesPrefix);
-            hr = _SHGetProfilesValue(key, AllUsersProfileValueW,
-             szAllUsers, AllUsersW);
-            PathAppendW(szDest, szAllUsers);
-            PathAppendW(szDest, szTemp + strlenW(AllUsersProfileW));
-        }
-        else if (!strncmpiW(szTemp, UserProfileW, strlenW(UserProfileW)))
-        {
-            WCHAR userName[MAX_PATH];
-            DWORD userLen = MAX_PATH;
-
-            strcpyW(szDest, szProfilesPrefix);
-            GetUserNameW(userName, &userLen);
-            PathAppendW(szDest, userName);
-            PathAppendW(szDest, szTemp + strlenW(UserProfileW));
-        }
-        else if (!strncmpiW(szTemp, SystemDriveW, strlenW(SystemDriveW)))
-        {
-            GetSystemDirectoryW(szDest, MAX_PATH);
-            if (szDest[1] != ':')
-            {
-                FIXME("non-drive system paths unsupported\n");
-                hr = E_FAIL;
-            }
-            else
-            {
-                strcpyW(szDest + 3, szTemp + strlenW(SystemDriveW) + 1);
-                hr = S_OK;
-            }
-        }
-        else
-        {
-            DWORD ret = ExpandEnvironmentStringsW(szSrc, szDest, MAX_PATH);
-
-            if (ret > MAX_PATH)
-                hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
-            else if (ret == 0)
-                hr = HRESULT_FROM_WIN32(GetLastError());
-            else
-                hr = S_OK;
-        }
-        if (SUCCEEDED(hr) && szDest[0] == '%')
-            strcpyW(szTemp, szDest);
-        else
-        {
-            /* terminate loop */
-            szTemp[0] = '\0';
-        }
-    }
-end:
-    if (key)
-        RegCloseKey(key);
-    TRACE("returning 0x%08x (input was %s, output is %s)\n", hr,
-     debugstr_w(szSrc), debugstr_w(szDest));
-    return hr;
-}
-
 /*************************************************************************
  * SHGetFolderPathW                    [SHELL32.@]
  *
@@ -1625,17 +1273,12 @@ end:
  * Most values can be overridden in either
  * HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders
  * or in the same location in HKLM.
- * The registry usage is explained by the following tech note:
- * http://www.microsoft.com/windows2000/techinfo/reskit/en-us/default.asp?url=/windows2000/techinfo/reskit/en-us/regentry/36173.asp
  * The "Shell Folders" registry key was used in NT4 and earlier systems.
  * Beginning with Windows 2000, the "User Shell Folders" key is used, so
  * changes made to it are made to the former key too.  This synchronization is
  * done on-demand: not until someone requests the value of one of these paths
  * (by calling one of the SHGet functions) is the value synchronized.
- * Furthermore, as explained here:
- * http://www.microsoft.com/windows2000/techinfo/reskit/en-us/default.asp?url=/windows2000/techinfo/reskit/en-us/regentry/36276.asp
- * the HKCU paths take precedence over the HKLM paths.
- *
+ * Furthermore, the HKCU paths take precedence over the HKLM paths.
  */
 HRESULT WINAPI SHGetFolderPathW(
        HWND hwndOwner,    /* [I] owner window */
@@ -1643,22 +1286,87 @@ HRESULT WINAPI SHGetFolderPathW(
        HANDLE hToken,     /* [I] access token */
        DWORD dwFlags,     /* [I] which path to return */
        LPWSTR pszPath)    /* [O] converted path */
+{
+    HRESULT hr =  SHGetFolderPathAndSubDirW(hwndOwner, nFolder, hToken, dwFlags, NULL, pszPath);
+    if(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr)
+        hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+    return hr;
+}
+
+HRESULT WINAPI SHGetFolderPathAndSubDirA(
+       HWND hwndOwner,    /* [I] owner window */
+       int nFolder,       /* [I] CSIDL identifying the folder */
+       HANDLE hToken,     /* [I] access token */
+       DWORD dwFlags,     /* [I] which path to return */
+       LPCSTR pszSubPath, /* [I] sub directory of the specified folder */
+       LPSTR pszPath)     /* [O] converted path */
+{
+    int length;
+    HRESULT hr = S_OK;
+    LPWSTR pszSubPathW = NULL;
+    LPWSTR pszPathW = NULL;
+    TRACE("%08x,%08x,%s\n",nFolder, dwFlags, debugstr_w(pszSubPathW));
+
+    if(pszPath) {
+        pszPathW = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
+        if(!pszPathW) {
+            hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+            goto cleanup;
+        }
+    }
+    TRACE("%08x,%08x,%s\n",nFolder, dwFlags, debugstr_w(pszSubPathW));
+
+    /* SHGetFolderPathAndSubDirW does not distinguish if pszSubPath isn't
+     * set (null), or an empty string.therefore call it without the parameter set
+     * if pszSubPath is an empty string
+     */
+    if (pszSubPath && pszSubPath[0]) {
+        length = MultiByteToWideChar(CP_ACP, 0, pszSubPath, -1, NULL, 0);
+        pszSubPathW = HeapAlloc(GetProcessHeap(), 0, length * sizeof(WCHAR));
+        if(!pszSubPathW) {
+            hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
+            goto cleanup;
+        }
+        MultiByteToWideChar(CP_ACP, 0, pszSubPath, -1, pszSubPathW, length);
+    }
+
+    hr = SHGetFolderPathAndSubDirW(hwndOwner, nFolder, hToken, dwFlags, pszSubPathW, pszPathW);
+
+    if (SUCCEEDED(hr) && pszPath)
+        WideCharToMultiByte(CP_ACP, 0, pszPathW, -1, pszPath, MAX_PATH, NULL, NULL);
+
+cleanup:
+    HeapFree(GetProcessHeap(), 0, pszPathW);
+    HeapFree(GetProcessHeap(), 0, pszSubPathW);
+    return hr;
+}
+
+HRESULT WINAPI SHGetFolderPathAndSubDirW(
+       HWND hwndOwner,    /* [I] owner window */
+       int nFolder,       /* [I] CSIDL identifying the folder */
+       HANDLE hToken,     /* [I] access token */
+       DWORD dwFlags,     /* [I] which path to return */
+       LPCWSTR pszSubPath,/* [I] sub directory of the specified folder */
+       LPWSTR pszPath)    /* [O] converted path */
 {
     HRESULT    hr;
     WCHAR      szBuildPath[MAX_PATH], szTemp[MAX_PATH];
-    DWORD      folder = nFolder & CSIDL_FOLDER_MASK;
+    DWORD      folder = nFolder & CSIDL_FOLDER_MASK; //FIXME
     CSIDL_Type type;
     int        ret;
 
-    TRACE("%p,%p,nFolder=0x%04x\n", hwndOwner,pszPath,nFolder);
+    TRACE("%p,%p,nFolder=0x%04x,%s\n", hwndOwner,pszPath,nFolder,debugstr_w(pszSubPath));
 
     /* Windows always NULL-terminates the resulting path regardless of success
      * or failure, so do so first
      */
     if (pszPath)
         *pszPath = '\0';
+
     if (folder >= sizeof(CSIDL_Data) / sizeof(CSIDL_Data[0]))
         return E_INVALIDARG;
+    if ((SHGFP_TYPE_CURRENT != dwFlags) && (SHGFP_TYPE_DEFAULT != dwFlags))
+        return E_INVALIDARG;
     szTemp[0] = 0;
     type = CSIDL_Data[folder].type;
     switch (type)
@@ -1676,7 +1384,7 @@ HRESULT WINAPI SHGetFolderPathW(
              *CSIDL_Data[folder].szDefaultPath)
             {
                 PathAddBackslashW(szTemp);
-                strcatW(szTemp, CSIDL_Data[folder].szDefaultPath);
+                wcscat(szTemp, CSIDL_Data[folder].szDefaultPath);
             }
             hr = S_OK;
             break;
@@ -1687,7 +1395,7 @@ HRESULT WINAPI SHGetFolderPathW(
              *CSIDL_Data[folder].szDefaultPath)
             {
                 PathAddBackslashW(szTemp);
-                strcatW(szTemp, CSIDL_Data[folder].szDefaultPath);
+                wcscat(szTemp, CSIDL_Data[folder].szDefaultPath);
             }
             hr = S_OK;
             break;
@@ -1708,15 +1416,37 @@ HRESULT WINAPI SHGetFolderPathW(
 
     /* Expand environment strings if necessary */
     if (*szTemp == '%')
-        hr = _SHExpandEnvironmentStrings(szTemp, szBuildPath);
+    {
+        DWORD ExpandRet = ExpandEnvironmentStringsW(szTemp, szBuildPath, MAX_PATH);
+
+        if (ExpandRet > MAX_PATH)
+            hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
+        else if (ExpandRet == 0)
+            hr = HRESULT_FROM_WIN32(GetLastError());
+        else
+            hr = S_OK;
+    }
     else
-        strcpyW(szBuildPath, szTemp);
-    /* Copy the path if it's available before we might return */
-    if (SUCCEEDED(hr) && pszPath)
-        strcpyW(pszPath, szBuildPath);
+    {
+        wcscpy(szBuildPath, szTemp);
+    }
 
     if (FAILED(hr)) goto end;
 
+    if(pszSubPath) {
+        /* make sure the new path does not exceed th bufferlength
+         * rememebr to backslash and the termination */
+        if(MAX_PATH < (wcslen(szBuildPath) + wcslen(pszSubPath) + 2)) {
+            hr = HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE);
+            goto end;
+        }
+        PathAppendW(szBuildPath, pszSubPath);
+        PathRemoveBackslashW(szBuildPath);
+    }
+    /* Copy the path if it's available before we might return */
+    if (SUCCEEDED(hr) && pszPath)
+        wcscpy(pszPath, szBuildPath);
+
     /* if we don't care about existing directories we are ready */
     if(nFolder & CSIDL_FLAG_DONT_VERIFY) goto end;
 
@@ -1727,7 +1457,7 @@ HRESULT WINAPI SHGetFolderPathW(
      */
     if (!(nFolder & CSIDL_FLAG_CREATE))
     {
-        hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+        hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
         goto end;
     }
 
@@ -1827,7 +1557,7 @@ static HRESULT _SHRegisterFolders(HKEY hRootKey, HANDLE hToken,
             {
                 ret = RegSetValueExW(hUserKey,
                  CSIDL_Data[folders[i]].szValueName, 0, REG_EXPAND_SZ,
-                 (LPBYTE)path, (strlenW(path) + 1) * sizeof(WCHAR));
+                 (LPBYTE)path, (wcslen(path) + 1) * sizeof(WCHAR));
                 if (ret)
                     hr = HRESULT_FROM_WIN32(ret);
                 else
@@ -1836,7 +1566,7 @@ static HRESULT _SHRegisterFolders(HKEY hRootKey, HANDLE hToken,
                      hToken, SHGFP_TYPE_DEFAULT, path);
                     ret = RegSetValueExW(hKey,
                      CSIDL_Data[folders[i]].szValueName, 0, REG_SZ,
-                     (LPBYTE)path, (strlenW(path) + 1) * sizeof(WCHAR));
+                     (LPBYTE)path, (wcslen(path) + 1) * sizeof(WCHAR));
                     if (ret)
                         hr = HRESULT_FROM_WIN32(ret);
                 }
@@ -1887,13 +1617,13 @@ static HRESULT _SHRegisterUserShellFolders(BOOL bDefault)
     {
         hToken = (HANDLE)-1;
         hRootKey = HKEY_USERS;
-        strcpyW(userShellFolderPath, DefaultW);
+        wcscpy(userShellFolderPath, DefaultW);
         PathAddBackslashW(userShellFolderPath);
-        strcatW(userShellFolderPath, szSHUserFolders);
+        wcscat(userShellFolderPath, szSHUserFolders);
         pUserShellFolderPath = userShellFolderPath;
-        strcpyW(shellFolderPath, DefaultW);
+        wcscpy(shellFolderPath, DefaultW);
         PathAddBackslashW(shellFolderPath);
-        strcatW(shellFolderPath, szSHFolders);
+        wcscat(shellFolderPath, szSHFolders);
         pShellFolderPath = shellFolderPath;
     }
     else
@@ -1946,7 +1676,7 @@ static HRESULT _SHRegisterCommonShellFolders(void)
  *  Success: TRUE,
  *  Failure: FALSE
  */
-static inline BOOL _SHAppendToUnixPath(char *szBasePath, LPCWSTR pwszSubPath) {
+static BOOL __inline _SHAppendToUnixPath(char *szBasePath, LPCWSTR pwszSubPath) {
     WCHAR wszSubPath[MAX_PATH];
     int cLen = strlen(szBasePath);
     char *pBackslash;
@@ -1956,16 +1686,16 @@ static inline BOOL _SHAppendToUnixPath(char *szBasePath, LPCWSTR pwszSubPath) {
             /* Fall back to hard coded defaults. */
             switch (LOWORD(pwszSubPath)) {
                 case IDS_PERSONAL:
-                    lstrcpyW(wszSubPath, PersonalW);
+                    wcscpy(wszSubPath, PersonalW);
                     break;
                 case IDS_MYMUSIC:
-                    lstrcpyW(wszSubPath, My_MusicW);
+                    wcscpy(wszSubPath, My_MusicW);
                     break;
                 case IDS_MYPICTURES:
-                    lstrcpyW(wszSubPath, My_PicturesW);
+                    wcscpy(wszSubPath, My_PicturesW);
                     break;
                 case IDS_MYVIDEO:
-                    lstrcpyW(wszSubPath, My_VideoW);
+                    wcscpy(wszSubPath, My_VideoW);
                     break;
                 default:
                     ERR("LoadString(%d) failed!\n", LOWORD(pwszSubPath));
@@ -1973,7 +1703,7 @@ static inline BOOL _SHAppendToUnixPath(char *szBasePath, LPCWSTR pwszSubPath) {
             }
         }
     } else {
-        lstrcpyW(wszSubPath, pwszSubPath);
+        wcscpy(wszSubPath, pwszSubPath);
     }
 
     if (szBasePath[cLen-1] != '/') szBasePath[cLen++] = '/';
@@ -2171,21 +1901,6 @@ BOOL WINAPI SHGetSpecialFolderPathW (
                szPath)) == S_OK ? TRUE : FALSE;
 }
 
-/*************************************************************************
- * SHGetSpecialFolderPath (SHELL32.175)
- */
-BOOL WINAPI SHGetSpecialFolderPathAW (
-       HWND hwndOwner,
-       LPVOID szPath,
-       int nFolder,
-       BOOL bCreate)
-
-{
-       if (SHELL_OsIsUnicode())
-         return SHGetSpecialFolderPathW (hwndOwner, szPath, nFolder, bCreate);
-       return SHGetSpecialFolderPathA (hwndOwner, szPath, nFolder, bCreate);
-}
-
 /*************************************************************************
  * SHGetFolderLocation [SHELL32.@]
  *