ntoskrnl.exe: Send PnP and Power IRPs to plug and play devices.
[wine.git] / dlls / shell32 / changenotify.c
blob2efb297ad57887c06d1f6f466d5c6d7fa11d1007
1 /*
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 #include <stdarg.h>
22 #include <string.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wine/list.h"
27 #include "wine/debug.h"
28 #include "shell32_main.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, { (DWORD_PTR)(__FILE__ ": SHELL32_ChangenotifyCS") }
39 static CRITICAL_SECTION SHELL32_ChangenotifyCS = { &critsect_debug, -1, 0, 0, 0, 0 };
41 typedef SHChangeNotifyEntry *LPNOTIFYREGISTER;
43 /* internal list of notification clients (internal) */
44 typedef struct _NOTIFICATIONLIST
46 struct list entry;
47 HWND hwnd; /* window to notify */
48 DWORD uMsg; /* message to send */
49 LPNOTIFYREGISTER apidl; /* array of entries to watch*/
50 UINT cidl; /* number of pidls in array */
51 LONG wEventMask; /* subscribed events */
52 DWORD dwFlags; /* client flags */
53 ULONG id;
54 } NOTIFICATIONLIST, *LPNOTIFICATIONLIST;
56 static struct list notifications = LIST_INIT( notifications );
57 static LONG next_id;
59 #define SHCNE_NOITEMEVENTS ( \
60 SHCNE_ASSOCCHANGED )
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"
79 DUMPEV(RENAMEITEM)
80 DUMPEV(CREATE)
81 DUMPEV(DELETE)
82 DUMPEV(MKDIR)
83 DUMPEV(RMDIR)
84 DUMPEV(MEDIAINSERTED)
85 DUMPEV(MEDIAREMOVED)
86 DUMPEV(DRIVEREMOVED)
87 DUMPEV(DRIVEADD)
88 DUMPEV(NETSHARE)
89 DUMPEV(NETUNSHARE)
90 DUMPEV(ATTRIBUTES)
91 DUMPEV(UPDATEDIR)
92 DUMPEV(UPDATEITEM)
93 DUMPEV(SERVERDISCONNECT)
94 DUMPEV(UPDATEIMAGE)
95 DUMPEV(DRIVEADDGUI)
96 DUMPEV(RENAMEFOLDER)
97 DUMPEV(FREESPACE)
98 DUMPEV(EXTENDED_EVENT)
99 DUMPEV(ASSOCCHANGED)
100 DUMPEV(INTERRUPT)
102 #undef DUMPEV
105 static const char * NodeName(const NOTIFICATIONLIST *item)
107 const char *str;
108 WCHAR path[MAX_PATH];
110 if(SHGetPathFromIDListW(item->apidl[0].pidl, path ))
111 str = wine_dbg_sprintf("%s", debugstr_w(path));
112 else
113 str = wine_dbg_sprintf("<not a disk file>" );
114 return str;
117 static void DeleteNode(LPNOTIFICATIONLIST item)
119 UINT i;
121 TRACE("item=%p\n", item);
123 /* remove item from list */
124 list_remove( &item->entry );
126 /* free the item */
127 for (i=0; i<item->cidl; i++)
128 SHFree((LPITEMIDLIST)item->apidl[i].pidl);
129 SHFree(item->apidl);
130 SHFree(item);
133 void InitChangeNotifications(void)
137 void FreeChangeNotifications(void)
139 LPNOTIFICATIONLIST ptr, next;
141 TRACE("\n");
143 EnterCriticalSection(&SHELL32_ChangenotifyCS);
145 LIST_FOR_EACH_ENTRY_SAFE( ptr, next, &notifications, NOTIFICATIONLIST, entry )
146 DeleteNode( ptr );
148 LeaveCriticalSection(&SHELL32_ChangenotifyCS);
150 DeleteCriticalSection(&SHELL32_ChangenotifyCS);
153 /*************************************************************************
154 * SHChangeNotifyRegister [SHELL32.2]
157 ULONG WINAPI
158 SHChangeNotifyRegister(
159 HWND hwnd,
160 int fSources,
161 LONG wEventMask,
162 UINT uMsg,
163 int cItems,
164 SHChangeNotifyEntry *lpItems)
166 LPNOTIFICATIONLIST item;
167 int i;
169 item = SHAlloc(sizeof(NOTIFICATIONLIST));
171 TRACE("(%p,0x%08x,0x%08x,0x%08x,%d,%p) item=%p\n",
172 hwnd, fSources, wEventMask, uMsg, cItems, lpItems, item);
174 item->cidl = cItems;
175 item->apidl = SHAlloc(sizeof(SHChangeNotifyEntry) * cItems);
176 for(i=0;i<cItems;i++)
178 item->apidl[i].pidl = ILClone(lpItems[i].pidl);
179 item->apidl[i].fRecursive = lpItems[i].fRecursive;
181 item->hwnd = hwnd;
182 item->uMsg = uMsg;
183 item->wEventMask = wEventMask;
184 item->dwFlags = fSources;
185 item->id = InterlockedIncrement( &next_id );
187 TRACE("new node: %s\n", NodeName( item ));
189 EnterCriticalSection(&SHELL32_ChangenotifyCS);
191 list_add_tail( &notifications, &item->entry );
193 LeaveCriticalSection(&SHELL32_ChangenotifyCS);
195 return item->id;
198 /*************************************************************************
199 * SHChangeNotifyDeregister [SHELL32.4]
201 BOOL WINAPI SHChangeNotifyDeregister(ULONG hNotify)
203 LPNOTIFICATIONLIST node;
205 TRACE("(0x%08x)\n", hNotify);
207 EnterCriticalSection(&SHELL32_ChangenotifyCS);
209 LIST_FOR_EACH_ENTRY( node, &notifications, NOTIFICATIONLIST, entry )
211 if (node->id == hNotify)
213 DeleteNode( node );
214 LeaveCriticalSection(&SHELL32_ChangenotifyCS);
215 return TRUE;
218 LeaveCriticalSection(&SHELL32_ChangenotifyCS);
219 return FALSE;
222 /*************************************************************************
223 * SHChangeNotifyUpdateEntryList [SHELL32.5]
225 BOOL WINAPI SHChangeNotifyUpdateEntryList(DWORD unknown1, DWORD unknown2,
226 DWORD unknown3, DWORD unknown4)
228 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
229 unknown1, unknown2, unknown3, unknown4);
231 return TRUE;
234 struct new_delivery_notification
236 LONG event;
237 DWORD pidl1_size;
238 DWORD pidl2_size;
239 LPITEMIDLIST pidls[2];
240 BYTE data[1];
243 static BOOL should_notify( LPCITEMIDLIST changed, LPCITEMIDLIST watched, BOOL sub )
245 TRACE("%p %p %d\n", changed, watched, sub );
246 if ( !watched )
247 return FALSE;
248 if (ILIsEqual( watched, changed ) )
249 return TRUE;
250 if( sub && ILIsParent( watched, changed, FALSE ) )
251 return TRUE;
252 return FALSE;
255 /*************************************************************************
256 * SHChangeNotify [SHELL32.@]
258 void WINAPI SHChangeNotify(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID dwItem2)
260 struct notification_recipients {
261 struct list entry;
262 HWND hwnd;
263 DWORD msg;
264 DWORD flags;
265 } *cur, *next;
267 HANDLE shared_data = NULL;
268 LPITEMIDLIST Pidls[2];
269 LPNOTIFICATIONLIST ptr;
270 struct list recipients;
272 Pidls[0] = NULL;
273 Pidls[1] = NULL;
275 TRACE("(0x%08x,0x%08x,%p,%p)\n", wEventId, uFlags, dwItem1, dwItem2);
277 if(uFlags & ~(SHCNF_TYPE|SHCNF_FLUSH))
278 FIXME("ignoring unsupported flags: %x\n", uFlags);
280 if( ( wEventId & SHCNE_NOITEMEVENTS ) && ( dwItem1 || dwItem2 ) )
282 TRACE("dwItem1 and dwItem2 are not zero, but should be\n");
283 dwItem1 = 0;
284 dwItem2 = 0;
285 return;
287 else if( ( wEventId & SHCNE_ONEITEMEVENTS ) && dwItem2 )
289 TRACE("dwItem2 is not zero, but should be\n");
290 dwItem2 = 0;
291 return;
294 if( ( ( wEventId & SHCNE_NOITEMEVENTS ) &&
295 ( wEventId & ~SHCNE_NOITEMEVENTS ) ) ||
296 ( ( wEventId & SHCNE_ONEITEMEVENTS ) &&
297 ( wEventId & ~SHCNE_ONEITEMEVENTS ) ) ||
298 ( ( wEventId & SHCNE_TWOITEMEVENTS ) &&
299 ( wEventId & ~SHCNE_TWOITEMEVENTS ) ) )
301 WARN("mutually incompatible events listed\n");
302 return;
305 /* convert paths in IDLists*/
306 switch (uFlags & SHCNF_TYPE)
308 case SHCNF_PATHA:
309 if (dwItem1) Pidls[0] = SHSimpleIDListFromPathA(dwItem1);
310 if (dwItem2) Pidls[1] = SHSimpleIDListFromPathA(dwItem2);
311 break;
312 case SHCNF_PATHW:
313 if (dwItem1) Pidls[0] = SHSimpleIDListFromPathW(dwItem1);
314 if (dwItem2) Pidls[1] = SHSimpleIDListFromPathW(dwItem2);
315 break;
316 case SHCNF_IDLIST:
317 Pidls[0] = ILClone(dwItem1);
318 Pidls[1] = ILClone(dwItem2);
319 break;
320 case SHCNF_PRINTERA:
321 case SHCNF_PRINTERW:
322 FIXME("SHChangeNotify with (uFlags & SHCNF_PRINTER)\n");
323 return;
324 case SHCNF_DWORD:
325 default:
326 FIXME("unknown type %08x\n", uFlags & SHCNF_TYPE);
327 return;
330 list_init(&recipients);
331 EnterCriticalSection(&SHELL32_ChangenotifyCS);
332 LIST_FOR_EACH_ENTRY( ptr, &notifications, NOTIFICATIONLIST, entry )
334 struct notification_recipients *item;
335 BOOL notify = FALSE;
336 DWORD i;
338 for( i=0; (i<ptr->cidl) && !notify ; i++ )
340 LPCITEMIDLIST pidl = ptr->apidl[i].pidl;
341 BOOL subtree = ptr->apidl[i].fRecursive;
343 if (wEventId & ptr->wEventMask)
345 if( !pidl ) /* all ? */
346 notify = TRUE;
347 else if( wEventId & SHCNE_NOITEMEVENTS )
348 notify = TRUE;
349 else if( wEventId & ( SHCNE_ONEITEMEVENTS | SHCNE_TWOITEMEVENTS ) )
350 notify = should_notify( Pidls[0], pidl, subtree );
351 else if( wEventId & SHCNE_TWOITEMEVENTS )
352 notify = should_notify( Pidls[1], pidl, subtree );
356 if( !notify )
357 continue;
359 item = SHAlloc(sizeof(struct notification_recipients));
360 if(!item) {
361 ERR("out of memory\n");
362 continue;
365 item->hwnd = ptr->hwnd;
366 item->msg = ptr->uMsg;
367 item->flags = ptr->dwFlags;
368 list_add_tail(&recipients, &item->entry);
370 LeaveCriticalSection(&SHELL32_ChangenotifyCS);
372 LIST_FOR_EACH_ENTRY_SAFE(cur, next, &recipients, struct notification_recipients, entry)
374 TRACE("notifying %p, event %s(%x)\n", cur->hwnd, DumpEvent(wEventId), wEventId);
376 if (cur->flags & SHCNRF_NewDelivery) {
377 if(!shared_data) {
378 struct new_delivery_notification *notification;
379 UINT size1 = ILGetSize(Pidls[0]), size2 = ILGetSize(Pidls[1]);
380 UINT offset = (size1+sizeof(int)-1)/sizeof(int)*sizeof(int);
382 notification = SHAlloc(sizeof(struct new_delivery_notification)+offset+size2);
383 if(!notification) {
384 ERR("out of memory\n");
385 } else {
386 notification->event = wEventId;
387 notification->pidl1_size = size1;
388 notification->pidl2_size = size2;
389 if(size1)
390 memcpy(notification->data, Pidls[0], size1);
391 if(size2)
392 memcpy(notification->data+offset, Pidls[1], size2);
394 shared_data = SHAllocShared(notification,
395 sizeof(struct new_delivery_notification)+size1+size2,
396 GetCurrentProcessId());
397 SHFree(notification);
401 if(shared_data)
402 SendMessageA(cur->hwnd, cur->msg, (WPARAM)shared_data, GetCurrentProcessId());
403 else
404 ERR("out of memory\n");
405 } else {
406 SendMessageA(cur->hwnd, cur->msg, (WPARAM)Pidls, wEventId);
409 list_remove(&cur->entry);
410 SHFree(cur);
412 SHFreeShared(shared_data, GetCurrentProcessId());
413 SHFree(Pidls[0]);
414 SHFree(Pidls[1]);
416 if (wEventId & SHCNE_ASSOCCHANGED)
418 static const WCHAR args[] = {' ','-','a',0 };
419 TRACE("refreshing file type associations\n");
420 run_winemenubuilder( args );
424 /*************************************************************************
425 * NTSHChangeNotifyRegister [SHELL32.640]
426 * NOTES
427 * Idlist is an array of structures and Count specifies how many items in the array
428 * (usually just one I think).
430 DWORD WINAPI NTSHChangeNotifyRegister(
431 HWND hwnd,
432 LONG events1,
433 LONG events2,
434 DWORD msg,
435 int count,
436 SHChangeNotifyEntry *idlist)
438 FIXME("(%p,0x%08x,0x%08x,0x%08x,0x%08x,%p):semi stub.\n",
439 hwnd,events1,events2,msg,count,idlist);
441 return SHChangeNotifyRegister(hwnd, events1, events2, msg, count, idlist);
444 /*************************************************************************
445 * SHChangeNotification_Lock [SHELL32.644]
447 HANDLE WINAPI SHChangeNotification_Lock(
448 HANDLE hChange,
449 DWORD dwProcessId,
450 LPITEMIDLIST **lppidls,
451 LPLONG lpwEventId)
453 struct new_delivery_notification *ndn;
454 UINT offset;
456 TRACE("%p %08x %p %p\n", hChange, dwProcessId, lppidls, lpwEventId);
458 ndn = SHLockShared(hChange, dwProcessId);
459 if(!ndn) {
460 WARN("SHLockShared failed\n");
461 return NULL;
464 if(lppidls) {
465 offset = (ndn->pidl1_size+sizeof(int)-1)/sizeof(int)*sizeof(int);
466 ndn->pidls[0] = ndn->pidl1_size ? (LPITEMIDLIST)ndn->data : NULL;
467 ndn->pidls[1] = ndn->pidl2_size ? (LPITEMIDLIST)(ndn->data+offset) : NULL;
468 *lppidls = ndn->pidls;
471 if(lpwEventId)
472 *lpwEventId = ndn->event;
474 return ndn;
477 /*************************************************************************
478 * SHChangeNotification_Unlock [SHELL32.645]
480 BOOL WINAPI SHChangeNotification_Unlock ( HANDLE hLock)
482 TRACE("%p\n", hLock);
483 return SHUnlockShared(hLock);
486 /*************************************************************************
487 * NTSHChangeNotifyDeregister [SHELL32.641]
489 DWORD WINAPI NTSHChangeNotifyDeregister(ULONG x1)
491 FIXME("(0x%08x):semi stub.\n",x1);
493 return SHChangeNotifyDeregister( x1 );