Additionally, SendMessageTimeoutA is used instead of SendMessageA because notify_recipient will be called from another thread and may need to be canceled when the window is being destroyed.
Signed-off-by: Nigel Baillie metreckk@gmaill.com --- dlls/shell32/changenotify.c | 106 +++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 44 deletions(-)
diff --git a/dlls/shell32/changenotify.c b/dlls/shell32/changenotify.c index 2efb297ad5..7656f43fee 100644 --- a/dlls/shell32/changenotify.c +++ b/dlls/shell32/changenotify.c @@ -56,6 +56,15 @@ typedef struct _NOTIFICATIONLIST static struct list notifications = LIST_INIT( notifications ); static LONG next_id;
+struct new_delivery_notification +{ + LONG event; + DWORD pidl1_size; + DWORD pidl2_size; + LPITEMIDLIST pidls[2]; + BYTE data[1]; +}; + #define SHCNE_NOITEMEVENTS ( \ SHCNE_ASSOCCHANGED )
@@ -150,6 +159,58 @@ void FreeChangeNotifications(void) DeleteCriticalSection(&SHELL32_ChangenotifyCS); }
+static BOOL notify_recipient( + HWND hwnd, DWORD msg, DWORD flags, LONG event_id, + LPITEMIDLIST pidls[2], HANDLE *shared_data) +{ + LRESULT sendmsg_result = 0; + TRACE("notifying %p, event %s(%x)\n", hwnd, DumpEvent(event_id), event_id); + + if (flags & SHCNRF_NewDelivery) { + if(!(*shared_data)) { + struct new_delivery_notification *notification; + UINT size1 = ILGetSize(pidls[0]), size2 = ILGetSize(pidls[1]); + UINT offset = (size1+sizeof(int)-1)/sizeof(int)*sizeof(int); + + notification = SHAlloc(sizeof(struct new_delivery_notification)+offset+size2); + if(!notification) { + ERR("out of memory\n"); + } else { + notification->event = event_id; + notification->pidl1_size = size1; + notification->pidl2_size = size2; + if(size1) + memcpy(notification->data, pidls[0], size1); + if(size2) + memcpy(notification->data+offset, pidls[1], size2); + + *shared_data = SHAllocShared(notification, + sizeof(struct new_delivery_notification)+size1+size2, + GetCurrentProcessId()); + SHFree(notification); + } + } + + if(*shared_data) { + sendmsg_result = SendMessageTimeoutA( + hwnd, msg, (WPARAM)*shared_data, GetCurrentProcessId(), + SMTO_NOTIMEOUTIFNOTHUNG | SMTO_ERRORONEXIT, + 10000, NULL + ); + } + else + ERR("out of memory\n"); + } else { + sendmsg_result = SendMessageTimeoutA( + hwnd, msg, (WPARAM)pidls, event_id, + SMTO_NOTIMEOUTIFNOTHUNG | SMTO_ERRORONEXIT, + 10000, NULL + ); + } + + return sendmsg_result != 0; +} + /************************************************************************* * SHChangeNotifyRegister [SHELL32.2] * @@ -231,15 +292,6 @@ BOOL WINAPI SHChangeNotifyUpdateEntryList(DWORD unknown1, DWORD unknown2, return TRUE; }
-struct new_delivery_notification -{ - LONG event; - DWORD pidl1_size; - DWORD pidl2_size; - LPITEMIDLIST pidls[2]; - BYTE data[1]; -}; - static BOOL should_notify( LPCITEMIDLIST changed, LPCITEMIDLIST watched, BOOL sub ) { TRACE("%p %p %d\n", changed, watched, sub ); @@ -371,41 +423,7 @@ void WINAPI SHChangeNotify(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID
LIST_FOR_EACH_ENTRY_SAFE(cur, next, &recipients, struct notification_recipients, entry) { - TRACE("notifying %p, event %s(%x)\n", cur->hwnd, DumpEvent(wEventId), wEventId); - - if (cur->flags & SHCNRF_NewDelivery) { - if(!shared_data) { - struct new_delivery_notification *notification; - UINT size1 = ILGetSize(Pidls[0]), size2 = ILGetSize(Pidls[1]); - UINT offset = (size1+sizeof(int)-1)/sizeof(int)*sizeof(int); - - notification = SHAlloc(sizeof(struct new_delivery_notification)+offset+size2); - if(!notification) { - ERR("out of memory\n"); - } else { - notification->event = wEventId; - notification->pidl1_size = size1; - notification->pidl2_size = size2; - if(size1) - memcpy(notification->data, Pidls[0], size1); - if(size2) - memcpy(notification->data+offset, Pidls[1], size2); - - shared_data = SHAllocShared(notification, - sizeof(struct new_delivery_notification)+size1+size2, - GetCurrentProcessId()); - SHFree(notification); - } - } - - if(shared_data) - SendMessageA(cur->hwnd, cur->msg, (WPARAM)shared_data, GetCurrentProcessId()); - else - ERR("out of memory\n"); - } else { - SendMessageA(cur->hwnd, cur->msg, (WPARAM)Pidls, wEventId); - } - + notify_recipient(cur->hwnd, cur->msg, cur->flags, wEventId, Pidls, &shared_data); list_remove(&cur->entry); SHFree(cur); }