https://git.reactos.org/?p=reactos.git;a=commitdiff;h=6d109254ababae6192aeb…
commit 6d109254ababae6192aebca48e4743b0e1efb445
Author: Whindmar Saksit <whindsaks(a)proton.me>
AuthorDate: Sat Nov 16 16:28:28 2024 +0100
Commit: GitHub <noreply(a)github.com>
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 */