ReactOS  0.4.14-dev-50-g13bb5e2
changenotify.c
Go to the documentation of this file.
1 /*
2  * shell change notification
3  *
4  * Copyright 2000 Juergen Schmied
5  *
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.
10  *
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.
15  *
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
19  */
20 
21 #define WIN32_NO_STATUS
22 #define _INC_WINDOWS
23 #define COBJMACROS
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
26 #define BUFFER_SIZE 1024
27 
28 #include <windef.h>
29 #include <winbase.h>
30 #include <shlobj.h>
31 #include <strsafe.h>
32 #include <undocshell.h>
33 #include <shlwapi.h>
34 #include <wine/debug.h>
35 #include <wine/list.h>
36 #include <process.h>
37 #include <shellutils.h>
38 
39 #include "pidl.h"
40 
42 
45 {
48  0, 0, { (DWORD_PTR)(__FILE__ ": SHELL32_ChangenotifyCS") }
49 };
50 static CRITICAL_SECTION SHELL32_ChangenotifyCS = { &critsect_debug, -1, 0, 0, 0, 0 };
51 
52 #ifdef __REACTOS__
53 typedef struct {
54  PCIDLIST_ABSOLUTE pidl;
55  BOOL fRecursive;
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 } SHChangeNotifyEntryInternal, *LPNOTIFYREGISTER;
63 #else
65 #endif
66 
67 /* internal list of notification clients (internal) */
68 typedef struct _NOTIFICATIONLIST
69 {
70  struct list entry;
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 
80 #ifdef __REACTOS__
81 VOID _ProcessNotification(LPNOTIFYREGISTER item);
82 BOOL _OpenDirectory(LPNOTIFYREGISTER item);
83 static void CALLBACK _RequestTermination(ULONG_PTR arg);
84 static void CALLBACK _RequestAllTermination(ULONG_PTR arg);
85 static void CALLBACK _AddDirectoryProc(ULONG_PTR arg);
86 static VOID _BeginRead(LPNOTIFYREGISTER item);
87 static unsigned int WINAPI _RunAsyncThreadProc(LPVOID arg);
88 #endif
89 
91 static LONG next_id;
92 
93 #ifdef __REACTOS__
94 HANDLE m_hThread;
95 UINT m_dwThreadId;
96 BOOL m_bTerminate;
97 #endif
98 
99 #define SHCNE_NOITEMEVENTS ( \
100  SHCNE_ASSOCCHANGED )
101 
102 #define SHCNE_ONEITEMEVENTS ( \
103  SHCNE_ATTRIBUTES | SHCNE_CREATE | SHCNE_DELETE | SHCNE_DRIVEADD | \
104  SHCNE_DRIVEADDGUI | SHCNE_DRIVEREMOVED | SHCNE_FREESPACE | \
105  SHCNE_MEDIAINSERTED | SHCNE_MEDIAREMOVED | SHCNE_MKDIR | \
106  SHCNE_NETSHARE | SHCNE_NETUNSHARE | SHCNE_RMDIR | \
107  SHCNE_SERVERDISCONNECT | SHCNE_UPDATEDIR | SHCNE_UPDATEIMAGE )
108 
109 #define SHCNE_TWOITEMEVENTS ( \
110  SHCNE_RENAMEFOLDER | SHCNE_RENAMEITEM | SHCNE_UPDATEITEM )
111 
112 /* for dumping events */
113 static const char * DumpEvent( LONG event )
114 {
115  if( event == SHCNE_ALLEVENTS )
116  return "SHCNE_ALLEVENTS";
117 #define DUMPEV(x) ,( event & SHCNE_##x )? #x " " : ""
118  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"
119  DUMPEV(RENAMEITEM)
120  DUMPEV(CREATE)
121  DUMPEV(DELETE)
122  DUMPEV(MKDIR)
123  DUMPEV(RMDIR)
124  DUMPEV(MEDIAINSERTED)
125  DUMPEV(MEDIAREMOVED)
126  DUMPEV(DRIVEREMOVED)
127  DUMPEV(DRIVEADD)
128  DUMPEV(NETSHARE)
129  DUMPEV(NETUNSHARE)
130  DUMPEV(ATTRIBUTES)
131  DUMPEV(UPDATEDIR)
132  DUMPEV(UPDATEITEM)
133  DUMPEV(SERVERDISCONNECT)
134  DUMPEV(UPDATEIMAGE)
135  DUMPEV(DRIVEADDGUI)
136  DUMPEV(RENAMEFOLDER)
137  DUMPEV(FREESPACE)
138  DUMPEV(EXTENDED_EVENT)
139  DUMPEV(ASSOCCHANGED)
140  DUMPEV(INTERRUPT)
141  );
142 #undef DUMPEV
143 }
144 
145 static const char * NodeName(const NOTIFICATIONLIST *item)
146 {
147  const char *str;
149 
150  if(SHGetPathFromIDListW(item->apidl[0].pidl, path ))
152  else
153  str = wine_dbg_sprintf("<not a disk file>" );
154  return str;
155 }
156 
158 {
159  UINT i;
160 
161  TRACE("item=%p\n", item);
162 
163  /* remove item from list */
164  list_remove( &item->entry );
165 
166  /* free the item */
167  for (i=0; i<item->cidl; i++)
168 #ifdef __REACTOS__
169  {
170  QueueUserAPC(_RequestTermination, m_hThread, (ULONG_PTR) &item->apidl[i] );
171  WaitForSingleObjectEx(m_hThread, 100, FALSE);
172 #endif
173  SHFree((LPITEMIDLIST)item->apidl[i].pidl);
174 #ifdef __REACTOS__
175  SHFree(item->apidl[i].buffer);
176  SHFree(item->apidl[i].backBuffer);
177  }
178 #endif
179  SHFree(item->apidl);
180  SHFree(item);
181 }
182 
184 {
185 #ifdef __REACTOS__
186  m_hThread = NULL;
187 #endif
188 }
189 
191 {
193 
194  TRACE("\n");
195 
197 
199  DeleteNode( ptr );
200 
202 
203 #ifdef __REACTOS__
204  QueueUserAPC(_RequestAllTermination, m_hThread, (ULONG_PTR) NULL );
205 #endif
206 
208 }
209 
210 /*************************************************************************
211  * SHChangeNotifyRegister [SHELL32.2]
212  *
213  */
216  HWND hwnd,
217  int fSources,
218  LONG wEventMask,
219  UINT uMsg,
220  int cItems,
221  SHChangeNotifyEntry *lpItems)
222 {
224  int i;
225 
226  item = SHAlloc(sizeof(NOTIFICATIONLIST));
227 
228  TRACE("(%p,0x%08x,0x%08x,0x%08x,%d,%p) item=%p\n",
229  hwnd, fSources, wEventMask, uMsg, cItems, lpItems, item);
230 
231 #ifdef __REACTOS__
232  if (!m_hThread)
233  m_hThread = (HANDLE) _beginthreadex(NULL, 0, _RunAsyncThreadProc, NULL, 0, &m_dwThreadId);
234 #endif
235 
236  item->cidl = cItems;
237 #ifdef __REACTOS__
238  item->apidl = SHAlloc(sizeof(SHChangeNotifyEntryInternal) * cItems);
239 #else
240  item->apidl = SHAlloc(sizeof(SHChangeNotifyEntry) * cItems);
241 #endif
242  for(i=0;i<cItems;i++)
243  {
244 #ifdef __REACTOS__
245  ZeroMemory(&item->apidl[i], sizeof(SHChangeNotifyEntryInternal));
246 #endif
247  item->apidl[i].pidl = ILClone(lpItems[i].pidl);
248  item->apidl[i].fRecursive = lpItems[i].fRecursive;
249 #ifdef __REACTOS__
250  item->apidl[i].buffer = SHAlloc(BUFFER_SIZE);
251  item->apidl[i].backBuffer = SHAlloc(BUFFER_SIZE);
252  item->apidl[i].overlapped.hEvent = &item->apidl[i];
253 
254  if (fSources & SHCNRF_InterruptLevel)
255  {
256  if (_OpenDirectory( &item->apidl[i] ))
257  {
258  QueueUserAPC( _AddDirectoryProc, m_hThread, (ULONG_PTR) &item->apidl[i] );
259  }
260  }
261 #endif
262  }
263  item->hwnd = hwnd;
264  item->uMsg = uMsg;
265  item->wEventMask = wEventMask;
266  item->dwFlags = fSources;
268 
269  TRACE("new node: %s\n", NodeName( item ));
270 
272 
273  list_add_tail( &notifications, &item->entry );
274 
276 
277  return item->id;
278 }
279 
280 /*************************************************************************
281  * SHChangeNotifyDeregister [SHELL32.4]
282  */
284 {
286 
287  TRACE("(0x%08x)\n", hNotify);
288 
290 
292  {
293  if (node->id == hNotify)
294  {
295  DeleteNode( node );
297  return TRUE;
298  }
299  }
301  return FALSE;
302 }
303 
304 /*************************************************************************
305  * SHChangeNotifyUpdateEntryList [SHELL32.5]
306  */
308  DWORD unknown3, DWORD unknown4)
309 {
310  FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
311  unknown1, unknown2, unknown3, unknown4);
312 
313  return TRUE;
314 }
315 
317 {
322  BYTE data[1];
323 };
324 
325 static BOOL should_notify( LPCITEMIDLIST changed, LPCITEMIDLIST watched, BOOL sub )
326 {
327  TRACE("%p %p %d\n", changed, watched, sub );
328  if ( !watched )
329  return FALSE;
330  if (ILIsEqual( watched, changed ) )
331  return TRUE;
332  if( sub && ILIsParent( watched, changed, FALSE ) )
333  return TRUE;
334  return FALSE;
335 }
336 
337 /*************************************************************************
338  * SHChangeNotify [SHELL32.@]
339  */
340 void WINAPI SHChangeNotify(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID dwItem2)
341 {
342  struct notification_recipients {
343  struct list entry;
344  HWND hwnd;
345  DWORD msg;
346  DWORD flags;
347  } *cur, *next;
348 
349  HANDLE shared_data = NULL;
350  LPITEMIDLIST Pidls[2];
352  struct list recipients;
353 
354  Pidls[0] = NULL;
355  Pidls[1] = NULL;
356 
357  TRACE("(0x%08x,0x%08x,%p,%p)\n", wEventId, uFlags, dwItem1, dwItem2);
358 
359  if(uFlags & ~(SHCNF_TYPE|SHCNF_FLUSH))
360  FIXME("ignoring unsupported flags: %x\n", uFlags);
361 
362  if( ( wEventId & SHCNE_NOITEMEVENTS ) && ( dwItem1 || dwItem2 ) )
363  {
364  TRACE("dwItem1 and dwItem2 are not zero, but should be\n");
365  dwItem1 = 0;
366  dwItem2 = 0;
367  return;
368  }
369  else if( ( wEventId & SHCNE_ONEITEMEVENTS ) && dwItem2 )
370  {
371  TRACE("dwItem2 is not zero, but should be\n");
372  dwItem2 = 0;
373  return;
374  }
375 
376  if( ( ( wEventId & SHCNE_NOITEMEVENTS ) &&
377  ( wEventId & ~(SHCNE_NOITEMEVENTS | SHCNE_INTERRUPT) ) ) ||
378  ( ( wEventId & SHCNE_ONEITEMEVENTS ) &&
379  ( wEventId & ~(SHCNE_ONEITEMEVENTS | SHCNE_INTERRUPT) ) ) ||
380  ( ( wEventId & SHCNE_TWOITEMEVENTS ) &&
381  ( wEventId & ~(SHCNE_TWOITEMEVENTS | SHCNE_INTERRUPT) ) ) )
382  {
383  WARN("mutually incompatible events listed\n");
384  return;
385  }
386 
387  /* convert paths in IDLists*/
388  switch (uFlags & SHCNF_TYPE)
389  {
390  case SHCNF_PATHA:
391  if (dwItem1) Pidls[0] = SHSimpleIDListFromPathA(dwItem1); //FIXME
392  if (dwItem2) Pidls[1] = SHSimpleIDListFromPathA(dwItem2); //FIXME
393  break;
394  case SHCNF_PATHW:
395  if (dwItem1) Pidls[0] = SHSimpleIDListFromPathW(dwItem1);
396  if (dwItem2) Pidls[1] = SHSimpleIDListFromPathW(dwItem2);
397 #ifdef __REACTOS__
399  {
400  /*
401  * The last items in the ID are currently files. So we chop off the last
402  * entry, and create a new one using a find data struct.
403  */
404  if (dwItem1 && Pidls[0]){
405  WIN32_FIND_DATAW wfd;
406  LPITEMIDLIST oldpidl, newpidl;
407  LPWSTR p = PathFindFileNameW((LPCWSTR)dwItem1);
408  ILRemoveLastID(Pidls[0]);
409  lstrcpynW(&wfd.cFileName[0], p, MAX_PATH);
410  wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
411  newpidl = _ILCreateFromFindDataW(&wfd);
412  oldpidl = ILClone(Pidls[0]);
413  ILFree(Pidls[0]);
414  Pidls[0] = ILCombine(oldpidl, newpidl);
415  ILFree(newpidl);
416  ILFree(oldpidl);
417  }
418  if (dwItem2 && Pidls[1]){
419  WIN32_FIND_DATAW wfd;
420  LPITEMIDLIST oldpidl, newpidl;
421  LPWSTR p = PathFindFileNameW((LPCWSTR)dwItem2);
422  ILRemoveLastID(Pidls[1]);
423  lstrcpynW(&wfd.cFileName[0], p, MAX_PATH);
424  wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
425  newpidl = _ILCreateFromFindDataW(&wfd);
426  oldpidl = ILClone(Pidls[0]);
427  ILFree(Pidls[1]);
428  Pidls[1] = ILCombine(oldpidl, newpidl);
429  ILFree(newpidl);
430  ILFree(oldpidl);
431  }
432  }
433 #endif
434  break;
435  case SHCNF_IDLIST:
436  Pidls[0] = ILClone(dwItem1);
437  Pidls[1] = ILClone(dwItem2);
438  break;
439  case SHCNF_PRINTERA:
440  case SHCNF_PRINTERW:
441  FIXME("SHChangeNotify with (uFlags & SHCNF_PRINTER)\n");
442  return;
443  case SHCNF_DWORD:
444  default:
445  FIXME("unknown type %08x\n", uFlags & SHCNF_TYPE);
446  return;
447  }
448 
449  list_init(&recipients);
452  {
453  struct notification_recipients *item;
454  BOOL notify = FALSE;
455  DWORD i;
456 
457  for( i=0; (i<ptr->cidl) && !notify ; i++ )
458  {
459  LPCITEMIDLIST pidl = ptr->apidl[i].pidl;
460  BOOL subtree = ptr->apidl[i].fRecursive;
461 
462  if (wEventId & ptr->wEventMask)
463  {
464  if( !pidl ) /* all ? */
465  notify = TRUE;
466  else if( wEventId & SHCNE_NOITEMEVENTS )
467  notify = TRUE;
468  else if( wEventId & ( SHCNE_ONEITEMEVENTS | SHCNE_TWOITEMEVENTS ) )
469  notify = should_notify( Pidls[0], pidl, subtree );
470  else if( wEventId & SHCNE_TWOITEMEVENTS )
471  notify = should_notify( Pidls[1], pidl, subtree );
472  }
473  }
474 
475  if( !notify )
476  continue;
477 
478  item = SHAlloc(sizeof(struct notification_recipients));
479  if(!item) {
480  ERR("out of memory\n");
481  continue;
482  }
483 
484  item->hwnd = ptr->hwnd;
485  item->msg = ptr->uMsg;
486  item->flags = ptr->dwFlags;
487  list_add_tail(&recipients, &item->entry);
488  }
490 
491  LIST_FOR_EACH_ENTRY_SAFE(cur, next, &recipients, struct notification_recipients, entry)
492  {
493  TRACE("notifying %p, event %s(%x)\n", cur->hwnd, DumpEvent(wEventId), wEventId);
494 
495  if (cur->flags & SHCNRF_NewDelivery) {
496  if(!shared_data) {
498  UINT size1 = ILGetSize(Pidls[0]), size2 = ILGetSize(Pidls[1]);
499  UINT offset = (size1+sizeof(int)-1)/sizeof(int)*sizeof(int);
500 
501  notification = SHAlloc(sizeof(struct new_delivery_notification)+offset+size2);
502  if(!notification) {
503  ERR("out of memory\n");
504  } else {
505  notification->event = wEventId;
506  notification->pidl1_size = size1;
507  notification->pidl2_size = size2;
508  if(size1)
509  memcpy(notification->data, Pidls[0], size1);
510  if(size2)
511  memcpy(notification->data+offset, Pidls[1], size2);
512 
513  shared_data = SHAllocShared(notification,
514  sizeof(struct new_delivery_notification)+size1+size2,
517  }
518  }
519 
520  if(shared_data)
521  SendMessageA(cur->hwnd, cur->msg, (WPARAM)shared_data, GetCurrentProcessId());
522  else
523  ERR("out of memory\n");
524  } else {
525  SendMessageA(cur->hwnd, cur->msg, (WPARAM)Pidls, wEventId);
526  }
527 
528  list_remove(&cur->entry);
529  SHFree(cur);
530  }
531  SHFreeShared(shared_data, GetCurrentProcessId());
532  SHFree(Pidls[0]);
533  SHFree(Pidls[1]);
534 
535 #ifndef __REACTOS__
536  if (wEventId & SHCNE_ASSOCCHANGED)
537  {
538  static const WCHAR args[] = {' ','-','a',0 };
539  TRACE("refreshing file type associations\n");
541  }
542 #endif
543 }
544 
545 /*************************************************************************
546  * NTSHChangeNotifyRegister [SHELL32.640]
547  * NOTES
548  * Idlist is an array of structures and Count specifies how many items in the array.
549  * count should always be one when calling SHChangeNotifyRegister, or
550  * SHChangeNotifyDeregister will not work properly.
551  */
553  HWND hwnd,
554  int fSources,
555  LONG fEvents,
556  UINT msg,
557  int count,
558  SHChangeNotifyEntry *idlist)
559 {
561  fEvents, msg, count, idlist);
562 }
563 
564 /*************************************************************************
565  * SHChangeNotification_Lock [SHELL32.644]
566  */
568  HANDLE hChange,
569  DWORD dwProcessId,
570  LPITEMIDLIST **lppidls,
571  LPLONG lpwEventId)
572 {
573  struct new_delivery_notification *ndn;
574  UINT offset;
575 
576  TRACE("%p %08x %p %p\n", hChange, dwProcessId, lppidls, lpwEventId);
577 
578  ndn = SHLockShared(hChange, dwProcessId);
579  if(!ndn) {
580  WARN("SHLockShared failed\n");
581  return NULL;
582  }
583 
584  if(lppidls) {
585  offset = (ndn->pidl1_size+sizeof(int)-1)/sizeof(int)*sizeof(int);
586  ndn->pidls[0] = ndn->pidl1_size ? (LPITEMIDLIST)ndn->data : NULL;
587  ndn->pidls[1] = ndn->pidl2_size ? (LPITEMIDLIST)(ndn->data+offset) : NULL;
588  *lppidls = ndn->pidls;
589  }
590 
591  if(lpwEventId)
592  *lpwEventId = ndn->event;
593 
594  return ndn;
595 }
596 
597 /*************************************************************************
598  * SHChangeNotification_Unlock [SHELL32.645]
599  */
601 {
602  TRACE("%p\n", hLock);
603  return SHUnlockShared(hLock);
604 }
605 
606 /*************************************************************************
607  * NTSHChangeNotifyDeregister [SHELL32.641]
608  */
610 {
611  FIXME("(0x%08x):semi stub.\n",x1);
612 
613  return SHChangeNotifyDeregister( x1 );
614 }
615 
616 #ifdef __REACTOS__
617 
618 static
619 void
620 CALLBACK
621 _AddDirectoryProc(ULONG_PTR arg)
622 {
624  _BeginRead(item);
625 }
626 
627 BOOL _OpenDirectory(LPNOTIFYREGISTER item)
628 {
629  STRRET strFile;
630  IShellFolder *psf;
631  HRESULT hr;
633  ULONG ulAttrs;
634 
635  // Makes function idempotent
636  if (item->hDirectory && !(item->hDirectory == INVALID_HANDLE_VALUE))
637  return TRUE;
638 
639  hr = SHBindToParent(item->pidl, &IID_IShellFolder, (LPVOID*)&psf, &child);
640  if (FAILED_UNEXPECTEDLY(hr))
641  return hr;
642 
643  ulAttrs = SFGAO_FILESYSTEM | SFGAO_FOLDER;
644  hr = IShellFolder_GetAttributesOf(psf, 1, (LPCITEMIDLIST*)&child, &ulAttrs);
645  if (SUCCEEDED(hr))
646  hr = IShellFolder_GetDisplayNameOf(psf, child, SHGDN_FORPARSING, &strFile);
647 
648  IShellFolder_Release(psf);
649  if (FAILED_UNEXPECTEDLY(hr))
650  return FALSE;
651 
652  hr = StrRetToBufW(&strFile, NULL, item->wstrDirectory, _countof(item->wstrDirectory));
653  if (FAILED_UNEXPECTEDLY(hr))
654  return FALSE;
655 
656  if ((ulAttrs & (SFGAO_FILESYSTEM | SFGAO_FOLDER)) != (SFGAO_FILESYSTEM | SFGAO_FOLDER))
657  {
658  TRACE("_OpenDirectory ignoring %s\n", debugstr_w(item->wstrDirectory));
659  item->hDirectory = INVALID_HANDLE_VALUE;
660  return FALSE;
661  }
662 
663  TRACE("_OpenDirectory %s\n", debugstr_w(item->wstrDirectory));
664 
665  item->hDirectory = CreateFileW(item->wstrDirectory, // pointer to the file name
666  GENERIC_READ | FILE_LIST_DIRECTORY, // access (read/write) mode
668  NULL, // security descriptor
669  OPEN_EXISTING, // how to create
671  NULL); // file with attributes to copy
672 
673  if (item->hDirectory == INVALID_HANDLE_VALUE)
674  {
675  ERR("_OpenDirectory failed for %s\n", debugstr_w(item->wstrDirectory));
676  return FALSE;
677  }
678  return TRUE;
679 }
680 
681 static void CALLBACK _RequestTermination(ULONG_PTR arg)
682 {
684  TRACE("_RequestTermination %p %p \n", item, item->hDirectory);
685  if (!item->hDirectory || item->hDirectory == INVALID_HANDLE_VALUE) return;
686 
687  CancelIo(item->hDirectory);
688  CloseHandle(item->hDirectory);
689  item->hDirectory = NULL;
690 }
691 
692 static
693 void
694 CALLBACK
695 _NotificationCompletion(DWORD dwErrorCode, // completion code
696  DWORD dwNumberOfBytesTransfered, // number of bytes transferred
697  LPOVERLAPPED lpOverlapped) // I/O information buffer
698 {
699  /* MSDN: The hEvent member of the OVERLAPPED structure is not used by the
700  system, so you can use it yourself. We do just this, storing a pointer
701  to the working struct in the overlapped structure. */
703  TRACE("_NotificationCompletion\n");
704 
705 #if 0
706  if (dwErrorCode == ERROR_OPERATION_ABORTED)
707  {
708  /* Command was induced by CancelIo in the shutdown procedure. */
709  TRACE("_NotificationCompletion ended.\n");
710  return;
711  }
712 #endif
713 
714 #ifdef __REACTOS__
715  /* If the FSD doesn't support directory change notifications, there's no
716  * no need to retry and requeue notification
717  */
718  if (dwErrorCode == ERROR_INVALID_FUNCTION)
719  {
720  WARN("Directory watching not supported\n");
721  return;
722  }
723 
724  /* Also, if the notify operation was canceled (like, user moved to another
725  * directory), then, don't requeue notification
726  */
727  if (dwErrorCode == ERROR_OPERATION_ABORTED)
728  {
729  TRACE("Notification aborted\n");
730  return;
731  }
732 
733  if (!item)
734  {
735  ERR("item == NULL\n");
736  return;
737  }
738 
739 #endif
740 
741  /* This likely means overflow, so force whole directory refresh. */
742  if (!dwNumberOfBytesTransfered)
743  {
744  ERR("_NotificationCompletion overflow\n");
745 
746  ZeroMemory(item->buffer, BUFFER_SIZE);
747  _BeginRead(item);
748 
750  SHCNF_IDLIST,
751  item->pidl,
752  NULL);
753 
754  return;
755  }
756 
757  /*
758  * Get the new read issued as fast as possible (before we do the
759  * processing and message posting). All of the file notification
760  * occur on one thread so the buffers should not collide with one another.
761  * The extra zero mems are because the FNI size isn't written correctly.
762  */
763 
764  ZeroMemory(item->backBuffer, BUFFER_SIZE);
765  memcpy(item->backBuffer, item->buffer, dwNumberOfBytesTransfered);
766  ZeroMemory(item->buffer, BUFFER_SIZE);
767 
768  _BeginRead(item);
769 
770  _ProcessNotification(item);
771 }
772 
773 static VOID _BeginRead(LPNOTIFYREGISTER item )
774 {
775  TRACE("_BeginRead %p \n", item->hDirectory);
776 
777  /* This call needs to be reissued after every APC. */
778  if (!ReadDirectoryChangesW(item->hDirectory, // handle to directory
779  item->buffer, // read results buffer
780  BUFFER_SIZE, // length of buffer
781  FALSE, // monitoring option (recursion)
783  NULL, // bytes returned
784  &item->overlapped, // overlapped buffer
785  _NotificationCompletion)) // completion routine
786  ERR("ReadDirectoryChangesW failed. (%p, %p, %p, %p, %p) Code: %u \n",
787  item,
788  item->hDirectory,
789  item->buffer,
790  &item->overlapped,
791  _NotificationCompletion,
792  GetLastError());
793 }
794 
795 DWORD _MapAction(DWORD dwAction, BOOL isDir)
796 {
797  switch (dwAction)
798  {
799  case FILE_ACTION_ADDED : return isDir ? SHCNE_MKDIR : SHCNE_CREATE;
800  case FILE_ACTION_REMOVED : return isDir ? SHCNE_RMDIR : SHCNE_DELETE;
801  case FILE_ACTION_MODIFIED : return isDir ? SHCNE_UPDATEDIR : SHCNE_UPDATEITEM;
804  default: return SHCNE_UPDATEITEM;
805  }
806 }
807 
808 VOID _ProcessNotification(LPNOTIFYREGISTER item)
809 {
810  BYTE* pBase = item->backBuffer;
811  TRACE("_ProcessNotification\n");
812 
813  for (;;)
814  {
816  LPWSTR wszFilename;
817  INT len = 0;
818  WCHAR wstrFilename[MAX_PATH];
819  WCHAR tmp[MAX_PATH];
820  StringCchCopy(tmp, fni->FileNameLength, fni->FileName);
821 
822  PathCombine(wstrFilename, item->wstrDirectory, tmp);
823 
824  /* If it could be a short filename, expand it. */
825  wszFilename = PathFindFileNameW(wstrFilename);
826 
827  len = lstrlenW(wszFilename);
828  /* The maximum length of an 8.3 filename is twelve, including the dot. */
829  if (len <= 12 && wcschr(wszFilename, L'~'))
830  {
831  /* Convert to the long filename form. Unfortunately, this
832  does not work for deletions, so it's an imperfect fix. */
833  wchar_t wbuf[MAX_PATH];
834  if (GetLongPathName(wstrFilename, wbuf, _countof (wbuf)) > 0)
835  StringCchCopyW(wstrFilename, MAX_PATH, wbuf);
836  }
837 
838  /* On deletion of a folder PathIsDirectory will return false even if
839  it *was* a directory, so, again, imperfect. */
840  SHChangeNotify(_MapAction(fni->Action, PathIsDirectory(wstrFilename)) | SHCNE_INTERRUPT,
841  SHCNF_PATHW,
842  wstrFilename,
843  NULL);
844 
845  if (!fni->NextEntryOffset)
846  break;
847  pBase += fni->NextEntryOffset;
848  }
849 }
850 
851 static void CALLBACK _RequestAllTermination(ULONG_PTR arg)
852 {
853  m_bTerminate = TRUE;
854 }
855 
856 static unsigned int WINAPI _RunAsyncThreadProc(LPVOID arg)
857 {
858  m_bTerminate = FALSE;
859  while (!m_bTerminate)
860  {
862  }
863  return 0;
864 }
865 
866 #endif /* __REACTOS__ */
#define SHCNE_MKDIR
Definition: shlobj.h:1723
ULONG WINAPI SHChangeNotifyRegister(HWND hwnd, int fSources, LONG wEventMask, UINT uMsg, int cItems, SHChangeNotifyEntry *lpItems)
Definition: changenotify.c:215
const DOCKBAR PVOID HWND HWND * hwnd
Definition: tooldock.h:22
DWORD WINAPI WaitForSingleObjectEx(IN HANDLE hHandle, IN DWORD dwMilliseconds, IN BOOL bAlertable)
Definition: synch.c:94
#define TRUE
Definition: types.h:120
#define SHCNE_RMDIR
Definition: shlobj.h:1724
#define CloseHandle
Definition: compat.h:398
void WINAPI ILFree(LPITEMIDLIST pidl)
Definition: pidl.c:925
#define FILE_ACTION_RENAMED_OLD_NAME
#define DWORD_PTR
Definition: treelist.c:76
HRESULT hr
Definition: shlfolder.c:183
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
static BOOL run_winemenubuilder(const WCHAR *args)
Definition: intshcut.c:85
#define ERROR_INVALID_FUNCTION
Definition: dderror.h:6
#define SHCNE_NOITEMEVENTS
Definition: changenotify.c:99
static BOOL should_notify(LPCITEMIDLIST changed, LPCITEMIDLIST watched, BOOL sub)
Definition: changenotify.c:325
void FreeChangeNotifications(void)
Definition: changenotify.c:190
LRESULT WINAPI SendMessageA(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define _countof(array)
Definition: fontsub.cpp:30
HRESULT WINAPI StrRetToBufW(LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, UINT len)
Definition: string.c:1522
#define PathCombine
Definition: shlwapi.h:825
GLuint GLuint GLsizei count
Definition: gl.h:1545
static struct list notifications
Definition: changenotify.c:90
_In_ CLIPOBJ _In_ BRUSHOBJ _In_ LONG x1
Definition: winddi.h:3706
#define WARN(fmt,...)
Definition: debug.h:111
int notify
Definition: msacm.c:1353
LPITEMIDLIST WINAPI ILCombine(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
Definition: pidl.c:699
#define SHCNE_RENAMEFOLDER
Definition: shlobj.h:1737
const ITEMIDLIST UNALIGNED * LPCITEMIDLIST
Definition: shtypes.idl:42
BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath)
Definition: pidl.c:1280
GLintptr offset
Definition: glext.h:5920
#define CALLBACK
Definition: compat.h:27
#define SHCNE_INTERRUPT
Definition: shlobj.h:1745
struct list entry
Definition: changenotify.c:70
#define INVALID_HANDLE_VALUE
Definition: compat.h:391
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
#define ZeroMemory
Definition: winbase.h:1635
GLuint buffer
Definition: glext.h:5915
HANDLE WINAPI SHChangeNotification_Lock(HANDLE hChange, DWORD dwProcessId, LPITEMIDLIST **lppidls, LPLONG lpwEventId)
Definition: changenotify.c:567
#define FILE_NOTIFY_CHANGE_FILE_NAME
BOOL WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
Definition: pidl.c:535
UINT_PTR WPARAM
Definition: windef.h:207
BOOL WINAPI ILRemoveLastID(LPITEMIDLIST pidl)
Definition: pidl.c:212
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
UINT uFlags
Definition: api.c:60
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
_CRTIMP uintptr_t __cdecl _beginthreadex(_In_opt_ void *_Security, _In_ unsigned _StackSize, _In_ unsigned(__stdcall *_StartAddress)(void *), _In_opt_ void *_ArgList, _In_ unsigned _InitFlag, _Out_opt_ unsigned *_ThrdAddr)
#define lstrlenW
Definition: compat.h:407
#define FILE_NOTIFY_CHANGE_DIR_NAME
Definition: match.c:390
int32_t INT
Definition: typedefs.h:56
static LONG next_id
Definition: changenotify.c:91
static HWND child
Definition: cursoricon.c:298
#define FILE_SHARE_READ
Definition: compat.h:125
LPNOTIFYREGISTER apidl
Definition: changenotify.c:73
#define lstrcpynW
Definition: compat.h:397
#define ERROR_OPERATION_ABORTED
Definition: winerror.h:575
uint32_t ULONG_PTR
Definition: typedefs.h:63
const char * wine_dbg_sprintf(const char *format,...)
Definition: compat.c:271
#define SHCNF_DWORD
Definition: shlobj.h:1754
SHChangeNotifyEntry * LPNOTIFYREGISTER
Definition: changenotify.c:64
__WINE_SERVER_LIST_INLINE void list_add_tail(struct list *list, struct list *elem)
Definition: list.h:102
struct node node
#define LIST_FOR_EACH_ENTRY(elem, list, type, field)
Definition: list.h:198
DWORD WINAPI QueueUserAPC(IN PAPCFUNC pfnAPC, IN HANDLE hThread, IN ULONG_PTR dwData)
Definition: thread.c:947
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define PathIsDirectory
Definition: shlwapi.h:935
unsigned int BOOL
Definition: ntddk_ex.h:94
#define SHCNE_ALLEVENTS
Definition: shlobj.h:1744
long LONG
Definition: pedump.c:60
STRSAFEAPI StringCchCopyW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:149
#define debugstr_w
Definition: kernel32.h:32
#define FIXME(fmt,...)
Definition: debug.h:110
#define SHCNE_ONEITEMEVENTS
Definition: changenotify.c:102
static PVOID ptr
Definition: dispmode.c:27
#define FILE_ACTION_MODIFIED
#define DUMPEV(x)
const WCHAR * str
BOOL WINAPI CancelIo(IN HANDLE hFile)
Definition: deviceio.c:290
#define SHCNRF_InterruptLevel
Definition: shlobj.h:1765
smooth NULL
Definition: ftsmooth.c:416
#define FILE_ACTION_REMOVED
LPWSTR WINAPI PathFindFileNameW(LPCWSTR lpszPath)
Definition: path.c:389
#define SHCNE_TWOITEMEVENTS
Definition: changenotify.c:109
#define OPEN_EXISTING
Definition: compat.h:426
static void DeleteNode(LPNOTIFICATIONLIST item)
Definition: changenotify.c:157
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
#define SHCNF_PRINTERW
Definition: shlobj.h:1756
__WINE_SERVER_LIST_INLINE void list_remove(struct list *elem)
Definition: list.h:108
#define TRACE(s)
Definition: solgame.cpp:4
DWORD WINAPI SleepEx(IN DWORD dwMilliseconds, IN BOOL bAlertable)
Definition: synch.c:802
#define FILE_LIST_DIRECTORY
Definition: nt_native.h:629
_CONST_RETURN wchar_t *__cdecl wcschr(_In_z_ const wchar_t *_Str, wchar_t _Ch)
HANDLE WINAPI SHAllocShared(LPCVOID lpvData, DWORD dwSize, DWORD dwProcId)
Definition: ordinal.c:162
#define LIST_INIT(head)
Definition: queue.h:197
LPITEMIDLIST WINAPI SHSimpleIDListFromPathW(LPCWSTR lpszPath)
Definition: pidl.c:1111
__wchar_t WCHAR
Definition: xmlstorage.h:180
void WINAPI DeleteCriticalSection(PCRITICAL_SECTION)
LONG HRESULT
Definition: typedefs.h:77
struct _NOTIFICATIONLIST NOTIFICATIONLIST
#define MKDIR(d)
Definition: compat.h:23
#define SHCNF_IDLIST
Definition: shlobj.h:1751
#define FAILED_UNEXPECTEDLY(hr)
Definition: shellutils.h:71
#define MAX_PATH
Definition: compat.h:26
#define WINAPI
Definition: msvc.h:8
PVOID HANDLE
Definition: typedefs.h:71
unsigned long DWORD
Definition: ntddk_ex.h:95
WINE_DEFAULT_DEBUG_CHANNEL(shell)
#define SHCNF_PRINTERA
Definition: shlobj.h:1753
BOOL WINAPI SHFreeShared(HANDLE hShared, DWORD dwProcId)
Definition: ordinal.c:262
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLbitfield flags
Definition: glext.h:7161
static const char * DumpEvent(LONG event)
Definition: changenotify.c:113
static CRITICAL_SECTION_DEBUG critsect_debug
Definition: changenotify.c:44
static const char * NodeName(const NOTIFICATIONLIST *item)
Definition: changenotify.c:145
#define SHCNF_TYPE
Definition: shlobj.h:1757
#define FILE_SHARE_DELETE
Definition: nt_native.h:682
void InitChangeNotifications(void)
Definition: changenotify.c:183
static const WCHAR L[]
Definition: oid.c:1250
#define SHCNF_FLUSH
Definition: shlobj.h:1758
#define StringCchCopy
Definition: strsafe.h:139
#define FILE_ACTION_RENAMED_NEW_NAME
BOOL WINAPI SHChangeNotification_Unlock(HANDLE hLock)
Definition: changenotify.c:600
uint32_t entry
Definition: isohybrid.c:63
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLenum GLsizei len
Definition: glext.h:6722
unsigned char BYTE
Definition: mem.h:68
Definition: _list.h:228
#define GENERIC_READ
Definition: compat.h:124
struct _cl_event * event
Definition: glext.h:7739
LIST_ENTRY ProcessLocksList
Definition: winbase.h:848
void WINAPI SHChangeNotify(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID dwItem2)
Definition: changenotify.c:340
#define SHCNF_PATHW
Definition: shlobj.h:1755
#define SHCNRF_NewDelivery
Definition: shlobj.h:1768
#define ERR(fmt,...)
Definition: debug.h:109
BOOL WINAPI ILIsParent(LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidlChild, BOOL bImmediate)
Definition: pidl.c:592
namespace GUID const ADDRINFOEXW ADDRINFOEXW struct timeval OVERLAPPED * overlapped
Definition: sock.c:82
int32_t * LPLONG
Definition: typedefs.h:56
static unsigned __int64 next
Definition: rand_nt.c:6
#define LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, list, type, field)
Definition: list.h:204
#define InterlockedIncrement
Definition: armddk.h:53
static ATOM item
Definition: dde.c:856
_In_ HANDLE _In_ DWORD _In_ DWORD _Inout_opt_ LPOVERLAPPED lpOverlapped
Definition: mswsock.h:90
HRESULT WINAPI SHBindToParent(LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppv, LPCITEMIDLIST *ppidlLast)
Definition: pidl.c:1323
void shell(int argc, const char *argv[])
Definition: cmds.c:1231
LPITEMIDLIST WINAPI ILClone(LPCITEMIDLIST pidl)
Definition: pidl.c:228
#define SHCNE_DELETE
Definition: shlobj.h:1722
Definition: services.c:325
#define SHCNE_UPDATEDIR
Definition: shlobj.h:1732
PVOID WINAPI SHLockShared(HANDLE hShared, DWORD dwProcId)
Definition: ordinal.c:210
static CRITICAL_SECTION SHELL32_ChangenotifyCS
Definition: changenotify.c:43
unsigned int UINT
Definition: ndis.h:50
#define ILGetSize
Definition: shellclasses.h:638
LPITEMIDLIST WINAPI SHSimpleIDListFromPathA(LPCSTR lpszPath)
Definition: pidl.c:1089
#define FILE_ACTION_ADDED
#define CreateFileW
Definition: compat.h:400
void WINAPI SHFree(LPVOID pv)
Definition: shellole.c:331
#define msg(x)
Definition: auth_time.c:54
BOOL WINAPI SHChangeNotifyDeregister(ULONG hNotify)
Definition: changenotify.c:283
LPITEMIDLIST _ILCreateFromFindDataW(const WIN32_FIND_DATAW *wfd)
Definition: pidl.c:1727
CONST void * LPCVOID
Definition: windef.h:191
#define FILE_FLAG_BACKUP_SEMANTICS
Definition: disk.h:41
__WINE_SERVER_LIST_INLINE void list_init(struct list *list)
Definition: list.h:149
BOOL WINAPI SHUnlockShared(LPVOID lpView)
Definition: ordinal.c:242
BOOL WINAPI ReadDirectoryChangesW(IN HANDLE hDirectory, IN LPVOID lpBuffer OPTIONAL, IN DWORD nBufferLength, IN BOOL bWatchSubtree, IN DWORD dwNotifyFilter, OUT LPDWORD lpBytesReturned, IN LPOVERLAPPED lpOverlapped OPTIONAL, IN LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
Definition: cnotify.c:253
unsigned int ULONG
Definition: retypes.h:1
#define SHCNE_CREATE
Definition: shlobj.h:1721
#define SHCNE_UPDATEITEM
Definition: shlobj.h:1733
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
GLfloat GLfloat p
Definition: glext.h:8902
WCHAR * LPWSTR
Definition: xmlstorage.h:184
#define FILE_FLAG_OVERLAPPED
Definition: disk.h:46
#define INFINITE
Definition: serial.h:102
#define EXTERN_C
Definition: basetyps.h:12
EXTERN_C ULONG WINAPI NTSHChangeNotifyRegister(HWND hwnd, int fSources, LONG fEvents, UINT msg, int count, SHChangeNotifyEntry *idlist)
Definition: changenotify.c:552
DWORD WINAPI NTSHChangeNotifyDeregister(ULONG x1)
Definition: changenotify.c:609
ITEMIDLIST UNALIGNED * LPITEMIDLIST
Definition: shtypes.idl:41
LPVOID WINAPI SHAlloc(SIZE_T len)
Definition: shellole.c:309
#define SHCNF_PATHA
Definition: shlobj.h:1752
#define BUFFER_SIZE
Definition: changenotify.c:26
DWORD WINAPI GetCurrentProcessId(VOID)
Definition: proc.c:1158
#define SUCCEEDED(hr)
Definition: intsafe.h:57
#define DELETE
Definition: nt_native.h:57
BOOL WINAPI SHChangeNotifyUpdateEntryList(DWORD unknown1, DWORD unknown2, DWORD unknown3, DWORD unknown4)
Definition: changenotify.c:307
struct _NOTIFICATIONLIST * LPNOTIFICATIONLIST
Definition: dlist.c:348
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
#define SHCNE_ASSOCCHANGED
Definition: shlobj.h:1741