From c1b8c4f96f77f451b471a5431c6dd47b3e78843b Mon Sep 17 00:00:00 2001 From: Whindmar Saksit Date: Tue, 25 Mar 2025 21:26:55 +0100 Subject: [PATCH] [SHELL32] Correctly implement common desktop items PIDL (#7730) The current implementation is broken, if a file/folder exists in both places, you always get the user item. CORE-19861 --- dll/win32/shell32/folders/CDesktopFolder.cpp | 54 ++++++++++++++------ dll/win32/shell32/folders/CDesktopFolder.h | 2 + dll/win32/shell32/wine/pidl.c | 53 ++++++++----------- dll/win32/shell32/wine/pidl.h | 1 + 4 files changed, 60 insertions(+), 50 deletions(-) diff --git a/dll/win32/shell32/folders/CDesktopFolder.cpp b/dll/win32/shell32/folders/CDesktopFolder.cpp index b785a28a959..626fe007ef7 100644 --- a/dll/win32/shell32/folders/CDesktopFolder.cpp +++ b/dll/win32/shell32/folders/CDesktopFolder.cpp @@ -49,11 +49,17 @@ static BOOL IsSelf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl) static const CLSID* IsRegItem(PCUITEMID_CHILD pidl) { - if (pidl && pidl->mkid.cb == 2 + 2 + sizeof(CLSID) && pidl->mkid.abID[0] == PT_GUID) + if (pidl && pidl->mkid.cb == 2 + 2 + sizeof(CLSID) && pidl->mkid.abID[0] == PT_DESKTOP_REGITEM) return (const CLSID*)(&pidl->mkid.abID[2]); return NULL; } +static inline void MarkAsCommonItem(LPITEMIDLIST pidl) +{ + ASSERT(_ILGetFSType(pidl) & PT_FS); + ((PIDLDATA*)pidl->mkid.abID)->type |= PT_FS_COMMON_FLAG; +} + STDMETHODIMP CDesktopFolder::ShellUrlParseDisplayName( HWND hwndOwner, @@ -201,8 +207,19 @@ class CDesktopFolderEnum : /* Enumerate the items in the two fs folders */ AppendItemsFromEnumerator(pDesktopEnumerator); + ENUMLIST *pCommon = this->mpLast; AppendItemsFromEnumerator(pCommonDesktopEnumerator); - + if (pCommon != this->mpLast) // Any common items added? + { + ENUMLIST fake; + if (!pCommon) // In the unlikely case that there are no RegItems nor user items + { + fake.pNext = this->mpFirst; + pCommon = &fake; + } + while ((pCommon = pCommon->pNext) != NULL) + MarkAsCommonItem(pCommon->pidl); + } return S_OK; } @@ -281,22 +298,20 @@ HRESULT WINAPI CDesktopFolder::FinalConstruct() HRESULT CDesktopFolder::_GetSFFromPidl(LPCITEMIDLIST pidl, IShellFolder2** psf) { - WCHAR szFileName[MAX_PATH]; - - if (_ILIsSpecialFolder(pidl)) + if (IsRegItem(pidl)) return m_regFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, psf)); - - lstrcpynW(szFileName, sPathTarget, MAX_PATH - 1); - PathAddBackslashW(szFileName); - int cLen = wcslen(szFileName); - - if (!_ILSimpleGetTextW(pidl, szFileName + cLen, MAX_PATH - cLen)) - return E_FAIL; - - if (GetFileAttributes(szFileName) == INVALID_FILE_ATTRIBUTES) - return m_SharedDesktopFSFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, psf)); +#if DBG + if (_ILIsDesktop(pidl)) + { + FIXME("Desktop is unexpected here!\n"); + } else - return m_DesktopFSFolder->QueryInterface(IID_PPV_ARG(IShellFolder2, psf)); + { + ASSERT(!_ILIsSpecialFolder(pidl)); + } +#endif + IShellFolder *pSF = IsCommonItem(pidl) ? m_SharedDesktopFSFolder : m_DesktopFSFolder; + return pSF->QueryInterface(IID_PPV_ARG(IShellFolder2, psf)); } HRESULT CDesktopFolder::_ParseDisplayNameByParent( @@ -502,6 +517,8 @@ HRESULT WINAPI CDesktopFolder::ParseDisplayName( pchEaten, ppidl, pdwAttributes); + if (SUCCEEDED(hr)) + MarkAsCommonItem(*ppidl); } if (FAILED(hr) && bCreate && m_DesktopFSFolder) @@ -604,7 +621,10 @@ HRESULT WINAPI CDesktopFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl if (_ILIsSpecialFolder(pidl1) || _ILIsSpecialFolder(pidl2)) return m_regFolder->CompareIDs(lParam, pidl1, pidl2); - return m_DesktopFSFolder->CompareIDs(lParam, pidl1, pidl2); + HRESULT ret = m_DesktopFSFolder->CompareIDs(lParam, pidl1, pidl2); + if (ret == 0 && ((lParam & SHCIDS_COLUMNMASK) == SHFSF_COL_NAME || (lParam & (SHCIDS_ALLFIELDS | SHCIDS_CANONICALONLY)))) + ret = MAKE_COMPARE_HRESULT(IsCommonItem(pidl1) - IsCommonItem(pidl2)); + return ret; } /************************************************************************** diff --git a/dll/win32/shell32/folders/CDesktopFolder.h b/dll/win32/shell32/folders/CDesktopFolder.h index b749d7a00ee..b117ac2c8d7 100644 --- a/dll/win32/shell32/folders/CDesktopFolder.h +++ b/dll/win32/shell32/folders/CDesktopFolder.h @@ -75,6 +75,8 @@ class CDesktopFolder : ~CDesktopFolder(); HRESULT WINAPI FinalConstruct(); + static inline BOOL IsCommonItem(LPCITEMIDLIST pidl) { return _ILGetFSType(pidl) & PT_FS_COMMON_FLAG; } + // *** IShellFolder methods *** STDMETHOD(ParseDisplayName)(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, DWORD *pchEaten, PIDLIST_RELATIVE *ppidl, DWORD *pdwAttributes) override; STDMETHOD(EnumObjects)(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList) override; diff --git a/dll/win32/shell32/wine/pidl.c b/dll/win32/shell32/wine/pidl.c index 576a623c545..1417192f8a8 100644 --- a/dll/win32/shell32/wine/pidl.c +++ b/dll/win32/shell32/wine/pidl.c @@ -2293,9 +2293,6 @@ static LPWSTR _ILGetTextPointerW(LPCITEMIDLIST pidl) /*return (LPSTR)&(pdata->u.drive.szDriveName);*/ return NULL; - case PT_FOLDER: - case PT_FOLDER1: - case PT_VALUE: case PT_IESPECIAL1: case PT_IESPECIAL2: /*return (LPSTR)&(pdata->u.file.szNames);*/ @@ -2327,11 +2324,18 @@ LPSTR _ILGetTextPointer(LPCITEMIDLIST pidl) { /* TRACE(pidl,"(pidl%p)\n", pidl);*/ + PIDLTYPE type; LPPIDLDATA pdata = _ILGetDataPointer(pidl); - if (!pdata) return NULL; + type = _ILGetFSType(pidl); + if (type && !(type & PT_FS_UNICODE_FLAG)) + return pdata->u.file.szNames; + + if (_ILIsDrive(pidl)) + return pdata->u.drive.szDriveName; + switch (pdata->type) { case PT_GUID: @@ -2339,15 +2343,6 @@ LPSTR _ILGetTextPointer(LPCITEMIDLIST pidl) case PT_YAGUID: return NULL; - case PT_DRIVE: - case PT_DRIVE1: - case PT_DRIVE2: - case PT_DRIVE3: - return pdata->u.drive.szDriveName; - - case PT_FOLDER: - case PT_FOLDER1: - case PT_VALUE: case PT_IESPECIAL1: case PT_IESPECIAL2: return pdata->u.file.szNames; @@ -2370,15 +2365,18 @@ static LPSTR _ILGetSTextPointer(LPCITEMIDLIST pidl) { /* TRACE(pidl,"(pidl%p)\n", pidl); */ + PIDLTYPE type; LPPIDLDATA pdata =_ILGetDataPointer(pidl); - if (!pdata) return NULL; - switch (pdata->type) + type = pdata->type; + if (_ILGetFSType(pidl) && !(type & PT_FS_UNICODE_FLAG)) + type = PT_FS; + + switch (type) { - case PT_FOLDER: - case PT_VALUE: + case PT_FS: case PT_IESPECIAL1: case PT_IESPECIAL2: return pdata->u.file.szNames + strlen (pdata->u.file.szNames) + 1; @@ -2567,24 +2565,13 @@ BOOL _ILGetExtension(LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize) */ DWORD _ILGetFileAttributes(LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize) { - LPPIDLDATA pData = _ILGetDataPointer(pidl); - WORD wAttrib = 0; - int i; + DWORD wAttrib = 0; + if (_ILGetFSType(pidl)) + wAttrib = _ILGetDataPointer(pidl)->u.file.uFileAttribs; - if (!pData) - return 0; - - switch(pData->type) + if (uOutSize >= 6) { - case PT_FOLDER: - case PT_VALUE: - wAttrib = pData->u.file.uFileAttribs; - break; - } - - if(uOutSize >= 6) - { - i=0; + UINT i = 0; if(wAttrib & FILE_ATTRIBUTE_READONLY) pOut[i++] = L'R'; if(wAttrib & FILE_ATTRIBUTE_HIDDEN) diff --git a/dll/win32/shell32/wine/pidl.h b/dll/win32/shell32/wine/pidl.h index bd8e34ea4bd..7680b38645c 100644 --- a/dll/win32/shell32/wine/pidl.h +++ b/dll/win32/shell32/wine/pidl.h @@ -112,6 +112,7 @@ extern "C" { #define PT_FS_FOLDER_FLAG 0x01 #define PT_FS_FILE_FLAG 0x02 #define PT_FS_UNICODE_FLAG 0x04 +#define PT_FS_COMMON_FLAG 0x08 // PT_NET_REGITEM 0x4? // => SHDID_NET_OTHER #define PT_CONTROLS_OLDREGITEM 0x70 #define PT_CONTROLS_NEWREGITEM 0x71