Index: reactos/dll/win32/shell32/wine/shellpath.c =================================================================== --- reactos/dll/win32/shell32/wine/shellpath.c (revision 75198) +++ reactos/dll/win32/shell32/wine/shellpath.c (working copy) @@ -472,18 +472,232 @@ return PathQualifyA(pszPath); } -static BOOL PathResolveA(LPSTR path, LPCSTR *paths, DWORD flags) +static BOOL +PathTryResolve(LPWSTR new_path, LPCWSTR dir, LPCWSTR relative, DWORD flags) { - FIXME("(%s,%p,0x%08x),stub!\n", debugstr_a(path), paths, flags); + DWORD i; + WCHAR path1[MAX_PATH], path2[MAX_PATH]; + /* + * 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 const WCHAR dot_pif[] = {'.','p','i','f',0}; /* .pif */ + static const WCHAR dot_com[] = {'.','c','o','m',0}; /* .com */ + static const WCHAR dot_bat[] = {'.','b','a','t',0}; /* .bat */ + static const WCHAR dot_cmd[] = {'.','c','m','d',0}; /* .cmd */ + static const WCHAR dot_lnk[] = {'.','l','n','k',0}; /* .lnk */ + static const WCHAR dot_exe[] = {'.','e','x','e',0}; /* .exe */ + + static const LPCWSTR exts[] = + { + dot_pif, dot_com, dot_bat, dot_cmd, dot_lnk, dot_exe + }; + #define LNK_EXT_INDEX 4 /* ".lnk" has index 4 in the array above */ + + /* Build the path */ + if (dir) + { + lstrcpyW(path1, dir); + PathAddBackslashW(path1); + lstrcatW(path1, relative); + } + else + { + lstrcpyW(path1, relative); + } + + for (i = 0; i < _countof(exts); ++i) + { + if (i == LNK_EXT_INDEX && (flags & PRF_DONTFINDLNK)) + { + /* Ignore .lnk files. */ + } + else + { + /* Use the extension to build the path */ + lstrcpyW(path2, path1); + lstrcatW(path2, exts[i]); + if (PathFileExistsW(path2)) + { + lstrcpynW(new_path, path2, MAX_PATH); + return TRUE; + } + } + } + + if (PathFileExistsW(path1)) + { + lstrcpynW(new_path, path1, MAX_PATH); + return TRUE; + } + return FALSE; } static BOOL PathResolveW(LPWSTR path, LPCWSTR *paths, DWORD flags) { - FIXME("(%s,%p,0x%08x),stub!\n", debugstr_w(path), paths, flags); - return FALSE; + LPCWSTR *pszz; + WCHAR path1[MAX_PATH]; + BOOL found = FALSE; + + if (path[0] == UNICODE_NULL) + { + if (flags != 0) + SetLastError(ERROR_NO_MORE_FILES); + found = TRUE; + } + + if (!found && PathIsRelativeW(path)) + { + WCHAR szSysDir[MAX_PATH], szWinDir[MAX_PATH]; + LPCWSTR dirs[] = { szSysDir, szWinDir, NULL }; + + GetSystemDirectoryW(szSysDir, _countof(szSysDir)); + GetWindowsDirectoryW(szWinDir, _countof(szWinDir)); + + for (pszz = dirs; *pszz != NULL; ++pszz) + { + found = PathTryResolve(path, *pszz, path, flags); + if (found) + break; + } + } + + if (!found) + { + if (flags & PRF_FIRSTDIRDEF) + { + if (!PathIsRelativeW(path)) + DebugBreak(); + + if (paths) + { + for (pszz = paths; *pszz != NULL; ++pszz) + { + found = PathTryResolve(path, *pszz, path, flags); + if (found) + break; + } + } + } + } + + if (flags & PRF_VERIFYEXISTS) + { + if (!found) + { + found = PathTryResolve(path, NULL, path, flags); + } + if (!found) + { + lstrcpynW(path1, path, MAX_PATH); + found = PathFindOnPathW(path1, paths); + if (found) + { + lstrcpynW(path, path1, MAX_PATH); + } + } + } + else + { + if (!found && paths) + { + for (pszz = paths; *pszz != NULL; ++pszz) + { + found = PathTryResolve(path, *pszz, path, flags); + if (found) + break; + } + } + if (!found) + { + found = PathFileExistsW(path); + } + } + + if (found && (flags & PRF_REQUIREABSOLUTE)) + { + GetFullPathNameW(path, _countof(path1), path1, NULL); + lstrcpynW(path, path1, MAX_PATH); + } + + return found; } +static BOOL PathResolveA(LPSTR path, LPCSTR *paths, DWORD flags) +{ + BOOL Ret; + WCHAR pathW[MAX_PATH]; + LPCSTR *pdirsA; + DWORD i, Size, Count, dwError; + LPWSTR *pathsW = NULL; + + if (paths) + { + /* Count directories */ + Count = 0; + for (pdirsA = paths; *pdirsA; ++pdirsA) + { + ++Count; + } + pdirsA = paths; + + /* Allocate and convert to Unicode */ + Size = (Count + 1) * sizeof(LPWSTR); + pathsW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Size); + if (pathsW == NULL) + { + return FALSE; /* failure */ + } + for (i = 0; i < Count; ++i) + { + Size = MAX_PATH * sizeof(WCHAR); + pathsW[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Size); + if (pathsW[i] == NULL) + { + break; /* failure */ + } + MultiByteToWideChar(CP_ACP, 0, pdirsA[i], -1, pathsW[i], MAX_PATH); + } + + /* Free and return if failed */ + if (i != Count) + { + while (i > 0) + { + --i; + HeapFree(GetProcessHeap(), 0, pathsW[i]); + } + HeapFree(GetProcessHeap(), 0, pathsW); + + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; /* failure */ + } + } + + /* The main work */ + MultiByteToWideChar(CP_ACP, 0, path, -1, pathW, MAX_PATH); + Ret = PathResolveW(pathW, (LPCWSTR *)pathsW, flags); + dwError = GetLastError(); + WideCharToMultiByte(CP_ACP, 0, pathW, -1, path, MAX_PATH, NULL, NULL); + + if (pathsW) + { + /* Free them now */ + i = Count; + while (i > 0) + { + --i; + HeapFree(GetProcessHeap(), 0, pathsW[i]); + } + HeapFree(GetProcessHeap(), 0, pathsW); + } + + SetLastError(dwError); + return Ret; +} + /************************************************************************* * PathResolve [SHELL32.51] */