[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 * Unimplemented
*/ */
EXTERN_C BOOL
WINAPI
PathIsEqualOrSubFolder(LPWSTR lpFolder, LPWSTR lpSubFolder)
{
FIXME("PathIsEqualOrSubFolder() stub\n");
return FALSE;
}
EXTERN_C HRESULT EXTERN_C HRESULT
WINAPI WINAPI
SHGetUnreadMailCountW(HKEY hKeyUser, SHGetUnreadMailCountW(HKEY hKeyUser,

View file

@ -747,3 +747,119 @@ SHStartNetConnectionDialogA(
return SHStartNetConnectionDialogW(hwnd, pszRemoteNameW, dwType); 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. * 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; HRESULT hr;
LPCITEMIDLIST pidlLast; LPCITEMIDLIST pidlLast;
@ -1306,33 +1310,40 @@ BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath)
TRACE_(shell)("(pidl=%p,%p)\n", pidl, pszPath); TRACE_(shell)("(pidl=%p,%p)\n", pidl, pszPath);
pdump(pidl); pdump(pidl);
*pszPath = '\0'; *pszPath = UNICODE_NULL;
if (!pidl) if (!pidl)
return FALSE; return E_FAIL;
hr = SHBindToParent(pidl, &IID_IShellFolder, (VOID**)&psfFolder, &pidlLast); hr = SHBindToParent(pidl, &IID_IShellFolder, (VOID**)&psfFolder, &pidlLast);
if (FAILED(hr)) if (FAILED(hr))
{ {
ERR("SHBindToParent failed: %x\n", hr); ERR("SHBindToParent failed: %x\n", hr);
return FALSE; return hr;
} }
dwAttributes = SFGAO_FILESYSTEM; dwAttributes = SFGAO_FILESYSTEM;
hr = IShellFolder_GetAttributesOf(psfFolder, 1, &pidlLast, &dwAttributes); 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); WARN("Wrong dwAttributes or GetAttributesOf failed: %x\n", hr);
IShellFolder_Release(psfFolder); IShellFolder_Release(psfFolder);
return FALSE; return E_FAIL;
} }
hr = IShellFolder_GetDisplayNameOf(psfFolder, pidlLast, SHGDN_FORPARSING, &strret); hr = IShellFolder_GetDisplayNameOf(psfFolder, pidlLast, SHGDN_FORPARSING, &strret);
IShellFolder_Release(psfFolder); 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); 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 Int64ToString.cpp
IShellFolderViewCB.cpp IShellFolderViewCB.cpp
OpenAs_RunDLL.cpp OpenAs_RunDLL.cpp
PathIsEqualOrSubFolder.cpp
PathResolve.cpp PathResolve.cpp
SHAppBarMessage.cpp SHAppBarMessage.cpp
SHChangeNotify.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_IShellFolderViewCB(void);
extern void func_menu(void); extern void func_menu(void);
extern void func_OpenAs_RunDLL(void); extern void func_OpenAs_RunDLL(void);
extern void func_PathIsEqualOrSubFolder(void);
extern void func_PathResolve(void); extern void func_PathResolve(void);
extern void func_SHAppBarMessage(void); extern void func_SHAppBarMessage(void);
extern void func_SHChangeNotify(void); extern void func_SHChangeNotify(void);
@ -57,6 +58,7 @@ const struct test winetest_testlist[] =
{ "IShellFolderViewCB", func_IShellFolderViewCB }, { "IShellFolderViewCB", func_IShellFolderViewCB },
{ "menu", func_menu }, { "menu", func_menu },
{ "OpenAs_RunDLL", func_OpenAs_RunDLL }, { "OpenAs_RunDLL", func_OpenAs_RunDLL },
{ "PathIsEqualOrSubFolder", func_PathIsEqualOrSubFolder },
{ "PathResolve", func_PathResolve }, { "PathResolve", func_PathResolve },
{ "SHAppBarMessage", func_SHAppBarMessage }, { "SHAppBarMessage", func_SHAppBarMessage },
{ "SHChangeNotify", func_SHChangeNotify }, { "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 PathFindOnPathAW(LPVOID sFile, LPCVOID *sOtherDirs);
BOOL WINAPI PathIsEqualOrSubFolder(_In_ LPCWSTR pszFile1OrCSIDL, _In_ LPCWSTR pszFile2);
/**************************************************************************** /****************************************************************************
* Shell File Operations error codes - SHFileOperationA/W * Shell File Operations error codes - SHFileOperationA/W
*/ */