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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "wine/debug.h"
27 #include "shell32_main.h"
28 #include "undocshell.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
32 static CRITICAL_SECTION SHELL32_ChangenotifyCS
;
33 static CRITICAL_SECTION_DEBUG critsect_debug
=
35 0, 0, &SHELL32_ChangenotifyCS
,
36 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
37 0, 0, { 0, (DWORD
)(__FILE__
": SHELL32_ChangenotifyCS") }
39 static CRITICAL_SECTION SHELL32_ChangenotifyCS
= { &critsect_debug
, -1, 0, 0, 0, 0 };
41 /* internal list of notification clients (internal) */
42 typedef struct _NOTIFICATIONLIST
44 struct _NOTIFICATIONLIST
*next
;
45 struct _NOTIFICATIONLIST
*prev
;
46 HWND hwnd
; /* window to notify */
47 DWORD uMsg
; /* message to send */
48 LPNOTIFYREGISTER apidl
; /* array of entries to watch*/
49 UINT cidl
; /* number of pidls in array */
50 LONG wEventMask
; /* subscribed events */
51 LONG wSignalledEvent
; /* event that occurred */
52 DWORD dwFlags
; /* client flags */
53 LPCITEMIDLIST pidlSignaled
; /*pidl of the path that caused the signal*/
55 } NOTIFICATIONLIST
, *LPNOTIFICATIONLIST
;
57 static NOTIFICATIONLIST
*head
, *tail
;
59 #define SHCNE_NOITEMEVENTS ( \
62 #define SHCNE_ONEITEMEVENTS ( \
63 SHCNE_ATTRIBUTES | SHCNE_CREATE | SHCNE_DELETE | SHCNE_DRIVEADD | \
64 SHCNE_DRIVEADDGUI | SHCNE_DRIVEREMOVED | SHCNE_FREESPACE | \
65 SHCNE_MEDIAINSERTED | SHCNE_MEDIAREMOVED | SHCNE_MKDIR | \
66 SHCNE_NETSHARE | SHCNE_NETUNSHARE | SHCNE_RMDIR | \
67 SHCNE_SERVERDISCONNECT | SHCNE_UPDATEDIR | SHCNE_UPDATEIMAGE )
69 #define SHCNE_TWOITEMEVENTS ( \
70 SHCNE_RENAMEFOLDER | SHCNE_RENAMEITEM | SHCNE_UPDATEITEM )
72 /* for dumping events */
73 static const char * DumpEvent( LONG event
)
75 if( event
== SHCNE_ALLEVENTS
)
76 return "SHCNE_ALLEVENTS";
77 #define DUMPEV(x) ,( event & SHCNE_##x )? #x " " : ""
78 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"
93 DUMPEV(SERVERDISCONNECT
)
98 DUMPEV(EXTENDED_EVENT
)
105 static const char * NodeName(LPNOTIFICATIONLIST item
)
108 WCHAR path
[MAX_PATH
];
110 if(SHGetPathFromIDListW(item
->apidl
[0].pidlPath
, path
))
111 str
= wine_dbg_sprintf("%s", debugstr_w(path
));
113 str
= wine_dbg_sprintf("<not a disk file>" );
117 static void AddNode(LPNOTIFICATIONLIST item
)
119 TRACE("item %p\n", item
);
131 static LPNOTIFICATIONLIST
FindNode( HANDLE hitem
)
133 LPNOTIFICATIONLIST ptr
;
134 for( ptr
= head
; ptr
; ptr
= ptr
->next
)
135 if( ptr
== (LPNOTIFICATIONLIST
) hitem
)
140 static void DeleteNode(LPNOTIFICATIONLIST item
)
144 TRACE("item=%p prev=%p next=%p\n", item
, item
->prev
, item
->next
);
146 /* remove item from list */
148 item
->prev
->next
= item
->next
;
152 item
->next
->prev
= item
->prev
;
157 for (i
=0; i
<item
->cidl
; i
++)
158 SHFree(item
->apidl
[i
].pidlPath
);
163 void InitChangeNotifications(void)
167 void FreeChangeNotifications(void)
171 EnterCriticalSection(&SHELL32_ChangenotifyCS
);
176 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
178 DeleteCriticalSection(&SHELL32_ChangenotifyCS
);
181 /*************************************************************************
182 * SHChangeNotifyRegister [SHELL32.2]
186 SHChangeNotifyRegister(
192 LPCNOTIFYREGISTER lpItems
)
194 LPNOTIFICATIONLIST item
;
197 item
= SHAlloc(sizeof(NOTIFICATIONLIST
));
199 TRACE("(%p,0x%08lx,0x%08lx,0x%08x,0x%08x,%p) item=%p\n",
200 hwnd
, dwFlags
, wEventMask
, uMsg
, cItems
, lpItems
, item
);
205 item
->apidl
= SHAlloc(sizeof(NOTIFYREGISTER
) * cItems
);
206 for(i
=0;i
<cItems
;i
++)
208 item
->apidl
[i
].pidlPath
= ILClone(lpItems
[i
].pidlPath
);
209 item
->apidl
[i
].bWatchSubtree
= lpItems
[i
].bWatchSubtree
;
213 item
->wEventMask
= wEventMask
;
214 item
->wSignalledEvent
= 0;
215 item
->dwFlags
= dwFlags
;
217 TRACE("new node: %s\n", NodeName( item
));
219 EnterCriticalSection(&SHELL32_ChangenotifyCS
);
223 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
228 /*************************************************************************
229 * SHChangeNotifyDeregister [SHELL32.4]
231 BOOL WINAPI
SHChangeNotifyDeregister(HANDLE hNotify
)
233 LPNOTIFICATIONLIST node
;
235 TRACE("(%p)\n",hNotify
);
237 EnterCriticalSection(&SHELL32_ChangenotifyCS
);
239 node
= FindNode(hNotify
);
243 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
245 return node
?TRUE
:FALSE
;
248 /*************************************************************************
249 * SHChangeNotifyUpdateEntryList [SHELL32.5]
251 BOOL WINAPI
SHChangeNotifyUpdateEntryList(DWORD unknown1
, DWORD unknown2
,
252 DWORD unknown3
, DWORD unknown4
)
254 FIXME("(0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx)\n",
255 unknown1
, unknown2
, unknown3
, unknown4
);
260 static BOOL
should_notify( LPITEMIDLIST changed
, LPITEMIDLIST watched
, BOOL sub
)
262 TRACE("%p %p %d\n", changed
, watched
, sub
);
265 if (ILIsEqual( watched
, changed
) )
267 if( sub
&& ILIsParent( watched
, changed
, FALSE
) )
272 /*************************************************************************
273 * SHChangeNotify [SHELL32.@]
275 void WINAPI
SHChangeNotify(LONG wEventId
, UINT uFlags
, LPCVOID dwItem1
, LPCVOID dwItem2
)
277 LPITEMIDLIST Pidls
[2];
278 LPNOTIFICATIONLIST ptr
;
280 UINT typeFlag
= uFlags
& SHCNF_TYPE
;
285 TRACE("(0x%08lx,0x%08x,%p,%p):stub.\n", wEventId
, uFlags
, dwItem1
, dwItem2
);
287 if( ( wEventId
& SHCNE_NOITEMEVENTS
) && ( dwItem1
|| dwItem2
) )
289 TRACE("dwItem1 and dwItem2 are not zero, but should be\n");
294 else if( ( wEventId
& SHCNE_ONEITEMEVENTS
) && dwItem2
)
296 TRACE("dwItem2 is not zero, but should be\n");
301 if( ( ( wEventId
& SHCNE_NOITEMEVENTS
) &&
302 ( wEventId
& ~SHCNE_NOITEMEVENTS
) ) ||
303 ( ( wEventId
& SHCNE_ONEITEMEVENTS
) &&
304 ( wEventId
& ~SHCNE_ONEITEMEVENTS
) ) ||
305 ( ( wEventId
& SHCNE_TWOITEMEVENTS
) &&
306 ( wEventId
& ~SHCNE_TWOITEMEVENTS
) ) )
308 WARN("mutually incompatible events listed\n");
312 /* convert paths in IDLists*/
316 if (dwItem1
) SHILCreateFromPathA((LPCSTR
)dwItem1
, &Pidls
[0], &dummy
);
317 if (dwItem2
) SHILCreateFromPathA((LPCSTR
)dwItem2
, &Pidls
[1], &dummy
);
320 if (dwItem1
) SHILCreateFromPathW((LPCWSTR
)dwItem1
, &Pidls
[0], &dummy
);
321 if (dwItem2
) SHILCreateFromPathW((LPCWSTR
)dwItem2
, &Pidls
[1], &dummy
);
324 Pidls
[0] = (LPITEMIDLIST
)dwItem1
;
325 Pidls
[1] = (LPITEMIDLIST
)dwItem2
;
329 FIXME("SHChangeNotify with (uFlags & SHCNF_PRINTER)");
333 FIXME("unknown type %08x\n",typeFlag
);
338 WCHAR path
[MAX_PATH
];
340 if( Pidls
[0] && SHGetPathFromIDListW(Pidls
[0], path
))
341 TRACE("notify %08lx on item1 = %s\n", wEventId
, debugstr_w(path
));
343 if( Pidls
[1] && SHGetPathFromIDListW(Pidls
[1], path
))
344 TRACE("notify %08lx on item2 = %s\n", wEventId
, debugstr_w(path
));
347 EnterCriticalSection(&SHELL32_ChangenotifyCS
);
349 /* loop through the list */
350 for( ptr
= head
; ptr
; ptr
= ptr
->next
)
357 TRACE("trying %p\n", ptr
);
359 for( i
=0; (i
<ptr
->cidl
) && !notify
; i
++ )
361 LPITEMIDLIST pidl
= ptr
->apidl
[i
].pidlPath
;
362 BOOL subtree
= ptr
->apidl
[i
].bWatchSubtree
;
364 if (wEventId
& ptr
->wEventMask
)
366 if( !pidl
) /* all ? */
368 else if( wEventId
& SHCNE_NOITEMEVENTS
)
370 else if( wEventId
& ( SHCNE_ONEITEMEVENTS
| SHCNE_TWOITEMEVENTS
) )
371 notify
= should_notify( Pidls
[0], pidl
, subtree
);
372 else if( wEventId
& SHCNE_TWOITEMEVENTS
)
373 notify
= should_notify( Pidls
[1], pidl
, subtree
);
380 ptr
->pidlSignaled
= ILClone(Pidls
[0]);
382 TRACE("notifying %s, event %s(%lx) before\n", NodeName( ptr
), DumpEvent(
383 wEventId
),wEventId
);
385 ptr
->wSignalledEvent
|= wEventId
;
386 SendMessageA(ptr
->hwnd
, ptr
->uMsg
, (WPARAM
)ptr
, GetCurrentProcessId());
388 TRACE("notifying %s, event %s(%lx) after\n", NodeName( ptr
), DumpEvent(
389 wEventId
),wEventId
);
392 TRACE("notify Done\n");
393 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
395 /* if we allocated it, free it */
396 if ((typeFlag
== SHCNF_PATHA
) || (typeFlag
== SHCNF_PATHW
))
398 if (Pidls
[0]) SHFree(Pidls
[0]);
399 if (Pidls
[1]) SHFree(Pidls
[1]);
403 /*************************************************************************
404 * NTSHChangeNotifyRegister [SHELL32.640]
406 * Idlist is an array of structures and Count specifies how many items in the array
407 * (usually just one I think).
409 DWORD WINAPI
NTSHChangeNotifyRegister(
415 LPCNOTIFYREGISTER idlist
)
417 FIXME("(%p,0x%08lx,0x%08lx,0x%08lx,0x%08x,%p):semi stub.\n",
418 hwnd
,events1
,events2
,msg
,count
,idlist
);
420 return (DWORD
) SHChangeNotifyRegister(hwnd
, events1
, events2
, msg
, count
, idlist
);
423 /*************************************************************************
424 * SHChangeNotification_Lock [SHELL32.644]
426 HANDLE WINAPI
SHChangeNotification_Lock(
429 LPCITEMIDLIST
**lppidls
,
433 LPNOTIFICATIONLIST node
;
434 LPCITEMIDLIST
*idlist
;
436 TRACE("%p %08lx %p %p\n", hChange
, dwProcessId
, lppidls
, lpwEventId
);
438 /* EnterCriticalSection(&SHELL32_ChangenotifyCS); */
440 node
= FindNode( hChange
);
443 idlist
= SHAlloc( sizeof(LPCITEMIDLIST
*) * node
->cidl
);
444 for(i
=0; i
<node
->cidl
; i
++)
445 idlist
[i
] = node
->pidlSignaled
;
446 *lpwEventId
= node
->wSignalledEvent
;
448 node
->wSignalledEvent
= 0;
451 ERR("Couldn't find %p\n", hChange
);
453 /* LeaveCriticalSection(&SHELL32_ChangenotifyCS); */
455 return (HANDLE
) node
;
458 /*************************************************************************
459 * SHChangeNotification_Unlock [SHELL32.645]
461 BOOL WINAPI
SHChangeNotification_Unlock ( HANDLE hLock
)
467 /*************************************************************************
468 * NTSHChangeNotifyDeregister [SHELL32.641]
470 DWORD WINAPI
NTSHChangeNotifyDeregister(LONG x1
)
472 FIXME("(0x%08lx):semi stub.\n",x1
);
474 return SHChangeNotifyDeregister( (HANDLE
)x1
);