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>
37 #include <shellutils.h>
41 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
43 static CRITICAL_SECTION SHELL32_ChangenotifyCS
;
44 static CRITICAL_SECTION_DEBUG critsect_debug
=
46 0, 0, &SHELL32_ChangenotifyCS
,
47 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
48 0, 0, { (DWORD_PTR
)(__FILE__
": SHELL32_ChangenotifyCS") }
50 static CRITICAL_SECTION SHELL32_ChangenotifyCS
= { &critsect_debug
, -1, 0, 0, 0, 0 };
54 PCIDLIST_ABSOLUTE pidl
;
56 /* File system notification items */
57 HANDLE hDirectory
; /* Directory handle */
58 WCHAR wstrDirectory
[MAX_PATH
]; /* Directory name */
59 OVERLAPPED overlapped
; /* Overlapped structure */
60 BYTE
*buffer
; /* Async buffer to fill */
61 BYTE
*backBuffer
; /* Back buffer to swap buffer into */
62 struct _NOTIFICATIONLIST
* pParent
;
63 } SHChangeNotifyEntryInternal
, *LPNOTIFYREGISTER
;
65 typedef SHChangeNotifyEntry
*LPNOTIFYREGISTER
;
68 /* internal list of notification clients (internal) */
69 typedef struct _NOTIFICATIONLIST
72 HWND hwnd
; /* window to notify */
73 DWORD uMsg
; /* message to send */
74 LPNOTIFYREGISTER apidl
; /* array of entries to watch*/
75 UINT cidl
; /* number of pidls in array */
76 LONG wEventMask
; /* subscribed events */
77 DWORD dwFlags
; /* client flags */
80 volatile LONG wQueuedCount
;
82 } NOTIFICATIONLIST
, *LPNOTIFICATIONLIST
;
85 VOID
_ProcessNotification(LPNOTIFYREGISTER item
);
86 BOOL
_OpenDirectory(LPNOTIFYREGISTER item
);
87 static void CALLBACK
_RequestTermination(ULONG_PTR arg
);
88 static void CALLBACK
_RequestAllTermination(ULONG_PTR arg
);
89 static void CALLBACK
_AddDirectoryProc(ULONG_PTR arg
);
90 static VOID
_BeginRead(LPNOTIFYREGISTER item
);
91 static unsigned int WINAPI
_RunAsyncThreadProc(LPVOID arg
);
94 static struct list notifications
= LIST_INIT( notifications
);
103 #define SHCNE_NOITEMEVENTS ( \
106 #define SHCNE_ONEITEMEVENTS ( \
107 SHCNE_ATTRIBUTES | SHCNE_CREATE | SHCNE_DELETE | SHCNE_DRIVEADD | \
108 SHCNE_DRIVEADDGUI | SHCNE_DRIVEREMOVED | SHCNE_FREESPACE | \
109 SHCNE_MEDIAINSERTED | SHCNE_MEDIAREMOVED | SHCNE_MKDIR | \
110 SHCNE_NETSHARE | SHCNE_NETUNSHARE | SHCNE_RMDIR | \
111 SHCNE_SERVERDISCONNECT | SHCNE_UPDATEDIR | SHCNE_UPDATEIMAGE )
113 #define SHCNE_TWOITEMEVENTS ( \
114 SHCNE_RENAMEFOLDER | SHCNE_RENAMEITEM | SHCNE_UPDATEITEM )
116 /* for dumping events */
117 static const char * DumpEvent( LONG event
)
119 if( event
== SHCNE_ALLEVENTS
)
120 return "SHCNE_ALLEVENTS";
121 #define DUMPEV(x) ,( event & SHCNE_##x )? #x " " : ""
122 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"
128 DUMPEV(MEDIAINSERTED
)
137 DUMPEV(SERVERDISCONNECT
)
142 DUMPEV(EXTENDED_EVENT
)
149 static const char * NodeName(const NOTIFICATIONLIST
*item
)
152 WCHAR path
[MAX_PATH
];
154 if(SHGetPathFromIDListW(item
->apidl
[0].pidl
, path
))
155 str
= wine_dbg_sprintf("%s", debugstr_w(path
));
157 str
= wine_dbg_sprintf("<not a disk file>" );
161 static void DeleteNode(LPNOTIFICATIONLIST item
)
168 TRACE("item=%p\n", item
);
171 queued
= InterlockedCompareExchange(&item
->wQueuedCount
, 0, 0);
174 ERR("Not freeing, still %d queued events\n", queued
);
177 TRACE("Freeing for real! %p (%d) \n", item
, item
->cidl
);
180 /* remove item from list */
181 list_remove( &item
->entry
);
184 for (i
=0; i
<item
->cidl
; i
++)
187 QueueUserAPC(_RequestTermination
, m_hThread
, (ULONG_PTR
) &item
->apidl
[i
] );
188 WaitForSingleObjectEx(m_hThread
, 100, FALSE
);
190 SHFree((LPITEMIDLIST
)item
->apidl
[i
].pidl
);
192 SHFree(item
->apidl
[i
].buffer
);
193 SHFree(item
->apidl
[i
].backBuffer
);
200 void InitChangeNotifications(void)
207 void FreeChangeNotifications(void)
209 LPNOTIFICATIONLIST ptr
, next
;
213 EnterCriticalSection(&SHELL32_ChangenotifyCS
);
215 LIST_FOR_EACH_ENTRY_SAFE( ptr
, next
, ¬ifications
, NOTIFICATIONLIST
, entry
)
218 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
221 QueueUserAPC(_RequestAllTermination
, m_hThread
, (ULONG_PTR
) NULL
);
224 DeleteCriticalSection(&SHELL32_ChangenotifyCS
);
227 /*************************************************************************
228 * SHChangeNotifyRegister [SHELL32.2]
232 SHChangeNotifyRegister(
238 SHChangeNotifyEntry
*lpItems
)
240 LPNOTIFICATIONLIST item
;
243 item
= SHAlloc(sizeof(NOTIFICATIONLIST
));
245 TRACE("(%p,0x%08x,0x%08x,0x%08x,%d,%p) item=%p\n",
246 hwnd
, fSources
, wEventMask
, uMsg
, cItems
, lpItems
, item
);
250 m_hThread
= (HANDLE
) _beginthreadex(NULL
, 0, _RunAsyncThreadProc
, NULL
, 0, &m_dwThreadId
);
255 item
->apidl
= SHAlloc(sizeof(SHChangeNotifyEntryInternal
) * cItems
);
256 item
->wQueuedCount
= 0;
258 item
->apidl
= SHAlloc(sizeof(SHChangeNotifyEntry
) * cItems
);
260 for(i
=0;i
<cItems
;i
++)
263 ZeroMemory(&item
->apidl
[i
], sizeof(SHChangeNotifyEntryInternal
));
265 item
->apidl
[i
].pidl
= ILClone(lpItems
[i
].pidl
);
266 item
->apidl
[i
].fRecursive
= lpItems
[i
].fRecursive
;
268 item
->apidl
[i
].buffer
= SHAlloc(BUFFER_SIZE
);
269 item
->apidl
[i
].backBuffer
= SHAlloc(BUFFER_SIZE
);
270 item
->apidl
[i
].overlapped
.hEvent
= &item
->apidl
[i
];
271 item
->apidl
[i
].pParent
= item
;
273 if (fSources
& SHCNRF_InterruptLevel
)
275 if (_OpenDirectory( &item
->apidl
[i
] ))
277 InterlockedIncrement(&item
->wQueuedCount
);
278 QueueUserAPC( _AddDirectoryProc
, m_hThread
, (ULONG_PTR
) &item
->apidl
[i
] );
285 item
->wEventMask
= wEventMask
;
286 item
->dwFlags
= fSources
;
287 item
->id
= InterlockedIncrement( &next_id
);
289 TRACE("new node: %s\n", NodeName( item
));
291 EnterCriticalSection(&SHELL32_ChangenotifyCS
);
293 list_add_tail( ¬ifications
, &item
->entry
);
295 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
300 /*************************************************************************
301 * SHChangeNotifyDeregister [SHELL32.4]
303 BOOL WINAPI
SHChangeNotifyDeregister(ULONG hNotify
)
305 LPNOTIFICATIONLIST node
;
307 TRACE("(0x%08x)\n", hNotify
);
309 EnterCriticalSection(&SHELL32_ChangenotifyCS
);
311 LIST_FOR_EACH_ENTRY( node
, ¬ifications
, NOTIFICATIONLIST
, entry
)
313 if (node
->id
== hNotify
)
316 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
320 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
324 /*************************************************************************
325 * SHChangeNotifyUpdateEntryList [SHELL32.5]
327 BOOL WINAPI
SHChangeNotifyUpdateEntryList(DWORD unknown1
, DWORD unknown2
,
328 DWORD unknown3
, DWORD unknown4
)
330 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
331 unknown1
, unknown2
, unknown3
, unknown4
);
336 struct new_delivery_notification
341 LPITEMIDLIST pidls
[2];
345 static BOOL
should_notify( LPCITEMIDLIST changed
, LPCITEMIDLIST watched
, BOOL sub
)
347 TRACE("%p %p %d\n", changed
, watched
, sub
);
350 if (ILIsEqual( watched
, changed
) )
352 if( sub
&& ILIsParent( watched
, changed
, FALSE
) )
357 /*************************************************************************
358 * SHChangeNotify [SHELL32.@]
360 void WINAPI
SHChangeNotify(LONG wEventId
, UINT uFlags
, LPCVOID dwItem1
, LPCVOID dwItem2
)
362 struct notification_recipients
{
369 HANDLE shared_data
= NULL
;
370 LPITEMIDLIST Pidls
[2];
371 LPNOTIFICATIONLIST ptr
;
372 struct list recipients
;
377 TRACE("(0x%08x,0x%08x,%p,%p)\n", wEventId
, uFlags
, dwItem1
, dwItem2
);
379 if(uFlags
& ~(SHCNF_TYPE
|SHCNF_FLUSH
))
380 FIXME("ignoring unsupported flags: %x\n", uFlags
);
382 if( ( wEventId
& SHCNE_NOITEMEVENTS
) && ( dwItem1
|| dwItem2
) )
384 TRACE("dwItem1 and dwItem2 are not zero, but should be\n");
389 else if( ( wEventId
& SHCNE_ONEITEMEVENTS
) && dwItem2
)
391 TRACE("dwItem2 is not zero, but should be\n");
396 if( ( ( wEventId
& SHCNE_NOITEMEVENTS
) &&
397 ( wEventId
& ~(SHCNE_NOITEMEVENTS
| SHCNE_INTERRUPT
) ) ) ||
398 ( ( wEventId
& SHCNE_ONEITEMEVENTS
) &&
399 ( wEventId
& ~(SHCNE_ONEITEMEVENTS
| SHCNE_INTERRUPT
) ) ) ||
400 ( ( wEventId
& SHCNE_TWOITEMEVENTS
) &&
401 ( wEventId
& ~(SHCNE_TWOITEMEVENTS
| SHCNE_INTERRUPT
) ) ) )
403 WARN("mutually incompatible events listed\n");
407 /* convert paths in IDLists*/
408 switch (uFlags
& SHCNF_TYPE
)
411 if (dwItem1
) Pidls
[0] = SHSimpleIDListFromPathA(dwItem1
); //FIXME
412 if (dwItem2
) Pidls
[1] = SHSimpleIDListFromPathA(dwItem2
); //FIXME
415 if (dwItem1
) Pidls
[0] = SHSimpleIDListFromPathW(dwItem1
);
416 if (dwItem2
) Pidls
[1] = SHSimpleIDListFromPathW(dwItem2
);
418 if (wEventId
& (SHCNE_MKDIR
| SHCNE_RMDIR
| SHCNE_UPDATEDIR
| SHCNE_RENAMEFOLDER
))
421 * The last items in the ID are currently files. So we chop off the last
422 * entry, and create a new one using a find data struct.
424 if (dwItem1
&& Pidls
[0]){
425 WIN32_FIND_DATAW wfd
;
426 LPITEMIDLIST oldpidl
, newpidl
;
427 LPWSTR p
= PathFindFileNameW((LPCWSTR
)dwItem1
);
428 ILRemoveLastID(Pidls
[0]);
429 lstrcpynW(&wfd
.cFileName
[0], p
, MAX_PATH
);
430 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
431 newpidl
= _ILCreateFromFindDataW(&wfd
);
432 oldpidl
= ILClone(Pidls
[0]);
434 Pidls
[0] = ILCombine(oldpidl
, newpidl
);
438 if (dwItem2
&& Pidls
[1]){
439 WIN32_FIND_DATAW wfd
;
440 LPITEMIDLIST oldpidl
, newpidl
;
441 LPWSTR p
= PathFindFileNameW((LPCWSTR
)dwItem2
);
442 ILRemoveLastID(Pidls
[1]);
443 lstrcpynW(&wfd
.cFileName
[0], p
, MAX_PATH
);
444 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
445 newpidl
= _ILCreateFromFindDataW(&wfd
);
446 oldpidl
= ILClone(Pidls
[0]);
448 Pidls
[1] = ILCombine(oldpidl
, newpidl
);
456 Pidls
[0] = ILClone(dwItem1
);
457 Pidls
[1] = ILClone(dwItem2
);
461 FIXME("SHChangeNotify with (uFlags & SHCNF_PRINTER)\n");
465 FIXME("unknown type %08x\n", uFlags
& SHCNF_TYPE
);
469 list_init(&recipients
);
470 EnterCriticalSection(&SHELL32_ChangenotifyCS
);
471 LIST_FOR_EACH_ENTRY( ptr
, ¬ifications
, NOTIFICATIONLIST
, entry
)
473 struct notification_recipients
*item
;
477 for( i
=0; (i
<ptr
->cidl
) && !notify
; i
++ )
479 LPCITEMIDLIST pidl
= ptr
->apidl
[i
].pidl
;
480 BOOL subtree
= ptr
->apidl
[i
].fRecursive
;
482 if (wEventId
& ptr
->wEventMask
)
484 if( !pidl
) /* all ? */
486 else if( wEventId
& SHCNE_NOITEMEVENTS
)
488 else if( wEventId
& ( SHCNE_ONEITEMEVENTS
| SHCNE_TWOITEMEVENTS
) )
489 notify
= should_notify( Pidls
[0], pidl
, subtree
);
490 else if( wEventId
& SHCNE_TWOITEMEVENTS
)
491 notify
= should_notify( Pidls
[1], pidl
, subtree
);
498 item
= SHAlloc(sizeof(struct notification_recipients
));
500 ERR("out of memory\n");
504 item
->hwnd
= ptr
->hwnd
;
505 item
->msg
= ptr
->uMsg
;
506 item
->flags
= ptr
->dwFlags
;
507 list_add_tail(&recipients
, &item
->entry
);
509 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
511 LIST_FOR_EACH_ENTRY_SAFE(cur
, next
, &recipients
, struct notification_recipients
, entry
)
513 TRACE("notifying %p, event %s(%x)\n", cur
->hwnd
, DumpEvent(wEventId
), wEventId
);
515 if (cur
->flags
& SHCNRF_NewDelivery
) {
517 struct new_delivery_notification
*notification
;
518 UINT size1
= ILGetSize(Pidls
[0]), size2
= ILGetSize(Pidls
[1]);
519 UINT offset
= (size1
+sizeof(int)-1)/sizeof(int)*sizeof(int);
521 notification
= SHAlloc(sizeof(struct new_delivery_notification
)+offset
+size2
);
523 ERR("out of memory\n");
525 notification
->event
= wEventId
;
526 notification
->pidl1_size
= size1
;
527 notification
->pidl2_size
= size2
;
529 memcpy(notification
->data
, Pidls
[0], size1
);
531 memcpy(notification
->data
+offset
, Pidls
[1], size2
);
533 shared_data
= SHAllocShared(notification
,
534 sizeof(struct new_delivery_notification
)+size1
+size2
,
535 GetCurrentProcessId());
536 SHFree(notification
);
541 SendMessageA(cur
->hwnd
, cur
->msg
, (WPARAM
)shared_data
, GetCurrentProcessId());
543 ERR("out of memory\n");
545 SendMessageA(cur
->hwnd
, cur
->msg
, (WPARAM
)Pidls
, wEventId
);
548 list_remove(&cur
->entry
);
551 SHFreeShared(shared_data
, GetCurrentProcessId());
556 if (wEventId
& SHCNE_ASSOCCHANGED
)
558 static const WCHAR args
[] = {' ','-','a',0 };
559 TRACE("refreshing file type associations\n");
560 run_winemenubuilder( args
);
565 /*************************************************************************
566 * NTSHChangeNotifyRegister [SHELL32.640]
568 * Idlist is an array of structures and Count specifies how many items in the array.
569 * count should always be one when calling SHChangeNotifyRegister, or
570 * SHChangeNotifyDeregister will not work properly.
572 EXTERN_C ULONG WINAPI
NTSHChangeNotifyRegister(
578 SHChangeNotifyEntry
*idlist
)
580 return SHChangeNotifyRegister(hwnd
, fSources
| SHCNRF_NewDelivery
,
581 fEvents
, msg
, count
, idlist
);
584 /*************************************************************************
585 * SHChangeNotification_Lock [SHELL32.644]
587 HANDLE WINAPI
SHChangeNotification_Lock(
590 LPITEMIDLIST
**lppidls
,
593 struct new_delivery_notification
*ndn
;
596 TRACE("%p %08x %p %p\n", hChange
, dwProcessId
, lppidls
, lpwEventId
);
598 ndn
= SHLockShared(hChange
, dwProcessId
);
600 WARN("SHLockShared failed\n");
605 offset
= (ndn
->pidl1_size
+sizeof(int)-1)/sizeof(int)*sizeof(int);
606 ndn
->pidls
[0] = ndn
->pidl1_size
? (LPITEMIDLIST
)ndn
->data
: NULL
;
607 ndn
->pidls
[1] = ndn
->pidl2_size
? (LPITEMIDLIST
)(ndn
->data
+offset
) : NULL
;
608 *lppidls
= ndn
->pidls
;
612 *lpwEventId
= ndn
->event
;
617 /*************************************************************************
618 * SHChangeNotification_Unlock [SHELL32.645]
620 BOOL WINAPI
SHChangeNotification_Unlock ( HANDLE hLock
)
622 TRACE("%p\n", hLock
);
623 return SHUnlockShared(hLock
);
626 /*************************************************************************
627 * NTSHChangeNotifyDeregister [SHELL32.641]
629 DWORD WINAPI
NTSHChangeNotifyDeregister(ULONG x1
)
631 FIXME("(0x%08x):semi stub.\n",x1
);
633 return SHChangeNotifyDeregister( x1
);
641 _AddDirectoryProc(ULONG_PTR arg
)
643 LPNOTIFYREGISTER item
= (LPNOTIFYREGISTER
)arg
;
647 BOOL
_OpenDirectory(LPNOTIFYREGISTER item
)
650 IShellFolder
*psfDesktop
;
653 // Makes function idempotent
654 if (item
->hDirectory
&& !(item
->hDirectory
== INVALID_HANDLE_VALUE
))
657 hr
= SHGetDesktopFolder(&psfDesktop
);
658 if (FAILED_UNEXPECTEDLY(hr
))
661 hr
= IShellFolder_GetDisplayNameOf(psfDesktop
, item
->pidl
, SHGDN_FORPARSING
, &strFile
);
662 IShellFolder_Release(psfDesktop
);
663 if (FAILED_UNEXPECTEDLY(hr
))
666 hr
= StrRetToBufW(&strFile
, NULL
, item
->wstrDirectory
, _countof(item
->wstrDirectory
));
667 if (FAILED_UNEXPECTEDLY(hr
))
670 TRACE("_OpenDirectory %s\n", debugstr_w(item
->wstrDirectory
));
672 item
->hDirectory
= CreateFileW(item
->wstrDirectory
, // pointer to the file name
673 GENERIC_READ
| FILE_LIST_DIRECTORY
, // access (read/write) mode
674 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, // share mode
675 NULL
, // security descriptor
676 OPEN_EXISTING
, // how to create
677 FILE_FLAG_BACKUP_SEMANTICS
| FILE_FLAG_OVERLAPPED
, // file attributes
678 NULL
); // file with attributes to copy
680 if (item
->hDirectory
== INVALID_HANDLE_VALUE
)
682 ERR("_OpenDirectory failed for %s\n", debugstr_w(item
->wstrDirectory
));
688 static void CALLBACK
_RequestTermination(ULONG_PTR arg
)
690 LPNOTIFYREGISTER item
= (LPNOTIFYREGISTER
) arg
;
691 TRACE("_RequestTermination %p %p \n", item
, item
->hDirectory
);
692 if (!item
->hDirectory
|| item
->hDirectory
== INVALID_HANDLE_VALUE
) return;
694 CancelIo(item
->hDirectory
);
695 CloseHandle(item
->hDirectory
);
696 item
->hDirectory
= NULL
;
702 _NotificationCompletion(DWORD dwErrorCode
, // completion code
703 DWORD dwNumberOfBytesTransfered
, // number of bytes transferred
704 LPOVERLAPPED lpOverlapped
) // I/O information buffer
706 /* MSDN: The hEvent member of the OVERLAPPED structure is not used by the
707 system, so you can use it yourself. We do just this, storing a pointer
708 to the working struct in the overlapped structure. */
709 LPNOTIFYREGISTER item
= (LPNOTIFYREGISTER
) lpOverlapped
->hEvent
;
710 TRACE("_NotificationCompletion\n");
713 if (dwErrorCode
== ERROR_OPERATION_ABORTED
)
715 /* Command was induced by CancelIo in the shutdown procedure. */
716 TRACE("_NotificationCompletion ended.\n");
722 /* If the FSD doesn't support directory change notifications, there's no
723 * no need to retry and requeue notification
725 if (dwErrorCode
== ERROR_INVALID_FUNCTION
)
727 WARN("Directory watching not supported\n");
732 /* This likely means overflow, so force whole directory refresh. */
733 if (!dwNumberOfBytesTransfered
)
735 ERR("_NotificationCompletion overflow\n");
737 ZeroMemory(item
->buffer
, BUFFER_SIZE
);
740 SHChangeNotify(SHCNE_UPDATEITEM
| SHCNE_INTERRUPT
,
753 * Get the new read issued as fast as possible (before we do the
754 * processing and message posting). All of the file notification
755 * occur on one thread so the buffers should not collide with one another.
756 * The extra zero mems are because the FNI size isn't written correctly.
759 ZeroMemory(item
->backBuffer
, BUFFER_SIZE
);
760 memcpy(item
->backBuffer
, item
->buffer
, dwNumberOfBytesTransfered
);
761 ZeroMemory(item
->buffer
, BUFFER_SIZE
);
765 _ProcessNotification(item
);
769 InterlockedDecrement(&item
->pParent
->wQueuedCount
);
770 DeleteNode(item
->pParent
);
774 static VOID
_BeginRead(LPNOTIFYREGISTER item
)
776 TRACE("_BeginRead %p \n", item
->hDirectory
);
779 InterlockedIncrement(&item
->pParent
->wQueuedCount
);
781 /* This call needs to be reissued after every APC. */
782 if (!ReadDirectoryChangesW(item
->hDirectory
, // handle to directory
783 item
->buffer
, // read results buffer
784 BUFFER_SIZE
, // length of buffer
785 FALSE
, // monitoring option (recursion)
786 FILE_NOTIFY_CHANGE_DIR_NAME
| FILE_NOTIFY_CHANGE_FILE_NAME
, // filter conditions
787 NULL
, // bytes returned
788 &item
->overlapped
, // overlapped buffer
789 _NotificationCompletion
)) // completion routine
793 ERR("ReadDirectoryChangesW failed. (%p, %p, %p, %p, %p, %p) Code: %u \n",
799 _NotificationCompletion
,
802 InterlockedDecrement(&item
->pParent
->wQueuedCount
);
803 DeleteNode(item
->pParent
);
808 DWORD
_MapAction(DWORD dwAction
, BOOL isDir
)
812 case FILE_ACTION_ADDED
: return isDir
? SHCNE_MKDIR
: SHCNE_CREATE
;
813 case FILE_ACTION_REMOVED
: return isDir
? SHCNE_RMDIR
: SHCNE_DELETE
;
814 case FILE_ACTION_MODIFIED
: return isDir
? SHCNE_UPDATEDIR
: SHCNE_UPDATEITEM
;
815 case FILE_ACTION_RENAMED_OLD_NAME
: return isDir
? SHCNE_UPDATEDIR
: SHCNE_UPDATEITEM
;
816 case FILE_ACTION_RENAMED_NEW_NAME
: return isDir
? SHCNE_UPDATEDIR
: SHCNE_UPDATEITEM
;
817 default: return SHCNE_UPDATEITEM
;
821 VOID
_ProcessNotification(LPNOTIFYREGISTER item
)
823 BYTE
* pBase
= item
->backBuffer
;
824 TRACE("_ProcessNotification\n");
828 FILE_NOTIFY_INFORMATION
* fni
= (FILE_NOTIFY_INFORMATION
*)pBase
;
831 WCHAR wstrFilename
[MAX_PATH
];
833 StringCchCopy(tmp
, fni
->FileNameLength
, fni
->FileName
);
835 PathCombine(wstrFilename
, item
->wstrDirectory
, tmp
);
837 /* If it could be a short filename, expand it. */
838 wszFilename
= PathFindFileNameW(wstrFilename
);
840 len
= lstrlenW(wszFilename
);
841 /* The maximum length of an 8.3 filename is twelve, including the dot. */
842 if (len
<= 12 && wcschr(wszFilename
, L
'~'))
844 /* Convert to the long filename form. Unfortunately, this
845 does not work for deletions, so it's an imperfect fix. */
846 wchar_t wbuf
[MAX_PATH
];
847 if (GetLongPathName(wstrFilename
, wbuf
, _countof (wbuf
)) > 0)
848 StringCchCopyW(wstrFilename
, MAX_PATH
, wbuf
);
851 /* On deletion of a folder PathIsDirectory will return false even if
852 it *was* a directory, so, again, imperfect. */
853 SHChangeNotify(_MapAction(fni
->Action
, PathIsDirectory(wstrFilename
)) | SHCNE_INTERRUPT
,
858 if (!fni
->NextEntryOffset
)
860 pBase
+= fni
->NextEntryOffset
;
864 static void CALLBACK
_RequestAllTermination(ULONG_PTR arg
)
869 static unsigned int WINAPI
_RunAsyncThreadProc(LPVOID arg
)
871 m_bTerminate
= FALSE
;
872 while (!m_bTerminate
)
874 SleepEx(INFINITE
, TRUE
);
879 #endif /* __REACTOS__ */