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
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
28 #include "wine/list.h"
29 #include "wine/debug.h"
30 #include "shell32_main.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
34 static CRITICAL_SECTION SHELL32_ChangenotifyCS
;
35 static CRITICAL_SECTION_DEBUG critsect_debug
=
37 0, 0, &SHELL32_ChangenotifyCS
,
38 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
39 0, 0, { (DWORD_PTR
)(__FILE__
": SHELL32_ChangenotifyCS") }
41 static CRITICAL_SECTION SHELL32_ChangenotifyCS
= { &critsect_debug
, -1, 0, 0, 0, 0 };
43 typedef SHChangeNotifyEntry
*LPNOTIFYREGISTER
;
45 /* internal list of notification clients (internal) */
46 typedef struct _NOTIFICATIONLIST
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 struct list notifications
= LIST_INIT( notifications
);
63 #define SHCNE_NOITEMEVENTS ( \
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 )
73 #define SHCNE_TWOITEMEVENTS ( \
74 SHCNE_RENAMEFOLDER | SHCNE_RENAMEITEM | SHCNE_UPDATEITEM )
76 /* for dumping events */
77 static const char * DumpEvent( LONG event
)
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"
97 DUMPEV(SERVERDISCONNECT
)
102 DUMPEV(EXTENDED_EVENT
)
109 static const char * NodeName(const NOTIFICATIONLIST
*item
)
112 WCHAR path
[MAX_PATH
];
114 if(SHGetPathFromIDListW(item
->apidl
[0].pidl
, path
))
115 str
= wine_dbg_sprintf("%s", debugstr_w(path
));
117 str
= wine_dbg_sprintf("<not a disk file>" );
121 static void DeleteNode(LPNOTIFICATIONLIST item
)
125 TRACE("item=%p\n", item
);
127 /* remove item from list */
128 list_remove( &item
->entry
);
131 for (i
=0; i
<item
->cidl
; i
++)
132 SHFree((LPITEMIDLIST
)item
->apidl
[i
].pidl
);
137 void InitChangeNotifications(void)
141 void FreeChangeNotifications(void)
143 LPNOTIFICATIONLIST ptr
, next
;
147 EnterCriticalSection(&SHELL32_ChangenotifyCS
);
149 LIST_FOR_EACH_ENTRY_SAFE( ptr
, next
, ¬ifications
, NOTIFICATIONLIST
, entry
)
152 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
154 DeleteCriticalSection(&SHELL32_ChangenotifyCS
);
157 /*************************************************************************
158 * SHChangeNotifyRegister [SHELL32.2]
162 SHChangeNotifyRegister(
168 SHChangeNotifyEntry
*lpItems
)
170 LPNOTIFICATIONLIST item
;
173 item
= SHAlloc(sizeof(NOTIFICATIONLIST
));
175 TRACE("(%p,0x%08x,0x%08x,0x%08x,%d,%p) item=%p\n",
176 hwnd
, fSources
, wEventMask
, uMsg
, cItems
, lpItems
, item
);
179 item
->apidl
= SHAlloc(sizeof(SHChangeNotifyEntry
) * cItems
);
180 for(i
=0;i
<cItems
;i
++)
182 item
->apidl
[i
].pidl
= ILClone(lpItems
[i
].pidl
);
183 item
->apidl
[i
].fRecursive
= lpItems
[i
].fRecursive
;
187 item
->wEventMask
= wEventMask
;
188 item
->wSignalledEvent
= 0;
189 item
->dwFlags
= fSources
;
190 item
->id
= InterlockedIncrement( &next_id
);
192 TRACE("new node: %s\n", NodeName( item
));
194 EnterCriticalSection(&SHELL32_ChangenotifyCS
);
196 list_add_tail( ¬ifications
, &item
->entry
);
198 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
203 /*************************************************************************
204 * SHChangeNotifyDeregister [SHELL32.4]
206 BOOL WINAPI
SHChangeNotifyDeregister(ULONG hNotify
)
208 LPNOTIFICATIONLIST node
;
210 TRACE("(0x%08x)\n", hNotify
);
212 EnterCriticalSection(&SHELL32_ChangenotifyCS
);
214 LIST_FOR_EACH_ENTRY( node
, ¬ifications
, NOTIFICATIONLIST
, entry
)
216 if (node
->id
== hNotify
)
219 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
223 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
227 /*************************************************************************
228 * SHChangeNotifyUpdateEntryList [SHELL32.5]
230 BOOL WINAPI
SHChangeNotifyUpdateEntryList(DWORD unknown1
, DWORD unknown2
,
231 DWORD unknown3
, DWORD unknown4
)
233 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
234 unknown1
, unknown2
, unknown3
, unknown4
);
239 static BOOL
should_notify( LPCITEMIDLIST changed
, LPCITEMIDLIST watched
, BOOL sub
)
241 TRACE("%p %p %d\n", changed
, watched
, sub
);
244 if (ILIsEqual( watched
, changed
) )
246 if( sub
&& ILIsParent( watched
, changed
, TRUE
) )
251 /*************************************************************************
252 * SHChangeNotify [SHELL32.@]
254 void WINAPI
SHChangeNotify(LONG wEventId
, UINT uFlags
, LPCVOID dwItem1
, LPCVOID dwItem2
)
256 LPCITEMIDLIST Pidls
[2];
257 LPNOTIFICATIONLIST ptr
;
258 UINT typeFlag
= uFlags
& SHCNF_TYPE
;
263 TRACE("(0x%08x,0x%08x,%p,%p):stub.\n", wEventId
, uFlags
, dwItem1
, dwItem2
);
265 if( ( wEventId
& SHCNE_NOITEMEVENTS
) && ( dwItem1
|| dwItem2
) )
267 TRACE("dwItem1 and dwItem2 are not zero, but should be\n");
272 else if( ( wEventId
& SHCNE_ONEITEMEVENTS
) && dwItem2
)
274 TRACE("dwItem2 is not zero, but should be\n");
279 if( ( ( wEventId
& SHCNE_NOITEMEVENTS
) &&
280 ( wEventId
& ~SHCNE_NOITEMEVENTS
) ) ||
281 ( ( wEventId
& SHCNE_ONEITEMEVENTS
) &&
282 ( wEventId
& ~SHCNE_ONEITEMEVENTS
) ) ||
283 ( ( wEventId
& SHCNE_TWOITEMEVENTS
) &&
284 ( wEventId
& ~SHCNE_TWOITEMEVENTS
) ) )
286 WARN("mutually incompatible events listed\n");
290 /* convert paths in IDLists*/
294 if (dwItem1
) Pidls
[0] = SHSimpleIDListFromPathA(dwItem1
);
295 if (dwItem2
) Pidls
[1] = SHSimpleIDListFromPathA(dwItem2
);
298 if (dwItem1
) Pidls
[0] = SHSimpleIDListFromPathW(dwItem1
);
299 if (dwItem2
) Pidls
[1] = SHSimpleIDListFromPathW(dwItem2
);
307 FIXME("SHChangeNotify with (uFlags & SHCNF_PRINTER)\n");
311 FIXME("unknown type %08x\n",typeFlag
);
316 WCHAR path
[MAX_PATH
];
318 if( Pidls
[0] && SHGetPathFromIDListW(Pidls
[0], path
))
319 TRACE("notify %08x on item1 = %s\n", wEventId
, debugstr_w(path
));
321 if( Pidls
[1] && SHGetPathFromIDListW(Pidls
[1], path
))
322 TRACE("notify %08x on item2 = %s\n", wEventId
, debugstr_w(path
));
325 EnterCriticalSection(&SHELL32_ChangenotifyCS
);
327 /* loop through the list */
328 LIST_FOR_EACH_ENTRY( ptr
, ¬ifications
, NOTIFICATIONLIST
, entry
)
335 TRACE("trying %p\n", ptr
);
337 for( i
=0; (i
<ptr
->cidl
) && !notify
; i
++ )
339 LPCITEMIDLIST pidl
= ptr
->apidl
[i
].pidl
;
340 BOOL subtree
= ptr
->apidl
[i
].fRecursive
;
342 if (wEventId
& ptr
->wEventMask
)
344 if( !pidl
) /* all ? */
346 else if( wEventId
& SHCNE_NOITEMEVENTS
)
348 else if( wEventId
& ( SHCNE_ONEITEMEVENTS
| SHCNE_TWOITEMEVENTS
) )
349 notify
= should_notify( Pidls
[0], pidl
, subtree
);
350 else if( wEventId
& SHCNE_TWOITEMEVENTS
)
351 notify
= should_notify( Pidls
[1], pidl
, subtree
);
358 ptr
->pidlSignaled
= ILClone(Pidls
[0]);
360 TRACE("notifying %s, event %s(%x) before\n", NodeName( ptr
), DumpEvent(
361 wEventId
),wEventId
);
363 ptr
->wSignalledEvent
|= wEventId
;
365 if (ptr
->dwFlags
& SHCNRF_NewDelivery
)
366 SendMessageA(ptr
->hwnd
, ptr
->uMsg
, (WPARAM
) ptr
, GetCurrentProcessId());
368 SendMessageA(ptr
->hwnd
, ptr
->uMsg
, (WPARAM
)Pidls
, wEventId
);
370 TRACE("notifying %s, event %s(%x) after\n", NodeName( ptr
), DumpEvent(
371 wEventId
),wEventId
);
374 TRACE("notify Done\n");
375 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
377 if (wEventId
& SHCNE_ASSOCCHANGED
)
379 static const WCHAR args
[] = {' ','-','a',0 };
380 TRACE("refreshing file type associations\n");
381 run_winemenubuilder( args
);
384 /* if we allocated it, free it. The ANSI flag is also set in its Unicode sibling. */
385 if ((typeFlag
& SHCNF_PATHA
) || (typeFlag
& SHCNF_PRINTERA
))
387 SHFree((LPITEMIDLIST
)Pidls
[0]);
388 SHFree((LPITEMIDLIST
)Pidls
[1]);
392 /*************************************************************************
393 * NTSHChangeNotifyRegister [SHELL32.640]
395 * Idlist is an array of structures and Count specifies how many items in the array
396 * (usually just one I think).
398 DWORD WINAPI
NTSHChangeNotifyRegister(
404 SHChangeNotifyEntry
*idlist
)
406 FIXME("(%p,0x%08x,0x%08x,0x%08x,0x%08x,%p):semi stub.\n",
407 hwnd
,events1
,events2
,msg
,count
,idlist
);
409 return SHChangeNotifyRegister(hwnd
, events1
, events2
, msg
, count
, idlist
);
412 /*************************************************************************
413 * SHChangeNotification_Lock [SHELL32.644]
415 HANDLE WINAPI
SHChangeNotification_Lock(
418 LPITEMIDLIST
**lppidls
,
422 LPNOTIFICATIONLIST node
;
423 LPCITEMIDLIST
*idlist
;
425 TRACE("%p %08x %p %p\n", hChange
, dwProcessId
, lppidls
, lpwEventId
);
427 /* EnterCriticalSection(&SHELL32_ChangenotifyCS); */
429 LIST_FOR_EACH_ENTRY( node
, ¬ifications
, NOTIFICATIONLIST
, entry
)
433 idlist
= SHAlloc( sizeof(LPCITEMIDLIST
*) * node
->cidl
);
434 for(i
=0; i
<node
->cidl
; i
++)
435 idlist
[i
] = node
->pidlSignaled
;
436 *lpwEventId
= node
->wSignalledEvent
;
437 *lppidls
= (LPITEMIDLIST
*)idlist
;
438 node
->wSignalledEvent
= 0;
439 /* LeaveCriticalSection(&SHELL32_ChangenotifyCS); */
443 ERR("Couldn't find %p\n", hChange
);
445 /* LeaveCriticalSection(&SHELL32_ChangenotifyCS); */
450 /*************************************************************************
451 * SHChangeNotification_Unlock [SHELL32.645]
453 BOOL WINAPI
SHChangeNotification_Unlock ( HANDLE hLock
)
459 /*************************************************************************
460 * NTSHChangeNotifyDeregister [SHELL32.641]
462 DWORD WINAPI
NTSHChangeNotifyDeregister(ULONG x1
)
464 FIXME("(0x%08x):semi stub.\n",x1
);
466 return SHChangeNotifyDeregister( x1
);