ReactOS  0.4.15-dev-499-g1f31905
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
15 static 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 
61 // There are two delivery methods: "old delivery method" and "new delivery method".
62 //
63 // The old delivery method creates a broker window in the caller process
64 // for message trampoline. The old delivery method is slow and deprecated.
65 //
66 // The new delivery method is enabled by SHCNRF_NewDelivery flag.
67 // With the new delivery method the server directly sends the delivery message.
68 
69 typedef CWinTraits <
73 
74 // This class brokers all notifications that don't have the SHCNRF_NewDelivery flag
76  public CWindowImpl<CChangeNotifyBroker, CWindow, CBrokerTraits>
77 {
78 public:
79  CChangeNotifyBroker(HWND hwndClient, UINT uMsg) :
80  m_hwndClient(hwndClient), m_uMsg(uMsg)
81  {
82  }
83 
84  // Message handlers
86  {
88  }
89 
91  {
92  // The server will destroy this window.
93  // After the window gets destroyed we can delete this broker here.
94  delete this;
95  }
96 
97  DECLARE_WND_CLASS_EX(L"WorkerW", 0, 0)
98 
101  END_MSG_MAP()
102 
103 private:
106 
107  BOOL BrokerNotification(HANDLE hTicket, DWORD dwOwnerPID)
108  {
109  // lock the ticket
110  PIDLIST_ABSOLUTE *ppidl = NULL;
111  LONG lEvent;
112  HANDLE hLock = SHChangeNotification_Lock(hTicket, dwOwnerPID, &ppidl, &lEvent);
113  if (hLock == NULL)
114  {
115  ERR("hLock is NULL\n");
116  return FALSE;
117  }
118 
119  // perform the delivery
120  TRACE("broker notifying: %p, 0x%x, %p, 0x%lx\n",
121  m_hwndClient, m_uMsg, ppidl, lEvent);
123 
124  // unlock the ticket
126  return TRUE;
127  }
128 };
129 
130 // This function creates a notification broker for old method. Used in SHChangeNotifyRegister.
131 static HWND
133 {
134  // Create a new broker. It will be freed when the window gets destroyed
135  CChangeNotifyBroker* pBroker = new CChangeNotifyBroker(hwnd, wMsg);
136  if (pBroker == NULL)
137  {
138  ERR("Out of memory\n");
139  return NULL;
140  }
141 
142  HWND hwndBroker = pBroker->Create(0);
143  if (hwndBroker == NULL)
144  {
145  ERR("hwndBroker == NULL\n");
146  delete pBroker;
147  }
148 
149  return hwndBroker;
150 }
151 
152 // This function creates a delivery ticket for shell change nofitication.
153 // Used in SHChangeNotify.
154 static HANDLE
156  DWORD dwOwnerPID, DWORD dwTick)
157 {
158  // pidl1 and pidl2 have variable length. To store them into the delivery ticket,
159  // we have to consider the offsets and the sizes of pidl1 and pidl2.
160  DWORD cbPidl1 = 0, cbPidl2 = 0, ibOffset1 = 0, ibOffset2 = 0;
161  if (pidl1)
162  {
163  cbPidl1 = ILGetSize(pidl1);
164  ibOffset1 = DWORD_ALIGNMENT(sizeof(DELITICKET));
165  }
166  if (pidl2)
167  {
168  cbPidl2 = ILGetSize(pidl2);
169  ibOffset2 = DWORD_ALIGNMENT(ibOffset1 + cbPidl1);
170  }
171 
172  // allocate the delivery ticket
173  DWORD cbSize = ibOffset2 + cbPidl2;
174  HANDLE hTicket = SHAllocShared(NULL, cbSize, dwOwnerPID);
175  if (hTicket == NULL)
176  {
177  ERR("Out of memory\n");
178  return NULL;
179  }
180 
181  // lock the ticket
182  LPDELITICKET pTicket = (LPDELITICKET)SHLockSharedEx(hTicket, dwOwnerPID, TRUE);
183  if (pTicket == NULL)
184  {
185  ERR("SHLockSharedEx failed\n");
186  SHFreeShared(hTicket, dwOwnerPID);
187  return NULL;
188  }
189 
190  // populate the ticket
191  pTicket->dwMagic = DELITICKET_MAGIC;
192  pTicket->wEventId = wEventId;
193  pTicket->uFlags = uFlags;
194  pTicket->ibOffset1 = ibOffset1;
195  pTicket->ibOffset2 = ibOffset2;
196  if (pidl1)
197  memcpy((LPBYTE)pTicket + ibOffset1, pidl1, cbPidl1);
198  if (pidl2)
199  memcpy((LPBYTE)pTicket + ibOffset2, pidl2, cbPidl2);
200 
201  // unlock the ticket and return
202  SHUnlockShared(pTicket);
203  return hTicket;
204 }
205 
206 // This function creates a "handbag" by using a delivery ticket.
207 // The handbag is created in SHChangeNotification_Lock and used in OnBrokerNotification.
208 // hTicket is a ticket handle of a shared memory block and dwOwnerPID is
209 // the owner PID of the ticket.
210 static LPHANDBAG
211 DoGetHandbagFromTicket(HANDLE hTicket, DWORD dwOwnerPID)
212 {
213  // lock and validate the delivery ticket
214  LPDELITICKET pTicket = (LPDELITICKET)SHLockSharedEx(hTicket, dwOwnerPID, FALSE);
215  if (pTicket == NULL || pTicket->dwMagic != DELITICKET_MAGIC)
216  {
217  ERR("pTicket is invalid\n");
218  SHUnlockShared(pTicket);
219  return NULL;
220  }
221 
222  // allocate the handbag
223  LPHANDBAG pHandbag = (LPHANDBAG)LocalAlloc(LMEM_FIXED, sizeof(HANDBAG));
224  if (pHandbag == NULL)
225  {
226  ERR("Out of memory\n");
227  SHUnlockShared(pTicket);
228  return NULL;
229  }
230 
231  // populate the handbag
232  pHandbag->dwMagic = HANDBAG_MAGIC;
233  pHandbag->pTicket = pTicket;
234 
235  pHandbag->pidls[0] = pHandbag->pidls[1] = NULL;
236  if (pTicket->ibOffset1)
237  pHandbag->pidls[0] = (LPITEMIDLIST)((LPBYTE)pTicket + pTicket->ibOffset1);
238  if (pTicket->ibOffset2)
239  pHandbag->pidls[1] = (LPITEMIDLIST)((LPBYTE)pTicket + pTicket->ibOffset2);
240 
241  return pHandbag;
242 }
243 
244 // This function creates a registration entry in SHChangeNotifyRegister function.
245 static HANDLE
246 CreateRegistrationParam(ULONG nRegID, HWND hwnd, UINT wMsg, INT fSources, LONG fEvents,
247  LONG fRecursive, LPCITEMIDLIST pidl, DWORD dwOwnerPID,
248  HWND hwndBroker)
249 {
250  // pidl has variable length. To store it into the registration entry,
251  // we have to consider the length of pidl.
252  DWORD cbPidl = ILGetSize(pidl);
253  DWORD ibPidl = DWORD_ALIGNMENT(sizeof(REGENTRY));
254  DWORD cbSize = ibPidl + cbPidl;
255 
256  // create the registration entry and lock it
257  HANDLE hRegEntry = SHAllocShared(NULL, cbSize, dwOwnerPID);
258  if (hRegEntry == NULL)
259  {
260  ERR("Out of memory\n");
261  return NULL;
262  }
263  LPREGENTRY pRegEntry = (LPREGENTRY)SHLockSharedEx(hRegEntry, dwOwnerPID, TRUE);
264  if (pRegEntry == NULL)
265  {
266  ERR("SHLockSharedEx failed\n");
267  SHFreeShared(hRegEntry, dwOwnerPID);
268  return NULL;
269  }
270 
271  // populate the registration entry
272  pRegEntry->dwMagic = REGENTRY_MAGIC;
273  pRegEntry->cbSize = cbSize;
274  pRegEntry->nRegID = nRegID;
275  pRegEntry->hwnd = hwnd;
276  pRegEntry->uMsg = wMsg;
277  pRegEntry->fSources = fSources;
278  pRegEntry->fEvents = fEvents;
279  pRegEntry->fRecursive = fRecursive;
280  pRegEntry->hwndBroker = hwndBroker;
281  pRegEntry->ibPidl = 0;
282  if (pidl)
283  {
284  pRegEntry->ibPidl = ibPidl;
285  memcpy((LPBYTE)pRegEntry + ibPidl, pidl, cbPidl);
286  }
287 
288  // unlock and return
289  SHUnlockShared(pRegEntry);
290  return hRegEntry;
291 }
292 
293 // This function is the body of SHChangeNotify function.
294 // It creates a delivery ticket and send CN_DELIVER_NOTIFICATION message to
295 // transport the change.
296 static void
298  DWORD dwTick)
299 {
300  // get server window
301  HWND hwndServer = GetNotificationServer(FALSE);
302  if (hwndServer == NULL)
303  return;
304 
305  // the ticket owner is the process of the notification server
306  DWORD pid;
307  GetWindowThreadProcessId(hwndServer, &pid);
308 
309  // create a delivery ticket
310  HANDLE hTicket = CreateNotificationParam(wEventId, uFlags, pidl1, pidl2, pid, dwTick);
311  if (hTicket == NULL)
312  return;
313 
314  TRACE("hTicket: %p, 0x%lx\n", hTicket, pid);
315 
316  // send the ticket by using CN_DELIVER_NOTIFICATION
318  SendMessageW(hwndServer, CN_DELIVER_NOTIFICATION, (WPARAM)hTicket, pid);
319  else
320  SendNotifyMessageW(hwndServer, CN_DELIVER_NOTIFICATION, (WPARAM)hTicket, pid);
321 }
322 
323 /*************************************************************************
324  * SHChangeNotifyRegister [SHELL32.2]
325  */
327 SHChangeNotifyRegister(HWND hwnd, INT fSources, LONG wEventMask, UINT uMsg,
328  INT cItems, SHChangeNotifyEntry *lpItems)
329 {
330  HWND hwndServer, hwndBroker = NULL;
331  HANDLE hRegEntry;
332  INT iItem;
333  ULONG nRegID = INVALID_REG_ID;
334  DWORD dwOwnerPID;
335  LPREGENTRY pRegEntry;
336 
337  TRACE("(%p,0x%08x,0x%08x,0x%08x,%d,%p)\n",
338  hwnd, fSources, wEventMask, uMsg, cItems, lpItems);
339 
340  // sanity check
341  if (wEventMask == 0 || cItems <= 0 || cItems > 0x7FFF || lpItems == NULL ||
342  hwnd == NULL || !IsWindow(hwnd))
343  {
344  return INVALID_REG_ID;
345  }
346 
347  // request the window of the server
348  hwndServer = GetNotificationServer(TRUE);
349  if (hwndServer == NULL)
350  return INVALID_REG_ID;
351 
352  // disable new delivery method in specific condition
353  if ((fSources & SHCNRF_RecursiveInterrupt) != 0 &&
354  (fSources & SHCNRF_InterruptLevel) == 0)
355  {
356  fSources &= ~SHCNRF_NewDelivery;
357  }
358 
359  // if it is old delivery method, then create a broker window
360  if ((fSources & SHCNRF_NewDelivery) == 0)
361  {
362  hwndBroker = hwnd = CreateNotificationBroker(hwnd, uMsg);
363  uMsg = WM_BROKER_NOTIFICATION;
364  }
365 
366  // The owner PID is the process ID of the server
367  GetWindowThreadProcessId(hwndServer, &dwOwnerPID);
368 
370  for (iItem = 0; iItem < cItems; ++iItem)
371  {
372  // create a registration entry
373  hRegEntry = CreateRegistrationParam(nRegID, hwnd, uMsg, fSources, wEventMask,
374  lpItems[iItem].fRecursive, lpItems[iItem].pidl,
375  dwOwnerPID, hwndBroker);
376  if (hRegEntry)
377  {
378  TRACE("CN_REGISTER: hwnd:%p, hRegEntry:%p, pid:0x%lx\n",
379  hwndServer, hRegEntry, dwOwnerPID);
380 
381  // send CN_REGISTER to the server
382  SendMessageW(hwndServer, CN_REGISTER, (WPARAM)hRegEntry, dwOwnerPID);
383 
384  // update nRegID
385  pRegEntry = (LPREGENTRY)SHLockSharedEx(hRegEntry, dwOwnerPID, FALSE);
386  if (pRegEntry)
387  {
388  nRegID = pRegEntry->nRegID;
389  SHUnlockShared(pRegEntry);
390  }
391 
392  // free registration entry
393  SHFreeShared(hRegEntry, dwOwnerPID);
394  }
395 
396  // if failed, then destroy the broker
397  if (nRegID == INVALID_REG_ID && (fSources & SHCNRF_NewDelivery) == 0)
398  {
399  ERR("Delivery failed\n");
400  DestroyWindow(hwndBroker);
401  break;
402  }
403  }
405 
406  return nRegID;
407 }
408 
409 /*************************************************************************
410  * SHChangeNotifyDeregister [SHELL32.4]
411  */
414 {
415  TRACE("(0x%08x)\n", hNotify);
416 
417  // get the server window
418  HWND hwndServer = GetNotificationServer(FALSE);
419  if (hwndServer == NULL)
420  return FALSE;
421 
422  // send CN_UNREGISTER message and try to unregister
423  BOOL ret = (BOOL)SendMessageW(hwndServer, CN_UNREGISTER, hNotify, 0);
424  if (!ret)
425  ERR("CN_UNREGISTER failed\n");
426 
427  return ret;
428 }
429 
430 /*************************************************************************
431  * SHChangeNotifyUpdateEntryList [SHELL32.5]
432  */
435  DWORD unknown3, DWORD unknown4)
436 {
437  FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
438  unknown1, unknown2, unknown3, unknown4);
439  return TRUE;
440 }
441 
442 /* for dumping events */
444 {
445  if (event == SHCNE_ALLEVENTS)
446  return "SHCNE_ALLEVENTS";
447 #define DUMPEV(x) ,( event & SHCNE_##x )? #x " " : ""
448  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"
449  DUMPEV(RENAMEITEM)
450  DUMPEV(CREATE)
451  DUMPEV(DELETE)
452  DUMPEV(MKDIR)
453  DUMPEV(RMDIR)
454  DUMPEV(MEDIAINSERTED)
455  DUMPEV(MEDIAREMOVED)
456  DUMPEV(DRIVEREMOVED)
457  DUMPEV(DRIVEADD)
458  DUMPEV(NETSHARE)
459  DUMPEV(NETUNSHARE)
460  DUMPEV(ATTRIBUTES)
461  DUMPEV(UPDATEDIR)
462  DUMPEV(UPDATEITEM)
463  DUMPEV(SERVERDISCONNECT)
464  DUMPEV(UPDATEIMAGE)
465  DUMPEV(DRIVEADDGUI)
466  DUMPEV(RENAMEFOLDER)
467  DUMPEV(FREESPACE)
468  DUMPEV(EXTENDED_EVENT)
469  DUMPEV(ASSOCCHANGED)
470  DUMPEV(INTERRUPT)
471  );
472 #undef DUMPEV
473 }
474 
475 /*************************************************************************
476  * SHChangeNotify [SHELL32.@]
477  */
478 EXTERN_C void WINAPI
479 SHChangeNotify(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID dwItem2)
480 {
481  LPITEMIDLIST pidl1 = NULL, pidl2 = NULL, pidlTemp1 = NULL, pidlTemp2 = NULL;
482  DWORD dwTick = GetTickCount();
483  WCHAR szPath1[MAX_PATH], szPath2[MAX_PATH];
484  LPWSTR psz1, psz2;
485  TRACE("(0x%08x,0x%08x,%p,%p)\n", wEventId, uFlags, dwItem1, dwItem2);
486 
487  switch (uFlags & SHCNF_TYPE)
488  {
489  case SHCNF_IDLIST:
490  pidl1 = (LPITEMIDLIST)dwItem1;
491  pidl2 = (LPITEMIDLIST)dwItem2;
492  break;
493 
494  case SHCNF_PATHA:
495  psz1 = psz2 = NULL;
496  if (dwItem1)
497  {
498  SHAnsiToUnicode((LPCSTR)dwItem1, szPath1, _countof(szPath1));
499  psz1 = szPath1;
500  }
501  if (dwItem2)
502  {
503  SHAnsiToUnicode((LPCSTR)dwItem2, szPath2, _countof(szPath2));
504  psz2 = szPath2;
505  }
506  uFlags &= ~SHCNF_TYPE;
507  uFlags |= SHCNF_PATHW;
508  SHChangeNotify(wEventId, uFlags, psz1, psz2);
509  return;
510 
511  case SHCNF_PATHW:
512  if (dwItem1)
513  {
514  pidl1 = pidlTemp1 = SHSimpleIDListFromPathW((LPCWSTR)dwItem1);
515  }
516  if (dwItem2)
517  {
518  pidl2 = pidlTemp2 = SHSimpleIDListFromPathW((LPCWSTR)dwItem2);
519  }
520  break;
521 
522  case SHCNF_PRINTERA:
523  case SHCNF_PRINTERW:
524  FIXME("SHChangeNotify with (uFlags & SHCNF_PRINTER)\n");
525  return;
526 
527  default:
528  FIXME("unknown type %08x\n", uFlags & SHCNF_TYPE);
529  return;
530  }
531 
532  if (wEventId == 0 || (wEventId & SHCNE_ASSOCCHANGED) || pidl1 != NULL)
533  {
534  TRACE("notifying event %s(%x)\n", DumpEvent(wEventId), wEventId);
535  CreateNotificationParamAndSend(wEventId, uFlags, pidl1, pidl2, dwTick);
536  }
537 
538  if (pidlTemp1)
539  ILFree(pidlTemp1);
540  if (pidlTemp2)
541  ILFree(pidlTemp2);
542 }
543 
544 /*************************************************************************
545  * NTSHChangeNotifyRegister [SHELL32.640]
546  */
549  INT count, SHChangeNotifyEntry *idlist)
550 {
552  fEvents, msg, count, idlist);
553 }
554 
555 /*************************************************************************
556  * SHChangeNotification_Lock [SHELL32.644]
557  */
559 SHChangeNotification_Lock(HANDLE hTicket, DWORD dwOwnerPID, LPITEMIDLIST **lppidls,
560  LPLONG lpwEventId)
561 {
562  TRACE("%p %08x %p %p\n", hTicket, dwOwnerPID, lppidls, lpwEventId);
563 
564  // create a handbag from the ticket
565  LPHANDBAG pHandbag = DoGetHandbagFromTicket(hTicket, dwOwnerPID);
566  if (pHandbag == NULL || pHandbag->dwMagic != HANDBAG_MAGIC)
567  {
568  ERR("pHandbag is invalid\n");
569  return NULL;
570  }
571 
572  // populate parameters from the handbag
573  if (lppidls)
574  *lppidls = pHandbag->pidls;
575  if (lpwEventId)
576  *lpwEventId = (pHandbag->pTicket->wEventId & ~SHCNE_INTERRUPT);
577 
578  // return the handbag
579  return pHandbag;
580 }
581 
582 /*************************************************************************
583  * SHChangeNotification_Unlock [SHELL32.645]
584  */
587 {
588  TRACE("%p\n", hLock);
589 
590  // validate the handbag
591  LPHANDBAG pHandbag = (LPHANDBAG)hLock;
592  if (pHandbag == NULL || pHandbag->dwMagic != HANDBAG_MAGIC)
593  {
594  ERR("pHandbag is invalid\n");
595  return FALSE;
596  }
597 
598  // free the handbag
599  BOOL ret = SHUnlockShared(pHandbag->pTicket);
600  LocalFree(hLock);
601  return ret;
602 }
603 
604 /*************************************************************************
605  * NTSHChangeNotifyDeregister [SHELL32.641]
606  */
609 {
610  FIXME("(0x%08x):semi stub.\n", hNotify);
611  return SHChangeNotifyDeregister(hNotify);
612 }
#define WS_CLIPSIBLINGS
Definition: pedump.c:618
#define DUMPEV(x)
#define HANDBAG_MAGIC
static HWND GetNotificationServer(BOOL bCreate)
const DOCKBAR PVOID HWND HWND * hwnd
Definition: tooldock.h:22
static HWND CreateNotificationBroker(HWND hwnd, UINT wMsg)
_In_ ULONG_PTR _In_ ULONG _Out_ ULONG_PTR * pid
Definition: winddi.h:3835
HWND WINAPI GetShellWindow(VOID)
Definition: desktop.c:651
#define TRUE
Definition: types.h:120
PVOID WINAPI SHLockSharedEx(HANDLE hData, DWORD dwProcessId, BOOL bWriteAccess)
void WINAPI ILFree(LPITEMIDLIST pidl)
Definition: pidl.c:925
CWinTraits< WS_POPUP|WS_CLIPSIBLINGS|WS_CLIPCHILDREN, WS_EX_TOOLWINDOW > CBrokerTraits
EXTERN_C DWORD WINAPI NTSHChangeNotifyDeregister(ULONG hNotify)
EXTERN_C void FreeChangeNotifications(void)
CRITICAL_SECTION SHELL32_ChangenotifyCS
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
BOOL WINAPI IsWindow(_In_opt_ HWND)
EXTERN_C void InitChangeNotifications(void)
EXTERN_C BOOL WINAPI SHChangeNotification_Unlock(HANDLE hLock)
#define WM_DESKTOP_GET_CNOTIFY_SERVER
HWND Create(HWND hWndParent, _U_RECT rect=NULL, LPCTSTR szWindowName=NULL, DWORD dwStyle=0, DWORD dwExStyle=0, _U_MENUorID MenuOrID=0U, LPVOID lpCreateParam=NULL)
Definition: atlwin.h:1637
GLuint GLuint GLsizei count
Definition: gl.h:1545
const ITEMIDLIST UNALIGNED * LPCITEMIDLIST
Definition: shtypes.idl:42
#define DECLARE_WND_CLASS_EX(WndClassName, style, bkgnd)
Definition: atlwin.h:1886
#define SHCNE_INTERRUPT
Definition: shlobj.h:1754
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:455
HANDLE HWND
Definition: compat.h:13
#define DELITICKET_MAGIC
void OnFinalMessage(HWND)
#define SHCNRF_RecursiveInterrupt
Definition: shlobj.h:1776
UINT_PTR WPARAM
Definition: windef.h:207
#define REGENTRY_MAGIC
UINT uFlags
Definition: api.c:59
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
#define WS_CLIPCHILDREN
Definition: pedump.c:619
#define BOOL
Definition: nt_native.h:43
BOOL WINAPI DestroyWindow(_In_ HWND)
#define WS_EX_TOOLWINDOW
Definition: winuser.h:404
int32_t INT
Definition: typedefs.h:57
WPARAM wParam
Definition: combotst.c:138
const char * wine_dbg_sprintf(const char *format,...)
Definition: compat.c:271
#define INVALID_REG_ID
unsigned char * LPBYTE
Definition: typedefs.h:53
BOOL WINAPI SendNotifyMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define CN_REGISTER
unsigned int BOOL
Definition: ntddk_ex.h:94
#define SHCNE_ALLEVENTS
Definition: shlobj.h:1753
long LONG
Definition: pedump.c:60
#define FIXME(fmt,...)
Definition: debug.h:111
EXTERN_C ULONG WINAPI NTSHChangeNotifyRegister(HWND hwnd, INT fSources, LONG fEvents, UINT msg, INT count, SHChangeNotifyEntry *idlist)
LPDELITICKET pTicket
DWORD WINAPI GetWindowThreadProcessId(HWND, PDWORD)
static LPCSTR DumpEvent(LONG event)
#define SHCNRF_InterruptLevel
Definition: shlobj.h:1774
VOID WINAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection)
Definition: synch.c:751
EXTERN_C BOOL WINAPI SHChangeNotifyUpdateEntryList(DWORD unknown1, DWORD unknown2, DWORD unknown3, DWORD unknown4)
smooth NULL
Definition: ftsmooth.c:416
#define CN_UNREGISTER_PROCESS
LONG_PTR LPARAM
Definition: windef.h:208
LPITEMIDLIST pidls[2]
const char * LPCSTR
Definition: xmlstorage.h:183
LRESULT OnBrokerNotification(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
#define LMEM_FIXED
Definition: winbase.h:349
#define SHCNF_PRINTERW
Definition: shlobj.h:1765
#define TRACE(s)
Definition: solgame.cpp:4
CChangeNotifyBroker(HWND hwndClient, UINT uMsg)
HANDLE WINAPI SHAllocShared(LPCVOID lpvData, DWORD dwSize, DWORD dwProcId)
Definition: ordinal.c:162
LPITEMIDLIST WINAPI SHSimpleIDListFromPathW(LPCWSTR lpszPath)
Definition: pidl.c:1115
__wchar_t WCHAR
Definition: xmlstorage.h:180
void WINAPI DeleteCriticalSection(PCRITICAL_SECTION)
#define END_MSG_MAP()
Definition: atlwin.h:1799
EXTERN_C BOOL WINAPI SHChangeNotifyDeregister(ULONG hNotify)
#define _countof(array)
Definition: sndvol32.h:68
#define MKDIR(d)
Definition: compat.h:23
#define SHCNF_IDLIST
Definition: shlobj.h:1760
#define MAX_PATH
Definition: compat.h:26
#define WINAPI
Definition: msvc.h:6
DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen)
Definition: string.c:2625
unsigned long DWORD
Definition: ntddk_ex.h:95
#define WM_BROKER_NOTIFICATION
#define SHCNF_PRINTERA
Definition: shlobj.h:1762
BOOL WINAPI SHFreeShared(HANDLE hShared, DWORD dwProcId)
Definition: ordinal.c:308
int ret
EXTERN_C void WINAPI SHChangeNotify(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID dwItem2)
#define SHCNF_TYPE
Definition: shlobj.h:1766
static const WCHAR L[]
Definition: oid.c:1250
#define SHCNF_FLUSH
Definition: shlobj.h:1767
struct HANDBAG * LPHANDBAG
HANDLE lEvent
Definition: tftpd.cpp:56
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define CN_DELIVER_NOTIFICATION
struct _cl_event * event
Definition: glext.h:7739
#define SHCNF_PATHW
Definition: shlobj.h:1764
#define SHCNRF_NewDelivery
Definition: shlobj.h:1777
#define ERR(fmt,...)
Definition: debug.h:110
#define CN_UNREGISTER
int32_t * LPLONG
Definition: typedefs.h:57
_In_ int _In_ BOOL bCreate
Definition: shlobj.h:1444
HLOCAL NTAPI LocalFree(HLOCAL hMem)
Definition: heapmem.c:1577
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define WS_POPUP
Definition: pedump.c:616
unsigned int UINT
Definition: ndis.h:50
EXTERN_C HANDLE WINAPI SHChangeNotification_Lock(HANDLE hTicket, DWORD dwOwnerPID, LPITEMIDLIST **lppidls, LPLONG lpwEventId)
static LPHANDBAG DoGetHandbagFromTicket(HANDLE hTicket, DWORD dwOwnerPID)
struct DELITICKET * LPDELITICKET
#define ILGetSize
Definition: shellclasses.h:638
#define BEGIN_MSG_MAP(theClass)
Definition: atlwin.h:1780
static HANDLE CreateRegistrationParam(ULONG nRegID, HWND hwnd, UINT wMsg, INT fSources, LONG fEvents, LONG fRecursive, LPCITEMIDLIST pidl, DWORD dwOwnerPID, HWND hwndBroker)
#define MESSAGE_HANDLER(msg, func)
Definition: atlwin.h:1808
#define msg(x)
Definition: auth_time.c:54
CONST void * LPCVOID
Definition: windef.h:191
EXTERN_C ULONG WINAPI SHChangeNotifyRegister(HWND hwnd, INT fSources, LONG wEventMask, UINT uMsg, INT cItems, SHChangeNotifyEntry *lpItems)
BOOL BrokerNotification(HANDLE hTicket, DWORD dwOwnerPID)
BOOL WINAPI SHUnlockShared(LPVOID lpView)
Definition: ordinal.c:288
unsigned int ULONG
Definition: retypes.h:1
HLOCAL NTAPI LocalAlloc(UINT uFlags, SIZE_T dwBytes)
Definition: heapmem.c:1373
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
WCHAR * LPWSTR
Definition: xmlstorage.h:184
LONG_PTR LRESULT
Definition: windef.h:209
WINE_DEFAULT_DEBUG_CHANNEL(shcn)
#define EXTERN_C
Definition: basetyps.h:12
ITEMIDLIST UNALIGNED * LPITEMIDLIST
Definition: shtypes.idl:41
LPARAM lParam
Definition: combotst.c:139
struct REGENTRY * LPREGENTRY
#define DWORD_ALIGNMENT(offset)
static void CreateNotificationParamAndSend(LONG wEventId, UINT uFlags, LPITEMIDLIST pidl1, LPITEMIDLIST pidl2, DWORD dwTick)
#define SHCNF_PATHA
Definition: shlobj.h:1761
#define SHCNF_FLUSHNOWAIT
Definition: shlobj.h:1768
DWORD WINAPI GetCurrentProcessId(VOID)
Definition: proc.c:1158
#define DELETE
Definition: nt_native.h:57
static HANDLE CreateNotificationParam(LONG wEventId, UINT uFlags, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2, DWORD dwOwnerPID, DWORD dwTick)
#define SHCNE_ASSOCCHANGED
Definition: shlobj.h:1750