https://git.reactos.org/?p=reactos.git;a=commitdiff;h=2aeda3dc159a1b175a48876c0aee8a8a5b2c9574

commit 2aeda3dc159a1b175a48876c0aee8a8a5b2c9574
Author:     Katayama Hirofumi MZ <katayama.hirofumi...@gmail.com>
AuthorDate: Wed Nov 29 22:50:01 2023 +0900
Commit:     GitHub <nore...@github.com>
CommitDate: Wed Nov 29 22:50:01 2023 +0900

    [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
---
 dll/win32/shell32/stubs.cpp                        |   8 --
 dll/win32/shell32/utils.cpp                        | 116 +++++++++++++++++++++
 dll/win32/shell32/wine/pidl.c                      |  31 ++++--
 modules/rostests/apitests/shell32/CMakeLists.txt   |   1 +
 .../apitests/shell32/PathIsEqualOrSubFolder.cpp    |  41 ++++++++
 modules/rostests/apitests/shell32/testlist.c       |   2 +
 sdk/include/reactos/undocshell.h                   |   2 +
 7 files changed, 183 insertions(+), 18 deletions(-)

diff --git a/dll/win32/shell32/stubs.cpp b/dll/win32/shell32/stubs.cpp
index 91e8ae00beb..118e1c1f670 100644
--- a/dll/win32/shell32/stubs.cpp
+++ b/dll/win32/shell32/stubs.cpp
@@ -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,
diff --git a/dll/win32/shell32/utils.cpp b/dll/win32/shell32/utils.cpp
index 1e7cfbe28ac..9f9309b645c 100644
--- a/dll/win32/shell32/utils.cpp
+++ b/dll/win32/shell32/utils.cpp
@@ -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;
+}
diff --git a/dll/win32/shell32/wine/pidl.c b/dll/win32/shell32/wine/pidl.c
index 9ade43d1956..7279737c8eb 100644
--- a/dll/win32/shell32/wine/pidl.c
+++ b/dll/win32/shell32/wine/pidl.c
@@ -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));
 }
 
 /*************************************************************************
diff --git a/modules/rostests/apitests/shell32/CMakeLists.txt 
b/modules/rostests/apitests/shell32/CMakeLists.txt
index 07ba4a96ca6..82c1eeea279 100644
--- a/modules/rostests/apitests/shell32/CMakeLists.txt
+++ b/modules/rostests/apitests/shell32/CMakeLists.txt
@@ -19,6 +19,7 @@ list(APPEND SOURCE
     Int64ToString.cpp
     IShellFolderViewCB.cpp
     OpenAs_RunDLL.cpp
+    PathIsEqualOrSubFolder.cpp
     PathResolve.cpp
     SHAppBarMessage.cpp
     SHChangeNotify.cpp
diff --git a/modules/rostests/apitests/shell32/PathIsEqualOrSubFolder.cpp 
b/modules/rostests/apitests/shell32/PathIsEqualOrSubFolder.cpp
new file mode 100644
index 00000000000..59701738e3e
--- /dev/null
+++ b/modules/rostests/apitests/shell32/PathIsEqualOrSubFolder.cpp
@@ -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...@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);
+}
diff --git a/modules/rostests/apitests/shell32/testlist.c 
b/modules/rostests/apitests/shell32/testlist.c
index 424e878d3b9..1a4952cfc17 100644
--- a/modules/rostests/apitests/shell32/testlist.c
+++ b/modules/rostests/apitests/shell32/testlist.c
@@ -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 },
diff --git a/sdk/include/reactos/undocshell.h b/sdk/include/reactos/undocshell.h
index 8fad6faa6a8..b768552f708 100644
--- a/sdk/include/reactos/undocshell.h
+++ b/sdk/include/reactos/undocshell.h
@@ -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
  */

Reply via email to