From 1351e23b05566b1edd8be50abb81c28fa5951bcb Mon Sep 17 00:00:00 2001 From: Mike McCormack Date: Mon, 23 Jun 2003 19:49:40 +0000 Subject: [PATCH] Change notification fixes. --- dlls/shell32/changenotify.c | 473 ++++++++++++++++++++++++------------ dlls/shell32/shell32.spec | 4 +- 2 files changed, 314 insertions(+), 163 deletions(-) diff --git a/dlls/shell32/changenotify.c b/dlls/shell32/changenotify.c index bb4af3fe96b..77d78a4a2bb 100644 --- a/dlls/shell32/changenotify.c +++ b/dlls/shell32/changenotify.c @@ -39,108 +39,134 @@ typedef struct _NOTIFICATIONLIST LPNOTIFYREGISTER apidl; /* array of entries to watch*/ UINT cidl; /* number of pidls in array */ LONG wEventMask; /* subscribed events */ + LONG wSignalledEvent; /* event that occured */ DWORD dwFlags; /* client flags */ + LPCITEMIDLIST pidlSignaled; /*pidl of the path that caused the signal*/ + } NOTIFICATIONLIST, *LPNOTIFICATIONLIST; -static NOTIFICATIONLIST head; -static NOTIFICATIONLIST tail; +static NOTIFICATIONLIST *head, *tail; -void InitChangeNotifications() +#define SHCNE_NOITEMEVENTS ( \ + SHCNE_ASSOCCHANGED ) + +#define SHCNE_ONEITEMEVENTS ( \ + SHCNE_ATTRIBUTES | SHCNE_CREATE | SHCNE_DELETE | SHCNE_DRIVEADD | \ + SHCNE_DRIVEADDGUI | SHCNE_DRIVEREMOVED | SHCNE_FREESPACE | \ + SHCNE_MEDIAINSERTED | SHCNE_MEDIAREMOVED | SHCNE_MKDIR | \ + SHCNE_NETSHARE | SHCNE_NETUNSHARE | SHCNE_RMDIR | \ + SHCNE_SERVERDISCONNECT | SHCNE_UPDATEDIR | SHCNE_UPDATEIMAGE ) + +#define SHCNE_TWOITEMEVENTS ( \ + SHCNE_RENAMEFOLDER | SHCNE_RENAMEITEM | SHCNE_UPDATEITEM ) + +/* for dumping events */ +static const char * DumpEvent( LONG event ) { - TRACE("head=%p tail=%p\n", &head, &tail); - head.next = &tail; - tail.prev = &head; + if( event == SHCNE_ALLEVENTS ) + return "SHCNE_ALLEVENTS"; +#define DUMPEV(x) ,( event & SHCNE_##x )? #x " " : "" + return wine_dbg_sprintf( "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" + DUMPEV(RENAMEITEM) + DUMPEV(CREATE) + DUMPEV(DELETE) + DUMPEV(MKDIR) + DUMPEV(RMDIR) + DUMPEV(MEDIAINSERTED) + DUMPEV(MEDIAREMOVED) + DUMPEV(DRIVEREMOVED) + DUMPEV(DRIVEADD) + DUMPEV(NETSHARE) + DUMPEV(NETUNSHARE) + DUMPEV(ATTRIBUTES) + DUMPEV(UPDATEDIR) + DUMPEV(UPDATEITEM) + DUMPEV(SERVERDISCONNECT) + DUMPEV(UPDATEIMAGE) + DUMPEV(DRIVEADDGUI) + DUMPEV(RENAMEFOLDER) + DUMPEV(FREESPACE) + DUMPEV(EXTENDED_EVENT) + DUMPEV(ASSOCCHANGED) + DUMPEV(INTERRUPT) + ); +#undef DUMPEV } -void FreeChangeNotifications() +static const char * NodeName(LPNOTIFICATIONLIST item) { - LPNOTIFICATIONLIST ptr, item; + const char *str; + WCHAR path[MAX_PATH]; - TRACE("\n"); - - EnterCriticalSection(&SHELL32_ChangenotifyCS); - ptr = head.next; - - while(ptr != &tail) - { - UINT i; - item = ptr; - ptr = ptr->next; - - TRACE("item=%p\n", item); - - /* free the item */ - for (i=0; icidl;i++) SHFree(item->apidl[i].pidlPath); - SHFree(item->apidl); - SHFree(item); - } - head.next = NULL; - tail.prev = NULL; - - LeaveCriticalSection(&SHELL32_ChangenotifyCS); - - DeleteCriticalSection(&SHELL32_ChangenotifyCS); + if(SHGetPathFromIDListW(item->apidl[0].pidlPath, path )) + str = wine_dbg_sprintf("%s", debugstr_w(path)); + else + str = wine_dbg_sprintf("" ); + return str; } -static BOOL AddNode(LPNOTIFICATIONLIST item) +static void AddNode(LPNOTIFICATIONLIST item) { - LPNOTIFICATIONLIST last; + TRACE("item %p\n", item ); - EnterCriticalSection(&SHELL32_ChangenotifyCS); - - /* get last entry */ - last = tail.prev; - - /* link items */ - last->next = item; - item->prev = last; - item->next = &tail; - tail.prev = item; - TRACE("item=%p prev=%p next=%p\n", item, item->prev, item->next); - - LeaveCriticalSection(&SHELL32_ChangenotifyCS); - - return TRUE; + /* link items */ + item->prev = tail; + item->next = NULL; + if( tail ) + tail->next = item; + else + head = item; + tail = item; } -static BOOL DeleteNode(LPNOTIFICATIONLIST item) +static LPNOTIFICATIONLIST FindNode( HANDLE hitem ) { - LPNOTIFICATIONLIST ptr; - int ret = FALSE; + LPNOTIFICATIONLIST ptr; + for( ptr = head; ptr; ptr = ptr->next ) + if( ptr == (LPNOTIFICATIONLIST) hitem ) + return ptr; + return NULL; +} - TRACE("item=%p\n", item); +static void DeleteNode(LPNOTIFICATIONLIST item) +{ + UINT i; - EnterCriticalSection(&SHELL32_ChangenotifyCS); + TRACE("item=%p prev=%p next=%p\n", item, item->prev, item->next); - ptr = head.next; - while(ptr != &tail) - { - TRACE("ptr=%p\n", ptr); + /* remove item from list */ + if( item->prev ) + item->prev->next = item->next; + else + head = item->next; + if( item->next ) + item->next->prev = item->prev; + else + tail = item->prev; - if (ptr == item) - { - UINT i; + /* free the item */ + for (i=0; icidl; i++) + SHFree(item->apidl[i].pidlPath); + SHFree(item->apidl); + SHFree(item); +} - TRACE("item=%p prev=%p next=%p\n", item, item->prev, item->next); +void InitChangeNotifications(void) +{ +} - /* remove item from list */ - item->prev->next = item->next; - item->next->prev = item->prev; +void FreeChangeNotifications(void) +{ + TRACE("\n"); - /* free the item */ - for (i=0; icidl;i++) SHFree(item->apidl[i].pidlPath); - SHFree(item->apidl); - SHFree(item); + EnterCriticalSection(&SHELL32_ChangenotifyCS); - ret = TRUE; - break; - } - ptr = ptr->next; - } + while( head ) + DeleteNode( head ); - LeaveCriticalSection(&SHELL32_ChangenotifyCS); - return ret; + LeaveCriticalSection(&SHELL32_ChangenotifyCS); + DeleteCriticalSection(&SHELL32_ChangenotifyCS); } /************************************************************************* @@ -156,53 +182,82 @@ SHChangeNotifyRegister( int cItems, LPCNOTIFYREGISTER lpItems) { - LPNOTIFICATIONLIST item; - int i; + LPNOTIFICATIONLIST item; + DWORD i; - item = SHAlloc(sizeof(NOTIFICATIONLIST)); + item = SHAlloc(sizeof(NOTIFICATIONLIST)); - TRACE("(%p,0x%08lx,0x%08lx,0x%08lx,0x%08x,%p) item=%p\n", - hwnd,dwFlags,wEventMask,uMsg,cItems,lpItems,item); + TRACE("(%p,0x%08lx,0x%08lx,0x%08lx,0x%08x,%p) item=%p\n", + hwnd,dwFlags,wEventMask,uMsg,cItems,lpItems,item); - item->next = NULL; - item->prev = NULL; - item->cidl = cItems; - item->apidl = SHAlloc(sizeof(NOTIFYREGISTER) * cItems); - for(i=0;iapidl[i].pidlPath = ILClone(lpItems[i].pidlPath); - item->apidl[i].bWatchSubtree = lpItems[i].bWatchSubtree; - } - item->hwnd = hwnd; - item->uMsg = uMsg; - item->wEventMask = wEventMask; - item->dwFlags = dwFlags; - AddNode(item); - return (HANDLE)item; + item->next = NULL; + item->prev = NULL; + item->cidl = cItems; + item->apidl = SHAlloc(sizeof(NOTIFYREGISTER) * cItems); + for(i=0;iapidl[i].pidlPath = ILClone(lpItems[i].pidlPath); + item->apidl[i].bWatchSubtree = lpItems[i].bWatchSubtree; + } + item->hwnd = hwnd; + item->uMsg = uMsg; + item->wEventMask = wEventMask; + item->wSignalledEvent = 0; + item->dwFlags = dwFlags; + + TRACE("new node: %s\n", NodeName( item )); + + EnterCriticalSection(&SHELL32_ChangenotifyCS); + + AddNode(item); + + LeaveCriticalSection(&SHELL32_ChangenotifyCS); + + return (HANDLE)item; } /************************************************************************* * SHChangeNotifyDeregister [SHELL32.4] */ -BOOL WINAPI -SHChangeNotifyDeregister(HANDLE hNotify) +BOOL WINAPI SHChangeNotifyDeregister(HANDLE hNotify) { - TRACE("(%p)\n",hNotify); + LPNOTIFICATIONLIST node; - return DeleteNode((LPNOTIFICATIONLIST)hNotify); + TRACE("(%p)\n",hNotify); + + EnterCriticalSection(&SHELL32_ChangenotifyCS); + + node = FindNode(hNotify); + if( node ) + DeleteNode(node); + + LeaveCriticalSection(&SHELL32_ChangenotifyCS); + + return node?TRUE:FALSE; } /************************************************************************* * SHChangeNotifyUpdateEntryList [SHELL32.5] */ -BOOL WINAPI -SHChangeNotifyUpdateEntryList(DWORD unknown1, DWORD unknown2, +BOOL WINAPI SHChangeNotifyUpdateEntryList(DWORD unknown1, DWORD unknown2, DWORD unknown3, DWORD unknown4) { - FIXME("(0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx)\n", - unknown1, unknown2, unknown3, unknown4); + FIXME("(0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx)\n", + unknown1, unknown2, unknown3, unknown4); - return -1; + return -1; +} + +static BOOL should_notify( LPITEMIDLIST changed, LPITEMIDLIST watched, BOOL sub ) +{ + TRACE("%p %p %d\n", changed, watched, sub ); + if ( !watched ) + return FALSE; + if (ILIsEqual( watched, changed ) ) + return TRUE; + if( sub && ILIsParent( watched, changed, FALSE ) ) + return TRUE; + return FALSE; } /************************************************************************* @@ -210,57 +265,130 @@ SHChangeNotifyUpdateEntryList(DWORD unknown1, DWORD unknown2, */ void WINAPI SHChangeNotify(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID dwItem2) { - LPITEMIDLIST Pidls[2]; - LPNOTIFICATIONLIST ptr; - DWORD dummy; - UINT typeFlag = uFlags & SHCNF_TYPE; + LPITEMIDLIST Pidls[2]; + LPNOTIFICATIONLIST ptr; + DWORD dummy; + UINT typeFlag = uFlags & SHCNF_TYPE; - Pidls[0] = (LPITEMIDLIST)dwItem1; - Pidls[1] = (LPITEMIDLIST)dwItem2; + Pidls[0] = NULL; + Pidls[1] = NULL; - TRACE("(0x%08lx,0x%08x,%p,%p):stub.\n", wEventId, uFlags, dwItem1, dwItem2); + TRACE("(0x%08lx,0x%08x,%p,%p):stub.\n", wEventId, uFlags, dwItem1, dwItem2); - /* convert paths in IDLists*/ - switch (typeFlag) - { - case SHCNF_PATHA: - if (dwItem1) SHILCreateFromPathA((LPCSTR)dwItem1, &Pidls[0], &dummy); - if (dwItem2) SHILCreateFromPathA((LPCSTR)dwItem2, &Pidls[1], &dummy); - break; - case SHCNF_PATHW: - if (dwItem1) SHILCreateFromPathW((LPCWSTR)dwItem1, &Pidls[0], &dummy); - if (dwItem2) SHILCreateFromPathW((LPCWSTR)dwItem2, &Pidls[1], &dummy); - break; - case SHCNF_PRINTERA: - case SHCNF_PRINTERW: - FIXME("SHChangeNotify with (uFlags & SHCNF_PRINTER)"); - break; - } + if( ( wEventId & SHCNE_NOITEMEVENTS ) && ( dwItem1 || dwItem2 ) ) + { + TRACE("dwItem1 and dwItem2 are not zero, but should be\n"); + dwItem1 = 0; + dwItem2 = 0; + return; + } + else if( ( wEventId & SHCNE_ONEITEMEVENTS ) && dwItem2 ) + { + TRACE("dwItem2 is not zero, but should be\n"); + dwItem2 = 0; + return; + } - EnterCriticalSection(&SHELL32_ChangenotifyCS); + if( ( ( wEventId & SHCNE_NOITEMEVENTS ) && + ( wEventId & ~SHCNE_NOITEMEVENTS ) ) || + ( ( wEventId & SHCNE_ONEITEMEVENTS ) && + ( wEventId & ~SHCNE_ONEITEMEVENTS ) ) || + ( ( wEventId & SHCNE_TWOITEMEVENTS ) && + ( wEventId & ~SHCNE_TWOITEMEVENTS ) ) ) + { + WARN("mutually incompatible events listed\n"); + return; + } - /* loop through the list */ - ptr = head.next; - while (ptr != &tail) - { - TRACE("trying %p\n", ptr); + /* convert paths in IDLists*/ + switch (typeFlag) + { + case SHCNF_PATHA: + if (dwItem1) SHILCreateFromPathA((LPCSTR)dwItem1, &Pidls[0], &dummy); + if (dwItem2) SHILCreateFromPathA((LPCSTR)dwItem2, &Pidls[1], &dummy); + break; + case SHCNF_PATHW: + if (dwItem1) SHILCreateFromPathW((LPCWSTR)dwItem1, &Pidls[0], &dummy); + if (dwItem2) SHILCreateFromPathW((LPCWSTR)dwItem2, &Pidls[1], &dummy); + break; + case SHCNF_IDLIST: + Pidls[0] = (LPITEMIDLIST)dwItem1; + Pidls[1] = (LPITEMIDLIST)dwItem2; + break; + case SHCNF_PRINTERA: + case SHCNF_PRINTERW: + FIXME("SHChangeNotify with (uFlags & SHCNF_PRINTER)"); + return; + case SHCNF_DWORD: + default: + FIXME("unknown type %08x\n",typeFlag); + return; + } - if (wEventId & ptr->wEventMask) - { - TRACE("notifying\n"); - SendMessageA(ptr->hwnd, ptr->uMsg, (WPARAM)&Pidls, (LPARAM)wEventId); - } - ptr = ptr->next; - } + { + WCHAR path[MAX_PATH]; - LeaveCriticalSection(&SHELL32_ChangenotifyCS); + if( Pidls[0] && SHGetPathFromIDListW(Pidls[0], path )) + TRACE("notify %08lx on item1 = %s\n", wEventId, debugstr_w(path)); + + if( Pidls[1] && SHGetPathFromIDListW(Pidls[1], path )) + TRACE("notify %08lx on item2 = %s\n", wEventId, debugstr_w(path)); + } - /* if we allocated it, free it */ - if ((typeFlag == SHCNF_PATHA) || (typeFlag == SHCNF_PATHW)) - { - if (Pidls[0]) SHFree(Pidls[0]); - if (Pidls[1]) SHFree(Pidls[1]); - } + EnterCriticalSection(&SHELL32_ChangenotifyCS); + + /* loop through the list */ + for( ptr = head; ptr; ptr = ptr->next ) + { + BOOL notify; + DWORD i; + + notify = FALSE; + + TRACE("trying %p\n", ptr); + + for( i=0; (icidl) && !notify ; i++ ) + { + LPITEMIDLIST pidl = ptr->apidl[i].pidlPath; + BOOL subtree = ptr->apidl[i].bWatchSubtree; + + if (wEventId & ptr->wEventMask) + { + if( !pidl ) /* all ? */ + notify = TRUE; + else if( wEventId & SHCNE_NOITEMEVENTS ) + notify = TRUE; + else if( wEventId & ( SHCNE_ONEITEMEVENTS | SHCNE_TWOITEMEVENTS ) ) + notify = should_notify( Pidls[0], pidl, subtree ); + else if( wEventId & SHCNE_TWOITEMEVENTS ) + notify = should_notify( Pidls[1], pidl, subtree ); + } + } + + if( !notify ) + continue; + + ptr->pidlSignaled = ILClone(Pidls[0]); + + TRACE("notifying %s, event %s(%lx) before\n", NodeName( ptr ), DumpEvent( + wEventId ),wEventId ); + + ptr->wSignalledEvent |= wEventId; + SendMessageA(ptr->hwnd, ptr->uMsg, (WPARAM)ptr, GetCurrentProcessId()); + + TRACE("notifying %s, event %s(%lx) after\n", NodeName( ptr ), DumpEvent( + wEventId ),wEventId ); + + } + TRACE("notify Done\n"); + LeaveCriticalSection(&SHELL32_ChangenotifyCS); + + /* if we allocated it, free it */ + if ((typeFlag == SHCNF_PATHA) || (typeFlag == SHCNF_PATHW)) + { + if (Pidls[0]) SHFree(Pidls[0]); + if (Pidls[1]) SHFree(Pidls[1]); + } } /************************************************************************* @@ -275,34 +403,56 @@ DWORD WINAPI NTSHChangeNotifyRegister( LONG events2, DWORD msg, int count, - LPNOTIFYREGISTER idlist) + LPCNOTIFYREGISTER idlist) { - FIXME("(%p,0x%08lx,0x%08lx,0x%08lx,0x%08x,%p):stub.\n", + FIXME("(%p,0x%08lx,0x%08lx,0x%08lx,0x%08x,%p):semi stub.\n", hwnd,events1,events2,msg,count,idlist); - return 0; + + return (DWORD) SHChangeNotifyRegister(hwnd, events1, events2, msg, count, idlist); } /************************************************************************* * SHChangeNotification_Lock [SHELL32.644] */ HANDLE WINAPI SHChangeNotification_Lock( - HANDLE hMemoryMap, + HANDLE hChange, DWORD dwProcessId, - LPCITEMIDLIST **lppidls, + LPITEMIDLIST **lppidls, LPLONG lpwEventId) { - FIXME("\n"); - return 0; + DWORD i; + LPNOTIFICATIONLIST node; + LPCITEMIDLIST *idlist; + + TRACE("%p %08lx %p %p\n", hChange, dwProcessId, lppidls, lpwEventId); + + /* EnterCriticalSection(&SHELL32_ChangenotifyCS); */ + + node = FindNode( hChange ); + if( node ) + { + idlist = SHAlloc( sizeof(LPCITEMIDLIST *) * node->cidl ); + for(i=0; icidl; i++) + idlist[i] = node->pidlSignaled; + *lpwEventId = node->wSignalledEvent; + *lppidls = idlist; + node->wSignalledEvent = 0; + } + else + ERR("Couldn't find %p\n", hChange ); + + /* LeaveCriticalSection(&SHELL32_ChangenotifyCS); */ + + return (HANDLE) node; } /************************************************************************* * SHChangeNotification_Unlock [SHELL32.645] */ -BOOL WINAPI SHChangeNotification_Unlock ( - HANDLE hLock) +BOOL WINAPI SHChangeNotification_Unlock ( HANDLE hLock) { - FIXME("\n"); - return 0; + TRACE("\n"); + return 1; } /************************************************************************* @@ -310,6 +460,7 @@ BOOL WINAPI SHChangeNotification_Unlock ( */ DWORD WINAPI NTSHChangeNotifyDeregister(LONG x1) { - FIXME("(0x%08lx):stub.\n",x1); - return 0; + FIXME("(0x%08lx):semi stub.\n",x1); + + return SHChangeNotifyDeregister( (HANDLE)x1 ); } diff --git a/dlls/shell32/shell32.spec b/dlls/shell32/shell32.spec index b301ce1ce69..c1cad1149ea 100644 --- a/dlls/shell32/shell32.spec +++ b/dlls/shell32/shell32.spec @@ -281,8 +281,8 @@ 641 stdcall NTSHChangeNotifyDeregister (long) 643 stub SHChangeNotifyReceive@16 - 644 stub SHChangeNotification_Lock@16 - 645 stub SHChangeNotification_Unlock@4 + 644 stdcall SHChangeNotification_Lock(long long ptr ptr) + 645 stdcall SHChangeNotification_Unlock(long) 646 stub SHChangeRegistrationReceive@8 647 stub ReceiveAddToRecentDocs@8 648 stub SHWaitOp_Operate@8