ReactOS 0.4.15-dev-7942-gd23573b
changenotify.cpp
Go to the documentation of this file.
1/*
2 * PROJECT: shell32
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: Shell change notification
5 * COPYRIGHT: Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
6 */
7
8#include "precomp.h"
9
11
13
14// This function requests creation of the server window if it doesn't exist yet
15static HWND
17{
18 static HWND s_hwndServer = NULL;
19
20 // use cache if any
21 if (s_hwndServer && IsWindow(s_hwndServer))
22 return s_hwndServer;
23
24 // get the shell window
25 HWND hwndShell = GetShellWindow();
26 if (hwndShell == NULL)
27 {
28 TRACE("GetShellWindow() returned NULL\n");
29 return NULL;
30 }
31
32 // Get the window of the notification server that runs in explorer
33 HWND hwndServer = (HWND)SendMessageW(hwndShell, WM_DESKTOP_GET_CNOTIFY_SERVER, bCreate, 0);
34 if (!IsWindow(hwndServer))
35 {
36 ERR("Unable to get server window\n");
37 hwndServer = NULL;
38 }
39
40 // save and return
41 s_hwndServer = hwndServer;
42 return hwndServer;
43}
44
45// This function will be called from DllMain.DLL_PROCESS_ATTACH.
47{
49}
50
51// This function will be called from DllMain.DLL_PROCESS_DETACH.
53{
54 HWND hwndServer = GetNotificationServer(FALSE);
55 if (hwndServer)
58}
59
60static HRESULT
62 _In_ LPCWSTR pszName,
63 _Out_ LPITEMIDLIST *ppidl,
64 _In_ IBindCtx *pBindCtx)
65{
66 *ppidl = NULL;
67
68 CComHeapPtr<ITEMIDLIST> pidlPrinters;
71 return hr;
72
74 hr = SHBindToObject(NULL, pidlPrinters, IID_PPV_ARG(IShellFolder, &pFolder));
76 return hr;
77
79 hr = pFolder->ParseDisplayName(NULL, pBindCtx, (LPWSTR)pszName, NULL, &pidlTemp, NULL);
81 return hr;
82
83 return SHILCombine(pidlPrinters, pidlTemp, ppidl);
84}
85
87// There are two delivery methods: "old delivery method" and "new delivery method".
88//
89// The old delivery method creates a broker window in the caller process
90// for message trampoline. The old delivery method is slow and deprecated.
91//
92// The new delivery method is enabled by SHCNRF_NewDelivery flag.
93// With the new delivery method the server directly sends the delivery message.
94
95// This class brokers all notifications that don't have the SHCNRF_NewDelivery flag
97 public CWindowImpl<CChangeNotifyBroker, CWindow, CWorkerTraits>
98{
99public:
100 CChangeNotifyBroker(HWND hwndClient, UINT uMsg) :
101 m_hwndClient(hwndClient), m_uMsg(uMsg)
102 {
103 }
104
105 // Message handlers
107 {
109 }
110
112 {
113 // The server will destroy this window.
114 // After the window gets destroyed we can delete this broker here.
115 delete this;
116 }
117
118 DECLARE_WND_CLASS_EX(L"WorkerW", 0, 0)
119
123
124private:
127
128 BOOL BrokerNotification(HANDLE hTicket, DWORD dwOwnerPID)
129 {
130 // lock the ticket
131 PIDLIST_ABSOLUTE *ppidl = NULL;
132 LONG lEvent;
133 HANDLE hLock = SHChangeNotification_Lock(hTicket, dwOwnerPID, &ppidl, &lEvent);
134 if (hLock == NULL)
135 {
136 ERR("hLock is NULL\n");
137 return FALSE;
138 }
139
140 // perform the delivery
141 TRACE("broker notifying: %p, 0x%x, %p, 0x%lx\n",
142 m_hwndClient, m_uMsg, ppidl, lEvent);
144
145 // unlock the ticket
147 return TRUE;
148 }
149};
150
151// This function creates a notification broker for old method. Used in SHChangeNotifyRegister.
152static HWND
154{
155 // Create a new broker. It will be freed when the window gets destroyed
156 CChangeNotifyBroker* pBroker = new CChangeNotifyBroker(hwnd, wMsg);
157 if (pBroker == NULL)
158 {
159 ERR("Out of memory\n");
160 return NULL;
161 }
162
163 HWND hwndBroker = SHCreateDefaultWorkerWindow();
164 if (hwndBroker == NULL)
165 {
166 ERR("hwndBroker == NULL\n");
167 delete pBroker;
168 return NULL;
169 }
170
171 pBroker->SubclassWindow(hwndBroker);
172 return hwndBroker;
173}
174
175// This function creates a delivery ticket for shell change nofitication.
176// Used in SHChangeNotify.
177static HANDLE
179 DWORD dwOwnerPID, DWORD dwTick)
180{
181 // pidl1 and pidl2 have variable length. To store them into the delivery ticket,
182 // we have to consider the offsets and the sizes of pidl1 and pidl2.
183 DWORD cbPidl1 = 0, cbPidl2 = 0, ibOffset1 = 0, ibOffset2 = 0;
184 if (pidl1)
185 {
186 cbPidl1 = ILGetSize(pidl1);
187 ibOffset1 = DWORD_ALIGNMENT(sizeof(DELITICKET));
188 }
189 if (pidl2)
190 {
191 cbPidl2 = ILGetSize(pidl2);
192 ibOffset2 = DWORD_ALIGNMENT(ibOffset1 + cbPidl1);
193 }
194
195 // allocate the delivery ticket
196 DWORD cbSize = ibOffset2 + cbPidl2;
197 HANDLE hTicket = SHAllocShared(NULL, cbSize, dwOwnerPID);
198 if (hTicket == NULL)
199 {
200 ERR("Out of memory\n");
201 return NULL;
202 }
203
204 // lock the ticket
205 LPDELITICKET pTicket = (LPDELITICKET)SHLockSharedEx(hTicket, dwOwnerPID, TRUE);
206 if (pTicket == NULL)
207 {
208 ERR("SHLockSharedEx failed\n");
209 SHFreeShared(hTicket, dwOwnerPID);
210 return NULL;
211 }
212
213 // populate the ticket
214 pTicket->dwMagic = DELITICKET_MAGIC;
215 pTicket->wEventId = wEventId;
216 pTicket->uFlags = uFlags;
217 pTicket->ibOffset1 = ibOffset1;
218 pTicket->ibOffset2 = ibOffset2;
219 if (pidl1)
220 memcpy((LPBYTE)pTicket + ibOffset1, pidl1, cbPidl1);
221 if (pidl2)
222 memcpy((LPBYTE)pTicket + ibOffset2, pidl2, cbPidl2);
223
224 // unlock the ticket and return
225 SHUnlockShared(pTicket);
226 return hTicket;
227}
228
229// This function creates a "handbag" by using a delivery ticket.
230// The handbag is created in SHChangeNotification_Lock and used in OnBrokerNotification.
231// hTicket is a ticket handle of a shared memory block and dwOwnerPID is
232// the owner PID of the ticket.
233static LPHANDBAG
235{
236 // lock and validate the delivery ticket
237 LPDELITICKET pTicket = (LPDELITICKET)SHLockSharedEx(hTicket, dwOwnerPID, FALSE);
238 if (pTicket == NULL || pTicket->dwMagic != DELITICKET_MAGIC)
239 {
240 ERR("pTicket is invalid\n");
241 SHUnlockShared(pTicket);
242 return NULL;
243 }
244
245 // allocate the handbag
246 LPHANDBAG pHandbag = (LPHANDBAG)LocalAlloc(LMEM_FIXED, sizeof(HANDBAG));
247 if (pHandbag == NULL)
248 {
249 ERR("Out of memory\n");
250 SHUnlockShared(pTicket);
251 return NULL;
252 }
253
254 // populate the handbag
255 pHandbag->dwMagic = HANDBAG_MAGIC;
256 pHandbag->pTicket = pTicket;
257
258 pHandbag->pidls[0] = pHandbag->pidls[1] = NULL;
259 if (pTicket->ibOffset1)
260 pHandbag->pidls[0] = (LPITEMIDLIST)((LPBYTE)pTicket + pTicket->ibOffset1);
261 if (pTicket->ibOffset2)
262 pHandbag->pidls[1] = (LPITEMIDLIST)((LPBYTE)pTicket + pTicket->ibOffset2);
263
264 return pHandbag;
265}
266
267// This function creates a registration entry in SHChangeNotifyRegister function.
268static HANDLE
269CreateRegistrationParam(ULONG nRegID, HWND hwnd, UINT wMsg, INT fSources, LONG fEvents,
270 LONG fRecursive, LPCITEMIDLIST pidl, DWORD dwOwnerPID,
271 HWND hwndBroker)
272{
273 // pidl has variable length. To store it into the registration entry,
274 // we have to consider the length of pidl.
275 DWORD cbPidl = ILGetSize(pidl);
276 DWORD ibPidl = DWORD_ALIGNMENT(sizeof(REGENTRY));
277 DWORD cbSize = ibPidl + cbPidl;
278
279 // create the registration entry and lock it
280 HANDLE hRegEntry = SHAllocShared(NULL, cbSize, dwOwnerPID);
281 if (hRegEntry == NULL)
282 {
283 ERR("Out of memory\n");
284 return NULL;
285 }
286 LPREGENTRY pRegEntry = (LPREGENTRY)SHLockSharedEx(hRegEntry, dwOwnerPID, TRUE);
287 if (pRegEntry == NULL)
288 {
289 ERR("SHLockSharedEx failed\n");
290 SHFreeShared(hRegEntry, dwOwnerPID);
291 return NULL;
292 }
293
294 // populate the registration entry
295 pRegEntry->dwMagic = REGENTRY_MAGIC;
296 pRegEntry->cbSize = cbSize;
297 pRegEntry->nRegID = nRegID;
298 pRegEntry->hwnd = hwnd;
299 pRegEntry->uMsg = wMsg;
300 pRegEntry->fSources = fSources;
301 pRegEntry->fEvents = fEvents;
302 pRegEntry->fRecursive = fRecursive;
303 pRegEntry->hwndBroker = hwndBroker;
304 pRegEntry->ibPidl = 0;
305 if (pidl)
306 {
307 pRegEntry->ibPidl = ibPidl;
308 memcpy((LPBYTE)pRegEntry + ibPidl, pidl, cbPidl);
309 }
310
311 // unlock and return
312 SHUnlockShared(pRegEntry);
313 return hRegEntry;
314}
315
316// This function is the body of SHChangeNotify function.
317// It creates a delivery ticket and send CN_DELIVER_NOTIFICATION message to
318// transport the change.
319static void
321 DWORD dwTick)
322{
323 // get server window
324 HWND hwndServer = GetNotificationServer(FALSE);
325 if (hwndServer == NULL)
326 return;
327
328 // the ticket owner is the process of the notification server
329 DWORD pid;
330 GetWindowThreadProcessId(hwndServer, &pid);
331
332 // create a delivery ticket
333 HANDLE hTicket = CreateNotificationParam(wEventId, uFlags, pidl1, pidl2, pid, dwTick);
334 if (hTicket == NULL)
335 return;
336
337 TRACE("hTicket: %p, 0x%lx\n", hTicket, pid);
338
339 // send the ticket by using CN_DELIVER_NOTIFICATION
340 if (pid != GetCurrentProcessId() ||
342 {
343 SendMessageW(hwndServer, CN_DELIVER_NOTIFICATION, (WPARAM)hTicket, pid);
344 }
345 else
346 {
348 }
349}
350
352{
353 INT csidl1; // from
354 INT csidl2; // to
359};
360
362{
366};
367
369{
370 static BOOL s_bInit = FALSE;
371 if (!s_bInit)
372 {
373 for (SIZE_T i = 0; i < _countof(AliasPIDLs); ++i)
374 {
376
377 SHGetSpecialFolderLocation(NULL, alias->csidl1, &alias->pidl1);
378 SHGetPathFromIDListW(alias->pidl1, alias->szPath1);
379
380 SHGetSpecialFolderLocation(NULL, alias->csidl2, &alias->pidl2);
381 SHGetPathFromIDListW(alias->pidl2, alias->szPath2);
382 }
383 s_bInit = TRUE;
384 }
385}
386
388{
390
391 apidls[0] = apidls[1] = NULL;
392
393 INT k = 0;
394 for (SIZE_T i = 0; i < _countof(AliasPIDLs); ++i)
395 {
396 const ALIAS_PIDL *alias = &AliasPIDLs[i];
397 if (ILIsEqual(pidl, alias->pidl1))
398 {
399 if (alias->csidl1 == alias->csidl2)
400 {
401 apidls[k++] = ILCreateFromPathW(alias->szPath2);
402 }
403 else
404 {
405 apidls[k++] = ILClone(alias->pidl2);
406 }
407 if (k >= 2)
408 break;
409 }
410 }
411
412 return k > 0;
413}
414
415/*************************************************************************
416 * SHChangeNotifyRegister [SHELL32.2]
417 */
419SHChangeNotifyRegister(HWND hwnd, INT fSources, LONG wEventMask, UINT uMsg,
420 INT cItems, SHChangeNotifyEntry *lpItems)
421{
422 HWND hwndServer, hwndBroker = NULL;
423 HANDLE hRegEntry;
424 INT iItem;
425 ULONG nRegID = INVALID_REG_ID;
426 DWORD dwOwnerPID;
427 LPREGENTRY pRegEntry;
428
429 TRACE("(%p,0x%08x,0x%08x,0x%08x,%d,%p)\n",
430 hwnd, fSources, wEventMask, uMsg, cItems, lpItems);
431
432 // sanity check
433 if (wEventMask == 0 || cItems <= 0 || cItems > 0x7FFF || lpItems == NULL ||
434 hwnd == NULL || !IsWindow(hwnd))
435 {
436 return INVALID_REG_ID;
437 }
438
439 // request the window of the server
440 hwndServer = GetNotificationServer(TRUE);
441 if (hwndServer == NULL)
442 return INVALID_REG_ID;
443
444 // disable recursive interrupt in specific condition
445 if ((fSources & SHCNRF_RecursiveInterrupt) && !(fSources & SHCNRF_InterruptLevel))
446 {
447 fSources &= ~SHCNRF_RecursiveInterrupt;
448 }
449
450 // if it is old delivery method, then create a broker window
451 if ((fSources & SHCNRF_NewDelivery) == 0)
452 {
453 hwndBroker = hwnd = CreateNotificationBroker(hwnd, uMsg);
455 }
456
457 // The owner PID is the process ID of the server
458 GetWindowThreadProcessId(hwndServer, &dwOwnerPID);
459
461 for (iItem = 0; iItem < cItems; ++iItem)
462 {
463 // create a registration entry
464 hRegEntry = CreateRegistrationParam(nRegID, hwnd, uMsg, fSources, wEventMask,
465 lpItems[iItem].fRecursive, lpItems[iItem].pidl,
466 dwOwnerPID, hwndBroker);
467 if (hRegEntry)
468 {
469 TRACE("CN_REGISTER: hwnd:%p, hRegEntry:%p, pid:0x%lx\n",
470 hwndServer, hRegEntry, dwOwnerPID);
471
472 // send CN_REGISTER to the server
473 SendMessageW(hwndServer, CN_REGISTER, (WPARAM)hRegEntry, dwOwnerPID);
474
475 // update nRegID
476 pRegEntry = (LPREGENTRY)SHLockSharedEx(hRegEntry, dwOwnerPID, FALSE);
477 if (pRegEntry)
478 {
479 nRegID = pRegEntry->nRegID;
480 SHUnlockShared(pRegEntry);
481 }
482
483 // free registration entry
484 SHFreeShared(hRegEntry, dwOwnerPID);
485 }
486
487 if (nRegID == INVALID_REG_ID)
488 {
489 ERR("Delivery failed\n");
490
491 if (hwndBroker)
492 {
493 // destroy the broker
494 DestroyWindow(hwndBroker);
495 }
496 break;
497 }
498
499 // PIDL alias
500 LPITEMIDLIST apidlAlias[2];
501 if (DoGetAliasPIDLs(apidlAlias, lpItems[iItem].pidl))
502 {
503 if (apidlAlias[0])
504 {
505 // create another registration entry
506 hRegEntry = CreateRegistrationParam(nRegID, hwnd, uMsg, fSources, wEventMask,
507 lpItems[iItem].fRecursive, apidlAlias[0],
508 dwOwnerPID, hwndBroker);
509 if (hRegEntry)
510 {
511 TRACE("CN_REGISTER: hwnd:%p, hRegEntry:%p, pid:0x%lx\n",
512 hwndServer, hRegEntry, dwOwnerPID);
513
514 // send CN_REGISTER to the server
515 SendMessageW(hwndServer, CN_REGISTER, (WPARAM)hRegEntry, dwOwnerPID);
516
517 // free registration entry
518 SHFreeShared(hRegEntry, dwOwnerPID);
519 }
520 ILFree(apidlAlias[0]);
521 }
522
523 if (apidlAlias[1])
524 {
525 // create another registration entry
526 hRegEntry = CreateRegistrationParam(nRegID, hwnd, uMsg, fSources, wEventMask,
527 lpItems[iItem].fRecursive, apidlAlias[1],
528 dwOwnerPID, hwndBroker);
529 if (hRegEntry)
530 {
531 TRACE("CN_REGISTER: hwnd:%p, hRegEntry:%p, pid:0x%lx\n",
532 hwndServer, hRegEntry, dwOwnerPID);
533
534 // send CN_REGISTER to the server
535 SendMessageW(hwndServer, CN_REGISTER, (WPARAM)hRegEntry, dwOwnerPID);
536
537 // free registration entry
538 SHFreeShared(hRegEntry, dwOwnerPID);
539 }
540 ILFree(apidlAlias[1]);
541 }
542 }
543 }
545
546 return nRegID;
547}
548
549/*************************************************************************
550 * SHChangeNotifyDeregister [SHELL32.4]
551 */
554{
555 TRACE("(0x%08x)\n", hNotify);
556
557 // get the server window
558 HWND hwndServer = GetNotificationServer(FALSE);
559 if (hwndServer == NULL)
560 return FALSE;
561
562 // send CN_UNREGISTER message and try to unregister
563 BOOL ret = (BOOL)SendMessageW(hwndServer, CN_UNREGISTER, hNotify, 0);
564 if (!ret)
565 ERR("CN_UNREGISTER failed\n");
566
567 return ret;
568}
569
570/*************************************************************************
571 * SHChangeNotifyUpdateEntryList [SHELL32.5]
572 */
575 DWORD unknown3, DWORD unknown4)
576{
577 FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
578 unknown1, unknown2, unknown3, unknown4);
579 return TRUE;
580}
581
582/* for dumping events */
584{
585 if (event == SHCNE_ALLEVENTS)
586 return "SHCNE_ALLEVENTS";
587#define DUMPEV(x) ,( event & SHCNE_##x )? #x " " : ""
588 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"
589 DUMPEV(RENAMEITEM)
590 DUMPEV(CREATE)
593 DUMPEV(RMDIR)
594 DUMPEV(MEDIAINSERTED)
595 DUMPEV(MEDIAREMOVED)
596 DUMPEV(DRIVEREMOVED)
597 DUMPEV(DRIVEADD)
598 DUMPEV(NETSHARE)
599 DUMPEV(NETUNSHARE)
600 DUMPEV(ATTRIBUTES)
601 DUMPEV(UPDATEDIR)
602 DUMPEV(UPDATEITEM)
603 DUMPEV(SERVERDISCONNECT)
604 DUMPEV(UPDATEIMAGE)
605 DUMPEV(DRIVEADDGUI)
606 DUMPEV(RENAMEFOLDER)
607 DUMPEV(FREESPACE)
608 DUMPEV(EXTENDED_EVENT)
609 DUMPEV(ASSOCCHANGED)
610 DUMPEV(INTERRUPT)
611 );
612#undef DUMPEV
613}
614
615/*************************************************************************
616 * SHChangeRegistrationReceive [SHELL32.646]
617 */
620{
621 TRACE("\n");
622 return FALSE; /* Just return FALSE */
623}
624
627 LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2, DWORD dwTick)
628{
629 // TODO: Queueing notifications
630 CreateNotificationParamAndSend(lEvent, uFlags, pidl1, pidl2, dwTick);
631}
632
633/*************************************************************************
634 * SHChangeNotifyReceive [SHELL32.643]
635 */
638{
640}
641
644{
645 SHChangeNotifyReceiveEx(lEvent, uFlags, pidl1, pidl2, dwTick);
646}
647
648/*************************************************************************
649 * SHChangeNotify [SHELL32.@]
650 */
651EXTERN_C void WINAPI
652SHChangeNotify(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID dwItem2)
653{
654 TRACE("(0x%08x,0x%08x,%p,%p)\n", wEventId, uFlags, dwItem1, dwItem2);
655
657 return;
658
659 DWORD dwTick = GetTickCount();
660
661 WCHAR szPath1[MAX_PATH], szPath2[MAX_PATH];
662 LPITEMIDLIST pidl1 = NULL, pidl2 = NULL;
663 LPWSTR psz1, psz2;
665 DWORD dwType;
666
667Retry:
668 dwType = (uFlags & SHCNF_TYPE);
669 switch (dwType)
670 {
671 case SHCNF_IDLIST:
672 {
673 if (wEventId == SHCNE_FREESPACE)
674 {
675 szPath1[0] = szPath2[0] = UNICODE_NULL;
676 if (dwItem1)
677 SHGetPathFromIDList((LPCITEMIDLIST)dwItem1, szPath1);
678 if (dwItem2)
679 SHGetPathFromIDList((LPCITEMIDLIST)dwItem2, szPath2);
680
682 dwItem1 = (szPath1[0] ? szPath1 : NULL);
683 dwItem2 = (szPath2[0] ? szPath2 : NULL);
684 goto Retry;
685 }
686
687 pidl1 = (LPITEMIDLIST)dwItem1;
688 pidl2 = (LPITEMIDLIST)dwItem2;
689 break;
690 }
691 case SHCNF_PATHA:
692 case SHCNF_PRINTERA:
693 {
694 psz1 = psz2 = NULL;
695 szPath1[0] = szPath2[0] = UNICODE_NULL;
696 if (dwItem1)
697 {
698 SHAnsiToUnicode((LPCSTR)dwItem1, szPath1, _countof(szPath1));
699 psz1 = szPath1;
700 }
701 if (dwItem2)
702 {
703 SHAnsiToUnicode((LPCSTR)dwItem2, szPath2, _countof(szPath2));
704 psz2 = szPath2;
705 }
706
708 dwItem1 = psz1;
709 dwItem2 = psz2;
710 goto Retry;
711 }
712 case SHCNF_PATHW:
713 {
714 if (wEventId == SHCNE_FREESPACE)
715 {
716 INT iDrive1 = -1, iDrive2 = -1;
717 if (dwItem1)
718 iDrive1 = PathGetDriveNumberW((LPCWSTR)dwItem1);
719 if (dwItem2)
720 iDrive2 = PathGetDriveNumberW((LPCWSTR)dwItem2);
721
722 DWORD dwValue = 0;
723 if (iDrive1 >= 0)
724 dwValue |= (1 << iDrive1);
725 if (iDrive2 >= 0)
726 dwValue |= (1 << iDrive2);
727
728 if (!dwValue)
729 return;
730
732 dwItem1 = UlongToPtr(dwValue);
733 dwItem2 = NULL;
734 goto Retry;
735 }
736
737 if (dwItem1)
738 pidl1 = SHSimpleIDListFromPathW((LPCWSTR)dwItem1);
739 if (dwItem2)
740 pidl2 = SHSimpleIDListFromPathW((LPCWSTR)dwItem2);
741 break;
742 }
743 case SHCNF_PRINTERW:
744 {
745 if (dwItem1)
746 {
747 HRESULT hr = Shell_ParsePrinterName((LPCWSTR)dwItem1, &pidl1, NULL);
749 return;
750 }
751
752 if (dwItem2)
753 {
754 HRESULT hr = Shell_ParsePrinterName((LPCWSTR)dwItem2, &pidl2, NULL);
756 {
757 ILFree(pidl1);
758 return;
759 }
760 }
761 break;
762 }
763 case SHCNF_DWORD:
764 {
765 dwidl.cb = offsetof(SHChangeDWORDAsIDList, cbZero);
766 dwidl.dwItem1 = PtrToUlong(dwItem1);
767 dwidl.dwItem2 = PtrToUlong(dwItem2);
768 dwidl.cbZero = 0;
769 pidl1 = (LPITEMIDLIST)&dwidl;
770 break;
771 }
772 default:
773 {
774 FIXME("Unknown type: 0x%X\n", dwType);
775 return;
776 }
777 }
778
779 if (pidl1 || !wEventId || (wEventId & SHCNE_ASSOCCHANGED))
780 {
781 TRACE("notifying event %s(%x)\n", DumpEvent(wEventId), wEventId);
782 SHChangeNotifyTransmit(wEventId, uFlags, pidl1, pidl2, dwTick);
783 }
784
785 if ((dwType == SHCNF_PATHW) || (dwType == SHCNF_PRINTERW))
786 {
787 ILFree(pidl1);
788 ILFree(pidl2);
789 }
790}
791
792/*************************************************************************
793 * NTSHChangeNotifyRegister [SHELL32.640]
794 */
798{
800 fEvents, msg, count, idlist);
801}
802
803/*************************************************************************
804 * SHChangeNotification_Lock [SHELL32.644]
805 */
807SHChangeNotification_Lock(HANDLE hTicket, DWORD dwOwnerPID, LPITEMIDLIST **lppidls,
808 LPLONG lpwEventId)
809{
810 TRACE("%p %08x %p %p\n", hTicket, dwOwnerPID, lppidls, lpwEventId);
811
812 // create a handbag from the ticket
813 LPHANDBAG pHandbag = DoGetHandbagFromTicket(hTicket, dwOwnerPID);
814 if (pHandbag == NULL || pHandbag->dwMagic != HANDBAG_MAGIC)
815 {
816 ERR("pHandbag is invalid\n");
817 return NULL;
818 }
819
820 // populate parameters from the handbag
821 if (lppidls)
822 *lppidls = pHandbag->pidls;
823 if (lpwEventId)
824 *lpwEventId = (pHandbag->pTicket->wEventId & ~SHCNE_INTERRUPT);
825
826 // return the handbag
827 return pHandbag;
828}
829
830/*************************************************************************
831 * SHChangeNotification_Unlock [SHELL32.645]
832 */
835{
836 TRACE("%p\n", hLock);
837
838 // validate the handbag
839 LPHANDBAG pHandbag = (LPHANDBAG)hLock;
840 if (pHandbag == NULL || pHandbag->dwMagic != HANDBAG_MAGIC)
841 {
842 ERR("pHandbag is invalid\n");
843 return FALSE;
844 }
845
846 // free the handbag
847 BOOL ret = SHUnlockShared(pHandbag->pTicket);
848 LocalFree(hLock);
849 return ret;
850}
851
852/*************************************************************************
853 * NTSHChangeNotifyDeregister [SHELL32.641]
854 */
857{
858 FIXME("(0x%08x):semi stub.\n", hNotify);
859 return SHChangeNotifyDeregister(hNotify);
860}
861
862/*************************************************************************
863 * SHChangeNotifySuspendResume [SHELL32.277]
864 */
866WINAPI
868 LPITEMIDLIST pidl,
869 BOOL bRecursive,
871{
872 FIXME("SHChangeNotifySuspendResume() stub\n");
873 return FALSE;
874}
#define CN_UNREGISTER
#define HANDBAG_MAGIC
struct DELITICKET * LPDELITICKET
#define CN_DELIVER_NOTIFICATION
#define CN_UNREGISTER_PROCESS
#define REGENTRY_MAGIC
struct REGENTRY * LPREGENTRY
#define DELITICKET_MAGIC
#define CN_REGISTER
#define DWORD_ALIGNMENT(offset)
struct HANDBAG * LPHANDBAG
#define WM_DESKTOP_GET_CNOTIFY_SERVER
#define WM_BROKER_NOTIFICATION
HWND SHCreateDefaultWorkerWindow(VOID)
#define INVALID_REG_ID
#define msg(x)
Definition: auth_time.c:54
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
const WCHAR * alias
Definition: main.c:67
#define EXTERN_C
Definition: basetyps.h:12
#define FIXME(fmt,...)
Definition: debug.h:111
#define ERR(fmt,...)
Definition: debug.h:110
EXTERN_C ULONG WINAPI NTSHChangeNotifyRegister(HWND hwnd, INT fSources, LONG fEvents, UINT msg, INT count, SHChangeNotifyEntry *idlist)
EXTERN_C VOID WINAPI SHChangeNotifyTransmit(LONG lEvent, UINT uFlags, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2, DWORD dwTick)
static HWND CreateNotificationBroker(HWND hwnd, UINT wMsg)
EXTERN_C HANDLE WINAPI SHChangeNotification_Lock(HANDLE hTicket, DWORD dwOwnerPID, LPITEMIDLIST **lppidls, LPLONG lpwEventId)
static VOID DoInitAliasPIDLs(void)
EXTERN_C ULONG WINAPI SHChangeNotifyRegister(HWND hwnd, INT fSources, LONG wEventMask, UINT uMsg, INT cItems, SHChangeNotifyEntry *lpItems)
EXTERN_C void InitChangeNotifications(void)
EXTERN_C BOOL WINAPI SHChangeRegistrationReceive(LPVOID lpUnknown1, DWORD dwUnknown2)
static void CreateNotificationParamAndSend(LONG wEventId, UINT uFlags, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2, DWORD dwTick)
static LPHANDBAG DoGetHandbagFromTicket(HANDLE hTicket, DWORD dwOwnerPID)
static HRESULT Shell_ParsePrinterName(_In_ LPCWSTR pszName, _Out_ LPITEMIDLIST *ppidl, _In_ IBindCtx *pBindCtx)
static ALIAS_PIDL AliasPIDLs[]
static HWND GetNotificationServer(BOOL bCreate)
static BOOL DoGetAliasPIDLs(LPITEMIDLIST apidls[2], PCIDLIST_ABSOLUTE pidl)
EXTERN_C DWORD WINAPI NTSHChangeNotifyDeregister(ULONG hNotify)
EXTERN_C void WINAPI SHChangeNotify(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID dwItem2)
static HANDLE CreateNotificationParam(LONG wEventId, UINT uFlags, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2, DWORD dwOwnerPID, DWORD dwTick)
EXTERN_C VOID WINAPI SHChangeNotifyReceive(LONG lEvent, UINT uFlags, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
EXTERN_C VOID WINAPI SHChangeNotifyReceiveEx(LONG lEvent, UINT uFlags, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2, DWORD dwTick)
static LPCSTR DumpEvent(LONG event)
EXTERN_C BOOL WINAPI SHChangeNotification_Unlock(HANDLE hLock)
EXTERN_C BOOL WINAPI SHChangeNotifySuspendResume(BOOL bSuspend, LPITEMIDLIST pidl, BOOL bRecursive, DWORD dwReserved)
EXTERN_C BOOL WINAPI SHChangeNotifyUpdateEntryList(DWORD unknown1, DWORD unknown2, DWORD unknown3, DWORD unknown4)
CRITICAL_SECTION SHELL32_ChangenotifyCS
#define DUMPEV(x)
EXTERN_C void FreeChangeNotifications(void)
EXTERN_C BOOL WINAPI SHChangeNotifyDeregister(ULONG hNotify)
static HANDLE CreateRegistrationParam(ULONG nRegID, HWND hwnd, UINT wMsg, INT fSources, LONG fEvents, LONG fRecursive, LPCITEMIDLIST pidl, DWORD dwOwnerPID, HWND hwndBroker)
BOOL SubclassWindow(HWND hWnd)
Definition: atlwin.h:1552
void OnFinalMessage(HWND)
CChangeNotifyBroker(HWND hwndClient, UINT uMsg)
LRESULT OnBrokerNotification(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
BOOL BrokerNotification(HANDLE hTicket, DWORD dwOwnerPID)
_In_ PSCSI_REQUEST_BLOCK _Out_ NTSTATUS _Inout_ BOOLEAN * Retry
Definition: classpnp.h:312
WPARAM wParam
Definition: combotst.c:138
LPARAM lParam
Definition: combotst.c:139
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
UINT uFlags
Definition: api.c:59
const char * wine_dbg_sprintf(const char *format,...)
Definition: compat.c:296
HANDLE HWND
Definition: compat.h:19
#define MAX_PATH
Definition: compat.h:34
#define FAILED_UNEXPECTEDLY(hr)
Definition: precomp.h:121
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:455
HRESULT SHBindToObject(_In_opt_ IShellFolder *psf, _In_ LPCITEMIDLIST pidl, _In_ REFIID riid, _Out_ void **ppvObj)
Definition: utils.cpp:205
HRESULT WINAPI SHGetSpecialFolderLocation(HWND hwndOwner, INT nFolder, LPITEMIDLIST *ppidl)
Definition: shellpath.c:3225
HANDLE WINAPI SHAllocShared(LPCVOID lpvData, DWORD dwSize, DWORD dwProcId)
Definition: ordinal.c:165
BOOL WINAPI SHFreeShared(HANDLE hShared, DWORD dwProcId)
Definition: ordinal.c:311
BOOL WINAPI SHUnlockShared(LPVOID lpView)
Definition: ordinal.c:291
int WINAPI PathGetDriveNumberW(const WCHAR *path)
Definition: path.c:553
DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
Definition: string.c:2667
#define UlongToPtr(u)
Definition: config.h:106
#define PtrToUlong(u)
Definition: config.h:107
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLuint GLuint GLsizei count
Definition: gl.h:1545
struct _cl_event * event
Definition: glext.h:7739
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
HLOCAL NTAPI LocalAlloc(UINT uFlags, SIZE_T dwBytes)
Definition: heapmem.c:1390
HLOCAL NTAPI LocalFree(HLOCAL hMem)
Definition: heapmem.c:1594
#define MESSAGE_HANDLER(msg, func)
Definition: atlwin.h:1926
#define BEGIN_MSG_MAP(theClass)
Definition: atlwin.h:1898
#define END_MSG_MAP()
Definition: atlwin.h:1917
#define DECLARE_WND_CLASS_EX(WndClassName, style, bkgnd)
Definition: atlwin.h:2004
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
int k
Definition: mpi.c:3369
#define _Out_
Definition: ms_sal.h:345
#define _In_
Definition: ms_sal.h:308
_In_ HANDLE _In_ DWORD _In_ DWORD _Inout_opt_ LPOVERLAPPED _In_opt_ LPTRANSMIT_FILE_BUFFERS _In_ DWORD dwReserved
Definition: mswsock.h:95
unsigned int UINT
Definition: ndis.h:50
#define BOOL
Definition: nt_native.h:43
#define DELETE
Definition: nt_native.h:57
#define UNICODE_NULL
#define L(x)
Definition: ntvdm.h:50
long LONG
Definition: pedump.c:60
LPITEMIDLIST WINAPI ILClone(LPCITEMIDLIST pidl)
Definition: pidl.c:237
void WINAPI ILFree(LPITEMIDLIST pidl)
Definition: pidl.c:938
BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath)
Definition: pidl.c:1353
LPITEMIDLIST WINAPI SHSimpleIDListFromPathW(LPCWSTR lpszPath)
Definition: pidl.c:1133
LPITEMIDLIST WINAPI ILCreateFromPathW(LPCWSTR path)
Definition: pidl.c:995
BOOL WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
Definition: pidl.c:548
#define offsetof(TYPE, MEMBER)
#define MKDIR(d)
Definition: compat.h:27
#define ILGetSize
Definition: shellclasses.h:638
HRESULT hr
Definition: shlfolder.c:183
#define CSIDL_COMMON_DESKTOPDIRECTORY
Definition: shlobj.h:2182
_In_ int _In_ BOOL bCreate
Definition: shlobj.h:1511
#define CSIDL_DESKTOPDIRECTORY
Definition: shlobj.h:2173
#define SHCNRF_RecursiveInterrupt
Definition: shlobj.h:1922
#define SHCNF_PRINTERW
Definition: shlobj.h:1911
#define CSIDL_PERSONAL
Definition: shlobj.h:2163
#define SHCNF_PATHA
Definition: shlobj.h:1907
#define SHCNRF_NewDelivery
Definition: shlobj.h:1923
#define CSIDL_PRINTERS
Definition: shlobj.h:2162
#define SHCNF_PRINTERA
Definition: shlobj.h:1908
#define SHCNF_TYPE
Definition: shlobj.h:1912
#define SHCNF_DWORD
Definition: shlobj.h:1909
#define SHCNF_FLUSH
Definition: shlobj.h:1913
#define SHCNE_ASSOCCHANGED
Definition: shlobj.h:1896
#define CSIDL_DESKTOP
Definition: shlobj.h:2158
#define SHCNF_PATHW
Definition: shlobj.h:1910
#define SHCNRF_InterruptLevel
Definition: shlobj.h:1920
#define SHCNE_ALLEVENTS
Definition: shlobj.h:1899
#define SHCNF_FLUSHNOWAIT
Definition: shlobj.h:1914
#define SHCNE_FREESPACE
Definition: shlobj.h:1893
#define SHGetPathFromIDList
Definition: shlobj.h:237
#define SHCNF_IDLIST
Definition: shlobj.h:1906
PVOID WINAPI SHLockSharedEx(HANDLE hData, DWORD dwProcessId, BOOL bWriteAccess)
ITEMIDLIST UNALIGNED * LPITEMIDLIST
Definition: shtypes.idl:41
const ITEMIDLIST UNALIGNED * LPCITEMIDLIST
Definition: shtypes.idl:42
#define _countof(array)
Definition: sndvol32.h:68
#define TRACE(s)
Definition: solgame.cpp:4
LPITEMIDLIST pidl1
WCHAR szPath1[MAX_PATH]
LPITEMIDLIST pidl2
WCHAR szPath2[MAX_PATH]
LPDELITICKET pTicket
LPITEMIDLIST pidls[2]
VOID WINAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection)
Definition: synch.c:751
HANDLE lEvent
Definition: tftpd.cpp:56
unsigned char * LPBYTE
Definition: typedefs.h:53
int32_t * LPLONG
Definition: typedefs.h:58
ULONG_PTR SIZE_T
Definition: typedefs.h:80
int32_t INT
Definition: typedefs.h:58
uint32_t ULONG
Definition: typedefs.h:59
int ret
HWND WINAPI GetShellWindow(VOID)
Definition: desktop.c:651
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
DWORD WINAPI GetCurrentProcessId(void)
Definition: proc.c:1158
DWORD WINAPI GetWindowThreadProcessId(HWND hWnd, PDWORD lpdwProcessId)
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
void WINAPI DeleteCriticalSection(PCRITICAL_SECTION)
#define LMEM_FIXED
Definition: winbase.h:368
_In_ LONG _In_ HWND hwnd
Definition: winddi.h:4023
_In_ ULONG_PTR _In_ ULONG _Out_ ULONG_PTR * pid
Definition: winddi.h:3837
LONG_PTR LPARAM
Definition: windef.h:208
LONG_PTR LRESULT
Definition: windef.h:209
UINT_PTR WPARAM
Definition: windef.h:207
CONST void * LPCVOID
Definition: windef.h:191
#define WINAPI
Definition: msvc.h:6
BOOL WINAPI IsWindow(_In_opt_ HWND)
BOOL WINAPI SendNotifyMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
BOOL WINAPI DestroyWindow(_In_ HWND)
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define IID_PPV_ARG(Itype, ppType)
const char * LPCSTR
Definition: xmlstorage.h:183
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185