2 * shell change notification
4 * Copyright 2000 Juergen Schmied
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define WIN32_NO_STATUS
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
26 #define BUFFER_SIZE 1024
32 #include <undocshell.h>
34 #include <wine/debug.h>
35 #include <wine/list.h>
40 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
42 static CRITICAL_SECTION SHELL32_ChangenotifyCS
;
43 static CRITICAL_SECTION_DEBUG critsect_debug
=
45 0, 0, &SHELL32_ChangenotifyCS
,
46 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
47 0, 0, { (DWORD_PTR
)(__FILE__
": SHELL32_ChangenotifyCS") }
49 static CRITICAL_SECTION SHELL32_ChangenotifyCS
= { &critsect_debug
, -1, 0, 0, 0, 0 };
53 PCIDLIST_ABSOLUTE pidl
;
55 /* File system notification items */
56 HANDLE hDirectory
; /* Directory handle */
57 WCHAR wstrDirectory
[MAX_PATH
]; /* Directory name */
58 OVERLAPPED overlapped
; /* Overlapped structure */
59 BYTE
*buffer
; /* Async buffer to fill */
60 BYTE
*backBuffer
; /* Back buffer to swap buffer into */
61 struct _NOTIFICATIONLIST
* pParent
;
62 } SHChangeNotifyEntryInternal
, *LPNOTIFYREGISTER
;
64 typedef SHChangeNotifyEntry
*LPNOTIFYREGISTER
;
67 /* internal list of notification clients (internal) */
68 typedef struct _NOTIFICATIONLIST
71 HWND hwnd
; /* window to notify */
72 DWORD uMsg
; /* message to send */
73 LPNOTIFYREGISTER apidl
; /* array of entries to watch*/
74 UINT cidl
; /* number of pidls in array */
75 LONG wEventMask
; /* subscribed events */
76 DWORD dwFlags
; /* client flags */
79 volatile LONG wQueuedCount
;
81 } NOTIFICATIONLIST
, *LPNOTIFICATIONLIST
;
84 VOID
_ProcessNotification(LPNOTIFYREGISTER item
);
85 BOOL
_OpenDirectory(LPNOTIFYREGISTER item
);
86 static void CALLBACK
_RequestTermination(ULONG_PTR arg
);
87 static void CALLBACK
_RequestAllTermination(ULONG_PTR arg
);
88 static void CALLBACK
_AddDirectoryProc(ULONG_PTR arg
);
89 static VOID
_BeginRead(LPNOTIFYREGISTER item
);
90 static unsigned int WINAPI
_RunAsyncThreadProc(LPVOID arg
);
93 static struct list notifications
= LIST_INIT( notifications
);
102 #define SHCNE_NOITEMEVENTS ( \
105 #define SHCNE_ONEITEMEVENTS ( \
106 SHCNE_ATTRIBUTES | SHCNE_CREATE | SHCNE_DELETE | SHCNE_DRIVEADD | \
107 SHCNE_DRIVEADDGUI | SHCNE_DRIVEREMOVED | SHCNE_FREESPACE | \
108 SHCNE_MEDIAINSERTED | SHCNE_MEDIAREMOVED | SHCNE_MKDIR | \
109 SHCNE_NETSHARE | SHCNE_NETUNSHARE | SHCNE_RMDIR | \
110 SHCNE_SERVERDISCONNECT | SHCNE_UPDATEDIR | SHCNE_UPDATEIMAGE )
112 #define SHCNE_TWOITEMEVENTS ( \
113 SHCNE_RENAMEFOLDER | SHCNE_RENAMEITEM | SHCNE_UPDATEITEM )
115 /* for dumping events */
116 static const char * DumpEvent( LONG event
)
118 if( event
== SHCNE_ALLEVENTS
)
119 return "SHCNE_ALLEVENTS";
120 #define DUMPEV(x) ,( event & SHCNE_##x )? #x " " : ""
121 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"
127 DUMPEV(MEDIAINSERTED
)
136 DUMPEV(SERVERDISCONNECT
)
141 DUMPEV(EXTENDED_EVENT
)
148 static const char * NodeName(const NOTIFICATIONLIST
*item
)
151 WCHAR path
[MAX_PATH
];
153 if(SHGetPathFromIDListW(item
->apidl
[0].pidl
, path
))
154 str
= wine_dbg_sprintf("%s", debugstr_w(path
));
156 str
= wine_dbg_sprintf("<not a disk file>" );
160 static void DeleteNode(LPNOTIFICATIONLIST item
)
167 TRACE("item=%p\n", item
);
170 queued
= InterlockedCompareExchange(&item
->wQueuedCount
, 0, 0);
173 TRACE("Not freeing, still %d queued events\n", queued
);
176 TRACE("Freeing for real!\n");
179 /* remove item from list */
180 list_remove( &item
->entry
);
183 for (i
=0; i
<item
->cidl
; i
++)
186 QueueUserAPC(_RequestTermination
, m_hThread
, (ULONG_PTR
) &item
->apidl
[i
] );
187 WaitForSingleObjectEx(m_hThread
, 100, FALSE
);
189 SHFree((LPITEMIDLIST
)item
->apidl
[i
].pidl
);
191 SHFree(item
->apidl
[i
].buffer
);
192 SHFree(item
->apidl
[i
].backBuffer
);
199 void InitChangeNotifications(void)
206 void FreeChangeNotifications(void)
208 LPNOTIFICATIONLIST ptr
, next
;
212 EnterCriticalSection(&SHELL32_ChangenotifyCS
);
214 LIST_FOR_EACH_ENTRY_SAFE( ptr
, next
, ¬ifications
, NOTIFICATIONLIST
, entry
)
217 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
220 QueueUserAPC(_RequestAllTermination
, m_hThread
, (ULONG_PTR
) NULL
);
223 DeleteCriticalSection(&SHELL32_ChangenotifyCS
);
226 /*************************************************************************
227 * SHChangeNotifyRegister [SHELL32.2]
231 SHChangeNotifyRegister(
237 SHChangeNotifyEntry
*lpItems
)
239 LPNOTIFICATIONLIST item
;
242 item
= SHAlloc(sizeof(NOTIFICATIONLIST
));
244 TRACE("(%p,0x%08x,0x%08x,0x%08x,%d,%p) item=%p\n",
245 hwnd
, fSources
, wEventMask
, uMsg
, cItems
, lpItems
, item
);
249 m_hThread
= (HANDLE
) _beginthreadex(NULL
, 0, _RunAsyncThreadProc
, NULL
, 0, &m_dwThreadId
);
254 item
->apidl
= SHAlloc(sizeof(SHChangeNotifyEntryInternal
) * cItems
);
255 item
->wQueuedCount
= 0;
257 item
->apidl
= SHAlloc(sizeof(SHChangeNotifyEntry
) * cItems
);
259 for(i
=0;i
<cItems
;i
++)
262 ZeroMemory(&item
->apidl
[i
], sizeof(SHChangeNotifyEntryInternal
));
264 item
->apidl
[i
].pidl
= ILClone(lpItems
[i
].pidl
);
265 item
->apidl
[i
].fRecursive
= lpItems
[i
].fRecursive
;
267 item
->apidl
[i
].buffer
= SHAlloc(BUFFER_SIZE
);
268 item
->apidl
[i
].backBuffer
= SHAlloc(BUFFER_SIZE
);
269 item
->apidl
[i
].overlapped
.hEvent
= &item
->apidl
[i
];
270 item
->apidl
[i
].pParent
= item
;
272 if (fSources
& SHCNRF_InterruptLevel
)
274 if (_OpenDirectory( &item
->apidl
[i
] ))
276 InterlockedIncrement(&item
->wQueuedCount
);
277 QueueUserAPC( _AddDirectoryProc
, m_hThread
, (ULONG_PTR
) &item
->apidl
[i
] );
281 CHAR buffer
[MAX_PATH
];
282 if (!SHGetPathFromIDListA( item
->apidl
[i
].pidl
, buffer
))
283 strcpy( buffer
, "<unknown>" );
284 ERR("_OpenDirectory failed for %s\n", buffer
);
291 item
->wEventMask
= wEventMask
;
292 item
->dwFlags
= fSources
;
293 item
->id
= InterlockedIncrement( &next_id
);
295 TRACE("new node: %s\n", NodeName( item
));
297 EnterCriticalSection(&SHELL32_ChangenotifyCS
);
299 list_add_tail( ¬ifications
, &item
->entry
);
301 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
306 /*************************************************************************
307 * SHChangeNotifyDeregister [SHELL32.4]
309 BOOL WINAPI
SHChangeNotifyDeregister(ULONG hNotify
)
311 LPNOTIFICATIONLIST node
;
313 TRACE("(0x%08x)\n", hNotify
);
315 EnterCriticalSection(&SHELL32_ChangenotifyCS
);
317 LIST_FOR_EACH_ENTRY( node
, ¬ifications
, NOTIFICATIONLIST
, entry
)
319 if (node
->id
== hNotify
)
322 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
326 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
330 /*************************************************************************
331 * SHChangeNotifyUpdateEntryList [SHELL32.5]
333 BOOL WINAPI
SHChangeNotifyUpdateEntryList(DWORD unknown1
, DWORD unknown2
,
334 DWORD unknown3
, DWORD unknown4
)
336 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
337 unknown1
, unknown2
, unknown3
, unknown4
);
342 struct new_delivery_notification
347 LPITEMIDLIST pidls
[2];
351 static BOOL
should_notify( LPCITEMIDLIST changed
, LPCITEMIDLIST watched
, BOOL sub
)
353 TRACE("%p %p %d\n", changed
, watched
, sub
);
356 if (ILIsEqual( watched
, changed
) )
358 if( sub
&& ILIsParent( watched
, changed
, FALSE
) )
363 /*************************************************************************
364 * SHChangeNotify [SHELL32.@]
366 void WINAPI
SHChangeNotify(LONG wEventId
, UINT uFlags
, LPCVOID dwItem1
, LPCVOID dwItem2
)
368 struct notification_recipients
{
375 HANDLE shared_data
= NULL
;
376 LPITEMIDLIST Pidls
[2];
377 LPNOTIFICATIONLIST ptr
;
378 struct list recipients
;
383 TRACE("(0x%08x,0x%08x,%p,%p)\n", wEventId
, uFlags
, dwItem1
, dwItem2
);
385 if(uFlags
& ~(SHCNF_TYPE
|SHCNF_FLUSH
))
386 FIXME("ignoring unsupported flags: %x\n", uFlags
);
388 if( ( wEventId
& SHCNE_NOITEMEVENTS
) && ( dwItem1
|| dwItem2
) )
390 TRACE("dwItem1 and dwItem2 are not zero, but should be\n");
395 else if( ( wEventId
& SHCNE_ONEITEMEVENTS
) && dwItem2
)
397 TRACE("dwItem2 is not zero, but should be\n");
402 if( ( ( wEventId
& SHCNE_NOITEMEVENTS
) &&
403 ( wEventId
& ~(SHCNE_NOITEMEVENTS
| SHCNE_INTERRUPT
) ) ) ||
404 ( ( wEventId
& SHCNE_ONEITEMEVENTS
) &&
405 ( wEventId
& ~(SHCNE_ONEITEMEVENTS
| SHCNE_INTERRUPT
) ) ) ||
406 ( ( wEventId
& SHCNE_TWOITEMEVENTS
) &&
407 ( wEventId
& ~(SHCNE_TWOITEMEVENTS
| SHCNE_INTERRUPT
) ) ) )
409 WARN("mutually incompatible events listed\n");
413 /* convert paths in IDLists*/
414 switch (uFlags
& SHCNF_TYPE
)
417 if (dwItem1
) Pidls
[0] = SHSimpleIDListFromPathA(dwItem1
); //FIXME
418 if (dwItem2
) Pidls
[1] = SHSimpleIDListFromPathA(dwItem2
); //FIXME
421 if (dwItem1
) Pidls
[0] = SHSimpleIDListFromPathW(dwItem1
);
422 if (dwItem2
) Pidls
[1] = SHSimpleIDListFromPathW(dwItem2
);
424 if (wEventId
& (SHCNE_MKDIR
| SHCNE_RMDIR
| SHCNE_UPDATEDIR
| SHCNE_RENAMEFOLDER
))
427 * The last items in the ID are currently files. So we chop off the last
428 * entry, and create a new one using a find data struct.
430 if (dwItem1
&& Pidls
[0]){
431 WIN32_FIND_DATAW wfd
;
432 LPITEMIDLIST oldpidl
, newpidl
;
433 LPWSTR p
= PathFindFileNameW((LPCWSTR
)dwItem1
);
434 ILRemoveLastID(Pidls
[0]);
435 lstrcpynW(&wfd
.cFileName
[0], p
, MAX_PATH
);
436 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
437 newpidl
= _ILCreateFromFindDataW(&wfd
);
438 oldpidl
= ILClone(Pidls
[0]);
440 Pidls
[0] = ILCombine(oldpidl
, newpidl
);
444 if (dwItem2
&& Pidls
[1]){
445 WIN32_FIND_DATAW wfd
;
446 LPITEMIDLIST oldpidl
, newpidl
;
447 LPWSTR p
= PathFindFileNameW((LPCWSTR
)dwItem2
);
448 ILRemoveLastID(Pidls
[1]);
449 lstrcpynW(&wfd
.cFileName
[0], p
, MAX_PATH
);
450 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
451 newpidl
= _ILCreateFromFindDataW(&wfd
);
452 oldpidl
= ILClone(Pidls
[0]);
454 Pidls
[1] = ILCombine(oldpidl
, newpidl
);
462 Pidls
[0] = ILClone(dwItem1
);
463 Pidls
[1] = ILClone(dwItem2
);
467 FIXME("SHChangeNotify with (uFlags & SHCNF_PRINTER)\n");
471 FIXME("unknown type %08x\n", uFlags
& SHCNF_TYPE
);
475 list_init(&recipients
);
476 EnterCriticalSection(&SHELL32_ChangenotifyCS
);
477 LIST_FOR_EACH_ENTRY( ptr
, ¬ifications
, NOTIFICATIONLIST
, entry
)
479 struct notification_recipients
*item
;
483 for( i
=0; (i
<ptr
->cidl
) && !notify
; i
++ )
485 LPCITEMIDLIST pidl
= ptr
->apidl
[i
].pidl
;
486 BOOL subtree
= ptr
->apidl
[i
].fRecursive
;
488 if (wEventId
& ptr
->wEventMask
)
490 if( !pidl
) /* all ? */
492 else if( wEventId
& SHCNE_NOITEMEVENTS
)
494 else if( wEventId
& ( SHCNE_ONEITEMEVENTS
| SHCNE_TWOITEMEVENTS
) )
495 notify
= should_notify( Pidls
[0], pidl
, subtree
);
496 else if( wEventId
& SHCNE_TWOITEMEVENTS
)
497 notify
= should_notify( Pidls
[1], pidl
, subtree
);
504 item
= SHAlloc(sizeof(struct notification_recipients
));
506 ERR("out of memory\n");
510 item
->hwnd
= ptr
->hwnd
;
511 item
->msg
= ptr
->uMsg
;
512 item
->flags
= ptr
->dwFlags
;
513 list_add_tail(&recipients
, &item
->entry
);
515 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
517 LIST_FOR_EACH_ENTRY_SAFE(cur
, next
, &recipients
, struct notification_recipients
, entry
)
519 TRACE("notifying %p, event %s(%x)\n", cur
->hwnd
, DumpEvent(wEventId
), wEventId
);
521 if (cur
->flags
& SHCNRF_NewDelivery
) {
523 struct new_delivery_notification
*notification
;
524 UINT size1
= ILGetSize(Pidls
[0]), size2
= ILGetSize(Pidls
[1]);
525 UINT offset
= (size1
+sizeof(int)-1)/sizeof(int)*sizeof(int);
527 notification
= SHAlloc(sizeof(struct new_delivery_notification
)+offset
+size2
);
529 ERR("out of memory\n");
531 notification
->event
= wEventId
;
532 notification
->pidl1_size
= size1
;
533 notification
->pidl2_size
= size2
;
535 memcpy(notification
->data
, Pidls
[0], size1
);
537 memcpy(notification
->data
+offset
, Pidls
[1], size2
);
539 shared_data
= SHAllocShared(notification
,
540 sizeof(struct new_delivery_notification
)+size1
+size2
,
541 GetCurrentProcessId());
542 SHFree(notification
);
547 SendMessageA(cur
->hwnd
, cur
->msg
, (WPARAM
)shared_data
, GetCurrentProcessId());
549 ERR("out of memory\n");
551 SendMessageA(cur
->hwnd
, cur
->msg
, (WPARAM
)Pidls
, wEventId
);
554 list_remove(&cur
->entry
);
557 SHFreeShared(shared_data
, GetCurrentProcessId());
562 if (wEventId
& SHCNE_ASSOCCHANGED
)
564 static const WCHAR args
[] = {' ','-','a',0 };
565 TRACE("refreshing file type associations\n");
566 run_winemenubuilder( args
);
571 /*************************************************************************
572 * NTSHChangeNotifyRegister [SHELL32.640]
574 * Idlist is an array of structures and Count specifies how many items in the array.
575 * count should always be one when calling SHChangeNotifyRegister, or
576 * SHChangeNotifyDeregister will not work properly.
578 EXTERN_C ULONG WINAPI
NTSHChangeNotifyRegister(
584 SHChangeNotifyEntry
*idlist
)
586 return SHChangeNotifyRegister(hwnd
, fSources
| SHCNRF_NewDelivery
,
587 fEvents
, msg
, count
, idlist
);
590 /*************************************************************************
591 * SHChangeNotification_Lock [SHELL32.644]
593 HANDLE WINAPI
SHChangeNotification_Lock(
596 LPITEMIDLIST
**lppidls
,
599 struct new_delivery_notification
*ndn
;
602 TRACE("%p %08x %p %p\n", hChange
, dwProcessId
, lppidls
, lpwEventId
);
604 ndn
= SHLockShared(hChange
, dwProcessId
);
606 WARN("SHLockShared failed\n");
611 offset
= (ndn
->pidl1_size
+sizeof(int)-1)/sizeof(int)*sizeof(int);
612 ndn
->pidls
[0] = ndn
->pidl1_size
? (LPITEMIDLIST
)ndn
->data
: NULL
;
613 ndn
->pidls
[1] = ndn
->pidl2_size
? (LPITEMIDLIST
)(ndn
->data
+offset
) : NULL
;
614 *lppidls
= ndn
->pidls
;
618 *lpwEventId
= ndn
->event
;
623 /*************************************************************************
624 * SHChangeNotification_Unlock [SHELL32.645]
626 BOOL WINAPI
SHChangeNotification_Unlock ( HANDLE hLock
)
628 TRACE("%p\n", hLock
);
629 return SHUnlockShared(hLock
);
632 /*************************************************************************
633 * NTSHChangeNotifyDeregister [SHELL32.641]
635 DWORD WINAPI
NTSHChangeNotifyDeregister(ULONG x1
)
637 FIXME("(0x%08x):semi stub.\n",x1
);
639 return SHChangeNotifyDeregister( x1
);
647 _AddDirectoryProc(ULONG_PTR arg
)
649 LPNOTIFYREGISTER item
= (LPNOTIFYREGISTER
)arg
;
653 BOOL
_OpenDirectory(LPNOTIFYREGISTER item
)
656 IShellFolder
*psfDesktop
;
659 // Makes function idempotent
660 if (item
->hDirectory
&& !(item
->hDirectory
== INVALID_HANDLE_VALUE
))
663 hr
= SHGetDesktopFolder(&psfDesktop
);
667 hr
= IShellFolder_GetDisplayNameOf(psfDesktop
, item
->pidl
, SHGDN_FORPARSING
, &strFile
);
668 IShellFolder_Release(psfDesktop
);
672 hr
= StrRetToBufW(&strFile
, NULL
, item
->wstrDirectory
, _countof(item
->wstrDirectory
));
676 TRACE("_OpenDirectory %s\n", debugstr_w(item
->wstrDirectory
));
678 item
->hDirectory
= CreateFileW(item
->wstrDirectory
, // pointer to the file name
679 GENERIC_READ
| FILE_LIST_DIRECTORY
, // access (read/write) mode
680 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, // share mode
681 NULL
, // security descriptor
682 OPEN_EXISTING
, // how to create
683 FILE_FLAG_BACKUP_SEMANTICS
| FILE_FLAG_OVERLAPPED
, // file attributes
684 NULL
); // file with attributes to copy
686 if (item
->hDirectory
== INVALID_HANDLE_VALUE
)
693 static void CALLBACK
_RequestTermination(ULONG_PTR arg
)
695 LPNOTIFYREGISTER item
= (LPNOTIFYREGISTER
) arg
;
696 TRACE("_RequestTermination %p \n", item
->hDirectory
);
697 if (!item
->hDirectory
|| item
->hDirectory
== INVALID_HANDLE_VALUE
) return;
699 CancelIo(item
->hDirectory
);
700 CloseHandle(item
->hDirectory
);
701 item
->hDirectory
= NULL
;
707 _NotificationCompletion(DWORD dwErrorCode
, // completion code
708 DWORD dwNumberOfBytesTransfered
, // number of bytes transferred
709 LPOVERLAPPED lpOverlapped
) // I/O information buffer
711 /* MSDN: The hEvent member of the OVERLAPPED structure is not used by the
712 system, so you can use it yourself. We do just this, storing a pointer
713 to the working struct in the overlapped structure. */
714 LPNOTIFYREGISTER item
= (LPNOTIFYREGISTER
) lpOverlapped
->hEvent
;
715 TRACE("_NotificationCompletion\n");
718 if (dwErrorCode
== ERROR_OPERATION_ABORTED
)
720 /* Command was induced by CancelIo in the shutdown procedure. */
721 TRACE("_NotificationCompletion ended.\n");
726 /* This likely means overflow, so force whole directory refresh. */
727 if (!dwNumberOfBytesTransfered
)
729 ERR("_NotificationCompletion overflow\n");
731 ZeroMemory(item
->buffer
, BUFFER_SIZE
);
734 SHChangeNotify(SHCNE_UPDATEITEM
| SHCNE_INTERRUPT
,
747 * Get the new read issued as fast as possible (before we do the
748 * processing and message posting). All of the file notification
749 * occur on one thread so the buffers should not collide with one another.
750 * The extra zero mems are because the FNI size isn't written correctly.
753 ZeroMemory(item
->backBuffer
, BUFFER_SIZE
);
754 memcpy(item
->backBuffer
, item
->buffer
, dwNumberOfBytesTransfered
);
755 ZeroMemory(item
->buffer
, BUFFER_SIZE
);
759 _ProcessNotification(item
);
763 InterlockedDecrement(&item
->pParent
->wQueuedCount
);
764 DeleteNode(item
->pParent
);
768 static VOID
_BeginRead(LPNOTIFYREGISTER item
)
770 TRACE("_BeginRead %p \n", item
->hDirectory
);
773 InterlockedIncrement(&item
->pParent
->wQueuedCount
);
775 /* This call needs to be reissued after every APC. */
776 if (!ReadDirectoryChangesW(item
->hDirectory
, // handle to directory
777 item
->buffer
, // read results buffer
778 BUFFER_SIZE
, // length of buffer
779 FALSE
, // monitoring option (recursion)
780 FILE_NOTIFY_CHANGE_DIR_NAME
| FILE_NOTIFY_CHANGE_FILE_NAME
, // filter conditions
781 NULL
, // bytes returned
782 &item
->overlapped
, // overlapped buffer
783 _NotificationCompletion
)) // completion routine
787 ERR("ReadDirectoryChangesW failed. (%p, %p, %p, %p) Code: %u \n",
791 _NotificationCompletion
,
794 InterlockedDecrement(&item
->pParent
->wQueuedCount
);
795 DeleteNode(item
->pParent
);
800 DWORD
_MapAction(DWORD dwAction
, BOOL isDir
)
804 case FILE_ACTION_ADDED
: return isDir
? SHCNE_MKDIR
: SHCNE_CREATE
;
805 case FILE_ACTION_REMOVED
: return isDir
? SHCNE_RMDIR
: SHCNE_DELETE
;
806 case FILE_ACTION_MODIFIED
: return isDir
? SHCNE_UPDATEDIR
: SHCNE_UPDATEITEM
;
807 case FILE_ACTION_RENAMED_OLD_NAME
: return isDir
? SHCNE_UPDATEDIR
: SHCNE_UPDATEITEM
;
808 case FILE_ACTION_RENAMED_NEW_NAME
: return isDir
? SHCNE_UPDATEDIR
: SHCNE_UPDATEITEM
;
809 default: return SHCNE_UPDATEITEM
;
813 VOID
_ProcessNotification(LPNOTIFYREGISTER item
)
815 BYTE
* pBase
= item
->backBuffer
;
816 TRACE("_ProcessNotification\n");
820 FILE_NOTIFY_INFORMATION
* fni
= (FILE_NOTIFY_INFORMATION
*)pBase
;
823 WCHAR wstrFilename
[MAX_PATH
];
825 StringCchCopy(tmp
, fni
->FileNameLength
, fni
->FileName
);
827 PathCombine(wstrFilename
, item
->wstrDirectory
, tmp
);
829 /* If it could be a short filename, expand it. */
830 wszFilename
= PathFindFileNameW(wstrFilename
);
832 len
= lstrlenW(wszFilename
);
833 /* The maximum length of an 8.3 filename is twelve, including the dot. */
834 if (len
<= 12 && wcschr(wszFilename
, L
'~'))
836 /* Convert to the long filename form. Unfortunately, this
837 does not work for deletions, so it's an imperfect fix. */
838 wchar_t wbuf
[MAX_PATH
];
839 if (GetLongPathName(wstrFilename
, wbuf
, _countof (wbuf
)) > 0)
840 StringCchCopyW(wstrFilename
, MAX_PATH
, wbuf
);
843 /* On deletion of a folder PathIsDirectory will return false even if
844 it *was* a directory, so, again, imperfect. */
845 SHChangeNotify(_MapAction(fni
->Action
, PathIsDirectory(wstrFilename
)) | SHCNE_INTERRUPT
,
850 if (!fni
->NextEntryOffset
)
852 pBase
+= fni
->NextEntryOffset
;
856 static void CALLBACK
_RequestAllTermination(ULONG_PTR arg
)
861 static unsigned int WINAPI
_RunAsyncThreadProc(LPVOID arg
)
863 m_bTerminate
= FALSE
;
864 while (!m_bTerminate
)
866 SleepEx(INFINITE
, TRUE
);
871 #endif /* __REACTOS__ */