[SHELL32] Translate PIDLs for change notification and ParseDisplayName (#8569)

Change notification on a folder on
Desktop was failing due to
mismatching PIDLs.
We translate PIDLs to match the
alias PIDLs.
JIRA issue: CORE-19630
JIRA issue: CORE-19820
JIRA issue: CORE-16941
- Add SHELL32_ReparentAsAliasPidl
  and SHELL32_AliasTranslatePidl
  helper functions. They translate a
  PIDL to an "alias" PIDL.
- Implement SHLogILFromFSIL
  function.
- Use SHELL32_AliasTranslatePidl
 in CDesktopFolder::ParseDisplayName
  instread of Shell_TranslateIDListAlias.
- Use SHELL32_AliasTranslatePidl
  in CreateNotificationParam.
This commit is contained in:
Katayama Hirofumi MZ
2026-01-11 20:29:54 +09:00
committed by GitHub
parent 3885311c85
commit eae4bdb95e
6 changed files with 162 additions and 19 deletions

View File

@@ -334,17 +334,41 @@ CreateNotificationParamAndSend(LONG wEventId, UINT uFlags, LPCITEMIDLIST pidl1,
if (hTicket == NULL)
return;
TRACE("hTicket: %p, 0x%lx\n", hTicket, pid);
// Create alias PIDLs
CComHeapPtr<ITEMIDLIST> pidl1Alias, pidl2Alias;
if (pidl1)
SHELL32_AliasTranslatePidl(pidl1, &pidl1Alias, ALIAS_ANY);
if (pidl2)
SHELL32_AliasTranslatePidl(pidl2, &pidl2Alias, ALIAS_ANY);
HANDLE hTicket2 = NULL;
if ((pidl1Alias || pidl2Alias) &&
(!ILIsEqual(pidl1, pidl1Alias) || !ILIsEqual(pidl2, pidl2Alias)))
{
hTicket2 = CreateNotificationParam(wEventId, uFlags, pidl1Alias, pidl2Alias,
pid, dwTick);
if (!hTicket2)
{
SHFreeShared(hTicket, pid);
return;
}
}
TRACE("hTicket:%p, hTicket2:%p, pid:0x%lx\n", hTicket, hTicket2, pid);
// send the ticket by using CN_DELIVER_NOTIFICATION
if (pid != GetCurrentProcessId() ||
(uFlags & (SHCNF_FLUSH | SHCNF_FLUSHNOWAIT)) == SHCNF_FLUSH)
{
SendMessageW(hwndServer, CN_DELIVER_NOTIFICATION, (WPARAM)hTicket, pid);
if (hTicket2)
SendMessageW(hwndServer, CN_DELIVER_NOTIFICATION, (WPARAM)hTicket2, pid);
}
else
{
SendNotifyMessageW(hwndServer, CN_DELIVER_NOTIFICATION, (WPARAM)hTicket, pid);
if (hTicket2)
SendNotifyMessageW(hwndServer, CN_DELIVER_NOTIFICATION, (WPARAM)hTicket2, pid);
}
}

View File

@@ -475,8 +475,9 @@ HRESULT WINAPI CDesktopFolder::ParseDisplayName(
{
if (BindCtx_ContainsObject(pbc, STR_PARSE_TRANSLATE_ALIASES))
{
// Use "alias" PIDL if possible
CComHeapPtr<ITEMIDLIST> pidlAlias;
if (SUCCEEDED(Shell_TranslateIDListAlias(*ppidl, NULL, &pidlAlias, 0xFFFF)))
if (SUCCEEDED(SHELL32_AliasTranslatePidl(*ppidl, &pidlAlias, ALIAS_ANY)))
{
ILFree(*ppidl);
*ppidl = pidlAlias.Detach();

View File

@@ -244,13 +244,6 @@ public:
void PostCabinetMessage(UINT Msg, WPARAM wParam, LPARAM lParam);
HRESULT
Shell_TranslateIDListAlias(
_In_ LPCITEMIDLIST pidl,
_In_ HANDLE hToken,
_Out_ LPITEMIDLIST *ppidlAlias,
_In_ DWORD dwFlags);
BOOL BindCtx_ContainsObject(_In_ IBindCtx *pBindCtx, _In_ LPCWSTR pszName);
DWORD BindCtx_GetMode(_In_ IBindCtx *pbc, _In_ DWORD dwDefault);
BOOL SHSkipJunctionBinding(_In_ IBindCtx *pbc, _In_ CLSID *pclsid);

View File

@@ -257,16 +257,6 @@ OpenEffectiveToken(
return ret;
}
HRESULT
Shell_TranslateIDListAlias(
_In_ LPCITEMIDLIST pidl,
_In_ HANDLE hToken,
_Out_ LPITEMIDLIST *ppidlAlias,
_In_ DWORD dwFlags)
{
return E_FAIL; //FIXME
}
BOOL BindCtx_ContainsObject(_In_ IBindCtx *pBindCtx, _In_ LPCWSTR pszName)
{
CComPtr<IUnknown> punk;
@@ -2091,3 +2081,113 @@ SHGetComputerDisplayNameW(
// Build a string like "Description (SERVERNAME)"
return SHELL_BuildDisplayMachineName(pszName, cchNameMax, pszServerName, szDesc);
}
typedef struct tagALIAS_MAPPING
{
BYTE bFlagMask; // The combination of ALIAS_USER_FOLDER and/or ALIAS_DESKTOP
BYTE bCommonDesktop;
WORD nCsidlSrc; // CSIDL_... (source)
WORD nCsidlDest; // CSIDL_... (destination)
} ALIAS_MAPPING, *PALIAS_MAPPING;
//! PIDL alias table
static const ALIAS_MAPPING g_AliasTable[] =
{
{
ALIAS_USER_FOLDER,
FALSE,
CSIDL_PERSONAL | CSIDL_FLAG_NO_ALIAS,
CSIDL_PERSONAL
},
{
ALIAS_USER_FOLDER | ALIAS_DESKTOP,
FALSE,
CSIDL_COMMON_DOCUMENTS | CSIDL_FLAG_NO_ALIAS,
CSIDL_COMMON_DOCUMENTS
},
{
ALIAS_DESKTOP,
FALSE,
CSIDL_DESKTOPDIRECTORY,
CSIDL_DESKTOP
},
{
ALIAS_DESKTOP,
TRUE,
CSIDL_COMMON_DESKTOPDIRECTORY,
CSIDL_DESKTOP
}
};
//! Translate a PIDL to an "alias" PIDL.
EXTERN_C BOOL
SHELL32_ReparentAsAliasPidl(
_In_opt_ HWND hwnd,
_In_opt_ HANDLE hToken,
_In_ LPCITEMIDLIST pidlTarget,
_Out_ LPITEMIDLIST *ppidlNew,
_In_ DWORD dwFlags)
{
if (!pidlTarget || !ppidlNew)
return FALSE;
*ppidlNew = NULL;
for (SIZE_T iEntry = 0; iEntry < _countof(g_AliasTable); ++iEntry)
{
const ALIAS_MAPPING *pEntry = &g_AliasTable[iEntry];
if (!(dwFlags & pEntry->bFlagMask))
continue;
// Get the source root PIDL
LPITEMIDLIST pidlSrcRoot = NULL;
HRESULT hr = SHGetFolderLocation(hwnd, pEntry->nCsidlSrc, hToken, 0, &pidlSrcRoot);
if (FAILED(hr))
continue;
// Check whether the input pidlTarget is under the source folder.
// If it matches, ILFindChild returns the relative PIDL in the pidlTarget.
LPCITEMIDLIST pidlRelative = ILFindChild(pidlSrcRoot, pidlTarget);
if (!pidlRelative) // Not found?
{
ILFree(pidlSrcRoot);
continue;
}
// Found. Get the destination root PIDL
LPITEMIDLIST pidlDestRoot = NULL;
hr = SHGetFolderLocation(hwnd, pEntry->nCsidlDest, hToken, 0, &pidlDestRoot);
if (SUCCEEDED(hr))
{
// Create a new PIDL by combining the destination root PIDL and the relative PIDL
*ppidlNew = ILCombine(pidlDestRoot, pidlRelative);
if (*ppidlNew)
{
// Manipulate specific flags in the PIDL if necessary
if (pEntry->bCommonDesktop && (*ppidlNew)->mkid.cb)
{
UINT cbRoot = ILGetSize(pidlDestRoot);
PBYTE pAttr = (PBYTE)(*ppidlNew) + cbRoot - sizeof(USHORT);
*pAttr |= (PT_FS | PT_FS_COMMON_FLAG);
}
}
ILFree(pidlDestRoot);
}
ILFree(pidlSrcRoot);
break; // A match was found, so exit the loop
}
return (*ppidlNew != NULL);
}
//! Translate a PIDL to an "alias" PIDL.
EXTERN_C HRESULT
SHELL32_AliasTranslatePidl(
_In_ LPCITEMIDLIST pidl,
_Out_ LPITEMIDLIST *ppidlNew,
_In_ DWORD dwFlags)
{
return SHELL32_ReparentAsAliasPidl(NULL, NULL, pidl, ppidlNew, dwFlags) ? S_OK : E_FAIL;
}

View File

@@ -911,11 +911,17 @@ HRESULT WINAPI SHGetRealIDL(LPSHELLFOLDER lpsf, LPCITEMIDLIST pidlSimple, LPITEM
*/
LPITEMIDLIST WINAPI SHLogILFromFSIL(LPITEMIDLIST pidl)
{
#ifdef __REACTOS__
LPITEMIDLIST pidlNew = NULL;
SHELL32_AliasTranslatePidl(pidl, &pidlNew, ALIAS_ANY);
return pidlNew;
#else
FIXME("(pidl=%p)\n",pidl);
pdump(pidl);
return 0;
#endif
}
/*************************************************************************

View File

@@ -101,6 +101,25 @@ PathProcessCommandW(
_In_ INT cchDest,
_In_ DWORD dwFlags);
HRESULT
SHELL32_AliasTranslatePidl(
_In_ LPCITEMIDLIST pidl,
_Out_ LPITEMIDLIST *ppidlNew,
_In_ DWORD dwFlags);
BOOL
SHELL32_ReparentAsAliasPidl(
_In_opt_ HWND hwnd,
_In_opt_ HANDLE hToken,
_In_ LPCITEMIDLIST pidlTarget,
_Out_ LPITEMIDLIST *ppidlNew,
_In_ DWORD dwFlags);
// Flags for SHELL32_AliasTranslatePidl and SHELL32_ReparentAsAliasPidl
#define ALIAS_USER_FOLDER 0x1
#define ALIAS_DESKTOP 0x2
#define ALIAS_ANY 0xFFFF
/****************************************************************************
* Class constructors
*/