mshtml: Check for null pointers in IHTMLLocation_get*.
[wine/hramrach.git] / dlls / shell32 / changenotify.c
blob43a5fb8263b430a9aa75d8d4cfd52cba3aa5203a
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 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wine/debug.h"
29 #include "shell32_main.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(shell);
33 static CRITICAL_SECTION SHELL32_ChangenotifyCS;
34 static CRITICAL_SECTION_DEBUG critsect_debug =
36 0, 0, &SHELL32_ChangenotifyCS,
37 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
38 0, 0, { (DWORD_PTR)(__FILE__ ": SHELL32_ChangenotifyCS") }
40 static CRITICAL_SECTION SHELL32_ChangenotifyCS = { &critsect_debug, -1, 0, 0, 0, 0 };
42 typedef SHChangeNotifyEntry *LPNOTIFYREGISTER;
44 /* internal list of notification clients (internal) */
45 typedef struct _NOTIFICATIONLIST
47 struct _NOTIFICATIONLIST *next;
48 struct _NOTIFICATIONLIST *prev;
49 HWND hwnd; /* window to notify */
50 DWORD uMsg; /* message to send */
51 LPNOTIFYREGISTER apidl; /* array of entries to watch*/
52 UINT cidl; /* number of pidls in array */
53 LONG wEventMask; /* subscribed events */
54 LONG wSignalledEvent; /* event that occurred */
55 DWORD dwFlags; /* client flags */
56 LPCITEMIDLIST pidlSignaled; /*pidl of the path that caused the signal*/
58 } NOTIFICATIONLIST, *LPNOTIFICATIONLIST;
60 static NOTIFICATIONLIST *head, *tail;
62 #define SHCNE_NOITEMEVENTS ( \
63 SHCNE_ASSOCCHANGED )
65 #define SHCNE_ONEITEMEVENTS ( \
66 SHCNE_ATTRIBUTES | SHCNE_CREATE | SHCNE_DELETE | SHCNE_DRIVEADD | \
67 SHCNE_DRIVEADDGUI | SHCNE_DRIVEREMOVED | SHCNE_FREESPACE | \
68 SHCNE_MEDIAINSERTED | SHCNE_MEDIAREMOVED | SHCNE_MKDIR | \
69 SHCNE_NETSHARE | SHCNE_NETUNSHARE | SHCNE_RMDIR | \
70 SHCNE_SERVERDISCONNECT | SHCNE_UPDATEDIR | SHCNE_UPDATEIMAGE )
72 #define SHCNE_TWOITEMEVENTS ( \
73 SHCNE_RENAMEFOLDER | SHCNE_RENAMEITEM | SHCNE_UPDATEITEM )
75 /* for dumping events */
76 static const char * DumpEvent( LONG event )
78 if( event == SHCNE_ALLEVENTS )
79 return "SHCNE_ALLEVENTS";
80 #define DUMPEV(x) ,( event & SHCNE_##x )? #x " " : ""
81 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"
82 DUMPEV(RENAMEITEM)
83 DUMPEV(CREATE)
84 DUMPEV(DELETE)
85 DUMPEV(MKDIR)
86 DUMPEV(RMDIR)
87 DUMPEV(MEDIAINSERTED)
88 DUMPEV(MEDIAREMOVED)
89 DUMPEV(DRIVEREMOVED)
90 DUMPEV(DRIVEADD)
91 DUMPEV(NETSHARE)
92 DUMPEV(NETUNSHARE)
93 DUMPEV(ATTRIBUTES)
94 DUMPEV(UPDATEDIR)
95 DUMPEV(UPDATEITEM)
96 DUMPEV(SERVERDISCONNECT)
97 DUMPEV(UPDATEIMAGE)
98 DUMPEV(DRIVEADDGUI)
99 DUMPEV(RENAMEFOLDER)
100 DUMPEV(FREESPACE)
101 DUMPEV(EXTENDED_EVENT)
102 DUMPEV(ASSOCCHANGED)
103 DUMPEV(INTERRUPT)
105 #undef DUMPEV
108 static BOOL RefreshFileTypeAssociations(void)
110 static WCHAR szWinemenubuilder[] = {
111 'w','i','n','e','m','e','n','u','b','u','i','l','d','e','r','.','e','x','e',
112 ' ','-','a',0 };
113 STARTUPINFOW si;
114 PROCESS_INFORMATION pi;
115 BOOL ret;
117 TRACE("starting %s\n",debugstr_w(szWinemenubuilder));
119 memset(&si, 0, sizeof(si));
120 si.cb = sizeof(si);
122 ret = CreateProcessW( NULL, szWinemenubuilder, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi );
124 if (ret)
126 CloseHandle( pi.hProcess );
127 CloseHandle( pi.hThread );
130 return ret;
133 static const char * NodeName(const NOTIFICATIONLIST *item)
135 const char *str;
136 WCHAR path[MAX_PATH];
138 if(SHGetPathFromIDListW(item->apidl[0].pidl, path ))
139 str = wine_dbg_sprintf("%s", debugstr_w(path));
140 else
141 str = wine_dbg_sprintf("<not a disk file>" );
142 return str;
145 static void AddNode(LPNOTIFICATIONLIST item)
147 TRACE("item %p\n", item );
149 /* link items */
150 item->prev = tail;
151 item->next = NULL;
152 if( tail )
153 tail->next = item;
154 else
155 head = item;
156 tail = item;
159 static LPNOTIFICATIONLIST FindNode( HANDLE hitem )
161 LPNOTIFICATIONLIST ptr;
162 for( ptr = head; ptr; ptr = ptr->next )
163 if( ptr == hitem )
164 return ptr;
165 return NULL;
168 static void DeleteNode(LPNOTIFICATIONLIST item)
170 UINT i;
172 TRACE("item=%p prev=%p next=%p\n", item, item->prev, item->next);
174 /* remove item from list */
175 if( item->prev )
176 item->prev->next = item->next;
177 else
178 head = item->next;
179 if( item->next )
180 item->next->prev = item->prev;
181 else
182 tail = item->prev;
184 /* free the item */
185 for (i=0; i<item->cidl; i++)
186 SHFree((LPITEMIDLIST)item->apidl[i].pidl);
187 SHFree(item->apidl);
188 SHFree(item);
191 void InitChangeNotifications(void)
195 void FreeChangeNotifications(void)
197 TRACE("\n");
199 EnterCriticalSection(&SHELL32_ChangenotifyCS);
201 while( head )
202 DeleteNode( head );
204 LeaveCriticalSection(&SHELL32_ChangenotifyCS);
206 DeleteCriticalSection(&SHELL32_ChangenotifyCS);
209 /*************************************************************************
210 * SHChangeNotifyRegister [SHELL32.2]
213 ULONG WINAPI
214 SHChangeNotifyRegister(
215 HWND hwnd,
216 int fSources,
217 LONG wEventMask,
218 UINT uMsg,
219 int cItems,
220 SHChangeNotifyEntry *lpItems)
222 LPNOTIFICATIONLIST item;
223 int i;
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);
230 item->next = NULL;
231 item->prev = NULL;
232 item->cidl = cItems;
233 item->apidl = SHAlloc(sizeof(SHChangeNotifyEntry) * cItems);
234 for(i=0;i<cItems;i++)
236 item->apidl[i].pidl = ILClone(lpItems[i].pidl);
237 item->apidl[i].fRecursive = lpItems[i].fRecursive;
239 item->hwnd = hwnd;
240 item->uMsg = uMsg;
241 item->wEventMask = wEventMask;
242 item->wSignalledEvent = 0;
243 item->dwFlags = fSources;
245 TRACE("new node: %s\n", NodeName( item ));
247 EnterCriticalSection(&SHELL32_ChangenotifyCS);
249 AddNode(item);
251 LeaveCriticalSection(&SHELL32_ChangenotifyCS);
253 return (ULONG)item;
256 /*************************************************************************
257 * SHChangeNotifyDeregister [SHELL32.4]
259 BOOL WINAPI SHChangeNotifyDeregister(ULONG hNotify)
261 LPNOTIFICATIONLIST node;
263 TRACE("(0x%08x)\n", hNotify);
265 EnterCriticalSection(&SHELL32_ChangenotifyCS);
267 node = FindNode((HANDLE)hNotify);
268 if( node )
269 DeleteNode(node);
271 LeaveCriticalSection(&SHELL32_ChangenotifyCS);
273 return node?TRUE:FALSE;
276 /*************************************************************************
277 * SHChangeNotifyUpdateEntryList [SHELL32.5]
279 BOOL WINAPI SHChangeNotifyUpdateEntryList(DWORD unknown1, DWORD unknown2,
280 DWORD unknown3, DWORD unknown4)
282 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
283 unknown1, unknown2, unknown3, unknown4);
285 return -1;
288 static BOOL should_notify( LPCITEMIDLIST changed, LPCITEMIDLIST watched, BOOL sub )
290 TRACE("%p %p %d\n", changed, watched, sub );
291 if ( !watched )
292 return FALSE;
293 if (ILIsEqual( watched, changed ) )
294 return TRUE;
295 if( sub && ILIsParent( watched, changed, TRUE ) )
296 return TRUE;
297 return FALSE;
300 /*************************************************************************
301 * SHChangeNotify [SHELL32.@]
303 void WINAPI SHChangeNotify(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID dwItem2)
305 LPCITEMIDLIST Pidls[2];
306 LPNOTIFICATIONLIST ptr;
307 UINT typeFlag = uFlags & SHCNF_TYPE;
309 Pidls[0] = NULL;
310 Pidls[1] = NULL;
312 TRACE("(0x%08x,0x%08x,%p,%p):stub.\n", wEventId, uFlags, dwItem1, dwItem2);
314 if( ( wEventId & SHCNE_NOITEMEVENTS ) && ( dwItem1 || dwItem2 ) )
316 TRACE("dwItem1 and dwItem2 are not zero, but should be\n");
317 dwItem1 = 0;
318 dwItem2 = 0;
319 return;
321 else if( ( wEventId & SHCNE_ONEITEMEVENTS ) && dwItem2 )
323 TRACE("dwItem2 is not zero, but should be\n");
324 dwItem2 = 0;
325 return;
328 if( ( ( wEventId & SHCNE_NOITEMEVENTS ) &&
329 ( wEventId & ~SHCNE_NOITEMEVENTS ) ) ||
330 ( ( wEventId & SHCNE_ONEITEMEVENTS ) &&
331 ( wEventId & ~SHCNE_ONEITEMEVENTS ) ) ||
332 ( ( wEventId & SHCNE_TWOITEMEVENTS ) &&
333 ( wEventId & ~SHCNE_TWOITEMEVENTS ) ) )
335 WARN("mutually incompatible events listed\n");
336 return;
339 /* convert paths in IDLists*/
340 switch (typeFlag)
342 case SHCNF_PATHA:
343 if (dwItem1) Pidls[0] = SHSimpleIDListFromPathA(dwItem1);
344 if (dwItem2) Pidls[1] = SHSimpleIDListFromPathA(dwItem2);
345 break;
346 case SHCNF_PATHW:
347 if (dwItem1) Pidls[0] = SHSimpleIDListFromPathW(dwItem1);
348 if (dwItem2) Pidls[1] = SHSimpleIDListFromPathW(dwItem2);
349 break;
350 case SHCNF_IDLIST:
351 Pidls[0] = dwItem1;
352 Pidls[1] = dwItem2;
353 break;
354 case SHCNF_PRINTERA:
355 case SHCNF_PRINTERW:
356 FIXME("SHChangeNotify with (uFlags & SHCNF_PRINTER)\n");
357 return;
358 case SHCNF_DWORD:
359 default:
360 FIXME("unknown type %08x\n",typeFlag);
361 return;
365 WCHAR path[MAX_PATH];
367 if( Pidls[0] && SHGetPathFromIDListW(Pidls[0], path ))
368 TRACE("notify %08x on item1 = %s\n", wEventId, debugstr_w(path));
370 if( Pidls[1] && SHGetPathFromIDListW(Pidls[1], path ))
371 TRACE("notify %08x on item2 = %s\n", wEventId, debugstr_w(path));
374 EnterCriticalSection(&SHELL32_ChangenotifyCS);
376 /* loop through the list */
377 for( ptr = head; ptr; ptr = ptr->next )
379 BOOL notify;
380 DWORD i;
382 notify = FALSE;
384 TRACE("trying %p\n", ptr);
386 for( i=0; (i<ptr->cidl) && !notify ; i++ )
388 LPCITEMIDLIST pidl = ptr->apidl[i].pidl;
389 BOOL subtree = ptr->apidl[i].fRecursive;
391 if (wEventId & ptr->wEventMask)
393 if( !pidl ) /* all ? */
394 notify = TRUE;
395 else if( wEventId & SHCNE_NOITEMEVENTS )
396 notify = TRUE;
397 else if( wEventId & ( SHCNE_ONEITEMEVENTS | SHCNE_TWOITEMEVENTS ) )
398 notify = should_notify( Pidls[0], pidl, subtree );
399 else if( wEventId & SHCNE_TWOITEMEVENTS )
400 notify = should_notify( Pidls[1], pidl, subtree );
404 if( !notify )
405 continue;
407 ptr->pidlSignaled = ILClone(Pidls[0]);
409 TRACE("notifying %s, event %s(%x) before\n", NodeName( ptr ), DumpEvent(
410 wEventId ),wEventId );
412 ptr->wSignalledEvent |= wEventId;
414 if (ptr->dwFlags & SHCNRF_NewDelivery)
415 SendMessageA(ptr->hwnd, ptr->uMsg, (WPARAM) ptr, (LPARAM) GetCurrentProcessId());
416 else
417 SendMessageA(ptr->hwnd, ptr->uMsg, (WPARAM)Pidls, wEventId);
419 TRACE("notifying %s, event %s(%x) after\n", NodeName( ptr ), DumpEvent(
420 wEventId ),wEventId );
423 TRACE("notify Done\n");
424 LeaveCriticalSection(&SHELL32_ChangenotifyCS);
426 if (wEventId & SHCNE_ASSOCCHANGED)
428 TRACE("refreshing file type associations\n");
429 RefreshFileTypeAssociations();
432 /* if we allocated it, free it. The ANSI flag is also set in its Unicode sibling. */
433 if ((typeFlag & SHCNF_PATHA) || (typeFlag & SHCNF_PRINTERA))
435 SHFree((LPITEMIDLIST)Pidls[0]);
436 SHFree((LPITEMIDLIST)Pidls[1]);
440 /*************************************************************************
441 * NTSHChangeNotifyRegister [SHELL32.640]
442 * NOTES
443 * Idlist is an array of structures and Count specifies how many items in the array
444 * (usually just one I think).
446 DWORD WINAPI NTSHChangeNotifyRegister(
447 HWND hwnd,
448 LONG events1,
449 LONG events2,
450 DWORD msg,
451 int count,
452 SHChangeNotifyEntry *idlist)
454 FIXME("(%p,0x%08x,0x%08x,0x%08x,0x%08x,%p):semi stub.\n",
455 hwnd,events1,events2,msg,count,idlist);
457 return SHChangeNotifyRegister(hwnd, events1, events2, msg, count, idlist);
460 /*************************************************************************
461 * SHChangeNotification_Lock [SHELL32.644]
463 HANDLE WINAPI SHChangeNotification_Lock(
464 HANDLE hChange,
465 DWORD dwProcessId,
466 LPITEMIDLIST **lppidls,
467 LPLONG lpwEventId)
469 DWORD i;
470 LPNOTIFICATIONLIST node;
471 LPCITEMIDLIST *idlist;
473 TRACE("%p %08x %p %p\n", hChange, dwProcessId, lppidls, lpwEventId);
475 /* EnterCriticalSection(&SHELL32_ChangenotifyCS); */
477 node = FindNode( hChange );
478 if( node )
480 idlist = SHAlloc( sizeof(LPCITEMIDLIST *) * node->cidl );
481 for(i=0; i<node->cidl; i++)
482 idlist[i] = node->pidlSignaled;
483 *lpwEventId = node->wSignalledEvent;
484 *lppidls = (LPITEMIDLIST*)idlist;
485 node->wSignalledEvent = 0;
487 else
488 ERR("Couldn't find %p\n", hChange );
490 /* LeaveCriticalSection(&SHELL32_ChangenotifyCS); */
492 return node;
495 /*************************************************************************
496 * SHChangeNotification_Unlock [SHELL32.645]
498 BOOL WINAPI SHChangeNotification_Unlock ( HANDLE hLock)
500 TRACE("\n");
501 return 1;
504 /*************************************************************************
505 * NTSHChangeNotifyDeregister [SHELL32.641]
507 DWORD WINAPI NTSHChangeNotifyDeregister(ULONG x1)
509 FIXME("(0x%08x):semi stub.\n",x1);
511 return SHChangeNotifyDeregister( x1 );