Nikolay Sivov : shell32: Move retrieving folder path logic to SHGetKnownFolderPath().

Alexandre Julliard julliard at winehq.org
Tue Feb 28 03:45:54 CST 2017


Module: wine
Branch: oldstable
Commit: e5a36c4a3d48c941ff38421cc667a1e96e0c408f
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=e5a36c4a3d48c941ff38421cc667a1e96e0c408f

Author: Nikolay Sivov <nsivov at codeweavers.com>
Date:   Sun Dec  4 23:33:08 2016 +0300

shell32: Move retrieving folder path logic to SHGetKnownFolderPath().

Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
(cherry picked from commit a0c259cf562b32268df86053a5e0785b1ad78cc1)
Signed-off-by: Michael Stefaniuc <mstefani at winehq.org>

---

 dlls/shell32/shellpath.c | 137 ++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 113 insertions(+), 24 deletions(-)

diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c
index cb79d6f..1c3ab59 100644
--- a/dlls/shell32/shellpath.c
+++ b/dlls/shell32/shellpath.c
@@ -4704,45 +4704,134 @@ static int csidl_from_id( const KNOWNFOLDERID *id )
 /*************************************************************************
  * SHGetKnownFolderPath           [SHELL32.@]
  */
-HRESULT WINAPI SHGetKnownFolderPath(REFKNOWNFOLDERID rfid, DWORD flags, HANDLE token, PWSTR *path)
+HRESULT WINAPI SHGetKnownFolderPath(REFKNOWNFOLDERID rfid, DWORD flags, HANDLE token, WCHAR **ret_path)
 {
-    HRESULT hr;
-    WCHAR folder[MAX_PATH];
-    int index = csidl_from_id( rfid );
+    WCHAR pathW[MAX_PATH], tempW[MAX_PATH];
+    HRESULT    hr;
+    CSIDL_Type type;
+    int        ret;
+    int folder = csidl_from_id(rfid), shgfp_flags;
 
-    TRACE("%s, 0x%08x, %p, %p\n", debugstr_guid(rfid), flags, token, path);
+    TRACE("%s, 0x%08x, %p, %p\n", debugstr_guid(rfid), flags, token, ret_path);
 
-    *path = NULL;
+    *ret_path = NULL;
 
-    if (index < 0)
+    if (folder < 0)
         return HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
 
-    if (flags & KF_FLAG_CREATE)
-        index |= CSIDL_FLAG_CREATE;
+    if (flags & ~(KF_FLAG_CREATE|KF_FLAG_DONT_VERIFY|KF_FLAG_NO_ALIAS|
+        KF_FLAG_INIT|KF_FLAG_DEFAULT_PATH))
+    {
+        FIXME("flags 0x%08x not supported\n", flags);
+        return E_INVALIDARG;
+    }
+
+    shgfp_flags = flags & KF_FLAG_DEFAULT_PATH ? SHGFP_TYPE_DEFAULT : SHGFP_TYPE_CURRENT;
+
+    type = CSIDL_Data[folder].type;
+    switch (type)
+    {
+        case CSIDL_Type_Disallowed:
+            hr = E_INVALIDARG;
+            break;
+        case CSIDL_Type_NonExistent:
+            hr = S_FALSE;
+            break;
+        case CSIDL_Type_WindowsPath:
+            GetWindowsDirectoryW(tempW, MAX_PATH);
+            if (CSIDL_Data[folder].szDefaultPath &&
+             !IS_INTRESOURCE(CSIDL_Data[folder].szDefaultPath) &&
+             *CSIDL_Data[folder].szDefaultPath)
+            {
+                PathAddBackslashW(tempW);
+                strcatW(tempW, CSIDL_Data[folder].szDefaultPath);
+            }
+            hr = S_OK;
+            break;
+        case CSIDL_Type_SystemPath:
+            GetSystemDirectoryW(tempW, MAX_PATH);
+            if (CSIDL_Data[folder].szDefaultPath &&
+             !IS_INTRESOURCE(CSIDL_Data[folder].szDefaultPath) &&
+             *CSIDL_Data[folder].szDefaultPath)
+            {
+                PathAddBackslashW(tempW);
+                strcatW(tempW, CSIDL_Data[folder].szDefaultPath);
+            }
+            hr = S_OK;
+            break;
+        case CSIDL_Type_SystemX86Path:
+            if (!GetSystemWow64DirectoryW(tempW, MAX_PATH)) GetSystemDirectoryW(tempW, MAX_PATH);
+            if (CSIDL_Data[folder].szDefaultPath &&
+             !IS_INTRESOURCE(CSIDL_Data[folder].szDefaultPath) &&
+             *CSIDL_Data[folder].szDefaultPath)
+            {
+                PathAddBackslashW(tempW);
+                strcatW(tempW, CSIDL_Data[folder].szDefaultPath);
+            }
+            hr = S_OK;
+            break;
+        case CSIDL_Type_CurrVer:
+            hr = _SHGetCurrentVersionPath(shgfp_flags, folder, tempW);
+            break;
+        case CSIDL_Type_User:
+            hr = _SHGetUserProfilePath(token, shgfp_flags, folder, tempW);
+            break;
+        case CSIDL_Type_AllUsers:
+            hr = _SHGetAllUsersProfilePath(shgfp_flags, folder, tempW);
+            break;
+        default:
+            FIXME("bogus type %d, please fix\n", type);
+            hr = E_INVALIDARG;
+            break;
+    }
+
+    /* Expand environment strings if necessary */
+    if (*tempW == '%')
+        hr = _SHExpandEnvironmentStrings(tempW, pathW);
+    else
+        strcpyW(pathW, tempW);
 
-    if (flags & KF_FLAG_DONT_VERIFY)
-        index |= CSIDL_FLAG_DONT_VERIFY;
+    if (FAILED(hr))
+        goto failed;
 
-    if (flags & KF_FLAG_NO_ALIAS)
-        index |= CSIDL_FLAG_NO_ALIAS;
+    /* if we don't care about existing directories we are ready */
+    if (flags & KF_FLAG_DONT_VERIFY) goto done;
 
-    if (flags & KF_FLAG_INIT)
-        index |= CSIDL_FLAG_PER_USER_INIT;
+    if (PathFileExistsW(pathW)) goto done;
 
-    if (flags & ~(KF_FLAG_CREATE|KF_FLAG_DONT_VERIFY|KF_FLAG_NO_ALIAS|KF_FLAG_INIT))
+    /* Does not exist but we are not allowed to create it. The return value
+     * is verified against shell32 version 6.0.
+     */
+    if (!(flags & KF_FLAG_CREATE))
     {
-        FIXME("flags 0x%08x not supported\n", flags);
-        return E_INVALIDARG;
+        hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
+        goto done;
     }
 
-    hr = SHGetFolderPathW( NULL, index, token, 0, folder );
-    if (SUCCEEDED(hr))
+    /* create directory/directories */
+    ret = SHCreateDirectoryExW(NULL, pathW, NULL);
+    if (ret && ret != ERROR_ALREADY_EXISTS)
     {
-        *path = CoTaskMemAlloc( (strlenW( folder ) + 1) * sizeof(WCHAR) );
-        if (!*path)
-            return E_OUTOFMEMORY;
-        strcpyW( *path, folder );
+        ERR("Failed to create directory %s.\n", debugstr_w(pathW));
+        hr = E_FAIL;
+        goto failed;
     }
+
+    TRACE("Created missing system directory %s\n", debugstr_w(pathW));
+
+done:
+    TRACE("Final path is %s, %#x\n", debugstr_w(pathW), hr);
+
+    *ret_path = CoTaskMemAlloc((strlenW(pathW) + 1) * sizeof(WCHAR));
+    if (!*ret_path)
+        return E_OUTOFMEMORY;
+    strcpyW(*ret_path, pathW);
+
+    return hr;
+
+failed:
+    TRACE("Failed to get folder path, %#x.\n", hr);
+
     return hr;
 }
 




More information about the wine-cvs mailing list