https://git.reactos.org/?p=reactos.git;a=commitdiff;h=3a822e4f74ea6ea8335a86...
commit 3a822e4f74ea6ea8335a8684c5071d264fee4bed Author: Katayama Hirofumi MZ katayama.hirofumi.mz@gmail.com AuthorDate: Mon Jun 28 07:53:26 2021 +0900 Commit: GitHub noreply@github.com 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).a... - */ - 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);