[SHELL32] Big fix for change notification (#3048)

- Reduced the failures of SHChangeNotify testcase.
- Simplified change notification mechanism.
- Realized PIDL aliasing.
CORE-13950
This commit is contained in:
Katayama Hirofumi MZ 2020-09-03 13:36:31 +09:00 committed by GitHub
parent 7ffb6a09c3
commit 7c134e4d14
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 244 additions and 151 deletions

View file

@ -1166,39 +1166,14 @@ LRESULT CDefView::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandl
SetShellWindowEx(hwndSB, m_ListView); SetShellWindowEx(hwndSB, m_ListView);
} }
INT nRegCount; SHChangeNotifyEntry ntreg[1];
SHChangeNotifyEntry ntreg[3]; ntreg[0].fRecursive = FALSE;
PIDLIST_ABSOLUTE pidls[3]; ntreg[0].pidl = m_pidlParent;
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;
}
m_hNotify = SHChangeNotifyRegister(m_hWnd, m_hNotify = SHChangeNotifyRegister(m_hWnd,
SHCNRF_InterruptLevel | SHCNRF_ShellLevel | SHCNRF_InterruptLevel | SHCNRF_ShellLevel |
SHCNRF_NewDelivery, SHCNRF_NewDelivery,
SHCNE_ALLEVENTS, SHV_CHANGE_NOTIFY, SHCNE_ALLEVENTS, SHV_CHANGE_NOTIFY,
nRegCount, ntreg); 1, ntreg);
if (nRegCount == 3)
{
ILFree(pidls[0]);
ILFree(pidls[1]);
ILFree(pidls[2]);
}
/* _DoFolderViewCB(SFVM_GETNOTIFY, ?? ??) */ /* _DoFolderViewCB(SFVM_GETNOTIFY, ?? ??) */

View file

@ -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 // It creates a delivery ticket and send CN_DELIVER_NOTIFICATION message to
// transport the change. // transport the change.
static void static void
CreateNotificationParamAndSend(LONG wEventId, UINT uFlags, LPITEMIDLIST pidl1, LPITEMIDLIST pidl2, CreateNotificationParamAndSend(LONG wEventId, UINT uFlags, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2,
DWORD dwTick) DWORD dwTick)
{ {
// get server window // get server window
HWND hwndServer = GetNotificationServer(FALSE); HWND hwndServer = GetNotificationServer(FALSE);
if (hwndServer == NULL) if (hwndServer == NULL)
{
ERR("hwndServer == NULL\n");
return; return;
}
// the ticket owner is the process of the notification server // the ticket owner is the process of the notification server
DWORD pid; DWORD pid;
@ -314,10 +317,79 @@ CreateNotificationParamAndSend(LONG wEventId, UINT uFlags, LPITEMIDLIST pidl1, L
TRACE("hTicket: %p, 0x%lx\n", hTicket, pid); TRACE("hTicket: %p, 0x%lx\n", hTicket, pid);
// send the ticket by using CN_DELIVER_NOTIFICATION // 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); SendMessageW(hwndServer, CN_DELIVER_NOTIFICATION, (WPARAM)hTicket, pid);
}
else else
{
SendNotifyMessageW(hwndServer, CN_DELIVER_NOTIFICATION, (WPARAM)hTicket, pid); 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) if (hwndServer == NULL)
return INVALID_REG_ID; return INVALID_REG_ID;
// disable new delivery method in specific condition // disable recursive interrupt in specific condition
if ((fSources & SHCNRF_RecursiveInterrupt) != 0 && if ((fSources & SHCNRF_RecursiveInterrupt) && !(fSources & SHCNRF_InterruptLevel))
(fSources & SHCNRF_InterruptLevel) == 0)
{ {
fSources &= ~SHCNRF_NewDelivery; fSources &= ~SHCNRF_RecursiveInterrupt;
} }
// if it is old delivery method, then create a broker window // 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); SHFreeShared(hRegEntry, dwOwnerPID);
} }
// if failed, then destroy the broker if (nRegID == INVALID_REG_ID)
if (nRegID == INVALID_REG_ID && (fSources & SHCNRF_NewDelivery) == 0)
{ {
ERR("Delivery failed\n"); ERR("Delivery failed\n");
DestroyWindow(hwndBroker);
if (hwndBroker)
{
// destroy the broker
DestroyWindow(hwndBroker);
}
break; 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); LeaveCriticalSection(&SHELL32_ChangenotifyCS);
@ -472,6 +592,39 @@ static LPCSTR DumpEvent(LONG event)
#undef DUMPEV #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.@] * SHChangeNotify [SHELL32.@]
*/ */
@ -532,7 +685,7 @@ SHChangeNotify(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID dwItem2)
if (wEventId == 0 || (wEventId & SHCNE_ASSOCCHANGED) || pidl1 != NULL) if (wEventId == 0 || (wEventId & SHCNE_ASSOCCHANGED) || pidl1 != NULL)
{ {
TRACE("notifying event %s(%x)\n", DumpEvent(wEventId), wEventId); TRACE("notifying event %s(%x)\n", DumpEvent(wEventId), wEventId);
CreateNotificationParamAndSend(wEventId, uFlags, pidl1, pidl2, dwTick); SHChangeNotifyTransmit(wEventId, uFlags, pidl1, pidl2, dwTick);
} }
if (pidlTemp1) if (pidlTemp1)
@ -610,3 +763,17 @@ NTSHChangeNotifyDeregister(ULONG hNotify)
FIXME("(0x%08x):semi stub.\n", hNotify); FIXME("(0x%08x):semi stub.\n", hNotify);
return SHChangeNotifyDeregister(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;
}

View file

@ -11,8 +11,6 @@
WINE_DEFAULT_DEBUG_CHANNEL(shcn); WINE_DEFAULT_DEBUG_CHANNEL(shcn);
// TODO: SHCNRF_RecursiveInterrupt
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// notification target item // notification target item
@ -188,10 +186,6 @@ CreateDirectoryWatcherFromRegEntry(LPREGENTRY pRegEntry)
if (pRegEntry->ibPidl == 0) if (pRegEntry->ibPidl == 0)
return NULL; return NULL;
// it must be interrupt level if pRegEntry is a filesystem watch
if (!(pRegEntry->fSources & SHCNRF_InterruptLevel))
return NULL;
// get the path // get the path
WCHAR szPath[MAX_PATH]; WCHAR szPath[MAX_PATH];
LPITEMIDLIST pidl = (LPITEMIDLIST)((LPBYTE)pRegEntry + pRegEntry->ibPidl); 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 // create a directory watch if necessary
CDirectoryWatcher *pDirWatch = CreateDirectoryWatcherFromRegEntry(pRegEntry); CDirectoryWatcher *pDirWatch = NULL;
if (pDirWatch && !pDirWatch->RequestAddWatcher()) if (pRegEntry->ibPidl && (pRegEntry->fSources & SHCNRF_InterruptLevel))
{ {
pRegEntry->nRegID = INVALID_REG_ID; pDirWatch = CreateDirectoryWatcherFromRegEntry(pRegEntry);
SHUnlockShared(pRegEntry); if (pDirWatch && !pDirWatch->RequestAddWatcher())
delete pDirWatch; {
return FALSE; ERR("RequestAddWatcher failed: %u\n", pRegEntry->nRegID);
pRegEntry->nRegID = INVALID_REG_ID;
SHUnlockShared(pRegEntry);
delete pDirWatch;
return FALSE;
}
} }
// unlock the registry entry // unlock the registry entry
@ -386,6 +385,7 @@ BOOL CChangeNotifyServer::DeliverNotification(HANDLE hTicket, DWORD dwOwnerPID)
TRACE("Notifying: %p, 0x%x, %p, %lu\n", TRACE("Notifying: %p, 0x%x, %p, %lu\n",
pRegEntry->hwnd, pRegEntry->uMsg, hTicket, dwOwnerPID); pRegEntry->hwnd, pRegEntry->uMsg, hTicket, dwOwnerPID);
SendMessageW(pRegEntry->hwnd, pRegEntry->uMsg, (WPARAM)hTicket, dwOwnerPID); SendMessageW(pRegEntry->hwnd, pRegEntry->uMsg, (WPARAM)hTicket, dwOwnerPID);
TRACE("GetLastError(): %ld\n", ::GetLastError());
} }
// unlock the registration entry // unlock the registration entry
@ -400,91 +400,58 @@ BOOL CChangeNotifyServer::DeliverNotification(HANDLE hTicket, DWORD dwOwnerPID)
BOOL CChangeNotifyServer::ShouldNotify(LPDELITICKET pTicket, LPREGENTRY pRegEntry) BOOL CChangeNotifyServer::ShouldNotify(LPDELITICKET pTicket, LPREGENTRY pRegEntry)
{ {
LPITEMIDLIST pidl, pidl1 = NULL, pidl2 = NULL; #define RETURN(x) do { \
WCHAR szPath[MAX_PATH], szPath1[MAX_PATH], szPath2[MAX_PATH]; TRACE("ShouldNotify return %d\n", (x)); \
INT cch, cch1, cch2; return (x); \
} while (0)
// check fSources if (pTicket->wEventId & SHCNE_INTERRUPT)
if (pTicket->uFlags & SHCNE_INTERRUPT)
{ {
if (!(pRegEntry->fSources & SHCNRF_InterruptLevel)) if (!(pRegEntry->fSources & SHCNRF_InterruptLevel))
return FALSE; RETURN(FALSE);
if (!pRegEntry->ibPidl)
RETURN(FALSE);
} }
else else
{ {
if (!(pRegEntry->fSources & SHCNRF_ShellLevel)) if (!(pRegEntry->fSources & SHCNRF_ShellLevel))
return FALSE; RETURN(FALSE);
} }
if (pRegEntry->ibPidl == 0) if (!(pTicket->wEventId & pRegEntry->fEvents))
return TRUE; // there is no PIDL RETURN(FALSE);
// get the stored pidl LPITEMIDLIST pidl = NULL, pidl1 = NULL, pidl2 = NULL;
pidl = (LPITEMIDLIST)((LPBYTE)pRegEntry + pRegEntry->ibPidl); if (pRegEntry->ibPidl)
if (pidl->mkid.cb == 0 && pRegEntry->fRecursive) pidl = (LPITEMIDLIST)((LPBYTE)pRegEntry + pRegEntry->ibPidl);
return TRUE; // desktop is the root
// check pidl1
if (pTicket->ibOffset1) if (pTicket->ibOffset1)
{
pidl1 = (LPITEMIDLIST)((LPBYTE)pTicket + pTicket->ibOffset1); pidl1 = (LPITEMIDLIST)((LPBYTE)pTicket + pTicket->ibOffset1);
if (ILIsEqual(pidl, pidl1) || ILIsParent(pidl, pidl1, !pRegEntry->fRecursive))
return TRUE;
}
// check pidl2
if (pTicket->ibOffset2) if (pTicket->ibOffset2)
{
pidl2 = (LPITEMIDLIST)((LPBYTE)pTicket + pTicket->ibOffset2); pidl2 = (LPITEMIDLIST)((LPBYTE)pTicket + pTicket->ibOffset2);
if (ILIsEqual(pidl, pidl2) || ILIsParent(pidl, pidl2, !pRegEntry->fRecursive))
return TRUE;
}
// The paths: if (pidl == NULL || (pTicket->wEventId & SHCNE_GLOBALEVENTS))
// "C:\\Path\\To\\File1" RETURN(TRUE);
// "C:\\Path\\To\\File1Test"
// should be distinguished in comparison, so we add backslash at last as follows: if (pRegEntry->fRecursive)
// "C:\\Path\\To\\File1\\"
// "C:\\Path\\To\\File1Test\\"
if (SHGetPathFromIDListW(pidl, szPath))
{ {
PathAddBackslashW(szPath); if (ILIsParent(pidl, pidl1, FALSE) ||
cch = lstrlenW(szPath); (pidl2 && ILIsParent(pidl, pidl2, FALSE)))
if (pidl1 && SHGetPathFromIDListW(pidl1, szPath1))
{ {
PathAddBackslashW(szPath1); RETURN(TRUE);
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;
}
} }
}
if (pidl2 && SHGetPathFromIDListW(pidl2, szPath2)) else
{
if (ILIsEqual(pidl, pidl1) ||
ILIsParent(pidl, pidl1, TRUE) ||
(pidl2 && ILIsParent(pidl, pidl2, TRUE)))
{ {
PathAddBackslashW(szPath2); RETURN(TRUE);
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 FALSE; RETURN(FALSE);
#undef RETURN
} }
HRESULT WINAPI CChangeNotifyServer::GetWindow(HWND* phwnd) HRESULT WINAPI CChangeNotifyServer::GetWindow(HWND* phwnd)

View file

@ -28,6 +28,16 @@ BOOL CDirectoryList::ContainsPath(LPCWSTR pszPath) const
BOOL CDirectoryList::AddPath(LPCWSTR pszPath) BOOL CDirectoryList::AddPath(LPCWSTR pszPath)
{ {
assert(!PathIsRelativeW(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); return m_items.Add(pszPath);
} }

View file

@ -15,7 +15,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(shcn);
static inline void static inline void
NotifyFileSystemChange(LONG wEventId, LPCWSTR path1, LPCWSTR path2) 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 // The handle of the APC thread
@ -138,6 +138,7 @@ void CDirectoryWatcher::ProcessNotification()
WCHAR szName[MAX_PATH], szPath[MAX_PATH], szTempPath[MAX_PATH]; WCHAR szName[MAX_PATH], szPath[MAX_PATH], szTempPath[MAX_PATH];
DWORD dwEvent, cbName; DWORD dwEvent, cbName;
BOOL fDir; BOOL fDir;
TRACE("CDirectoryWatcher::ProcessNotification: enter\n");
// for each entry in s_buffer // for each entry in s_buffer
szPath[0] = szTempPath[0] = 0; szPath[0] = szTempPath[0] = 0;
@ -225,6 +226,8 @@ void CDirectoryWatcher::ProcessNotification()
// go next entry // go next entry
pInfo = (PFILE_NOTIFY_INFORMATION)((LPBYTE)pInfo + pInfo->NextEntryOffset); pInfo = (PFILE_NOTIFY_INFORMATION)((LPBYTE)pInfo + pInfo->NextEntryOffset);
} }
TRACE("CDirectoryWatcher::ProcessNotification: leave\n");
} }
void CDirectoryWatcher::ReadCompletion(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered) void CDirectoryWatcher::ReadCompletion(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered)

View file

@ -329,17 +329,6 @@ CDefFolderMenu_Create(LPITEMIDLIST pidlFolder,
return E_FAIL; return E_FAIL;
} }
/*
* Unimplemented
*/
EXTERN_C BOOL
WINAPI
SHChangeRegistrationReceive(LPVOID lpUnknown1, DWORD dwUnknown2)
{
FIXME("SHChangeRegistrationReceive() stub\n");
return FALSE;
}
/* /*
* Unimplemented * Unimplemented
*/ */
@ -350,16 +339,6 @@ SHWaitOp_Operate(LPVOID lpUnknown1, DWORD dwUnknown2)
FIXME("SHWaitOp_Operate() stub\n"); FIXME("SHWaitOp_Operate() stub\n");
} }
/*
* Unimplemented
*/
EXTERN_C VOID
WINAPI
SHChangeNotifyReceive(LONG lUnknown, UINT uUnknown, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
{
FIXME("SHChangeNotifyReceive() stub\n");
}
/* /*
* Unimplemented * Unimplemented
*/ */
@ -625,20 +604,6 @@ SHCreateProcessAsUserW(PSHCREATEPROCESSINFOW pscpi)
return FALSE; return FALSE;
} }
/*
* Unimplemented
*/
EXTERN_C BOOL
WINAPI
SHChangeNotifySuspendResume(BOOL bSuspend,
LPITEMIDLIST pidl,
BOOL bRecursive,
DWORD dwReserved)
{
FIXME("SHChangeNotifySuspendResume() stub\n");
return FALSE;
}
/* /*
* Unimplemented * Unimplemented
*/ */

View file

@ -1101,8 +1101,13 @@ LPITEMIDLIST WINAPI SHSimpleIDListFromPathA(LPCSTR lpszPath)
MultiByteToWideChar(CP_ACP, 0, lpszPath, -1, wPath, len); MultiByteToWideChar(CP_ACP, 0, lpszPath, -1, wPath, len);
} }
#ifdef __REACTOS__ #ifdef __REACTOS__
// FIXME: Needs folder attribute
if (PathFileExistsW(wPath)) if (PathFileExistsW(wPath))
return ILCreateFromPathW(wPath); {
pidl = ILCreateFromPathW(wPath);
HeapFree(GetProcessHeap(), 0, wPath);
return pidl;
}
#endif #endif
_ILParsePathW(wPath, NULL, TRUE, &pidl, NULL); _ILParsePathW(wPath, NULL, TRUE, &pidl, NULL);
@ -1118,6 +1123,7 @@ LPITEMIDLIST WINAPI SHSimpleIDListFromPathW(LPCWSTR lpszPath)
TRACE("%s\n", debugstr_w(lpszPath)); TRACE("%s\n", debugstr_w(lpszPath));
#ifdef __REACTOS__ #ifdef __REACTOS__
// FIXME: Needs folder attribute
if (PathFileExistsW(lpszPath)) if (PathFileExistsW(lpszPath))
return ILCreateFromPathW(lpszPath); return ILCreateFromPathW(lpszPath);
#endif #endif