https://git.reactos.org/?p=reactos.git;a=commitdiff;h=3a822e4f74ea6ea8335a8684c5071d264fee4bed

commit 3a822e4f74ea6ea8335a8684c5071d264fee4bed
Author:     Katayama Hirofumi MZ <[email protected]>
AuthorDate: Mon Jun 28 07:53:26 2021 +0900
Commit:     GitHub <[email protected]>
CommitDate: Mon Jun 28 07:53:26 2021 +0900

    [SHELL32] Implement PathResolveW function (#3762)
    
    - Implement PathResolveW function.
    - Implement PathQualifyA/W functions using newly-defined PathQualifyExW 
function.
    CORE-12665
---
 dll/win32/shell32/CShellLink.cpp    | 125 +++----------------
 dll/win32/shell32/wine/shellpath.c  | 232 +++++++++++++++++++++++++++++++++---
 sdk/include/reactos/shlwapi_undoc.h |  12 ++
 sdk/include/reactos/undocshell.h    |   7 +-
 4 files changed, 249 insertions(+), 127 deletions(-)

diff --git a/dll/win32/shell32/CShellLink.cpp b/dll/win32/shell32/CShellLink.cpp
index 7da9b8cf916..cd5d74e2c3f 100644
--- a/dll/win32/shell32/CShellLink.cpp
+++ b/dll/win32/shell32/CShellLink.cpp
@@ -2178,108 +2178,6 @@ HRESULT CShellLink::SetAdvertiseInfo(LPCWSTR str)
     return S_OK;
 }
 
-/*
- * Since the real PathResolve (from Wine) is unimplemented at the moment,
- * we use this local implementation, until a better one is written (using
- * code parts of the SHELL_xxx helpers in Wine's shellpath.c).
- */
-static BOOL HACKISH_PathResolve(
-    IN OUT PWSTR pszPath,
-    IN PZPCWSTR dirs OPTIONAL,
-    IN UINT fFlags)
-{
-    // FIXME: This is unimplemented!!!
-#if 0
-    return PathResolve(pszPath, dirs, fFlags);
-#else
-    BOOL Success = FALSE;
-    USHORT i;
-    LPWSTR fname = NULL;
-    WCHAR szPath[MAX_PATH];
-
-    /* First, search for a valid existing path */
-
-    // NOTE: See also: SHELL_FindExecutable()
-
-    /*
-     * List of extensions searched for, by PathResolve with the flag
-     * PRF_TRYPROGRAMEXTENSIONS == PRF_EXECUTABLE | PRF_VERIFYEXISTS set,
-     * according to MSDN: 
https://msdn.microsoft.com/en-us/library/windows/desktop/bb776478(v=vs.85).aspx
-     */
-    static PCWSTR Extensions[] = {L".pif", L".com", L".bat", L".cmd", L".lnk", 
L".exe", NULL};
-    #define LNK_EXT_INDEX   4   // ".lnk" has index 4 in the array above
-
-    /*
-     * Start at the beginning of the list if PRF_EXECUTABLE is set, otherwise
-     * just use the last element 'NULL' (no extension checking).
-     */
-    i = ((fFlags & PRF_EXECUTABLE) ? 0 : _countof(Extensions) - 1);
-    for (; i < _countof(Extensions); ++i)
-    {
-        /* Ignore shell links ".lnk" if needed */
-        if ((fFlags & PRF_DONTFINDLNK) && (i == LNK_EXT_INDEX))
-            continue;
-
-        Success = (SearchPathW(NULL, pszPath, Extensions[i],
-                               _countof(szPath), szPath, NULL) != 0);
-        if (!Success)
-        {
-            ERR("SearchPathW(pszPath = '%S') failed. Error code: %lu\n", 
pszPath, GetLastError());
-        }
-        else
-        {
-            ERR("SearchPathW(pszPath = '%S', szPath = '%S') succeeded\n", 
pszPath, szPath);
-            break;
-        }
-    }
-
-    if (!Success)
-    {
-        ERR("SearchPathW(pszPath = '%S') failed. Error code: %lu\n", pszPath, 
GetLastError());
-
-        /* We failed, try with PathFindOnPath, as explained by MSDN */
-        // Success = PathFindOnPathW(pszPath, dirs);
-        StringCchCopyW(szPath, _countof(szPath), pszPath);
-        Success = PathFindOnPathW(szPath, dirs);
-        if (!Success)
-        {
-            ERR("PathFindOnPathW(pszPath = '%S') failed\n", pszPath);
-
-            /* We failed again, fall back to building a possible non-existing 
path */
-            if (!GetFullPathNameW(pszPath, _countof(szPath), szPath, &fname))
-            {
-                ERR("GetFullPathNameW(pszPath = '%S') failed. Error code: 
%lu\n", pszPath, GetLastError());
-                return FALSE;
-            }
-
-            Success = PathFileExistsW(szPath);
-            if (!Success)
-                ERR("PathFileExistsW(szPath = '%S') failed. Error code: 
%lu\n", szPath, GetLastError());
-
-            /******************************************************/
-            /* Question: Why this line is needed only for files?? */
-            if (fname && (_wcsicmp(pszPath, fname) == 0))
-                *szPath = L'\0';
-            /******************************************************/
-        }
-        else
-        {
-            ERR("PathFindOnPathW(pszPath = '%S' ==> '%S') succeeded\n", 
pszPath, szPath);
-        }
-    }
-
-    /* Copy back the results to the caller */
-    StringCchCopyW(pszPath, MAX_PATH, szPath);
-
-    /*
-     * Since the called functions always checked whether the file path existed,
-     * we do not need to redo a final check: we can use instead the cached
-     * result in 'Success'.
-     */
-    return ((fFlags & PRF_VERIFYEXISTS) ? Success : TRUE);
-#endif
-}
-
 HRESULT CShellLink::SetTargetFromPIDLOrPath(LPCITEMIDLIST pidl, LPCWSTR 
pszFile)
 {
     HRESULT hr = S_OK;
@@ -2309,14 +2207,21 @@ HRESULT 
CShellLink::SetTargetFromPIDLOrPath(LPCITEMIDLIST pidl, LPCWSTR pszFile)
             /* This failed, try to resolve the path, then create a simple PIDL 
*/
 
             StringCchCopyW(szPath, _countof(szPath), pszFile);
-            // FIXME: Because PathResolve is unimplemented, we use our hackish 
implementation!
-            HACKISH_PathResolve(szPath, NULL, PRF_TRYPROGRAMEXTENSIONS);
-
-            pidlNew = SHSimpleIDListFromPathW(szPath);
-            /******************************************************/
-            /* Question: Why this line is needed only for files?? */
-            hr = (*szPath ? S_OK : E_INVALIDARG); // S_FALSE
-            /******************************************************/
+            PathResolveW(szPath, NULL, PRF_TRYPROGRAMEXTENSIONS);
+
+            if (PathIsFileSpecW(szPath))
+            {
+                hr = E_INVALIDARG;
+                szPath[0] = 0;
+            }
+            else
+            {
+                hr = S_OK;
+                pidlNew = SHSimpleIDListFromPathW(szPath);
+                // NOTE: Don't make it failed here even if pidlNew was NULL.
+                // We don't fail on purpose even if SHSimpleIDListFromPathW 
returns NULL.
+                // This behaviour has been verified with tests.
+            }
         }
     }
     // else if (!pidl && !pszFile) { pidlNew = NULL; hr = S_OK; }
diff --git a/dll/win32/shell32/wine/shellpath.c 
b/dll/win32/shell32/wine/shellpath.c
index 892748d56b7..e4234efffcd 100644
--- a/dll/win32/shell32/wine/shellpath.c
+++ b/dll/win32/shell32/wine/shellpath.c
@@ -3,7 +3,7 @@
  *
  * Copyright 1998, 1999, 2000 Juergen Schmied
  * Copyright 2004 Juan Lang
- * Copyright 2018-2020 Katayama Hirofumi MZ
+ * Copyright 2018-2021 Katayama Hirofumi MZ
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -50,6 +50,9 @@
 #include "shell32_main.h"
 #include "shresdef.h"
 
+#undef _WIN32_WINNT
+#define _WIN32_WINNT _WIN32_WINNT_WS03
+
 WINE_DEFAULT_DEBUG_CHANNEL(shell);
 
 static const BOOL is_win64 = sizeof(void *) > sizeof(int);
@@ -106,6 +109,127 @@ DoGetProductType(PNT_PRODUCT_TYPE ProductType)
        ########## Combining and Constructing paths ##########
 */
 
+/* @implemented */
+static BOOL WINAPI
+PathSearchOnExtensionsW(LPWSTR pszPath, LPCWSTR *ppszDirs, BOOL bDoSearch, 
DWORD dwWhich)
+{
+    if (*PathFindExtensionW(pszPath) != 0)
+        return FALSE;
+
+    if (bDoSearch)
+        return PathFindOnPathExW(pszPath, ppszDirs, dwWhich);
+    else
+        return PathFileExistsDefExtW(pszPath, dwWhich);
+}
+
+#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
+/* @implemented */
+static BOOL WINAPI PathIsAbsoluteW(LPCWSTR path)
+{
+    return PathIsUNCW(path) || (PathGetDriveNumberW(path) != -1 && path[2] == 
L'\\');
+}
+
+/* @implemented */
+static BOOL WINAPI PathMakeAbsoluteW(LPWSTR path)
+{
+    WCHAR path1[MAX_PATH];
+    DWORD cch;
+
+    if (path == NULL)
+        return FALSE;
+    cch = GetCurrentDirectoryW(_countof(path1), path1);
+    if (!cch || cch > _countof(path1))
+        return FALSE;
+    return (PathCombineW(path, path1, path) != NULL);
+}
+#endif
+
+/* NOTE: GetShortPathName fails if the pathname didn't exist.
+         GetShortPathNameAbsentW should set the short path name that even 
doesn't exist. */
+static DWORD GetShortPathNameAbsentW(LPCWSTR pszLong, LPWSTR pszShort, DWORD 
cchShort)
+{
+    FIXME("GetShortPathNameAbsentW(%ls, %p, %ld): stub\n", pszLong, pszShort, 
cchShort);
+    StringCchCopyW(pszShort, cchShort, pszLong);
+    return lstrlenW(pszShort);
+}
+
+BOOL WINAPI IsLFNDriveW(LPCWSTR lpszPath);
+
+/* @unconfirmed */
+static VOID WINAPI PathQualifyExW(LPWSTR pszPath, LPCWSTR pszDir, DWORD 
dwFlags)
+{
+    WCHAR szRoot[MAX_PATH], szCopy[MAX_PATH], szCurDir[MAX_PATH];
+    LPWSTR pch;
+    LONG cch;
+    BOOL bCheckLFN;
+
+    if (FAILED(StringCchCopyW(szCopy, _countof(szCopy), pszPath)))
+        return;
+
+    FixSlashesAndColonW(szCopy);
+
+    if (pszDir)
+    {
+        cch = GetCurrentDirectoryW(_countof(szCurDir), szCurDir);
+        if (cch <= 0 || cch >= _countof(szCurDir) || 
!SetCurrentDirectoryW(pszDir))
+            pszDir = NULL;
+    }
+
+    if (!GetFullPathNameW(szCopy, _countof(szRoot), szRoot, NULL))
+        goto Quit;
+
+    if (PathIsUNCW(szRoot)) /* it begins with double backslash */
+    {
+        pch = StrChrW(&szRoot[2], L'\\');
+        if (pch)
+        {
+            pch = StrChrW(&pch[1], L'\\');
+            if (pch)
+                *pch = 0;
+            if (!PathAddBackslashW(szRoot))
+                goto Quit;
+            /* szRoot is like \\MyServer\MyShare\ */
+            bCheckLFN = TRUE;
+        }
+        else
+        {
+            bCheckLFN = FALSE;
+        }
+    }
+    else
+    {
+        if (!PathStripToRootW(szRoot) || !PathAddBackslashW(szRoot))
+            goto Quit;
+        /* szRoot is like X:\ */
+        bCheckLFN = TRUE;
+    }
+
+    if (bCheckLFN && !IsLFNDriveW(szRoot)) /* not a long filename drive */
+    {
+        if (!GetFullPathNameW(szCopy, _countof(szRoot), szRoot, NULL))
+            goto Quit;
+        if (!GetShortPathNameW(szRoot, szCopy, _countof(szCopy)) &&
+            !GetShortPathNameAbsentW(szRoot, szCopy, _countof(szCopy)))
+        {
+            goto Quit;
+        }
+    }
+
+    PathRemoveBackslashW(szCopy);
+    StringCchCopyW(pszPath, MAX_PATH, szCopy);
+
+    if ((dwFlags & 1) == 0)
+    {
+        cch = lstrlenW(pszPath);
+        if (cch > 0 && pszPath[cch - 1] == L'.')
+            pszPath[cch - 1] = 0;
+    }
+
+Quit:
+    if (pszDir)
+        SetCurrentDirectoryW(szCurDir);
+}
+
 /*************************************************************************
  * PathAppend          [SHELL32.36]
  */
@@ -476,40 +600,118 @@ int WINAPI PathCleanupSpec( LPCWSTR lpszPathW, LPWSTR 
lpszFileW )
 /*************************************************************************
  * PathQualifyA                [SHELL32]
  */
-static BOOL PathQualifyA(LPCSTR pszPath)
+VOID WINAPI PathQualifyA(LPSTR pszPath)
 {
-       FIXME("%s\n",pszPath);
-       return FALSE;
+    WCHAR szPath[MAX_PATH];
+    TRACE("%s\n",pszPath);
+    SHAnsiToUnicode(pszPath, szPath, _countof(szPath));
+    PathQualifyW(szPath);
+    SHUnicodeToAnsi(szPath, pszPath, MAX_PATH);
 }
 
 /*************************************************************************
  * PathQualifyW                [SHELL32]
  */
-static BOOL PathQualifyW(LPCWSTR pszPath)
+VOID WINAPI PathQualifyW(LPWSTR pszPath)
 {
-       FIXME("%s\n",debugstr_w(pszPath));
-       return FALSE;
+    TRACE("%s\n",debugstr_w(pszPath));
+    PathQualifyExW(pszPath, NULL, 0);
 }
 
 /*************************************************************************
  * PathQualify [SHELL32.49]
  */
-BOOL WINAPI PathQualifyAW(LPCVOID pszPath)
+VOID WINAPI PathQualifyAW(LPVOID pszPath)
 {
-       if (SHELL_OsIsUnicode())
-         return PathQualifyW(pszPath);
-       return PathQualifyA(pszPath);
+    if (SHELL_OsIsUnicode())
+        PathQualifyW(pszPath);
+    else
+        PathQualifyA(pszPath);
 }
 
-static BOOL PathResolveA(LPSTR path, LPCSTR *paths, DWORD flags)
+BOOL WINAPI PathResolveA(LPSTR path, LPCSTR *dirs, DWORD flags)
 {
-    FIXME("(%s,%p,0x%08x),stub!\n", debugstr_a(path), paths, flags);
+    FIXME("(%s,%p,0x%08x),stub!\n", debugstr_a(path), dirs, flags);
     return FALSE;
 }
 
-static BOOL PathResolveW(LPWSTR path, LPCWSTR *paths, DWORD flags)
+#define WHICH_DONTFINDLNK (WHICH_PIF | WHICH_COM | WHICH_EXE | WHICH_BAT)
+#define WHICH_DEFAULT (WHICH_DONTFINDLNK | WHICH_LNK | WHICH_CMD)
+
+BOOL WINAPI PathResolveW(LPWSTR path, LPCWSTR *dirs, DWORD flags)
 {
-    FIXME("(%s,%p,0x%08x),stub!\n", debugstr_w(path), paths, flags);
+    DWORD dwWhich;
+    TRACE("PathResolveW(%s,%p,0x%08x)\n", debugstr_w(path), dirs, flags);
+    dwWhich = ((flags & PRF_DONTFINDLNK) ? WHICH_DONTFINDLNK : WHICH_DEFAULT);
+
+    if (flags & PRF_VERIFYEXISTS)
+        SetLastError(ERROR_FILE_NOT_FOUND);
+
+    PathUnquoteSpacesW(path);
+
+    if (PathIsRootW(path))
+    {
+        if ((path[0] == L'\\' && path[1] == 0) ||
+            PathIsUNCServerW(path) || PathIsUNCServerShareW(path))
+        {
+            if (flags & PRF_FIRSTDIRDEF)
+                PathQualifyExW(path, dirs[0], 0);
+            else
+                PathQualifyExW(path, NULL, 0);
+        }
+
+        if (flags & PRF_VERIFYEXISTS)
+            return PathFileExistsAndAttributesW(path, NULL);
+        return TRUE;
+    }
+    else if (PathIsFileSpecW(path))
+    {
+        if ((flags & PRF_TRYPROGRAMEXTENSIONS) && 
PathSearchOnExtensionsW(path, dirs, TRUE, dwWhich))
+            return TRUE;
+
+        if (PathFindOnPathW(path, dirs))
+        {
+#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
+            if (!(flags & PRF_REQUIREABSOLUTE))
+                return TRUE;
+
+            if (!PathIsAbsoluteW(path))
+                return PathMakeAbsoluteW(path) && 
PathFileExistsAndAttributesW(path, NULL);
+#else
+            return TRUE;
+#endif
+        }
+    }
+    else if (!PathIsURLW(path))
+    {
+        if (flags & PRF_FIRSTDIRDEF)
+            PathQualifyExW(path, *dirs, 1);
+        else
+            PathQualifyExW(path, NULL, 1);
+
+        if (flags & PRF_VERIFYEXISTS)
+        {
+            if ((flags & PRF_TRYPROGRAMEXTENSIONS) &&
+                PathSearchOnExtensionsW(path, dirs, FALSE, dwWhich))
+            {
+                return TRUE;
+            }
+            else if (!PathFileExistsAndAttributesW(path, NULL))
+            {
+                return FALSE;
+            }
+        }
+
+#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
+        if (flags & PRF_REQUIREABSOLUTE)
+        {
+            if (!PathIsAbsoluteW(path))
+                return PathMakeAbsoluteW(path) && 
PathFileExistsAndAttributesW(path, NULL);
+        }
+#endif
+        return TRUE;
+    }
+
     return FALSE;
 }
 
diff --git a/sdk/include/reactos/shlwapi_undoc.h 
b/sdk/include/reactos/shlwapi_undoc.h
index c1f92559e55..ed54a70c686 100644
--- a/sdk/include/reactos/shlwapi_undoc.h
+++ b/sdk/include/reactos/shlwapi_undoc.h
@@ -150,6 +150,18 @@ ShellMessageBoxWrapW(
   _In_ UINT fuStyle,
   ...);
 
+/* dwWhich flags for PathFileExistsDefExtW and PathFindOnPathExW */
+#define WHICH_PIF (1 << 0)
+#define WHICH_COM (1 << 1)
+#define WHICH_EXE (1 << 2)
+#define WHICH_BAT (1 << 3)
+#define WHICH_LNK (1 << 4)
+#define WHICH_CMD (1 << 5)
+
+BOOL WINAPI PathFileExistsDefExtW(LPWSTR lpszPath, DWORD dwWhich);
+BOOL WINAPI PathFindOnPathExW(LPWSTR lpszFile, LPCWSTR *lppszOtherDirs, DWORD 
dwWhich);
+VOID WINAPI FixSlashesAndColonW(LPWSTR);
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif /* defined(__cplusplus) */
diff --git a/sdk/include/reactos/undocshell.h b/sdk/include/reactos/undocshell.h
index a173174cb57..0aad1cf1851 100644
--- a/sdk/include/reactos/undocshell.h
+++ b/sdk/include/reactos/undocshell.h
@@ -440,8 +440,9 @@ BOOL WINAPI PathYetAnotherMakeUniqueName(
     LPCWSTR lpszShortName,
     LPCWSTR lpszLongName);
 
-BOOL  WINAPI PathQualifyAW(LPCVOID path);
-
+VOID WINAPI PathQualifyA(LPSTR pszPath);
+VOID WINAPI PathQualifyW(LPWSTR pszPath);
+VOID WINAPI PathQualifyAW(LPVOID path);
 
 /* PathResolve flags */
 #define PRF_CHECKEXISTANCE  0x01
@@ -449,6 +450,8 @@ BOOL  WINAPI PathQualifyAW(LPCVOID path);
 #define PRF_QUALIFYONPATH   0x04
 #define PRF_WINDOWS31       0x08
 
+BOOL WINAPI PathResolveA(LPSTR path, LPCSTR *dirs, DWORD flags);
+BOOL WINAPI PathResolveW(LPWSTR path, LPCWSTR *dirs, DWORD flags);
 BOOL WINAPI PathResolveAW(LPVOID lpszPath, LPCVOID *alpszPaths, DWORD dwFlags);
 
 VOID WINAPI PathSetDlgItemPathAW(HWND hDlg, int nIDDlgItem, LPCVOID lpszPath);

Reply via email to