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 } SHChangeNotifyEntryInternal
, *LPNOTIFYREGISTER
;
63 typedef SHChangeNotifyEntry
*LPNOTIFYREGISTER
;
66 /* internal list of notification clients (internal) */
67 typedef struct _NOTIFICATIONLIST
70 HWND hwnd
; /* window to notify */
71 DWORD uMsg
; /* message to send */
72 LPNOTIFYREGISTER apidl
; /* array of entries to watch*/
73 UINT cidl
; /* number of pidls in array */
74 LONG wEventMask
; /* subscribed events */
75 DWORD dwFlags
; /* client flags */
77 } NOTIFICATIONLIST
, *LPNOTIFICATIONLIST
;
80 VOID
_ProcessNotification(LPNOTIFYREGISTER item
);
81 BOOL
_OpenDirectory(LPNOTIFYREGISTER item
);
82 static void CALLBACK
_RequestTermination(ULONG_PTR arg
);
83 static void CALLBACK
_RequestAllTermination(ULONG_PTR arg
);
84 static void CALLBACK
_AddDirectoryProc(ULONG_PTR arg
);
85 static VOID
_BeginRead(LPNOTIFYREGISTER item
);
86 static unsigned int WINAPI
_RunAsyncThreadProc(LPVOID arg
);
89 static struct list notifications
= LIST_INIT( notifications
);
98 #define SHCNE_NOITEMEVENTS ( \
101 #define SHCNE_ONEITEMEVENTS ( \
102 SHCNE_ATTRIBUTES | SHCNE_CREATE | SHCNE_DELETE | SHCNE_DRIVEADD | \
103 SHCNE_DRIVEADDGUI | SHCNE_DRIVEREMOVED | SHCNE_FREESPACE | \
104 SHCNE_MEDIAINSERTED | SHCNE_MEDIAREMOVED | SHCNE_MKDIR | \
105 SHCNE_NETSHARE | SHCNE_NETUNSHARE | SHCNE_RMDIR | \
106 SHCNE_SERVERDISCONNECT | SHCNE_UPDATEDIR | SHCNE_UPDATEIMAGE )
108 #define SHCNE_TWOITEMEVENTS ( \
109 SHCNE_RENAMEFOLDER | SHCNE_RENAMEITEM | SHCNE_UPDATEITEM )
111 /* for dumping events */
112 static const char * DumpEvent( LONG event
)
114 if( event
== SHCNE_ALLEVENTS
)
115 return "SHCNE_ALLEVENTS";
116 #define DUMPEV(x) ,( event & SHCNE_##x )? #x " " : ""
117 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"
123 DUMPEV(MEDIAINSERTED
)
132 DUMPEV(SERVERDISCONNECT
)
137 DUMPEV(EXTENDED_EVENT
)
144 static const char * NodeName(const NOTIFICATIONLIST
*item
)
147 WCHAR path
[MAX_PATH
];
149 if(SHGetPathFromIDListW(item
->apidl
[0].pidl
, path
))
150 str
= wine_dbg_sprintf("%s", debugstr_w(path
));
152 str
= wine_dbg_sprintf("<not a disk file>" );
156 static void DeleteNode(LPNOTIFICATIONLIST item
)
160 TRACE("item=%p\n", item
);
162 /* remove item from list */
163 list_remove( &item
->entry
);
166 for (i
=0; i
<item
->cidl
; i
++)
169 QueueUserAPC(_RequestTermination
, m_hThread
, (ULONG_PTR
) &item
->apidl
[i
] );
170 WaitForSingleObjectEx(m_hThread
, 100, FALSE
);
172 SHFree((LPITEMIDLIST
)item
->apidl
[i
].pidl
);
174 SHFree(item
->apidl
[i
].buffer
);
175 SHFree(item
->apidl
[i
].backBuffer
);
182 void InitChangeNotifications(void)
189 void FreeChangeNotifications(void)
191 LPNOTIFICATIONLIST ptr
, next
;
195 EnterCriticalSection(&SHELL32_ChangenotifyCS
);
197 LIST_FOR_EACH_ENTRY_SAFE( ptr
, next
, ¬ifications
, NOTIFICATIONLIST
, entry
)
200 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
203 QueueUserAPC(_RequestAllTermination
, m_hThread
, (ULONG_PTR
) NULL
);
206 DeleteCriticalSection(&SHELL32_ChangenotifyCS
);
209 /*************************************************************************
210 * SHChangeNotifyRegister [SHELL32.2]
214 SHChangeNotifyRegister(
220 SHChangeNotifyEntry
*lpItems
)
222 LPNOTIFICATIONLIST item
;
225 item
= SHAlloc(sizeof(NOTIFICATIONLIST
));
227 TRACE("(%p,0x%08x,0x%08x,0x%08x,%d,%p) item=%p\n",
228 hwnd
, fSources
, wEventMask
, uMsg
, cItems
, lpItems
, item
);
232 m_hThread
= (HANDLE
) _beginthreadex(NULL
, 0, _RunAsyncThreadProc
, NULL
, 0, &m_dwThreadId
);
237 item
->apidl
= SHAlloc(sizeof(SHChangeNotifyEntryInternal
) * cItems
);
239 item
->apidl
= SHAlloc(sizeof(SHChangeNotifyEntry
) * cItems
);
241 for(i
=0;i
<cItems
;i
++)
244 ZeroMemory(&item
->apidl
[i
], sizeof(SHChangeNotifyEntryInternal
));
246 item
->apidl
[i
].pidl
= ILClone(lpItems
[i
].pidl
);
247 item
->apidl
[i
].fRecursive
= lpItems
[i
].fRecursive
;
249 item
->apidl
[i
].buffer
= SHAlloc(BUFFER_SIZE
);
250 item
->apidl
[i
].backBuffer
= SHAlloc(BUFFER_SIZE
);
251 item
->apidl
[i
].overlapped
.hEvent
= &item
->apidl
[i
];
253 if (fSources
& SHCNRF_InterruptLevel
&& _OpenDirectory( &item
->apidl
[i
] ))
254 QueueUserAPC(_AddDirectoryProc
, m_hThread
, (ULONG_PTR
) &item
->apidl
[i
] );
255 else ERR("_OpenDirectory Failed\n");
260 item
->wEventMask
= wEventMask
;
261 item
->dwFlags
= fSources
;
262 item
->id
= InterlockedIncrement( &next_id
);
264 TRACE("new node: %s\n", NodeName( item
));
266 EnterCriticalSection(&SHELL32_ChangenotifyCS
);
268 list_add_tail( ¬ifications
, &item
->entry
);
270 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
275 /*************************************************************************
276 * SHChangeNotifyDeregister [SHELL32.4]
278 BOOL WINAPI
SHChangeNotifyDeregister(ULONG hNotify
)
280 LPNOTIFICATIONLIST node
;
282 TRACE("(0x%08x)\n", hNotify
);
284 EnterCriticalSection(&SHELL32_ChangenotifyCS
);
286 LIST_FOR_EACH_ENTRY( node
, ¬ifications
, NOTIFICATIONLIST
, entry
)
288 if (node
->id
== hNotify
)
291 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
295 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
299 /*************************************************************************
300 * SHChangeNotifyUpdateEntryList [SHELL32.5]
302 BOOL WINAPI
SHChangeNotifyUpdateEntryList(DWORD unknown1
, DWORD unknown2
,
303 DWORD unknown3
, DWORD unknown4
)
305 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
306 unknown1
, unknown2
, unknown3
, unknown4
);
311 struct new_delivery_notification
316 LPITEMIDLIST pidls
[2];
320 static BOOL
should_notify( LPCITEMIDLIST changed
, LPCITEMIDLIST watched
, BOOL sub
)
322 TRACE("%p %p %d\n", changed
, watched
, sub
);
325 if (ILIsEqual( watched
, changed
) )
327 if( sub
&& ILIsParent( watched
, changed
, FALSE
) )
332 /*************************************************************************
333 * SHChangeNotify [SHELL32.@]
335 void WINAPI
SHChangeNotify(LONG wEventId
, UINT uFlags
, LPCVOID dwItem1
, LPCVOID dwItem2
)
337 struct notification_recipients
{
344 HANDLE shared_data
= NULL
;
345 LPITEMIDLIST Pidls
[2];
346 LPNOTIFICATIONLIST ptr
;
347 struct list recipients
;
352 TRACE("(0x%08x,0x%08x,%p,%p)\n", wEventId
, uFlags
, dwItem1
, dwItem2
);
354 if(uFlags
& ~(SHCNF_TYPE
|SHCNF_FLUSH
))
355 FIXME("ignoring unsupported flags: %x\n", uFlags
);
357 if( ( wEventId
& SHCNE_NOITEMEVENTS
) && ( dwItem1
|| dwItem2
) )
359 TRACE("dwItem1 and dwItem2 are not zero, but should be\n");
364 else if( ( wEventId
& SHCNE_ONEITEMEVENTS
) && dwItem2
)
366 TRACE("dwItem2 is not zero, but should be\n");
371 if( ( ( wEventId
& SHCNE_NOITEMEVENTS
) &&
372 ( wEventId
& ~SHCNE_NOITEMEVENTS
) ) ||
373 ( ( wEventId
& SHCNE_ONEITEMEVENTS
) &&
374 ( wEventId
& ~SHCNE_ONEITEMEVENTS
) ) ||
375 ( ( wEventId
& SHCNE_TWOITEMEVENTS
) &&
376 ( wEventId
& ~SHCNE_TWOITEMEVENTS
) ) )
378 WARN("mutually incompatible events listed\n");
382 /* convert paths in IDLists*/
383 switch (uFlags
& SHCNF_TYPE
)
386 if (dwItem1
) Pidls
[0] = SHSimpleIDListFromPathA(dwItem1
); //FIXME
387 if (dwItem2
) Pidls
[1] = SHSimpleIDListFromPathA(dwItem2
); //FIXME
390 if (dwItem1
) Pidls
[0] = SHSimpleIDListFromPathW(dwItem1
);
391 if (dwItem2
) Pidls
[1] = SHSimpleIDListFromPathW(dwItem2
);
393 if (wEventId
& (SHCNE_MKDIR
| SHCNE_RMDIR
| SHCNE_UPDATEDIR
| SHCNE_RENAMEFOLDER
))
396 * The last items in the ID are currently files. So we chop off the last
397 * entry, and create a new one using a find data struct.
399 if (dwItem1
&& Pidls
[0]){
400 WIN32_FIND_DATAW wfd
;
401 LPITEMIDLIST oldpidl
, newpidl
;
402 LPWSTR p
= PathFindFileNameW((LPCWSTR
)dwItem1
);
403 ILRemoveLastID(Pidls
[0]);
404 lstrcpynW(&wfd
.cFileName
[0], p
, MAX_PATH
);
405 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
406 newpidl
= _ILCreateFromFindDataW(&wfd
);
407 oldpidl
= ILClone(Pidls
[0]);
409 Pidls
[0] = ILCombine(oldpidl
, newpidl
);
413 if (dwItem2
&& Pidls
[1]){
414 WIN32_FIND_DATAW wfd
;
415 LPITEMIDLIST oldpidl
, newpidl
;
416 LPWSTR p
= PathFindFileNameW((LPCWSTR
)dwItem2
);
417 ILRemoveLastID(Pidls
[1]);
418 lstrcpynW(&wfd
.cFileName
[0], p
, MAX_PATH
);
419 wfd
.dwFileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
420 newpidl
= _ILCreateFromFindDataW(&wfd
);
421 oldpidl
= ILClone(Pidls
[0]);
423 Pidls
[1] = ILCombine(oldpidl
, newpidl
);
431 Pidls
[0] = ILClone(dwItem1
);
432 Pidls
[1] = ILClone(dwItem2
);
436 FIXME("SHChangeNotify with (uFlags & SHCNF_PRINTER)\n");
440 FIXME("unknown type %08x\n", uFlags
& SHCNF_TYPE
);
444 list_init(&recipients
);
445 EnterCriticalSection(&SHELL32_ChangenotifyCS
);
446 LIST_FOR_EACH_ENTRY( ptr
, ¬ifications
, NOTIFICATIONLIST
, entry
)
448 struct notification_recipients
*item
;
452 for( i
=0; (i
<ptr
->cidl
) && !notify
; i
++ )
454 LPCITEMIDLIST pidl
= ptr
->apidl
[i
].pidl
;
455 BOOL subtree
= ptr
->apidl
[i
].fRecursive
;
457 if (wEventId
& ptr
->wEventMask
)
459 if( !pidl
) /* all ? */
461 else if( wEventId
& SHCNE_NOITEMEVENTS
)
463 else if( wEventId
& ( SHCNE_ONEITEMEVENTS
| SHCNE_TWOITEMEVENTS
) )
464 notify
= should_notify( Pidls
[0], pidl
, subtree
);
465 else if( wEventId
& SHCNE_TWOITEMEVENTS
)
466 notify
= should_notify( Pidls
[1], pidl
, subtree
);
473 item
= SHAlloc(sizeof(struct notification_recipients
));
475 ERR("out of memory\n");
479 item
->hwnd
= ptr
->hwnd
;
480 item
->msg
= ptr
->uMsg
;
481 item
->flags
= ptr
->dwFlags
;
482 list_add_tail(&recipients
, &item
->entry
);
484 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
486 LIST_FOR_EACH_ENTRY_SAFE(cur
, next
, &recipients
, struct notification_recipients
, entry
)
488 TRACE("notifying %p, event %s(%x)\n", cur
->hwnd
, DumpEvent(wEventId
), wEventId
);
490 if (cur
->flags
& SHCNRF_NewDelivery
) {
492 struct new_delivery_notification
*notification
;
493 UINT size1
= ILGetSize(Pidls
[0]), size2
= ILGetSize(Pidls
[1]);
494 UINT offset
= (size1
+sizeof(int)-1)/sizeof(int)*sizeof(int);
496 notification
= SHAlloc(sizeof(struct new_delivery_notification
)+offset
+size2
);
498 ERR("out of memory\n");
500 notification
->event
= wEventId
;
501 notification
->pidl1_size
= size1
;
502 notification
->pidl2_size
= size2
;
504 memcpy(notification
->data
, Pidls
[0], size1
);
506 memcpy(notification
->data
+offset
, Pidls
[1], size2
);
508 shared_data
= SHAllocShared(notification
,
509 sizeof(struct new_delivery_notification
)+size1
+size2
,
510 GetCurrentProcessId());
511 SHFree(notification
);
516 SendMessageA(cur
->hwnd
, cur
->msg
, (WPARAM
)shared_data
, GetCurrentProcessId());
518 ERR("out of memory\n");
520 SendMessageA(cur
->hwnd
, cur
->msg
, (WPARAM
)Pidls
, wEventId
);
523 list_remove(&cur
->entry
);
526 SHFreeShared(shared_data
, GetCurrentProcessId());
531 if (wEventId
& SHCNE_ASSOCCHANGED
)
533 static const WCHAR args
[] = {' ','-','a',0 };
534 TRACE("refreshing file type associations\n");
535 run_winemenubuilder( args
);
540 /*************************************************************************
541 * NTSHChangeNotifyRegister [SHELL32.640]
543 * Idlist is an array of structures and Count specifies how many items in the array.
544 * count should always be one when calling SHChangeNotifyRegister, or
545 * SHChangeNotifyDeregister will not work properly.
547 EXTERN_C ULONG WINAPI
NTSHChangeNotifyRegister(
553 SHChangeNotifyEntry
*idlist
)
555 return SHChangeNotifyRegister(hwnd
, fSources
| SHCNRF_NewDelivery
,
556 fEvents
, msg
, count
, idlist
);
559 /*************************************************************************
560 * SHChangeNotification_Lock [SHELL32.644]
562 HANDLE WINAPI
SHChangeNotification_Lock(
565 LPITEMIDLIST
**lppidls
,
568 struct new_delivery_notification
*ndn
;
571 TRACE("%p %08x %p %p\n", hChange
, dwProcessId
, lppidls
, lpwEventId
);
573 ndn
= SHLockShared(hChange
, dwProcessId
);
575 WARN("SHLockShared failed\n");
580 offset
= (ndn
->pidl1_size
+sizeof(int)-1)/sizeof(int)*sizeof(int);
581 ndn
->pidls
[0] = ndn
->pidl1_size
? (LPITEMIDLIST
)ndn
->data
: NULL
;
582 ndn
->pidls
[1] = ndn
->pidl2_size
? (LPITEMIDLIST
)(ndn
->data
+offset
) : NULL
;
583 *lppidls
= ndn
->pidls
;
587 *lpwEventId
= ndn
->event
;
592 /*************************************************************************
593 * SHChangeNotification_Unlock [SHELL32.645]
595 BOOL WINAPI
SHChangeNotification_Unlock ( HANDLE hLock
)
597 TRACE("%p\n", hLock
);
598 return SHUnlockShared(hLock
);
601 /*************************************************************************
602 * NTSHChangeNotifyDeregister [SHELL32.641]
604 DWORD WINAPI
NTSHChangeNotifyDeregister(ULONG x1
)
606 FIXME("(0x%08x):semi stub.\n",x1
);
608 return SHChangeNotifyDeregister( x1
);
616 _AddDirectoryProc(ULONG_PTR arg
)
618 LPNOTIFYREGISTER item
= (LPNOTIFYREGISTER
)arg
;
622 BOOL
_OpenDirectory(LPNOTIFYREGISTER item
)
625 IShellFolder
*psfDesktop
;
628 // Makes function idempotent
629 if (item
->hDirectory
&& !(item
->hDirectory
== INVALID_HANDLE_VALUE
))
632 hr
= SHGetDesktopFolder(&psfDesktop
);
636 hr
= IShellFolder_GetDisplayNameOf(psfDesktop
, item
->pidl
, SHGDN_FORPARSING
, &strFile
);
637 IShellFolder_Release(psfDesktop
);
641 hr
= StrRetToBufW(&strFile
, NULL
, item
->wstrDirectory
, _countof(item
->wstrDirectory
));
645 TRACE("_OpenDirectory %s\n", debugstr_w(item
->wstrDirectory
));
647 item
->hDirectory
= CreateFileW(item
->wstrDirectory
, // pointer to the file name
648 GENERIC_READ
| FILE_LIST_DIRECTORY
, // access (read/write) mode
649 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, // share mode
650 NULL
, // security descriptor
651 OPEN_EXISTING
, // how to create
652 FILE_FLAG_BACKUP_SEMANTICS
| FILE_FLAG_OVERLAPPED
, // file attributes
653 NULL
); // file with attributes to copy
655 if (item
->hDirectory
== INVALID_HANDLE_VALUE
)
662 static void CALLBACK
_RequestTermination(ULONG_PTR arg
)
664 LPNOTIFYREGISTER item
= (LPNOTIFYREGISTER
) arg
;
665 TRACE("_RequestTermination %p \n", item
->hDirectory
);
666 if (!item
->hDirectory
|| item
->hDirectory
== INVALID_HANDLE_VALUE
) return;
668 CancelIo(item
->hDirectory
);
669 CloseHandle(item
->hDirectory
);
670 item
->hDirectory
= NULL
;
676 _NotificationCompletion(DWORD dwErrorCode
, // completion code
677 DWORD dwNumberOfBytesTransfered
, // number of bytes transferred
678 LPOVERLAPPED lpOverlapped
) // I/O information buffer
680 /* MSDN: The hEvent member of the OVERLAPPED structure is not used by the
681 system, so you can use it yourself. We do just this, storing a pointer
682 to the working struct in the overlapped structure. */
683 LPNOTIFYREGISTER item
= (LPNOTIFYREGISTER
) lpOverlapped
->hEvent
;
684 TRACE("_NotificationCompletion\n");
686 if (dwErrorCode
== ERROR_OPERATION_ABORTED
)
688 /* Command was induced by CancelIo in the shutdown procedure. */
689 TRACE("_NotificationCompletion ended.\n");
693 /* This likely means overflow, so force whole directory refresh. */
694 if (!dwNumberOfBytesTransfered
)
696 ERR("_NotificationCompletion overflow\n");
698 ZeroMemory(item
->buffer
, BUFFER_SIZE
);
701 SHChangeNotify(SHCNE_UPDATEITEM
| SHCNE_INTERRUPT
,
710 * Get the new read issued as fast as possible (before we do the
711 * processing and message posting). All of the file notification
712 * occur on one thread so the buffers should not collide with one another.
713 * The extra zero mems are because the FNI size isn't written correctly.
716 ZeroMemory(item
->backBuffer
, BUFFER_SIZE
);
717 memcpy(item
->backBuffer
, item
->buffer
, dwNumberOfBytesTransfered
);
718 ZeroMemory(item
->buffer
, BUFFER_SIZE
);
722 _ProcessNotification(item
);
725 static VOID
_BeginRead(LPNOTIFYREGISTER item
)
727 TRACE("_BeginRead %p \n", item
->hDirectory
);
729 /* This call needs to be reissued after every APC. */
730 if (!ReadDirectoryChangesW(item
->hDirectory
, // handle to directory
731 item
->buffer
, // read results buffer
732 BUFFER_SIZE
, // length of buffer
733 FALSE
, // monitoring option (recursion)
734 FILE_NOTIFY_CHANGE_DIR_NAME
| FILE_NOTIFY_CHANGE_FILE_NAME
, // filter conditions
735 NULL
, // bytes returned
736 &item
->overlapped
, // overlapped buffer
737 _NotificationCompletion
)) // completion routine
738 ERR("ReadDirectoryChangesW failed. (%p, %p, %p, %p) Code: %u \n",
742 _NotificationCompletion
,
746 DWORD
_MapAction(DWORD dwAction
, BOOL isDir
)
750 case FILE_ACTION_ADDED
: return isDir
? SHCNE_MKDIR
: SHCNE_CREATE
;
751 case FILE_ACTION_REMOVED
: return isDir
? SHCNE_RMDIR
: SHCNE_DELETE
;
752 case FILE_ACTION_MODIFIED
: return isDir
? SHCNE_UPDATEDIR
: SHCNE_UPDATEITEM
;
753 case FILE_ACTION_RENAMED_OLD_NAME
: return isDir
? SHCNE_UPDATEDIR
: SHCNE_UPDATEITEM
;
754 case FILE_ACTION_RENAMED_NEW_NAME
: return isDir
? SHCNE_UPDATEDIR
: SHCNE_UPDATEITEM
;
755 default: return SHCNE_UPDATEITEM
;
759 VOID
_ProcessNotification(LPNOTIFYREGISTER item
)
761 BYTE
* pBase
= item
->backBuffer
;
762 TRACE("_ProcessNotification\n");
766 FILE_NOTIFY_INFORMATION
* fni
= (FILE_NOTIFY_INFORMATION
*)pBase
;
769 WCHAR wstrFilename
[MAX_PATH
];
771 StringCchCopy(tmp
, fni
->FileNameLength
, fni
->FileName
);
773 PathCombine(wstrFilename
, item
->wstrDirectory
, tmp
);
775 /* If it could be a short filename, expand it. */
776 wszFilename
= PathFindFileNameW(wstrFilename
);
778 len
= lstrlenW(wszFilename
);
779 /* The maximum length of an 8.3 filename is twelve, including the dot. */
780 if (len
<= 12 && wcschr(wszFilename
, L
'~'))
782 /* Convert to the long filename form. Unfortunately, this
783 does not work for deletions, so it's an imperfect fix. */
784 wchar_t wbuf
[MAX_PATH
];
785 if (GetLongPathName(wstrFilename
, wbuf
, _countof (wbuf
)) > 0)
786 StringCchCopyW(wstrFilename
, MAX_PATH
, wbuf
);
789 /* On deletion of a folder PathIsDirectory will return false even if
790 it *was* a directory, so, again, imperfect. */
791 SHChangeNotify(_MapAction(fni
->Action
, PathIsDirectory(wstrFilename
)) | SHCNE_INTERRUPT
,
796 if (!fni
->NextEntryOffset
)
798 pBase
+= fni
->NextEntryOffset
;
802 static void CALLBACK
_RequestAllTermination(ULONG_PTR arg
)
807 static unsigned int WINAPI
_RunAsyncThreadProc(LPVOID arg
)
809 m_bTerminate
= FALSE
;
810 while (!m_bTerminate
)
812 SleepEx(INFINITE
, TRUE
);
817 #endif /* __REACTOS__ */