mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 08:25:03 +00:00
[SHELL32] Implement PathResolveW function (#3762)
- Implement PathResolveW function. - Implement PathQualifyA/W functions using newly-defined PathQualifyExW function. CORE-12665
This commit is contained in:
parent
81f8bcea8c
commit
3a822e4f74
4 changed files with 248 additions and 126 deletions
|
@ -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);
|
||||
PathResolveW(szPath, NULL, PRF_TRYPROGRAMEXTENSIONS);
|
||||
|
||||
pidlNew = SHSimpleIDListFromPathW(szPath);
|
||||
/******************************************************/
|
||||
/* Question: Why this line is needed only for files?? */
|
||||
hr = (*szPath ? S_OK : E_INVALIDARG); // S_FALSE
|
||||
/******************************************************/
|
||||
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; }
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue