reshuffling of dlls
[reactos.git] / reactos / dll / shell32 / changenotify.c
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include <stdarg.h>
22 #include <string.h>
23
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wine/debug.h"
29 #include "wingdi.h"
30 #include "shell32_main.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(shell);
33
34 static CRITICAL_SECTION SHELL32_ChangenotifyCS;
35 static CRITICAL_SECTION_DEBUG critsect_debug =
36 {
37 0, 0, &SHELL32_ChangenotifyCS,
38 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
39 0, 0, { (DWORD_PTR)(__FILE__ ": SHELL32_ChangenotifyCS") }
40 };
41 static CRITICAL_SECTION SHELL32_ChangenotifyCS = { &critsect_debug, -1, 0, 0, 0, 0 };
42
43 typedef SHChangeNotifyEntry *LPNOTIFYREGISTER;
44
45 /* internal list of notification clients (internal) */
46 typedef struct _NOTIFICATIONLIST
47 {
48 struct _NOTIFICATIONLIST *next;
49 struct _NOTIFICATIONLIST *prev;
50 HWND hwnd; /* window to notify */
51 DWORD uMsg; /* message to send */
52 LPNOTIFYREGISTER apidl; /* array of entries to watch*/
53 UINT cidl; /* number of pidls in array */
54 LONG wEventMask; /* subscribed events */
55 LONG wSignalledEvent; /* event that occurred */
56 DWORD dwFlags; /* client flags */
57 LPCITEMIDLIST pidlSignaled; /*pidl of the path that caused the signal*/
58
59 } NOTIFICATIONLIST, *LPNOTIFICATIONLIST;
60
61 static NOTIFICATIONLIST *head, *tail;
62
63 #define SHCNE_NOITEMEVENTS ( \
64 SHCNE_ASSOCCHANGED )
65
66 #define SHCNE_ONEITEMEVENTS ( \
67 SHCNE_ATTRIBUTES | SHCNE_CREATE | SHCNE_DELETE | SHCNE_DRIVEADD | \
68 SHCNE_DRIVEADDGUI | SHCNE_DRIVEREMOVED | SHCNE_FREESPACE | \
69 SHCNE_MEDIAINSERTED | SHCNE_MEDIAREMOVED | SHCNE_MKDIR | \
70 SHCNE_NETSHARE | SHCNE_NETUNSHARE | SHCNE_RMDIR | \
71 SHCNE_SERVERDISCONNECT | SHCNE_UPDATEDIR | SHCNE_UPDATEIMAGE )
72
73 #define SHCNE_TWOITEMEVENTS ( \
74 SHCNE_RENAMEFOLDER | SHCNE_RENAMEITEM | SHCNE_UPDATEITEM )
75
76 /* for dumping events */
77 static const char * DumpEvent( LONG event )
78 {
79 if( event == SHCNE_ALLEVENTS )
80 return "SHCNE_ALLEVENTS";
81 #define DUMPEV(x) ,( event & SHCNE_##x )? #x " " : ""
82 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"
83 DUMPEV(RENAMEITEM)
84 DUMPEV(CREATE)
85 DUMPEV(DELETE)
86 DUMPEV(MKDIR)
87 DUMPEV(RMDIR)
88 DUMPEV(MEDIAINSERTED)
89 DUMPEV(MEDIAREMOVED)
90 DUMPEV(DRIVEREMOVED)
91 DUMPEV(DRIVEADD)
92 DUMPEV(NETSHARE)
93 DUMPEV(NETUNSHARE)
94 DUMPEV(ATTRIBUTES)
95 DUMPEV(UPDATEDIR)
96 DUMPEV(UPDATEITEM)
97 DUMPEV(SERVERDISCONNECT)
98 DUMPEV(UPDATEIMAGE)
99 DUMPEV(DRIVEADDGUI)
100 DUMPEV(RENAMEFOLDER)
101 DUMPEV(FREESPACE)
102 DUMPEV(EXTENDED_EVENT)
103 DUMPEV(ASSOCCHANGED)
104 DUMPEV(INTERRUPT)
105 );
106 #undef DUMPEV
107 }
108
109 static const char * NodeName(LPNOTIFICATIONLIST item)
110 {
111 const char *str;
112 WCHAR path[MAX_PATH];
113
114 if(SHGetPathFromIDListW(item->apidl[0].pidl, path ))
115 str = wine_dbg_sprintf("%s", debugstr_w(path));
116 else
117 str = wine_dbg_sprintf("<not a disk file>" );
118 return str;
119 }
120
121 static void AddNode(LPNOTIFICATIONLIST item)
122 {
123 TRACE("item %p\n", item );
124
125 /* link items */
126 item->prev = tail;
127 item->next = NULL;
128 if( tail )
129 tail->next = item;
130 else
131 head = item;
132 tail = item;
133 }
134
135 static LPNOTIFICATIONLIST FindNode( HANDLE hitem )
136 {
137 LPNOTIFICATIONLIST ptr;
138 for( ptr = head; ptr; ptr = ptr->next )
139 if( ptr == (LPNOTIFICATIONLIST) hitem )
140 return ptr;
141 return NULL;
142 }
143
144 static void DeleteNode(LPNOTIFICATIONLIST item)
145 {
146 UINT i;
147
148 TRACE("item=%p prev=%p next=%p\n", item, item->prev, item->next);
149
150 /* remove item from list */
151 if( item->prev )
152 item->prev->next = item->next;
153 else
154 head = item->next;
155 if( item->next )
156 item->next->prev = item->prev;
157 else
158 tail = item->prev;
159
160 /* free the item */
161 for (i=0; i<item->cidl; i++)
162 SHFree((LPITEMIDLIST)item->apidl[i].pidl);
163 SHFree(item->apidl);
164 SHFree(item);
165 }
166
167 void InitChangeNotifications(void)
168 {
169 }
170
171 void FreeChangeNotifications(void)
172 {
173 TRACE("\n");
174
175 EnterCriticalSection(&SHELL32_ChangenotifyCS);
176
177 while( head )
178 DeleteNode( head );
179
180 LeaveCriticalSection(&SHELL32_ChangenotifyCS);
181 }
182
183 /*************************************************************************
184 * SHChangeNotifyRegister [SHELL32.2]
185 *
186 */
187 ULONG WINAPI
188 SHChangeNotifyRegister(
189 HWND hwnd,
190 int fSources,
191 LONG wEventMask,
192 UINT uMsg,
193 int cItems,
194 SHChangeNotifyEntry *lpItems)
195 {
196 LPNOTIFICATIONLIST item;
197 int i;
198
199 item = SHAlloc(sizeof(NOTIFICATIONLIST));
200
201 TRACE("(%p,0x%08x,0x%08lx,0x%08x,%d,%p) item=%p\n",
202 hwnd, fSources, wEventMask, uMsg, cItems, lpItems, item);
203
204 item->next = NULL;
205 item->prev = NULL;
206 item->cidl = cItems;
207 item->apidl = SHAlloc(sizeof(SHChangeNotifyEntry) * cItems);
208 for(i=0;i<cItems;i++)
209 {
210 item->apidl[i].pidl = ILClone(lpItems[i].pidl);
211 item->apidl[i].fRecursive = lpItems[i].fRecursive;
212 }
213 item->hwnd = hwnd;
214 item->uMsg = uMsg;
215 item->wEventMask = wEventMask;
216 item->wSignalledEvent = 0;
217 item->dwFlags = fSources;
218
219 TRACE("new node: %s\n", NodeName( item ));
220
221 EnterCriticalSection(&SHELL32_ChangenotifyCS);
222
223 AddNode(item);
224
225 LeaveCriticalSection(&SHELL32_ChangenotifyCS);
226
227 return (ULONG)item;
228 }
229
230 /*************************************************************************
231 * SHChangeNotifyDeregister [SHELL32.4]
232 */
233 BOOL WINAPI SHChangeNotifyDeregister(ULONG hNotify)
234 {
235 LPNOTIFICATIONLIST node;
236
237 TRACE("(0x%08lx)\n", hNotify);
238
239 EnterCriticalSection(&SHELL32_ChangenotifyCS);
240
241 node = FindNode((HANDLE)hNotify);
242 if( node )
243 DeleteNode(node);
244
245 LeaveCriticalSection(&SHELL32_ChangenotifyCS);
246
247 return node?TRUE:FALSE;
248 }
249
250 /*************************************************************************
251 * SHChangeNotifyUpdateEntryList [SHELL32.5]
252 */
253 BOOL WINAPI SHChangeNotifyUpdateEntryList(DWORD unknown1, DWORD unknown2,
254 DWORD unknown3, DWORD unknown4)
255 {
256 FIXME("(0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx)\n",
257 unknown1, unknown2, unknown3, unknown4);
258
259 return -1;
260 }
261
262 static BOOL should_notify( LPCITEMIDLIST changed, LPCITEMIDLIST watched, BOOL sub )
263 {
264 TRACE("%p %p %d\n", changed, watched, sub );
265 if ( !watched )
266 return FALSE;
267 if (ILIsEqual( watched, changed ) )
268 return TRUE;
269 if( sub && ILIsParent( watched, changed, FALSE ) )
270 return TRUE;
271 return FALSE;
272 }
273
274 /*************************************************************************
275 * SHChangeNotify [SHELL32.@]
276 */
277 void WINAPI SHChangeNotify(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID dwItem2)
278 {
279 LPCITEMIDLIST Pidls[2];
280 LPNOTIFICATIONLIST ptr;
281 UINT typeFlag = uFlags & SHCNF_TYPE;
282
283 Pidls[0] = NULL;
284 Pidls[1] = NULL;
285
286 TRACE("(0x%08lx,0x%08x,%p,%p):stub.\n", wEventId, uFlags, dwItem1, dwItem2);
287
288 if( ( wEventId & SHCNE_NOITEMEVENTS ) && ( dwItem1 || dwItem2 ) )
289 {
290 TRACE("dwItem1 and dwItem2 are not zero, but should be\n");
291 dwItem1 = 0;
292 dwItem2 = 0;
293 return;
294 }
295 else if( ( wEventId & SHCNE_ONEITEMEVENTS ) && dwItem2 )
296 {
297 TRACE("dwItem2 is not zero, but should be\n");
298 dwItem2 = 0;
299 return;
300 }
301
302 if( ( ( wEventId & SHCNE_NOITEMEVENTS ) &&
303 ( wEventId & ~SHCNE_NOITEMEVENTS ) ) ||
304 ( ( wEventId & SHCNE_ONEITEMEVENTS ) &&
305 ( wEventId & ~SHCNE_ONEITEMEVENTS ) ) ||
306 ( ( wEventId & SHCNE_TWOITEMEVENTS ) &&
307 ( wEventId & ~SHCNE_TWOITEMEVENTS ) ) )
308 {
309 WARN("mutually incompatible events listed\n");
310 return;
311 }
312
313 /* convert paths in IDLists*/
314 switch (typeFlag)
315 {
316 case SHCNF_PATHA:
317 if (dwItem1) Pidls[0] = SHSimpleIDListFromPathA((LPCSTR)dwItem1);
318 if (dwItem2) Pidls[1] = SHSimpleIDListFromPathA((LPCSTR)dwItem2);
319 break;
320 case SHCNF_PATHW:
321 if (dwItem1) Pidls[0] = SHSimpleIDListFromPathW((LPCWSTR)dwItem1);
322 if (dwItem2) Pidls[1] = SHSimpleIDListFromPathW((LPCWSTR)dwItem2);
323 break;
324 case SHCNF_IDLIST:
325 Pidls[0] = (LPCITEMIDLIST)dwItem1;
326 Pidls[1] = (LPCITEMIDLIST)dwItem2;
327 break;
328 case SHCNF_PRINTERA:
329 case SHCNF_PRINTERW:
330 FIXME("SHChangeNotify with (uFlags & SHCNF_PRINTER)\n");
331 return;
332 case SHCNF_DWORD:
333 default:
334 FIXME("unknown type %08x\n",typeFlag);
335 return;
336 }
337
338 {
339 WCHAR path[MAX_PATH];
340
341 if( Pidls[0] && SHGetPathFromIDListW(Pidls[0], path ))
342 TRACE("notify %08lx on item1 = %s\n", wEventId, debugstr_w(path));
343
344 if( Pidls[1] && SHGetPathFromIDListW(Pidls[1], path ))
345 TRACE("notify %08lx on item2 = %s\n", wEventId, debugstr_w(path));
346 }
347
348 EnterCriticalSection(&SHELL32_ChangenotifyCS);
349
350 /* loop through the list */
351 for( ptr = head; ptr; ptr = ptr->next )
352 {
353 BOOL notify;
354 DWORD i;
355
356 notify = FALSE;
357
358 TRACE("trying %p\n", ptr);
359
360 for( i=0; (i<ptr->cidl) && !notify ; i++ )
361 {
362 LPCITEMIDLIST pidl = ptr->apidl[i].pidl;
363 BOOL subtree = ptr->apidl[i].fRecursive;
364
365 if (wEventId & ptr->wEventMask)
366 {
367 if( !pidl ) /* all ? */
368 notify = TRUE;
369 else if( wEventId & SHCNE_NOITEMEVENTS )
370 notify = TRUE;
371 else if( wEventId & ( SHCNE_ONEITEMEVENTS | SHCNE_TWOITEMEVENTS ) )
372 notify = should_notify( Pidls[0], pidl, subtree );
373 else if( wEventId & SHCNE_TWOITEMEVENTS )
374 notify = should_notify( Pidls[1], pidl, subtree );
375 }
376 }
377
378 if( !notify )
379 continue;
380
381 ptr->pidlSignaled = ILClone(Pidls[0]);
382
383 TRACE("notifying %s, event %s(%lx) before\n", NodeName( ptr ), DumpEvent(
384 wEventId ),wEventId );
385
386 ptr->wSignalledEvent |= wEventId;
387
388 if (ptr->dwFlags & SHCNRF_NewDelivery)
389 SendMessageA(ptr->hwnd, ptr->uMsg, (WPARAM) ptr, (LPARAM) GetCurrentProcessId());
390 else
391 SendMessageA(ptr->hwnd, ptr->uMsg, (WPARAM)Pidls, wEventId);
392
393 TRACE("notifying %s, event %s(%lx) after\n", NodeName( ptr ), DumpEvent(
394 wEventId ),wEventId );
395
396 }
397 TRACE("notify Done\n");
398 LeaveCriticalSection(&SHELL32_ChangenotifyCS);
399
400 /* if we allocated it, free it. The ANSI flag is also set in its Unicode sibling. */
401 if ((typeFlag & SHCNF_PATHA) || (typeFlag & SHCNF_PRINTERA))
402 {
403 if (Pidls[0]) SHFree((LPITEMIDLIST)Pidls[0]);
404 if (Pidls[1]) SHFree((LPITEMIDLIST)Pidls[1]);
405 }
406 }
407
408 /*************************************************************************
409 * NTSHChangeNotifyRegister [SHELL32.640]
410 * NOTES
411 * Idlist is an array of structures and Count specifies how many items in the array
412 * (usually just one I think).
413 */
414 DWORD WINAPI NTSHChangeNotifyRegister(
415 HWND hwnd,
416 LONG events1,
417 LONG events2,
418 DWORD msg,
419 int count,
420 SHChangeNotifyEntry *idlist)
421 {
422 FIXME("(%p,0x%08lx,0x%08lx,0x%08lx,0x%08x,%p):semi stub.\n",
423 hwnd,events1,events2,msg,count,idlist);
424
425 return (DWORD) SHChangeNotifyRegister(hwnd, events1, events2, msg, count, idlist);
426 }
427
428 /*************************************************************************
429 * SHChangeNotification_Lock [SHELL32.644]
430 */
431 HANDLE WINAPI SHChangeNotification_Lock(
432 HANDLE hChange,
433 DWORD dwProcessId,
434 LPITEMIDLIST **lppidls,
435 LPLONG lpwEventId)
436 {
437 DWORD i;
438 LPNOTIFICATIONLIST node;
439 LPCITEMIDLIST *idlist;
440
441 TRACE("%p %08lx %p %p\n", hChange, dwProcessId, lppidls, lpwEventId);
442
443 /* EnterCriticalSection(&SHELL32_ChangenotifyCS); */
444
445 node = FindNode( hChange );
446 if( node )
447 {
448 idlist = SHAlloc( sizeof(LPCITEMIDLIST *) * node->cidl );
449 for(i=0; i<node->cidl; i++)
450 idlist[i] = (LPCITEMIDLIST)node->pidlSignaled;
451 *lpwEventId = node->wSignalledEvent;
452 *lppidls = (LPITEMIDLIST*)idlist;
453 node->wSignalledEvent = 0;
454 }
455 else
456 ERR("Couldn't find %p\n", hChange );
457
458 /* LeaveCriticalSection(&SHELL32_ChangenotifyCS); */
459
460 return (HANDLE) node;
461 }
462
463 /*************************************************************************
464 * SHChangeNotification_Unlock [SHELL32.645]
465 */
466 BOOL WINAPI SHChangeNotification_Unlock ( HANDLE hLock)
467 {
468 TRACE("\n");
469 return 1;
470 }
471
472 /*************************************************************************
473 * NTSHChangeNotifyDeregister [SHELL32.641]
474 */
475 DWORD WINAPI NTSHChangeNotifyDeregister(ULONG x1)
476 {
477 FIXME("(0x%08lx):semi stub.\n",x1);
478
479 return SHChangeNotifyDeregister( x1 );
480 }