https://git.reactos.org/?p=reactos.git;a=commitdiff;h=6d109254ababae6192aebca48e4743b0e1efb445

commit 6d109254ababae6192aebca48e4743b0e1efb445
Author:     Whindmar Saksit <[email protected]>
AuthorDate: Sat Nov 16 16:28:28 2024 +0100
Commit:     GitHub <[email protected]>
CommitDate: Sat Nov 16 16:28:28 2024 +0100

    [SHELL32] Correctly compare pidls for SHBrowseForFolder BFFM_SETEXPANDED 
(#7499)
    
    _ILIsEqualSimple just does a memcmp and that does not work for all items.
    
    Should improve shell change notifications (CORE-13950).
---
 dll/win32/shell32/CDefView.cpp          |   4 +-
 dll/win32/shell32/brfolder.cpp          | 190 +++++++++++++++++---------------
 dll/win32/shell32/folders/CFSFolder.cpp |  14 ++-
 dll/win32/shell32/precomp.h             |   1 +
 dll/win32/shell32/shlfileop.cpp         |   5 +-
 dll/win32/shell32/utils.cpp             |  12 ++
 dll/win32/shell32/wine/pidl.c           |  98 +++++++++++++++-
 dll/win32/shell32/wine/pidl.h           |  24 ++--
 sdk/include/reactos/shellutils.h        |  63 +++++++++--
 9 files changed, 297 insertions(+), 114 deletions(-)

diff --git a/dll/win32/shell32/CDefView.cpp b/dll/win32/shell32/CDefView.cpp
index 95f4a9bff14..d4c8ed82cab 100644
--- a/dll/win32/shell32/CDefView.cpp
+++ b/dll/win32/shell32/CDefView.cpp
@@ -4608,9 +4608,9 @@ HRESULT WINAPI CDefView::GetAdvise(DWORD *pAspects, DWORD 
*pAdvf, IAdviseSink **
 
 HRESULT STDMETHODCALLTYPE CDefView::QueryService(REFGUID guidService, REFIID 
riid, void **ppvObject)
 {
-    if (IsEqualIID(guidService, SID_IShellBrowser))
+    if (IsEqualIID(guidService, SID_IShellBrowser) && m_pShellBrowser)
         return m_pShellBrowser->QueryInterface(riid, ppvObject);
-    else if(IsEqualIID(guidService, SID_IFolderView))
+    else if (IsEqualIID(guidService, SID_IFolderView))
         return QueryInterface(riid, ppvObject);
 
     return E_NOINTERFACE;
diff --git a/dll/win32/shell32/brfolder.cpp b/dll/win32/shell32/brfolder.cpp
index c23eec56507..7b211939ef1 100644
--- a/dll/win32/shell32/brfolder.cpp
+++ b/dll/win32/shell32/brfolder.cpp
@@ -11,11 +11,36 @@
 #include "precomp.h"
 
 #include <ui/layout.h> // Resizable window
+#include <compat_undoc.h> // RosGetProcessEffectiveVersion
 
 WINE_DEFAULT_DEBUG_CHANNEL(shell);
 
 #define SHV_CHANGE_NOTIFY (WM_USER + 0x1111)
 
+static LPITEMIDLIST
+ILCloneToDepth(LPCITEMIDLIST pidlSrc, UINT depth)
+{
+    SIZE_T cb = 0;
+    for (LPCITEMIDLIST pidl = pidlSrc; pidl && depth--; pidl = ILGetNext(pidl))
+        cb += pidl->mkid.cb;
+
+    LPITEMIDLIST pidlOut = (LPITEMIDLIST)SHAlloc(cb + sizeof(WORD));
+    if (pidlOut)
+    {
+        CopyMemory(pidlOut, pidlSrc, cb);
+        ZeroMemory(((BYTE*)pidlOut) + cb, sizeof(WORD));
+    }
+    return pidlOut;
+}
+
+static INT
+GetIconIndex(PCIDLIST_ABSOLUTE pidl, UINT uFlags)
+{
+    SHFILEINFOW sfi;
+    SHGetFileInfoW((LPCWSTR)pidl, 0, &sfi, sizeof(sfi), uFlags);
+    return sfi.iIcon;
+}
+
 struct BrFolder
 {
     LPBROWSEINFOW    lpBrowseInfo;
@@ -145,12 +170,9 @@ BrFolder_InitTreeView(BrFolder *info)
 {
     HIMAGELIST hImageList;
     HRESULT hr;
-    CComPtr<IShellFolder> lpsfParent;
-    CComPtr<IEnumIDList> pEnumChildren;
     HTREEITEM hItem;
 
     Shell_GetImageLists(NULL, &hImageList);
-
     if (hImageList)
         TreeView_SetImageList(info->hwndTreeView, hImageList, 0);
 
@@ -171,54 +193,25 @@ BrFolder_InitTreeView(BrFolder *info)
     ILRemoveLastID(pidlParent);
     PCIDLIST_RELATIVE pidlChild = ILFindLastID(pidlRoot);
 
-    if (_ILIsDesktop(pidlParent))
-    {
-        hr = SHGetDesktopFolder(&lpsfParent);
-        if (FAILED_UNEXPECTEDLY(hr))
-            return;
-    }
-    else
-    {
-        CComPtr<IShellFolder> lpsfDesktop;
-        hr = SHGetDesktopFolder(&lpsfDesktop);
-        if (FAILED_UNEXPECTEDLY(hr))
-            return;
-
-        hr = lpsfDesktop->BindToObject(pidlParent, NULL, 
IID_PPV_ARG(IShellFolder, &lpsfParent));
-        if (FAILED_UNEXPECTEDLY(hr))
-            return;
-    }
+    CComPtr<IShellFolder> lpsfParent;
+    hr = SHBindToObject(NULL, pidlParent, /*NULL, */ IID_PPV_ARG(IShellFolder, 
&lpsfParent));
+    if (FAILED_UNEXPECTEDLY(hr))
+        return;
 
     TreeView_DeleteItem(info->hwndTreeView, TVI_ROOT);
     hItem = BrFolder_InsertItem(info, lpsfParent, pidlChild, pidlParent, 
TVI_ROOT);
     TreeView_Expand(info->hwndTreeView, hItem, TVE_EXPAND);
 }
 
-static INT
-BrFolder_GetIcon(PCIDLIST_ABSOLUTE pidl, UINT uFlags)
-{
-    SHFILEINFOW sfi;
-    SHGetFileInfoW((LPCWSTR)pidl, 0, &sfi, sizeof(sfi), uFlags);
-    return sfi.iIcon;
-}
-
 static void
 BrFolder_GetIconPair(PCIDLIST_ABSOLUTE pidl, LPTVITEMW pItem)
 {
-    DWORD flags;
-
-    CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidlDesktop;
+    static const ITEMIDLIST idlDesktop = { };
     if (!pidl)
-    {
-        pidlDesktop.Attach(_ILCreateDesktop());
-        pidl = pidlDesktop;
-    }
-
-    flags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON;
-    pItem->iImage = BrFolder_GetIcon(pidl, flags);
-
-    flags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_OPENICON;
-    pItem->iSelectedImage = BrFolder_GetIcon(pidl, flags);
+        pidl = &idlDesktop;
+    DWORD flags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON;
+    pItem->iImage = GetIconIndex(pidl, flags);
+    pItem->iSelectedImage = GetIconIndex(pidl, flags | SHGFI_OPENICON);
 }
 
 /******************************************************************************
@@ -766,6 +759,19 @@ BrFolder_OnInitDialog(HWND hWnd, BrFolder *info)
                                                  SHCNE_ALLEVENTS,
                                                  SHV_CHANGE_NOTIFY, 1, &ntreg);
 
+    if (!lpBrowseInfo->pidlRoot)
+    {
+        UINT csidl = (lpBrowseInfo->ulFlags & BIF_NEWDIALOGSTYLE) ? 
CSIDL_PERSONAL : CSIDL_DRIVES;
+        LPITEMIDLIST pidl = SHCloneSpecialIDList(NULL, csidl, TRUE);
+        if (pidl)
+        {
+            SendMessageW(info->hWnd, BFFM_SETSELECTION, FALSE, (LPARAM)pidl);
+            if (csidl == CSIDL_DRIVES)
+                SendMessageW(info->hWnd, BFFM_SETEXPANDED, FALSE, 
(LPARAM)pidl);
+            ILFree(pidl);
+        }
+    }
+
     BrFolder_Callback(info->lpBrowseInfo, hWnd, BFFM_INITIALIZED, 0);
 
     SHAutoComplete(GetDlgItem(hWnd, IDC_BROWSE_FOR_FOLDER_FOLDER_TEXT),
@@ -985,8 +991,9 @@ BrFolder_OnContextMenu(BrFolder &info, LPARAM lParam)
 }
 
 static BOOL
-BrFolder_OnSetExpandedPidl(BrFolder *info, LPITEMIDLIST pidlSelection, 
HTREEITEM *phItem)
+BrFolder_ExpandToPidl(BrFolder *info, LPITEMIDLIST pidlSelection, HTREEITEM 
*phItem)
 {
+    LPITEMIDLIST pidlCurrent = pidlSelection;
     if (_ILIsDesktop(pidlSelection))
     {
         if (phItem)
@@ -994,24 +1001,6 @@ BrFolder_OnSetExpandedPidl(BrFolder *info, LPITEMIDLIST 
pidlSelection, HTREEITEM
         return TRUE;
     }
 
-    // Move pidlCurrent behind the SHITEMIDs in pidlSelection, which are the 
root of
-    // the sub-tree currently displayed.
-    PCIDLIST_ABSOLUTE pidlRoot = info->lpBrowseInfo->pidlRoot;
-    LPITEMIDLIST pidlCurrent = pidlSelection;
-    while (!_ILIsEmpty(pidlRoot) && _ILIsEqualSimple(pidlRoot, pidlCurrent))
-    {
-        pidlRoot = ILGetNext(pidlRoot);
-        pidlCurrent = ILGetNext(pidlCurrent);
-    }
-
-    // The given ID List is not part of the SHBrowseForFolder's current 
sub-tree.
-    if (!_ILIsEmpty(pidlRoot))
-    {
-        if (phItem)
-            *phItem = NULL;
-        return FALSE;
-    }
-
     // Initialize item to point to the first child of the root folder.
     TVITEMEXW item = { TVIF_PARAM };
     item.hItem = TreeView_GetRoot(info->hwndTreeView);
@@ -1019,18 +1008,28 @@ BrFolder_OnSetExpandedPidl(BrFolder *info, LPITEMIDLIST 
pidlSelection, HTREEITEM
         item.hItem = TreeView_GetChild(info->hwndTreeView, item.hItem);
 
     // Walk the tree along the nodes corresponding to the remaining ITEMIDLIST
-    while (item.hItem && !_ILIsEmpty(pidlCurrent))
+    UINT depth = _ILGetDepth(info->lpBrowseInfo->pidlRoot);
+    while (item.hItem && pidlCurrent)
     {
+        LPITEMIDLIST pidlNeedle = ILCloneToDepth(pidlSelection, ++depth);
+        if (_ILIsEmpty(pidlNeedle))
+        {
+            ILFree(pidlNeedle);
+            item.hItem = NULL; // Failure
+            break;
+        }
+next:
         TreeView_GetItem(info->hwndTreeView, &item);
-        BrItemData *pItemData = (BrItemData *)item.lParam;
-
-        if (_ILIsEqualSimple(pItemData->pidlChild, pidlCurrent))
+        const BrItemData *pItemData = (BrItemData *)item.lParam;
+        if (ILIsEqual(pItemData->pidlFull, pidlNeedle))
         {
-            pidlCurrent = ILGetNext(pidlCurrent);
-            if (!_ILIsEmpty(pidlCurrent))
+            BOOL done = _ILGetDepth(pidlSelection) == _ILGetDepth(pidlNeedle);
+            if (done)
+            {
+                pidlCurrent = NULL; // Success
+            }
+            else
             {
-                // Only expand current node and move on to its first child,
-                // if we didn't already reach the last SHITEMID
                 TreeView_Expand(info->hwndTreeView, item.hItem, TVE_EXPAND);
                 item.hItem = TreeView_GetChild(info->hwndTreeView, item.hItem);
             }
@@ -1038,7 +1037,10 @@ BrFolder_OnSetExpandedPidl(BrFolder *info, LPITEMIDLIST 
pidlSelection, HTREEITEM
         else
         {
             item.hItem = TreeView_GetNextSibling(info->hwndTreeView, 
item.hItem);
+            if (item.hItem)
+                goto next;
         }
+        ILFree(pidlNeedle);
     }
 
     if (phItem)
@@ -1048,19 +1050,26 @@ BrFolder_OnSetExpandedPidl(BrFolder *info, LPITEMIDLIST 
pidlSelection, HTREEITEM
 }
 
 static BOOL
-BrFolder_OnSetExpandedString(BrFolder *info, LPWSTR pszString, HTREEITEM 
*phItem)
+BrFolder_ExpandToString(BrFolder *info, LPWSTR pszString, HTREEITEM *phItem)
 {
-    CComPtr<IShellFolder> psfDesktop;
-    HRESULT hr = SHGetDesktopFolder(&psfDesktop);
-    if (FAILED_UNEXPECTEDLY(hr))
-        return FALSE;
-
     CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidlSelection;
-    hr = psfDesktop->ParseDisplayName(NULL, NULL, pszString, NULL, 
&pidlSelection, NULL);
-    if (FAILED_UNEXPECTEDLY(hr))
-        return FALSE;
+    HRESULT hr = SHParseDisplayName(pszString, NULL, &pidlSelection, 0, NULL);
+    return SUCCEEDED(hr) && BrFolder_ExpandToPidl(info, pidlSelection, phItem);
+}
+
+static BOOL
+BrFolder_OnSetExpanded(BrFolder *info, LPITEMIDLIST pidlSelection, LPWSTR 
pszString)
+{
+    HTREEITEM hItem;
+    BOOL ret;
+    if (pszString)
+        ret = BrFolder_ExpandToString(info, pszString, &hItem);
+    else
+        ret = BrFolder_ExpandToPidl(info, pidlSelection, &hItem);
 
-    return BrFolder_OnSetExpandedPidl(info, pidlSelection, phItem);
+    if (ret)
+        TreeView_Expand(info->hwndTreeView, hItem, TVE_EXPAND);
+    return ret;
 }
 
 static BOOL
@@ -1070,7 +1079,7 @@ BrFolder_OnSetSelectionPidl(BrFolder *info, LPITEMIDLIST 
pidlSelection)
         return FALSE;
 
     HTREEITEM hItem;
-    BOOL ret = BrFolder_OnSetExpandedPidl(info, pidlSelection, &hItem);
+    BOOL ret = BrFolder_ExpandToPidl(info, pidlSelection, &hItem);
     if (ret)
         TreeView_SelectItem(info->hwndTreeView, hItem);
     return ret;
@@ -1083,7 +1092,7 @@ BrFolder_OnSetSelectionW(BrFolder *info, LPWSTR 
pszSelection)
         return FALSE;
 
     HTREEITEM hItem;
-    BOOL ret = BrFolder_OnSetExpandedString(info, pszSelection, &hItem);
+    BOOL ret = BrFolder_ExpandToString(info, pszSelection, &hItem);
     if (ret)
         TreeView_SelectItem(info->hwndTreeView, hItem);
     return ret;
@@ -1304,9 +1313,9 @@ BrFolderDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, 
LPARAM lParam)
 
         case BFFM_SETEXPANDED: // Unicode only
             if (wParam) // String
-                return BrFolder_OnSetExpandedString(info, (LPWSTR)lParam, 
NULL);
+                return BrFolder_OnSetExpanded(info, NULL, (LPWSTR)lParam);
             else // PIDL
-                return BrFolder_OnSetExpandedPidl(info, (LPITEMIDLIST)lParam, 
NULL);
+                return BrFolder_OnSetExpanded(info, (LPITEMIDLIST)lParam, 
NULL);
 
         case SHV_CHANGE_NOTIFY:
             BrFolder_OnChange(info, wParam, lParam);
@@ -1362,16 +1371,23 @@ SHBrowseForFolderW(LPBROWSEINFOW lpbi)
 {
     TRACE("%p\n", lpbi);
 
+    // MSDN says the caller must initialize COM. We do it anyway in case the 
caller forgot.
+    COleInit OleInit;
     BrFolder info = { lpbi };
 
-    HRESULT hr = OleInitialize(NULL);
-
     INT id = ((lpbi->ulFlags & BIF_USENEWUI) ? IDD_BROWSE_FOR_FOLDER_NEW : 
IDD_BROWSE_FOR_FOLDER);
     INT_PTR ret = DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(id), 
lpbi->hwndOwner,
                                   BrFolderDlgProc, (LPARAM)&info);
-    if (SUCCEEDED(hr))
-        OleUninitialize();
-
+    if (ret == IDOK && !(lpbi->ulFlags & BIF_NOTRANSLATETARGETS) &&
+        RosGetProcessEffectiveVersion() >= _WIN32_WINNT_WINXP)
+    {
+        PIDLIST_ABSOLUTE pidlTarget;
+        if (SHELL_GetIDListTarget(info.pidlRet, &pidlTarget) == S_OK)
+        {
+            ILFree(info.pidlRet);
+            info.pidlRet = pidlTarget;
+        }
+    }
     if (ret != IDOK)
     {
         ILFree(info.pidlRet);
diff --git a/dll/win32/shell32/folders/CFSFolder.cpp 
b/dll/win32/shell32/folders/CFSFolder.cpp
index 0a209ade806..8ff94898d81 100644
--- a/dll/win32/shell32/folders/CFSFolder.cpp
+++ b/dll/win32/shell32/folders/CFSFolder.cpp
@@ -20,13 +20,20 @@ static LPCWSTR GetItemFileName(PCUITEMID_CHILD pidl, LPWSTR 
Buf, UINT cchMax)
     if (pDataW)
         return pDataW->wszName;
     LPPIDLDATA pdata = _ILGetDataPointer(pidl);
-    if ((pdata->type & PT_VALUEW) == PT_VALUEW)
+    if (_ILGetFSType(pidl) & PT_FS_UNICODE_FLAG)
         return (LPWSTR)pdata->u.file.szNames;
     if (_ILSimpleGetTextW(pidl, Buf, cchMax))
         return Buf;
     return NULL;
 }
 
+static BOOL IsRealItem(const ITEMIDLIST &idl)
+{
+    // PIDLs created with SHSimpleIDListFromPath contain no data, otherwise, 
the item is "real"
+    FileStruct &fsitem = ((PIDLDATA*)idl.mkid.abID)->u.file;
+    return fsitem.dwFileSize | fsitem.uFileDate;
+}
+
 static HKEY OpenKeyFromFileType(LPCWSTR pExtension, LPCWSTR KeyName)
 {
     HKEY hkey;
@@ -1079,7 +1086,10 @@ HRESULT WINAPI CFSFolder::CompareIDs(LPARAM lParam,
     /* When sorting between a File and a Folder, the Folder gets sorted first 
*/
     if (bIsFolder1 != bIsFolder2)
     {
-        return MAKE_COMPARE_HRESULT(bIsFolder1 ? -1 : 1);
+        // ...but only if neither of them were generated by 
SHSimpleIDListFromPath
+        // because in that case we cannot tell if it's a file or a folder.
+        if (IsRealItem(*pidl1) && IsRealItem(*pidl2))
+            return MAKE_COMPARE_HRESULT(bIsFolder1 ? -1 : 1);
     }
 
     int result = 0;
diff --git a/dll/win32/shell32/precomp.h b/dll/win32/shell32/precomp.h
index 97fd073ab6d..614478a3d08 100644
--- a/dll/win32/shell32/precomp.h
+++ b/dll/win32/shell32/precomp.h
@@ -219,6 +219,7 @@ SHBindToObjectEx(
 
 DWORD
 SHGetAttributes(_In_ IShellFolder *psf, _In_ LPCITEMIDLIST pidl, _In_ DWORD 
dwAttributes);
+HRESULT SHELL_GetIDListTarget(_In_ LPCITEMIDLIST pidl, _Out_ PIDLIST_ABSOLUTE 
*ppidl);
 HRESULT SHCoInitializeAnyApartment(VOID);
 
 HRESULT
diff --git a/dll/win32/shell32/shlfileop.cpp b/dll/win32/shell32/shlfileop.cpp
index 53f209a8f4f..f26d54ecc68 100644
--- a/dll/win32/shell32/shlfileop.cpp
+++ b/dll/win32/shell32/shlfileop.cpp
@@ -1633,7 +1633,8 @@ static HRESULT delete_files(FILE_OPERATION *op, const 
FILE_LIST *flFrom)
             BOOL bDelete;
             if (TRASH_TrashFile(fileEntry->szFullPath))
             {
-                SHChangeNotify(SHCNE_DELETE, SHCNF_PATHW, 
fileEntry->szFullPath, NULL);
+                UINT event = IsAttribFile(fileEntry->attributes) ? 
SHCNE_DELETE : SHCNE_RMDIR;
+                SHChangeNotify(event, SHCNF_PATHW, fileEntry->szFullPath, 
NULL);
                 continue;
             }
 
@@ -1652,9 +1653,7 @@ static HRESULT delete_files(FILE_OPERATION *op, const 
FILE_LIST *flFrom)
 
         /* delete the file or directory */
         if (IsAttribFile(fileEntry->attributes))
-        {
             bPathExists = (ERROR_SUCCESS == SHNotifyDeleteFileW(op, 
fileEntry->szFullPath));
-        }
         else
             bPathExists = SHELL_DeleteDirectoryW(op, fileEntry->szFullPath, 
FALSE);
 
diff --git a/dll/win32/shell32/utils.cpp b/dll/win32/shell32/utils.cpp
index fe41af078c2..3fdce2eb5e3 100644
--- a/dll/win32/shell32/utils.cpp
+++ b/dll/win32/shell32/utils.cpp
@@ -277,6 +277,18 @@ SHGetAttributes(_In_ IShellFolder *psf, _In_ LPCITEMIDLIST 
pidl, _In_ DWORD dwAt
     return dwAttributes;
 }
 
+HRESULT SHELL_GetIDListTarget(_In_ LPCITEMIDLIST pidl, _Out_ PIDLIST_ABSOLUTE 
*ppidl)
+{
+    IShellLink *pSL;
+    HRESULT hr = SHBindToObject(NULL, pidl, IID_PPV_ARG(IShellLink, &pSL));
+    if (SUCCEEDED(hr))
+    {
+        hr = pSL->GetIDList(ppidl); // Note: Returns S_FALSE if no target pidl
+        pSL->Release();
+    }
+    return hr;
+}
+
 HRESULT SHCoInitializeAnyApartment(VOID)
 {
     HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | 
COINIT_DISABLE_OLE1DDE);
diff --git a/dll/win32/shell32/wine/pidl.c b/dll/win32/shell32/wine/pidl.c
index 54751ded772..f6058d04ee5 100644
--- a/dll/win32/shell32/wine/pidl.c
+++ b/dll/win32/shell32/wine/pidl.c
@@ -485,6 +485,37 @@ LPITEMIDLIST WINAPI ILGlobalClone(LPCITEMIDLIST pidl)
     return newpidl;
 }
 
+#ifdef __REACTOS__
+static inline LPITEMIDLIST _ILUnsafeNext(LPCITEMIDLIST pidl)
+{
+    return (LPITEMIDLIST)(((BYTE*)pidl) + pidl->mkid.cb);
+}
+
+UINT _ILGetDepth(LPCITEMIDLIST pidl)
+{
+    for (UINT i = 0;; ++i)
+    {
+        if (!pidl || !pidl->mkid.cb)
+            return i;
+        pidl = _ILUnsafeNext(pidl);
+    }
+}
+
+static BOOL _ILMemCmpEqualIDList(LPCITEMIDLIST p1, LPCITEMIDLIST p2)
+{
+    for (;; p1 = _ILUnsafeNext(p1), p2 = _ILUnsafeNext(p2))
+    {
+        DWORD cb1 = p1 ? p1->mkid.cb : 0x80000000; /* Empty != NULL */
+        DWORD cb2 = p2 ? p2->mkid.cb : 0x80000000;
+        if (cb1 != cb2)
+            return FALSE;
+        if (LOWORD(cb1) == 0)
+            return cb1 == cb2;
+        if (memcmp(p1, p2, cb1))
+            return FALSE;
+    }
+}
+#else /* __REACTOS__ */
 BOOL _ILHACKCompareSimpleIds(LPCITEMIDLIST pidltemp1, LPCITEMIDLIST pidltemp2)
 {
     LPPIDLDATA pdata1 = _ILGetDataPointer(pidltemp1);
@@ -540,6 +571,7 @@ BOOL _ILHACKCompareSimpleIds(LPCITEMIDLIST pidltemp1, 
LPCITEMIDLIST pidltemp2)
 
     return TRUE;
 }
+#endif /* __REACTOS__ */
 
 /*************************************************************************
  * ILIsEqual [SHELL32.21]
@@ -552,6 +584,21 @@ BOOL WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST 
pidl2)
 
     TRACE("pidl1=%p pidl2=%p\n",pidl1, pidl2);
 
+#ifdef __REACTOS__
+    IShellFolder *psfDesktop;
+    UINT depth1;
+
+    if (pidl1 == pidl2 || _ILMemCmpEqualIDList(pidltemp1, pidltemp2))
+        return TRUE;
+
+    depth1 = _ILGetDepth(pidl1);
+    if (depth1 && depth1 == _ILGetDepth(pidl2) && 
SUCCEEDED(SHGetDesktopFolder(&psfDesktop)))
+    {
+        HRESULT hr = IShellFolder_CompareIDs(psfDesktop, SHCIDS_CANONICALONLY, 
pidl1, pidl2);
+        IShellFolder_Release(psfDesktop);
+        return hr == 0;
+    }
+#else /* __REACTOS__ */
     /*
      * Explorer reads from registry directly (StreamMRU),
      * so we can only check here
@@ -582,10 +629,47 @@ BOOL WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST 
pidl2)
 
     if (!pidltemp1->mkid.cb && !pidltemp2->mkid.cb)
         return TRUE;
-
+#endif /* __REACTOS__ */
     return FALSE;
 }
 
+LPCITEMIDLIST _ILIsParentEx(LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidlChild, 
BOOL bImmediate)
+{
+    LPCITEMIDLIST pParentRoot = pidlParent, pChildRoot = pidlChild, pResult = 
NULL;
+    LPITEMIDLIST pidl;
+    SIZE_T cb = 0;
+
+    if (!pidlParent || !pidlChild)
+        return pResult;
+
+    while (pidlParent->mkid.cb)
+    {
+        cb += pidlChild->mkid.cb;
+        if (!pidlChild->mkid.cb)
+        {
+            if (pidlParent->mkid.cb)
+                return pResult; /* The child is shorter than the parent */
+            else
+                break;
+        }
+        pidlChild = _ILUnsafeNext(pidlChild);
+        pidlParent = _ILUnsafeNext(pidlParent);
+    }
+
+    if (bImmediate && (!pidlChild->mkid.cb || 
_ILUnsafeNext(pidlChild)->mkid.cb))
+        return pResult; /* Same as parent or a deeper grandchild */
+
+    if ((pidl = SHAlloc(cb + sizeof(WORD))) != NULL)
+    {
+        CopyMemory(pidl, pChildRoot, cb);
+        ZeroMemory((BYTE*)pidl + cb, sizeof(WORD));
+        if (ILIsEqual(pParentRoot, pidl))
+            pResult = pidlChild;
+        ILFree(pidl);
+    }
+    return pResult;
+}
+
 /*************************************************************************
  * ILIsParent                [SHELL32.23]
  *
@@ -615,6 +699,9 @@ BOOL WINAPI ILIsParent(LPCITEMIDLIST pidlParent, 
LPCITEMIDLIST pidlChild, BOOL b
 
     TRACE("%p %p %x\n", pidlParent, pidlChild, bImmediate);
 
+#ifdef __REACTOS__
+    return _ILIsParentEx(pParent, pChild, bImmediate) != NULL;
+#else /* __REACTOS__ */
     if (!pParent || !pChild)
         return FALSE;
 
@@ -636,6 +723,7 @@ BOOL WINAPI ILIsParent(LPCITEMIDLIST pidlParent, 
LPCITEMIDLIST pidlChild, BOOL b
         return FALSE;
 
     return TRUE;
+#endif /* __REACTOS__ */
 }
 
 /*************************************************************************
@@ -659,6 +747,13 @@ BOOL WINAPI ILIsParent(LPCITEMIDLIST pidlParent, 
LPCITEMIDLIST pidlChild, BOOL b
  */
 PUIDLIST_RELATIVE WINAPI ILFindChild(PIDLIST_ABSOLUTE pidl1, PCIDLIST_ABSOLUTE 
pidl2)
 {
+#ifdef __REACTOS__
+    TRACE("pidl1=%p pidl2=%p\n", pidl1, pidl2);
+
+    if (_ILIsDesktop(pidl1))
+        return (PUIDLIST_RELATIVE)pidl2;
+    return (PUIDLIST_RELATIVE)_ILIsParentEx(pidl1, pidl2, FALSE);
+#else /* __REACTOS__ */
     LPCITEMIDLIST pidltemp1 = pidl1;
     LPCITEMIDLIST pidltemp2 = pidl2;
     LPCITEMIDLIST ret=NULL;
@@ -694,6 +789,7 @@ PUIDLIST_RELATIVE WINAPI ILFindChild(PIDLIST_ABSOLUTE 
pidl1, PCIDLIST_ABSOLUTE p
     }
     TRACE_(shell)("--- %p\n", ret);
     return (PUIDLIST_RELATIVE)ret; /* pidl 1 is shorter */
+#endif /* __REACTOS__ */
 }
 
 /*************************************************************************
diff --git a/dll/win32/shell32/wine/pidl.h b/dll/win32/shell32/wine/pidl.h
index 304ce1cc19b..ef0002941f7 100644
--- a/dll/win32/shell32/wine/pidl.h
+++ b/dll/win32/shell32/wine/pidl.h
@@ -105,8 +105,9 @@ extern "C" {
 #define PT_SHARE       0xc3
 
 #ifdef __REACTOS__
+#define PT_FOLDERTYPEMASK       0x70
 #define PT_DESKTOP_REGITEM      0x1F // => SHDID_ROOT_REGITEM
-#define PT_COMPUTER_REGITEM     0x2E // => SHDID_COMPUTER_OTHER
+#define PT_COMPUTER_REGITEM     0x2E // => SHDID_COMPUTER_?
 #define PT_FS                   0x30 // Win95 SHSimpleIDListFromPath
 #define PT_FS_FOLDER_FLAG       0x01
 #define PT_FS_FILE_FLAG         0x02
@@ -116,6 +117,17 @@ extern "C" {
 #define PT_CONTROLS_NEWREGITEM  0x71
 #endif
 
+static inline BYTE _ILGetType(LPCITEMIDLIST pidl)
+{
+    return pidl && pidl->mkid.cb >= 3 ? pidl->mkid.abID[0] : 0;
+}
+
+static inline BYTE _ILGetFSType(LPCITEMIDLIST pidl)
+{
+    const BYTE type = _ILGetType(pidl);
+    return (type & PT_FOLDERTYPEMASK) == PT_FS ? type : 0;
+}
+
 #include "pshpack1.h"
 typedef BYTE PIDLTYPE;
 
@@ -257,14 +269,8 @@ BOOL       _ILIsValue              (LPCITEMIDLIST pidl) 
DECLSPEC_HIDDEN;
 BOOL   _ILIsSpecialFolder      (LPCITEMIDLIST pidl) DECLSPEC_HIDDEN;
 BOOL   _ILIsPidlSimple         (LPCITEMIDLIST pidl) DECLSPEC_HIDDEN;
 BOOL   _ILIsCPanelStruct       (LPCITEMIDLIST pidl) DECLSPEC_HIDDEN;
-static inline 
-BOOL    _ILIsEqualSimple        (LPCITEMIDLIST pidlA, LPCITEMIDLIST pidlB)
-{
-    return (pidlA->mkid.cb > 0 && !memcmp(pidlA, pidlB, pidlA->mkid.cb)) ||
-            (!pidlA->mkid.cb && !pidlB->mkid.cb);
-}
-static inline
-BOOL    _ILIsEmpty              (LPCITEMIDLIST pidl) { return 
_ILIsDesktop(pidl); }
+static inline BOOL _ILIsEmpty(LPCITEMIDLIST pidl) { return _ILIsDesktop(pidl); 
}
+UINT _ILGetDepth(LPCITEMIDLIST pidl);
 
 /*
  * simple pidls
diff --git a/sdk/include/reactos/shellutils.h b/sdk/include/reactos/shellutils.h
index 825e834897b..756c57c9d73 100644
--- a/sdk/include/reactos/shellutils.h
+++ b/sdk/include/reactos/shellutils.h
@@ -597,21 +597,19 @@ void DumpIdList(LPCITEMIDLIST pcidl)
     DbgPrint("End IDList Dump.\n");
 }
 
-struct CCoInit
+template <HRESULT (WINAPI *InitFunc)(void*), void (WINAPI *UninitFunc)()>
+struct CCoInitBase
 {
-    CCoInit()
-    {
-        hr = CoInitialize(NULL);
-    }
-    ~CCoInit()
+    HRESULT hr;
+    CCoInitBase() : hr(InitFunc(NULL)) { }
+    ~CCoInitBase()
     {
         if (SUCCEEDED(hr))
-        {
-            CoUninitialize();
-        }
+            UninitFunc();
     }
-    HRESULT hr;
 };
+typedef CCoInitBase<CoInitialize, CoUninitialize> CCoInit;
+typedef CCoInitBase<OleInitialize, OleUninitialize> COleInit;
 
 #endif /* __cplusplus */
 
@@ -828,5 +826,50 @@ struct SHELL_GetSettingImpl
 #define SHELL_GetSetting(pss, ssf, field) ( SHGetSetSettings((pss), (ssf), 
FALSE), (pss)->field )
 #endif
 
+static inline void DumpIdListOneLine(LPCITEMIDLIST pidl)
+{
+    char buf[1024], *data, drive = 0;
+    for (UINT depth = 0, type; ; pidl = ILGetNext(pidl), ++depth)
+    {
+        if (!pidl || !pidl->mkid.cb)
+        {
+            if (!depth)
+            {
+                wsprintfA(buf, "%p [] (%s)\n", pidl, pidl ? "Empty/Desktop" : 
"NULL");
+                OutputDebugStringA(buf);
+            }
+            break;
+        }
+        else if (!depth)
+        {
+            wsprintfA(buf, "%p", pidl);
+            OutputDebugStringA(buf);
+        }
+        type = pidl->mkid.abID[0] & 0x7f;
+        data = (char*)&pidl->mkid.abID[0];
+        if (depth == 0 && type == 0x1f && pidl->mkid.cb == 20 && 
*(UINT*)(&data[2]) == 0x20D04FE0)
+        {
+            wsprintfA(buf, " [%.2x ThisPC?]", type); /* "?" because we did not 
check the full GUID */
+        }
+        else if (depth == 1 && type >= 0x20 && type < 0x30 && type != 0x2E && 
pidl->mkid.cb > 4)
+        {
+            drive = data[1];
+            wsprintfA(buf, " [%.2x %c: %ub]", type, drive, pidl->mkid.cb);
+        }
+        else if (depth >= 2 && drive && (type & 0x70) == 0x30) /* PT_FS */
+        {
+            if (type & 4)
+                wsprintfA(buf, " [%.2x FS %.256ls %ub]", type, data + 12, 
pidl->mkid.cb);
+            else
+                wsprintfA(buf, " [%.2x FS %.256hs %ub]", type, data + 12, 
pidl->mkid.cb);
+        }
+        else
+        {
+            wsprintfA(buf, " [%.2x ? %ub]", type, pidl->mkid.cb);
+        }
+        OutputDebugStringA(buf);
+    }
+    OutputDebugStringA("\n");
+}
 
 #endif /* __ROS_SHELL_UTILS_H */

Reply via email to