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 DWORD dwFlags
; /* client flags */
56 } NOTIFICATIONLIST
, *LPNOTIFICATIONLIST
;
58 static struct list notifications
= LIST_INIT( notifications
);
61 #define SHCNE_NOITEMEVENTS ( \
64 #define SHCNE_ONEITEMEVENTS ( \
65 SHCNE_ATTRIBUTES | SHCNE_CREATE | SHCNE_DELETE | SHCNE_DRIVEADD | \
66 SHCNE_DRIVEADDGUI | SHCNE_DRIVEREMOVED | SHCNE_FREESPACE | \
67 SHCNE_MEDIAINSERTED | SHCNE_MEDIAREMOVED | SHCNE_MKDIR | \
68 SHCNE_NETSHARE | SHCNE_NETUNSHARE | SHCNE_RMDIR | \
69 SHCNE_SERVERDISCONNECT | SHCNE_UPDATEDIR | SHCNE_UPDATEIMAGE )
71 #define SHCNE_TWOITEMEVENTS ( \
72 SHCNE_RENAMEFOLDER | SHCNE_RENAMEITEM | SHCNE_UPDATEITEM )
74 /* for dumping events */
75 static const char * DumpEvent( LONG event
)
77 if( event
== SHCNE_ALLEVENTS
)
78 return "SHCNE_ALLEVENTS";
79 #define DUMPEV(x) ,( event & SHCNE_##x )? #x " " : ""
80 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"
95 DUMPEV(SERVERDISCONNECT
)
100 DUMPEV(EXTENDED_EVENT
)
107 static const char * NodeName(const NOTIFICATIONLIST
*item
)
110 WCHAR path
[MAX_PATH
];
112 if(SHGetPathFromIDListW(item
->apidl
[0].pidl
, path
))
113 str
= wine_dbg_sprintf("%s", debugstr_w(path
));
115 str
= wine_dbg_sprintf("<not a disk file>" );
119 static void DeleteNode(LPNOTIFICATIONLIST item
)
123 TRACE("item=%p\n", item
);
125 /* remove item from list */
126 list_remove( &item
->entry
);
129 for (i
=0; i
<item
->cidl
; i
++)
130 SHFree((LPITEMIDLIST
)item
->apidl
[i
].pidl
);
135 void InitChangeNotifications(void)
139 void FreeChangeNotifications(void)
141 LPNOTIFICATIONLIST ptr
, next
;
145 EnterCriticalSection(&SHELL32_ChangenotifyCS
);
147 LIST_FOR_EACH_ENTRY_SAFE( ptr
, next
, ¬ifications
, NOTIFICATIONLIST
, entry
)
150 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
152 DeleteCriticalSection(&SHELL32_ChangenotifyCS
);
155 /*************************************************************************
156 * SHChangeNotifyRegister [SHELL32.2]
160 SHChangeNotifyRegister(
166 SHChangeNotifyEntry
*lpItems
)
168 LPNOTIFICATIONLIST item
;
171 item
= SHAlloc(sizeof(NOTIFICATIONLIST
));
173 TRACE("(%p,0x%08x,0x%08x,0x%08x,%d,%p) item=%p\n",
174 hwnd
, fSources
, wEventMask
, uMsg
, cItems
, lpItems
, item
);
177 item
->apidl
= SHAlloc(sizeof(SHChangeNotifyEntry
) * cItems
);
178 for(i
=0;i
<cItems
;i
++)
180 item
->apidl
[i
].pidl
= ILClone(lpItems
[i
].pidl
);
181 item
->apidl
[i
].fRecursive
= lpItems
[i
].fRecursive
;
185 item
->wEventMask
= wEventMask
;
186 item
->dwFlags
= fSources
;
187 item
->id
= InterlockedIncrement( &next_id
);
189 TRACE("new node: %s\n", NodeName( item
));
191 EnterCriticalSection(&SHELL32_ChangenotifyCS
);
193 list_add_tail( ¬ifications
, &item
->entry
);
195 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
200 /*************************************************************************
201 * SHChangeNotifyDeregister [SHELL32.4]
203 BOOL WINAPI
SHChangeNotifyDeregister(ULONG hNotify
)
205 LPNOTIFICATIONLIST node
;
207 TRACE("(0x%08x)\n", hNotify
);
209 EnterCriticalSection(&SHELL32_ChangenotifyCS
);
211 LIST_FOR_EACH_ENTRY( node
, ¬ifications
, NOTIFICATIONLIST
, entry
)
213 if (node
->id
== hNotify
)
216 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
220 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
224 /*************************************************************************
225 * SHChangeNotifyUpdateEntryList [SHELL32.5]
227 BOOL WINAPI
SHChangeNotifyUpdateEntryList(DWORD unknown1
, DWORD unknown2
,
228 DWORD unknown3
, DWORD unknown4
)
230 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
231 unknown1
, unknown2
, unknown3
, unknown4
);
236 struct new_delivery_notification
241 LPITEMIDLIST pidls
[2];
245 static BOOL
should_notify( LPCITEMIDLIST changed
, LPCITEMIDLIST watched
, BOOL sub
)
247 TRACE("%p %p %d\n", changed
, watched
, sub
);
250 if (ILIsEqual( watched
, changed
) )
252 if( sub
&& ILIsParent( watched
, changed
, FALSE
) )
257 /*************************************************************************
258 * SHChangeNotify [SHELL32.@]
260 void WINAPI
SHChangeNotify(LONG wEventId
, UINT uFlags
, LPCVOID dwItem1
, LPCVOID dwItem2
)
262 struct notification_recipients
{
269 HANDLE shared_data
= NULL
;
270 LPITEMIDLIST Pidls
[2];
271 LPNOTIFICATIONLIST ptr
;
272 struct list recipients
;
277 TRACE("(0x%08x,0x%08x,%p,%p)\n", wEventId
, uFlags
, dwItem1
, dwItem2
);
279 if(uFlags
& ~(SHCNF_TYPE
|SHCNF_FLUSH
))
280 FIXME("ignoring unsupported flags: %x\n", uFlags
);
282 if( ( wEventId
& SHCNE_NOITEMEVENTS
) && ( dwItem1
|| dwItem2
) )
284 TRACE("dwItem1 and dwItem2 are not zero, but should be\n");
289 else if( ( wEventId
& SHCNE_ONEITEMEVENTS
) && dwItem2
)
291 TRACE("dwItem2 is not zero, but should be\n");
296 if( ( ( wEventId
& SHCNE_NOITEMEVENTS
) &&
297 ( wEventId
& ~SHCNE_NOITEMEVENTS
) ) ||
298 ( ( wEventId
& SHCNE_ONEITEMEVENTS
) &&
299 ( wEventId
& ~SHCNE_ONEITEMEVENTS
) ) ||
300 ( ( wEventId
& SHCNE_TWOITEMEVENTS
) &&
301 ( wEventId
& ~SHCNE_TWOITEMEVENTS
) ) )
303 WARN("mutually incompatible events listed\n");
307 /* convert paths in IDLists*/
308 switch (uFlags
& SHCNF_TYPE
)
311 if (dwItem1
) Pidls
[0] = SHSimpleIDListFromPathA(dwItem1
);
312 if (dwItem2
) Pidls
[1] = SHSimpleIDListFromPathA(dwItem2
);
315 if (dwItem1
) Pidls
[0] = SHSimpleIDListFromPathW(dwItem1
);
316 if (dwItem2
) Pidls
[1] = SHSimpleIDListFromPathW(dwItem2
);
319 Pidls
[0] = ILClone(dwItem1
);
320 Pidls
[1] = ILClone(dwItem2
);
324 FIXME("SHChangeNotify with (uFlags & SHCNF_PRINTER)\n");
328 FIXME("unknown type %08x\n", uFlags
& SHCNF_TYPE
);
332 list_init(&recipients
);
333 EnterCriticalSection(&SHELL32_ChangenotifyCS
);
334 LIST_FOR_EACH_ENTRY( ptr
, ¬ifications
, NOTIFICATIONLIST
, entry
)
336 struct notification_recipients
*item
;
340 for( i
=0; (i
<ptr
->cidl
) && !notify
; i
++ )
342 LPCITEMIDLIST pidl
= ptr
->apidl
[i
].pidl
;
343 BOOL subtree
= ptr
->apidl
[i
].fRecursive
;
345 if (wEventId
& ptr
->wEventMask
)
347 if( !pidl
) /* all ? */
349 else if( wEventId
& SHCNE_NOITEMEVENTS
)
351 else if( wEventId
& ( SHCNE_ONEITEMEVENTS
| SHCNE_TWOITEMEVENTS
) )
352 notify
= should_notify( Pidls
[0], pidl
, subtree
);
353 else if( wEventId
& SHCNE_TWOITEMEVENTS
)
354 notify
= should_notify( Pidls
[1], pidl
, subtree
);
361 item
= SHAlloc(sizeof(struct notification_recipients
));
363 ERR("out of memory\n");
367 item
->hwnd
= ptr
->hwnd
;
368 item
->msg
= ptr
->uMsg
;
369 item
->flags
= ptr
->dwFlags
;
370 list_add_tail(&recipients
, &item
->entry
);
372 LeaveCriticalSection(&SHELL32_ChangenotifyCS
);
374 LIST_FOR_EACH_ENTRY_SAFE(cur
, next
, &recipients
, struct notification_recipients
, entry
)
376 TRACE("notifying %p, event %s(%x)\n", cur
->hwnd
, DumpEvent(wEventId
), wEventId
);
378 if (cur
->flags
& SHCNRF_NewDelivery
) {
380 struct new_delivery_notification
*notification
;
381 UINT size1
= ILGetSize(Pidls
[0]), size2
= ILGetSize(Pidls
[1]);
382 UINT offset
= (size1
+sizeof(int)-1)/sizeof(int)*sizeof(int);
384 notification
= SHAlloc(sizeof(struct new_delivery_notification
)+offset
+size2
);
386 ERR("out of memory\n");
388 notification
->event
= wEventId
;
389 notification
->pidl1_size
= size1
;
390 notification
->pidl2_size
= size2
;
392 memcpy(notification
->data
, Pidls
[0], size1
);
394 memcpy(notification
->data
+offset
, Pidls
[1], size2
);
396 shared_data
= SHAllocShared(notification
,
397 sizeof(struct new_delivery_notification
)+size1
+size2
,
398 GetCurrentProcessId());
399 SHFree(notification
);
404 SendMessageA(cur
->hwnd
, cur
->msg
, (WPARAM
)shared_data
, GetCurrentProcessId());
406 ERR("out of memory\n");
408 SendMessageA(cur
->hwnd
, cur
->msg
, (WPARAM
)Pidls
, wEventId
);
411 list_remove(&cur
->entry
);
414 SHFreeShared(shared_data
, GetCurrentProcessId());
418 if (wEventId
& SHCNE_ASSOCCHANGED
)
420 static const WCHAR args
[] = {' ','-','a',0 };
421 TRACE("refreshing file type associations\n");
422 run_winemenubuilder( args
);
426 /*************************************************************************
427 * NTSHChangeNotifyRegister [SHELL32.640]
429 * Idlist is an array of structures and Count specifies how many items in the array
430 * (usually just one I think).
432 DWORD WINAPI
NTSHChangeNotifyRegister(
438 SHChangeNotifyEntry
*idlist
)
440 FIXME("(%p,0x%08x,0x%08x,0x%08x,0x%08x,%p):semi stub.\n",
441 hwnd
,events1
,events2
,msg
,count
,idlist
);
443 return SHChangeNotifyRegister(hwnd
, events1
, events2
, msg
, count
, idlist
);
446 /*************************************************************************
447 * SHChangeNotification_Lock [SHELL32.644]
449 HANDLE WINAPI
SHChangeNotification_Lock(
452 LPITEMIDLIST
**lppidls
,
455 struct new_delivery_notification
*ndn
;
458 TRACE("%p %08x %p %p\n", hChange
, dwProcessId
, lppidls
, lpwEventId
);
460 ndn
= SHLockShared(hChange
, dwProcessId
);
462 WARN("SHLockShared failed\n");
467 offset
= (ndn
->pidl1_size
+sizeof(int)-1)/sizeof(int)*sizeof(int);
468 ndn
->pidls
[0] = ndn
->pidl1_size
? (LPITEMIDLIST
)ndn
->data
: NULL
;
469 ndn
->pidls
[1] = ndn
->pidl2_size
? (LPITEMIDLIST
)(ndn
->data
+offset
) : NULL
;
470 *lppidls
= ndn
->pidls
;
474 *lpwEventId
= ndn
->event
;
479 /*************************************************************************
480 * SHChangeNotification_Unlock [SHELL32.645]
482 BOOL WINAPI
SHChangeNotification_Unlock ( HANDLE hLock
)
484 TRACE("%p\n", hLock
);
485 return SHUnlockShared(hLock
);
488 /*************************************************************************
489 * NTSHChangeNotifyDeregister [SHELL32.641]
491 DWORD WINAPI
NTSHChangeNotifyDeregister(ULONG x1
)
493 FIXME("(0x%08x):semi stub.\n",x1
);
495 return SHChangeNotifyDeregister( x1
);