[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
This commit is contained in:
Whindmar Saksit 2025-03-25 21:26:55 +01:00 committed by GitHub
parent 151ba9ee8f
commit c1b8c4f96f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 60 additions and 50 deletions

View file

@ -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;
}
/**************************************************************************

View file

@ -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;

View file

@ -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)

View file

@ -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