[SHELL32][SHELL32_APITEST][SDK] Implement PathIsEqualOrSubFolder (#5714)

Implement PathIsEqualOrSubFolder function.
- Add it to <undocshell.h>.
- Add PathIsEqualOrSubFolder testcase.
- Add SHGetPathCchFromIDListW as an
  extension of SHGetPathFromIDListW.
CORE-19278
This commit is contained in:
Katayama Hirofumi MZ 2023-11-29 22:50:01 +09:00 committed by GitHub
parent ea8a49d81f
commit 2aeda3dc15
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 183 additions and 18 deletions

View file

@ -17,14 +17,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(shell);
/*
* Unimplemented
*/
EXTERN_C BOOL
WINAPI
PathIsEqualOrSubFolder(LPWSTR lpFolder, LPWSTR lpSubFolder)
{
FIXME("PathIsEqualOrSubFolder() stub\n");
return FALSE;
}
EXTERN_C HRESULT
WINAPI
SHGetUnreadMailCountW(HKEY hKeyUser,

View file

@ -747,3 +747,119 @@ SHStartNetConnectionDialogA(
return SHStartNetConnectionDialogW(hwnd, pszRemoteNameW, dwType);
}
/*************************************************************************
* Helper functions for PathIsEqualOrSubFolder
*/
static INT
DynamicPathCommonPrefixW(
_In_ LPCWSTR lpszPath1,
_In_ LPCWSTR lpszPath2,
_Out_ CStringW& strPath)
{
SIZE_T cchPath1 = wcslen(lpszPath1);
SIZE_T cchPath2 = wcslen(lpszPath2);
LPWSTR lpszPath = strPath.GetBuffer((INT)max(cchPath1, cchPath2) + 16);
INT ret = PathCommonPrefixW(lpszPath1, lpszPath2, lpszPath);
strPath.ReleaseBuffer();
return ret;
}
EXTERN_C HRESULT WINAPI
SHGetPathCchFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath, SIZE_T cchPathMax);
static HRESULT
DynamicSHGetPathFromIDListW(
_In_ LPCITEMIDLIST pidl,
_Out_ CStringW& strPath)
{
HRESULT hr;
for (UINT cchPath = MAX_PATH;; cchPath *= 2)
{
LPWSTR lpszPath = strPath.GetBuffer(cchPath);
if (!lpszPath)
return E_OUTOFMEMORY;
hr = SHGetPathCchFromIDListW(pidl, lpszPath, cchPath);
strPath.ReleaseBuffer();
if (hr != E_NOT_SUFFICIENT_BUFFER)
break;
if (cchPath >= MAXUINT / 2)
{
hr = E_FAIL;
break;
}
}
if (FAILED(hr))
strPath.Empty();
return hr;
}
static HRESULT
DynamicSHGetSpecialFolderPathW(
_In_ HWND hwndOwner,
_Out_ CStringW& strPath,
_In_ INT nCSIDL,
_In_ BOOL bCreate)
{
LPITEMIDLIST pidl;
HRESULT hr = SHGetSpecialFolderLocation(hwndOwner, nCSIDL, &pidl);
if (SUCCEEDED(hr))
{
hr = DynamicSHGetPathFromIDListW(pidl, strPath);
CoTaskMemFree(pidl);
}
if (FAILED(hr))
strPath.Empty();
else if (bCreate)
CreateDirectoryW(strPath, NULL);
return hr;
}
static VOID
DynamicPathRemoveBackslashW(
_Out_ CStringW& strPath)
{
INT nLength = strPath.GetLength();
if (nLength > 0 && strPath[nLength - 1] == L'\\')
strPath = strPath.Left(nLength - 1);
}
/*************************************************************************
* PathIsEqualOrSubFolder (SHELL32.755)
*/
EXTERN_C
BOOL WINAPI
PathIsEqualOrSubFolder(
_In_ LPCWSTR pszPath1OrCSIDL,
_In_ LPCWSTR pszPath2)
{
CStringW strCommon, strPath1;
TRACE("(%s %s)\n", debugstr_w(pszPath1OrCSIDL), debugstr_w(pszPath2));
if (IS_INTRESOURCE(pszPath1OrCSIDL))
{
DynamicSHGetSpecialFolderPathW(
NULL, strPath1, LOWORD(pszPath1OrCSIDL) | CSIDL_FLAG_DONT_VERIFY, FALSE);
}
else
{
strPath1 = pszPath1OrCSIDL;
}
DynamicPathRemoveBackslashW(strPath1);
if (!DynamicPathCommonPrefixW(strPath1, pszPath2, strCommon))
return FALSE;
return strPath1.CompareNoCase(strCommon) == 0;
}

View file

@ -1295,7 +1295,11 @@ BOOL WINAPI SHGetPathFromIDListA(LPCITEMIDLIST pidl, LPSTR pszPath)
*
* See SHGetPathFromIDListA.
*/
BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath)
HRESULT WINAPI
SHGetPathCchFromIDListW(
_In_ LPCITEMIDLIST pidl,
_Out_writes_(cchPathMax) LPWSTR pszPath,
_In_ SIZE_T cchPathMax)
{
HRESULT hr;
LPCITEMIDLIST pidlLast;
@ -1306,33 +1310,40 @@ BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath)
TRACE_(shell)("(pidl=%p,%p)\n", pidl, pszPath);
pdump(pidl);
*pszPath = '\0';
*pszPath = UNICODE_NULL;
if (!pidl)
return FALSE;
return E_FAIL;
hr = SHBindToParent(pidl, &IID_IShellFolder, (VOID**)&psfFolder, &pidlLast);
if (FAILED(hr))
{
ERR("SHBindToParent failed: %x\n", hr);
return FALSE;
return hr;
}
dwAttributes = SFGAO_FILESYSTEM;
hr = IShellFolder_GetAttributesOf(psfFolder, 1, &pidlLast, &dwAttributes);
if (FAILED(hr) || !(dwAttributes & SFGAO_FILESYSTEM)) {
if (FAILED(hr) || !(dwAttributes & SFGAO_FILESYSTEM))
{
WARN("Wrong dwAttributes or GetAttributesOf failed: %x\n", hr);
IShellFolder_Release(psfFolder);
return FALSE;
return E_FAIL;
}
hr = IShellFolder_GetDisplayNameOf(psfFolder, pidlLast, SHGDN_FORPARSING, &strret);
IShellFolder_Release(psfFolder);
if (FAILED(hr)) return FALSE;
if (FAILED(hr))
return hr;
hr = StrRetToBufW(&strret, pidlLast, pszPath, MAX_PATH);
hr = StrRetToBufW(&strret, pidlLast, pszPath, cchPathMax);
TRACE_(shell)("-- %s, 0x%08x\n",debugstr_w(pszPath), hr);
return SUCCEEDED(hr);
return hr;
}
BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath)
{
return SUCCEEDED(SHGetPathCchFromIDListW(pidl, pszPath, MAX_PATH));
}
/*************************************************************************

View file

@ -19,6 +19,7 @@ list(APPEND SOURCE
Int64ToString.cpp
IShellFolderViewCB.cpp
OpenAs_RunDLL.cpp
PathIsEqualOrSubFolder.cpp
PathResolve.cpp
SHAppBarMessage.cpp
SHChangeNotify.cpp

View file

@ -0,0 +1,41 @@
/*
* PROJECT: ReactOS API Tests
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Tests for PathIsEqualOrSubFolder
* COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
*/
#include "shelltest.h"
#include <undocshell.h>
START_TEST(PathIsEqualOrSubFolder)
{
ok_int(PathIsEqualOrSubFolder(L"C:", L"C:"), TRUE);
ok_int(PathIsEqualOrSubFolder(L"C:", L"C:\\"), TRUE);
ok_int(PathIsEqualOrSubFolder(L"C:\\", L"C:"), TRUE);
ok_int(PathIsEqualOrSubFolder(L"C:\\", L"C:\\"), TRUE);
ok_int(PathIsEqualOrSubFolder(L"C:\\", L"C:\\TestTestTest"), TRUE);
ok_int(PathIsEqualOrSubFolder(L"C:\\TestTestTest", L"C:\\"), FALSE);
ok_int(PathIsEqualOrSubFolder(L"C:\\TestTestTest", L"C:\\TestTestTest"), TRUE);
ok_int(PathIsEqualOrSubFolder(L"C:\\TestTestTest", L"C:\\TestTestTest\\"), TRUE);
WCHAR szPath1[MAX_PATH], szPath2[MAX_PATH];
GetWindowsDirectoryW(szPath1, _countof(szPath1));
ok_int(PathIsEqualOrSubFolder(szPath1, szPath1), TRUE);
GetWindowsDirectoryW(szPath2, _countof(szPath2));
PathAppendW(szPath2, L"TestTestTest");
ok_int(PathIsEqualOrSubFolder(szPath1, szPath2), TRUE);
ok_int(PathIsEqualOrSubFolder(szPath2, szPath1), FALSE);
ok_int(PathIsEqualOrSubFolder(szPath2, szPath2), TRUE);
GetTempPathW(_countof(szPath1), szPath1);
GetTempPathW(_countof(szPath2), szPath2);
PathAppendW(szPath2, L"TestTestTest");
ok_int(PathIsEqualOrSubFolder(szPath1, szPath2), TRUE);
ok_int(PathIsEqualOrSubFolder(szPath2, szPath1), FALSE);
ok_int(PathIsEqualOrSubFolder(szPath2, szPath2), TRUE);
}

View file

@ -21,6 +21,7 @@ extern void func_Int64ToString(void);
extern void func_IShellFolderViewCB(void);
extern void func_menu(void);
extern void func_OpenAs_RunDLL(void);
extern void func_PathIsEqualOrSubFolder(void);
extern void func_PathResolve(void);
extern void func_SHAppBarMessage(void);
extern void func_SHChangeNotify(void);
@ -57,6 +58,7 @@ const struct test winetest_testlist[] =
{ "IShellFolderViewCB", func_IShellFolderViewCB },
{ "menu", func_menu },
{ "OpenAs_RunDLL", func_OpenAs_RunDLL },
{ "PathIsEqualOrSubFolder", func_PathIsEqualOrSubFolder },
{ "PathResolve", func_PathResolve },
{ "SHAppBarMessage", func_SHAppBarMessage },
{ "SHChangeNotify", func_SHChangeNotify },

View file

@ -498,6 +498,8 @@ BOOL WINAPI PathIsSameRootAW(LPCVOID lpszPath1, LPCVOID lpszPath2);
BOOL WINAPI PathFindOnPathAW(LPVOID sFile, LPCVOID *sOtherDirs);
BOOL WINAPI PathIsEqualOrSubFolder(_In_ LPCWSTR pszFile1OrCSIDL, _In_ LPCWSTR pszFile2);
/****************************************************************************
* Shell File Operations error codes - SHFileOperationA/W
*/