From 6d109254ababae6192aebca48e4743b0e1efb445 Mon Sep 17 00:00:00 2001 From: Whindmar Saksit Date: Sat, 16 Nov 2024 16:28:28 +0100 Subject: [PATCH] [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 | 192 +++++++++++++----------- 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, 298 insertions(+), 115 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 // Resizable window +#include // 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 lpsfParent; - CComPtr 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 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 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 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) { - TreeView_GetItem(info->hwndTreeView, &item); - BrItemData *pItemData = (BrItemData *)item.lParam; - - if (_ILIsEqualSimple(pItemData->pidlChild, pidlCurrent)) + LPITEMIDLIST pidlNeedle = ILCloneToDepth(pidlSelection, ++depth); + if (_ILIsEmpty(pidlNeedle)) { - pidlCurrent = ILGetNext(pidlCurrent); - if (!_ILIsEmpty(pidlCurrent)) + ILFree(pidlNeedle); + item.hItem = NULL; // Failure + break; + } +next: + TreeView_GetItem(info->hwndTreeView, &item); + const BrItemData *pItemData = (BrItemData *)item.lParam; + if (ILIsEqual(pItemData->pidlFull, pidlNeedle)) + { + 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 psfDesktop; - HRESULT hr = SHGetDesktopFolder(&psfDesktop); - if (FAILED_UNEXPECTEDLY(hr)) - return FALSE; - CComHeapPtr 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); +} - return BrFolder_OnSetExpandedPidl(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); + + 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 +struct CCoInitBase { - CCoInit() - { - hr = CoInitialize(NULL); - } - ~CCoInit() + HRESULT hr; + CCoInitBase() : hr(InitFunc(NULL)) { } + ~CCoInitBase() { if (SUCCEEDED(hr)) - { - CoUninitialize(); - } + UninitFunc(); } - HRESULT hr; }; +typedef CCoInitBase CCoInit; +typedef CCoInitBase 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 */