diff --git a/dll/win32/shell32/changenotify.cpp b/dll/win32/shell32/changenotify.cpp index 9c8bdad1230..e54c93a5fc2 100644 --- a/dll/win32/shell32/changenotify.cpp +++ b/dll/win32/shell32/changenotify.cpp @@ -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 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); } } diff --git a/dll/win32/shell32/folders/CDesktopFolder.cpp b/dll/win32/shell32/folders/CDesktopFolder.cpp index 408676973a7..9ebc246a5ae 100644 --- a/dll/win32/shell32/folders/CDesktopFolder.cpp +++ b/dll/win32/shell32/folders/CDesktopFolder.cpp @@ -475,8 +475,9 @@ HRESULT WINAPI CDesktopFolder::ParseDisplayName( { if (BindCtx_ContainsObject(pbc, STR_PARSE_TRANSLATE_ALIASES)) { + // Use "alias" PIDL if possible CComHeapPtr pidlAlias; - if (SUCCEEDED(Shell_TranslateIDListAlias(*ppidl, NULL, &pidlAlias, 0xFFFF))) + if (SUCCEEDED(SHELL32_AliasTranslatePidl(*ppidl, &pidlAlias, ALIAS_ANY))) { ILFree(*ppidl); *ppidl = pidlAlias.Detach(); diff --git a/dll/win32/shell32/precomp.h b/dll/win32/shell32/precomp.h index 28930d528d2..96b79985672 100644 --- a/dll/win32/shell32/precomp.h +++ b/dll/win32/shell32/precomp.h @@ -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); diff --git a/dll/win32/shell32/utils.cpp b/dll/win32/shell32/utils.cpp index 6d759a1d1b0..81986499f02 100644 --- a/dll/win32/shell32/utils.cpp +++ b/dll/win32/shell32/utils.cpp @@ -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 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; +} diff --git a/dll/win32/shell32/wine/pidl.c b/dll/win32/shell32/wine/pidl.c index afeeef8a02f..eb3dbef2dbc 100644 --- a/dll/win32/shell32/wine/pidl.c +++ b/dll/win32/shell32/wine/pidl.c @@ -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 } /************************************************************************* diff --git a/dll/win32/shell32/wine/shell32_main.h b/dll/win32/shell32/wine/shell32_main.h index 3b47e4a01ba..a3cc22a7bb7 100644 --- a/dll/win32/shell32/wine/shell32_main.h +++ b/dll/win32/shell32/wine/shell32_main.h @@ -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 */