From 7c134e4d14efa98eac47e8b6b4b3589d5db8f8ac Mon Sep 17 00:00:00 2001 From: Katayama Hirofumi MZ Date: Thu, 3 Sep 2020 13:36:31 +0900 Subject: [PATCH] [SHELL32] Big fix for change notification (#3048) - Reduced the failures of SHChangeNotify testcase. - Simplified change notification mechanism. - Realized PIDL aliasing. CORE-13950 --- dll/win32/shell32/CDefView.cpp | 33 +--- dll/win32/shell32/changenotify.cpp | 187 +++++++++++++++++- .../shelldesktop/CChangeNotifyServer.cpp | 117 ++++------- .../shell32/shelldesktop/CDirectoryList.cpp | 10 + .../shelldesktop/CDirectoryWatcher.cpp | 5 +- dll/win32/shell32/stubs.cpp | 35 ---- dll/win32/shell32/wine/pidl.c | 8 +- 7 files changed, 244 insertions(+), 151 deletions(-) diff --git a/dll/win32/shell32/CDefView.cpp b/dll/win32/shell32/CDefView.cpp index 6948e572958..6495b08610e 100644 --- a/dll/win32/shell32/CDefView.cpp +++ b/dll/win32/shell32/CDefView.cpp @@ -1166,39 +1166,14 @@ LRESULT CDefView::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandl SetShellWindowEx(hwndSB, m_ListView); } - INT nRegCount; - SHChangeNotifyEntry ntreg[3]; - PIDLIST_ABSOLUTE pidls[3]; - if (_ILIsDesktop(m_pidlParent)) - { - nRegCount = 3; - SHGetSpecialFolderLocation(m_hWnd, CSIDL_DESKTOPDIRECTORY, &pidls[0]); - SHGetSpecialFolderLocation(m_hWnd, CSIDL_COMMON_DESKTOPDIRECTORY, &pidls[1]); - SHGetSpecialFolderLocation(m_hWnd, CSIDL_BITBUCKET, &pidls[2]); - ntreg[0].fRecursive = FALSE; - ntreg[0].pidl = pidls[0]; - ntreg[1].fRecursive = FALSE; - ntreg[1].pidl = pidls[1]; - ntreg[2].fRecursive = FALSE; - ntreg[2].pidl = pidls[2]; - } - else - { - nRegCount = 1; - ntreg[0].fRecursive = FALSE; - ntreg[0].pidl = m_pidlParent; - } + SHChangeNotifyEntry ntreg[1]; + ntreg[0].fRecursive = FALSE; + ntreg[0].pidl = m_pidlParent; m_hNotify = SHChangeNotifyRegister(m_hWnd, SHCNRF_InterruptLevel | SHCNRF_ShellLevel | SHCNRF_NewDelivery, SHCNE_ALLEVENTS, SHV_CHANGE_NOTIFY, - nRegCount, ntreg); - if (nRegCount == 3) - { - ILFree(pidls[0]); - ILFree(pidls[1]); - ILFree(pidls[2]); - } + 1, ntreg); /* _DoFolderViewCB(SFVM_GETNOTIFY, ?? ??) */ diff --git a/dll/win32/shell32/changenotify.cpp b/dll/win32/shell32/changenotify.cpp index ae5e0e8bdb4..08a7e632eba 100644 --- a/dll/win32/shell32/changenotify.cpp +++ b/dll/win32/shell32/changenotify.cpp @@ -294,13 +294,16 @@ CreateRegistrationParam(ULONG nRegID, HWND hwnd, UINT wMsg, INT fSources, LONG f // It creates a delivery ticket and send CN_DELIVER_NOTIFICATION message to // transport the change. static void -CreateNotificationParamAndSend(LONG wEventId, UINT uFlags, LPITEMIDLIST pidl1, LPITEMIDLIST pidl2, +CreateNotificationParamAndSend(LONG wEventId, UINT uFlags, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2, DWORD dwTick) { // get server window HWND hwndServer = GetNotificationServer(FALSE); if (hwndServer == NULL) + { + ERR("hwndServer == NULL\n"); return; + } // the ticket owner is the process of the notification server DWORD pid; @@ -314,10 +317,79 @@ CreateNotificationParamAndSend(LONG wEventId, UINT uFlags, LPITEMIDLIST pidl1, L TRACE("hTicket: %p, 0x%lx\n", hTicket, pid); // send the ticket by using CN_DELIVER_NOTIFICATION - if ((uFlags & (SHCNF_FLUSH | SHCNF_FLUSHNOWAIT)) == SHCNF_FLUSH) + if (pid != GetCurrentProcessId() || + (uFlags & (SHCNF_FLUSH | SHCNF_FLUSHNOWAIT)) == SHCNF_FLUSH) + { SendMessageW(hwndServer, CN_DELIVER_NOTIFICATION, (WPARAM)hTicket, pid); + } else + { SendNotifyMessageW(hwndServer, CN_DELIVER_NOTIFICATION, (WPARAM)hTicket, pid); + } +} + +struct ALIAS_PIDL +{ + INT csidl1; // from + INT csidl2; // to + LPITEMIDLIST pidl1; // from + LPITEMIDLIST pidl2; // to + WCHAR szPath1[MAX_PATH]; // from + WCHAR szPath2[MAX_PATH]; // to +}; + +static ALIAS_PIDL AliasPIDLs[] = +{ + { CSIDL_PERSONAL, CSIDL_PERSONAL }, + { CSIDL_DESKTOP, CSIDL_COMMON_DESKTOPDIRECTORY, }, + { CSIDL_DESKTOP, CSIDL_DESKTOPDIRECTORY }, +}; + +static VOID DoInitAliasPIDLs(void) +{ + static BOOL s_bInit = FALSE; + if (!s_bInit) + { + for (SIZE_T i = 0; i < _countof(AliasPIDLs); ++i) + { + ALIAS_PIDL *alias = &AliasPIDLs[i]; + + SHGetSpecialFolderLocation(NULL, alias->csidl1, &alias->pidl1); + SHGetPathFromIDListW(alias->pidl1, alias->szPath1); + + SHGetSpecialFolderLocation(NULL, alias->csidl2, &alias->pidl2); + SHGetPathFromIDListW(alias->pidl2, alias->szPath2); + } + s_bInit = TRUE; + } +} + +static BOOL DoGetAliasPIDLs(LPITEMIDLIST apidls[2], PCIDLIST_ABSOLUTE pidl) +{ + DoInitAliasPIDLs(); + + apidls[0] = apidls[1] = NULL; + + INT k = 0; + for (SIZE_T i = 0; i < _countof(AliasPIDLs); ++i) + { + const ALIAS_PIDL *alias = &AliasPIDLs[i]; + if (ILIsEqual(pidl, alias->pidl1)) + { + if (alias->csidl1 == alias->csidl2) + { + apidls[k++] = ILCreateFromPathW(alias->szPath2); + } + else + { + apidls[k++] = ILClone(alias->pidl2); + } + if (k >= 2) + break; + } + } + + return k > 0; } /************************************************************************* @@ -349,11 +421,10 @@ SHChangeNotifyRegister(HWND hwnd, INT fSources, LONG wEventMask, UINT uMsg, if (hwndServer == NULL) return INVALID_REG_ID; - // disable new delivery method in specific condition - if ((fSources & SHCNRF_RecursiveInterrupt) != 0 && - (fSources & SHCNRF_InterruptLevel) == 0) + // disable recursive interrupt in specific condition + if ((fSources & SHCNRF_RecursiveInterrupt) && !(fSources & SHCNRF_InterruptLevel)) { - fSources &= ~SHCNRF_NewDelivery; + fSources &= ~SHCNRF_RecursiveInterrupt; } // if it is old delivery method, then create a broker window @@ -393,13 +464,62 @@ SHChangeNotifyRegister(HWND hwnd, INT fSources, LONG wEventMask, UINT uMsg, SHFreeShared(hRegEntry, dwOwnerPID); } - // if failed, then destroy the broker - if (nRegID == INVALID_REG_ID && (fSources & SHCNRF_NewDelivery) == 0) + if (nRegID == INVALID_REG_ID) { ERR("Delivery failed\n"); - DestroyWindow(hwndBroker); + + if (hwndBroker) + { + // destroy the broker + DestroyWindow(hwndBroker); + } break; } + + // PIDL alias + LPITEMIDLIST apidlAlias[2]; + if (DoGetAliasPIDLs(apidlAlias, lpItems[iItem].pidl)) + { + if (apidlAlias[0]) + { + // create another registration entry + hRegEntry = CreateRegistrationParam(nRegID, hwnd, uMsg, fSources, wEventMask, + lpItems[iItem].fRecursive, apidlAlias[0], + dwOwnerPID, hwndBroker); + if (hRegEntry) + { + TRACE("CN_REGISTER: hwnd:%p, hRegEntry:%p, pid:0x%lx\n", + hwndServer, hRegEntry, dwOwnerPID); + + // send CN_REGISTER to the server + SendMessageW(hwndServer, CN_REGISTER, (WPARAM)hRegEntry, dwOwnerPID); + + // free registration entry + SHFreeShared(hRegEntry, dwOwnerPID); + } + ILFree(apidlAlias[0]); + } + + if (apidlAlias[1]) + { + // create another registration entry + hRegEntry = CreateRegistrationParam(nRegID, hwnd, uMsg, fSources, wEventMask, + lpItems[iItem].fRecursive, apidlAlias[1], + dwOwnerPID, hwndBroker); + if (hRegEntry) + { + TRACE("CN_REGISTER: hwnd:%p, hRegEntry:%p, pid:0x%lx\n", + hwndServer, hRegEntry, dwOwnerPID); + + // send CN_REGISTER to the server + SendMessageW(hwndServer, CN_REGISTER, (WPARAM)hRegEntry, dwOwnerPID); + + // free registration entry + SHFreeShared(hRegEntry, dwOwnerPID); + } + ILFree(apidlAlias[1]); + } + } } LeaveCriticalSection(&SHELL32_ChangenotifyCS); @@ -472,6 +592,39 @@ static LPCSTR DumpEvent(LONG event) #undef DUMPEV } +/************************************************************************* + * SHChangeRegistrationReceive [SHELL32.646] + */ +EXTERN_C BOOL WINAPI +SHChangeRegistrationReceive(LPVOID lpUnknown1, DWORD dwUnknown2) +{ + FIXME("SHChangeRegistrationReceive() stub\n"); + return FALSE; +} + +EXTERN_C VOID WINAPI +SHChangeNotifyReceiveEx(LONG lEvent, UINT uFlags, + LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2, DWORD dwTick) +{ + // TODO: Queueing notifications + CreateNotificationParamAndSend(lEvent, uFlags, pidl1, pidl2, dwTick); +} + +/************************************************************************* + * SHChangeNotifyReceive [SHELL32.643] + */ +EXTERN_C VOID WINAPI +SHChangeNotifyReceive(LONG lEvent, UINT uFlags, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) +{ + SHChangeNotifyReceiveEx(lEvent, uFlags, pidl1, pidl2, GetTickCount()); +} + +EXTERN_C VOID WINAPI +SHChangeNotifyTransmit(LONG lEvent, UINT uFlags, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2, DWORD dwTick) +{ + SHChangeNotifyReceiveEx(lEvent, uFlags, pidl1, pidl2, dwTick); +} + /************************************************************************* * SHChangeNotify [SHELL32.@] */ @@ -532,7 +685,7 @@ SHChangeNotify(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID dwItem2) if (wEventId == 0 || (wEventId & SHCNE_ASSOCCHANGED) || pidl1 != NULL) { TRACE("notifying event %s(%x)\n", DumpEvent(wEventId), wEventId); - CreateNotificationParamAndSend(wEventId, uFlags, pidl1, pidl2, dwTick); + SHChangeNotifyTransmit(wEventId, uFlags, pidl1, pidl2, dwTick); } if (pidlTemp1) @@ -610,3 +763,17 @@ NTSHChangeNotifyDeregister(ULONG hNotify) FIXME("(0x%08x):semi stub.\n", hNotify); return SHChangeNotifyDeregister(hNotify); } + +/************************************************************************* + * SHChangeNotifySuspendResume [SHELL32.277] + */ +EXTERN_C BOOL +WINAPI +SHChangeNotifySuspendResume(BOOL bSuspend, + LPITEMIDLIST pidl, + BOOL bRecursive, + DWORD dwReserved) +{ + FIXME("SHChangeNotifySuspendResume() stub\n"); + return FALSE; +} diff --git a/dll/win32/shell32/shelldesktop/CChangeNotifyServer.cpp b/dll/win32/shell32/shelldesktop/CChangeNotifyServer.cpp index 2186fe20ca4..c0835faa919 100644 --- a/dll/win32/shell32/shelldesktop/CChangeNotifyServer.cpp +++ b/dll/win32/shell32/shelldesktop/CChangeNotifyServer.cpp @@ -11,8 +11,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(shcn); -// TODO: SHCNRF_RecursiveInterrupt - ////////////////////////////////////////////////////////////////////////////// // notification target item @@ -188,10 +186,6 @@ CreateDirectoryWatcherFromRegEntry(LPREGENTRY pRegEntry) if (pRegEntry->ibPidl == 0) return NULL; - // it must be interrupt level if pRegEntry is a filesystem watch - if (!(pRegEntry->fSources & SHCNRF_InterruptLevel)) - return NULL; - // get the path WCHAR szPath[MAX_PATH]; LPITEMIDLIST pidl = (LPITEMIDLIST)((LPBYTE)pRegEntry + pRegEntry->ibPidl); @@ -249,13 +243,18 @@ LRESULT CChangeNotifyServer::OnRegister(UINT uMsg, WPARAM wParam, LPARAM lParam, } // create a directory watch if necessary - CDirectoryWatcher *pDirWatch = CreateDirectoryWatcherFromRegEntry(pRegEntry); - if (pDirWatch && !pDirWatch->RequestAddWatcher()) + CDirectoryWatcher *pDirWatch = NULL; + if (pRegEntry->ibPidl && (pRegEntry->fSources & SHCNRF_InterruptLevel)) { - pRegEntry->nRegID = INVALID_REG_ID; - SHUnlockShared(pRegEntry); - delete pDirWatch; - return FALSE; + pDirWatch = CreateDirectoryWatcherFromRegEntry(pRegEntry); + if (pDirWatch && !pDirWatch->RequestAddWatcher()) + { + ERR("RequestAddWatcher failed: %u\n", pRegEntry->nRegID); + pRegEntry->nRegID = INVALID_REG_ID; + SHUnlockShared(pRegEntry); + delete pDirWatch; + return FALSE; + } } // unlock the registry entry @@ -386,6 +385,7 @@ BOOL CChangeNotifyServer::DeliverNotification(HANDLE hTicket, DWORD dwOwnerPID) TRACE("Notifying: %p, 0x%x, %p, %lu\n", pRegEntry->hwnd, pRegEntry->uMsg, hTicket, dwOwnerPID); SendMessageW(pRegEntry->hwnd, pRegEntry->uMsg, (WPARAM)hTicket, dwOwnerPID); + TRACE("GetLastError(): %ld\n", ::GetLastError()); } // unlock the registration entry @@ -400,91 +400,58 @@ BOOL CChangeNotifyServer::DeliverNotification(HANDLE hTicket, DWORD dwOwnerPID) BOOL CChangeNotifyServer::ShouldNotify(LPDELITICKET pTicket, LPREGENTRY pRegEntry) { - LPITEMIDLIST pidl, pidl1 = NULL, pidl2 = NULL; - WCHAR szPath[MAX_PATH], szPath1[MAX_PATH], szPath2[MAX_PATH]; - INT cch, cch1, cch2; +#define RETURN(x) do { \ + TRACE("ShouldNotify return %d\n", (x)); \ + return (x); \ +} while (0) - // check fSources - if (pTicket->uFlags & SHCNE_INTERRUPT) + if (pTicket->wEventId & SHCNE_INTERRUPT) { if (!(pRegEntry->fSources & SHCNRF_InterruptLevel)) - return FALSE; + RETURN(FALSE); + if (!pRegEntry->ibPidl) + RETURN(FALSE); } else { if (!(pRegEntry->fSources & SHCNRF_ShellLevel)) - return FALSE; + RETURN(FALSE); } - if (pRegEntry->ibPidl == 0) - return TRUE; // there is no PIDL + if (!(pTicket->wEventId & pRegEntry->fEvents)) + RETURN(FALSE); - // get the stored pidl - pidl = (LPITEMIDLIST)((LPBYTE)pRegEntry + pRegEntry->ibPidl); - if (pidl->mkid.cb == 0 && pRegEntry->fRecursive) - return TRUE; // desktop is the root - - // check pidl1 + LPITEMIDLIST pidl = NULL, pidl1 = NULL, pidl2 = NULL; + if (pRegEntry->ibPidl) + pidl = (LPITEMIDLIST)((LPBYTE)pRegEntry + pRegEntry->ibPidl); if (pTicket->ibOffset1) - { pidl1 = (LPITEMIDLIST)((LPBYTE)pTicket + pTicket->ibOffset1); - if (ILIsEqual(pidl, pidl1) || ILIsParent(pidl, pidl1, !pRegEntry->fRecursive)) - return TRUE; - } - - // check pidl2 if (pTicket->ibOffset2) - { pidl2 = (LPITEMIDLIST)((LPBYTE)pTicket + pTicket->ibOffset2); - if (ILIsEqual(pidl, pidl2) || ILIsParent(pidl, pidl2, !pRegEntry->fRecursive)) - return TRUE; - } - // The paths: - // "C:\\Path\\To\\File1" - // "C:\\Path\\To\\File1Test" - // should be distinguished in comparison, so we add backslash at last as follows: - // "C:\\Path\\To\\File1\\" - // "C:\\Path\\To\\File1Test\\" - if (SHGetPathFromIDListW(pidl, szPath)) + if (pidl == NULL || (pTicket->wEventId & SHCNE_GLOBALEVENTS)) + RETURN(TRUE); + + if (pRegEntry->fRecursive) { - PathAddBackslashW(szPath); - cch = lstrlenW(szPath); - - if (pidl1 && SHGetPathFromIDListW(pidl1, szPath1)) + if (ILIsParent(pidl, pidl1, FALSE) || + (pidl2 && ILIsParent(pidl, pidl2, FALSE))) { - PathAddBackslashW(szPath1); - cch1 = lstrlenW(szPath1); - - // Is szPath1 a subfile or subdirectory of szPath? - if (cch < cch1 && - (pRegEntry->fRecursive || - wcschr(&szPath1[cch], L'\\') == &szPath1[cch1 - 1])) - { - szPath1[cch] = 0; - if (lstrcmpiW(szPath, szPath1) == 0) - return TRUE; - } + RETURN(TRUE); } - - if (pidl2 && SHGetPathFromIDListW(pidl2, szPath2)) + } + else + { + if (ILIsEqual(pidl, pidl1) || + ILIsParent(pidl, pidl1, TRUE) || + (pidl2 && ILIsParent(pidl, pidl2, TRUE))) { - PathAddBackslashW(szPath2); - cch2 = lstrlenW(szPath2); - - // Is szPath2 a subfile or subdirectory of szPath? - if (cch < cch2 && - (pRegEntry->fRecursive || - wcschr(&szPath2[cch], L'\\') == &szPath2[cch2 - 1])) - { - szPath2[cch] = 0; - if (lstrcmpiW(szPath, szPath2) == 0) - return TRUE; - } + RETURN(TRUE); } } - return FALSE; + RETURN(FALSE); +#undef RETURN } HRESULT WINAPI CChangeNotifyServer::GetWindow(HWND* phwnd) diff --git a/dll/win32/shell32/shelldesktop/CDirectoryList.cpp b/dll/win32/shell32/shelldesktop/CDirectoryList.cpp index eff446df467..2bdd36f0eb0 100644 --- a/dll/win32/shell32/shelldesktop/CDirectoryList.cpp +++ b/dll/win32/shell32/shelldesktop/CDirectoryList.cpp @@ -28,6 +28,16 @@ BOOL CDirectoryList::ContainsPath(LPCWSTR pszPath) const BOOL CDirectoryList::AddPath(LPCWSTR pszPath) { assert(!PathIsRelativeW(pszPath)); + if (ContainsPath(pszPath)) + return FALSE; + for (INT i = 0; i < m_items.GetSize(); ++i) + { + if (m_items[i].IsEmpty()) + { + m_items[i].SetPath(pszPath); + return TRUE; + } + } return m_items.Add(pszPath); } diff --git a/dll/win32/shell32/shelldesktop/CDirectoryWatcher.cpp b/dll/win32/shell32/shelldesktop/CDirectoryWatcher.cpp index 9a206ac673a..1e4a7015287 100644 --- a/dll/win32/shell32/shelldesktop/CDirectoryWatcher.cpp +++ b/dll/win32/shell32/shelldesktop/CDirectoryWatcher.cpp @@ -15,7 +15,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(shcn); static inline void NotifyFileSystemChange(LONG wEventId, LPCWSTR path1, LPCWSTR path2) { - SHChangeNotify(wEventId | SHCNE_INTERRUPT, SHCNF_PATHW, path1, path2); + SHChangeNotify(wEventId | SHCNE_INTERRUPT, SHCNF_PATHW | SHCNF_FLUSH, path1, path2); } // The handle of the APC thread @@ -138,6 +138,7 @@ void CDirectoryWatcher::ProcessNotification() WCHAR szName[MAX_PATH], szPath[MAX_PATH], szTempPath[MAX_PATH]; DWORD dwEvent, cbName; BOOL fDir; + TRACE("CDirectoryWatcher::ProcessNotification: enter\n"); // for each entry in s_buffer szPath[0] = szTempPath[0] = 0; @@ -225,6 +226,8 @@ void CDirectoryWatcher::ProcessNotification() // go next entry pInfo = (PFILE_NOTIFY_INFORMATION)((LPBYTE)pInfo + pInfo->NextEntryOffset); } + + TRACE("CDirectoryWatcher::ProcessNotification: leave\n"); } void CDirectoryWatcher::ReadCompletion(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered) diff --git a/dll/win32/shell32/stubs.cpp b/dll/win32/shell32/stubs.cpp index ebba2f3b298..a995e395509 100644 --- a/dll/win32/shell32/stubs.cpp +++ b/dll/win32/shell32/stubs.cpp @@ -329,17 +329,6 @@ CDefFolderMenu_Create(LPITEMIDLIST pidlFolder, return E_FAIL; } -/* - * Unimplemented - */ -EXTERN_C BOOL -WINAPI -SHChangeRegistrationReceive(LPVOID lpUnknown1, DWORD dwUnknown2) -{ - FIXME("SHChangeRegistrationReceive() stub\n"); - return FALSE; -} - /* * Unimplemented */ @@ -350,16 +339,6 @@ SHWaitOp_Operate(LPVOID lpUnknown1, DWORD dwUnknown2) FIXME("SHWaitOp_Operate() stub\n"); } -/* - * Unimplemented - */ -EXTERN_C VOID -WINAPI -SHChangeNotifyReceive(LONG lUnknown, UINT uUnknown, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) -{ - FIXME("SHChangeNotifyReceive() stub\n"); -} - /* * Unimplemented */ @@ -625,20 +604,6 @@ SHCreateProcessAsUserW(PSHCREATEPROCESSINFOW pscpi) return FALSE; } -/* - * Unimplemented - */ -EXTERN_C BOOL -WINAPI -SHChangeNotifySuspendResume(BOOL bSuspend, - LPITEMIDLIST pidl, - BOOL bRecursive, - DWORD dwReserved) -{ - FIXME("SHChangeNotifySuspendResume() stub\n"); - return FALSE; -} - /* * Unimplemented */ diff --git a/dll/win32/shell32/wine/pidl.c b/dll/win32/shell32/wine/pidl.c index a813f9293cd..1f27557db9b 100644 --- a/dll/win32/shell32/wine/pidl.c +++ b/dll/win32/shell32/wine/pidl.c @@ -1101,8 +1101,13 @@ LPITEMIDLIST WINAPI SHSimpleIDListFromPathA(LPCSTR lpszPath) MultiByteToWideChar(CP_ACP, 0, lpszPath, -1, wPath, len); } #ifdef __REACTOS__ + // FIXME: Needs folder attribute if (PathFileExistsW(wPath)) - return ILCreateFromPathW(wPath); + { + pidl = ILCreateFromPathW(wPath); + HeapFree(GetProcessHeap(), 0, wPath); + return pidl; + } #endif _ILParsePathW(wPath, NULL, TRUE, &pidl, NULL); @@ -1118,6 +1123,7 @@ LPITEMIDLIST WINAPI SHSimpleIDListFromPathW(LPCWSTR lpszPath) TRACE("%s\n", debugstr_w(lpszPath)); #ifdef __REACTOS__ + // FIXME: Needs folder attribute if (PathFileExistsW(lpszPath)) return ILCreateFromPathW(lpszPath); #endif