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 #pragma once
8
9 #include <shlwapi_undoc.h> // for SHCreateWorkerWindowW
10
11 /////////////////////////////////////////////////////////////////////////////
12 // CChangeNotifyServer is a delivery worker window that is managed by CDesktopBrowser.
13 // The process of CChangeNotifyServer is same as the process of CDesktopBrowser.
14 // The caller process of SHChangeNotify function might be different from the
15 // process of CChangeNotifyServer.
16 /////////////////////////////////////////////////////////////////////////////
17
18 /////////////////////////////////////////////////////////////////////////////
19 // The shared memory block can be allocated by shlwapi!SHAllocShared function.
20 //
21 // HANDLE SHAllocShared(LPCVOID lpData, DWORD dwSize, DWORD dwProcessId);
22 // LPVOID SHLockShared(HANDLE hData, DWORD dwProcessId);
23 // LPVOID SHLockSharedEx(HANDLE hData, DWORD dwProcessId, BOOL bWriteAccess);
24 // BOOL SHUnlockShared(LPVOID lpData);
25 // BOOL SHFreeShared(HANDLE hData, DWORD dwProcessId);
26 //
27 // The shared memory block is managed by the pair of a HANDLE value and an owner PID.
28 // If the pair is known, it can be accessed by SHLockShared(Ex) function
29 // from another process.
30 /////////////////////////////////////////////////////////////////////////////
31
32 #define INVALID_REG_ID 0 /* invalid registration ID */
33
34 // This message is handled by CDesktopBrowser and returns
35 // the window of CChangeNotifyServer which responds to the CN_* messages
36 #define WM_DESKTOP_GET_CNOTIFY_SERVER (WM_USER + 25) /* 0x419 */
37
38 // The following messages are implemented by CChangeNotifyServer
39 // CChangeNotifyServer lives in the context of explorer and delivers notifications
40 // across all processes that register themselves with the SHChangeNotifyRegister api
41 #define CN_REGISTER (WM_USER + 1) /* 0x401 */
42 #define CN_UNREGISTER (WM_USER + 2) /* 0x402 */
43 #define CN_DELIVER_NOTIFICATION (WM_USER + 3) /* 0x403 */
44 #define CN_SUSPEND_RESUME (WM_USER + 6) /* 0x406 */
45 #define CN_UNREGISTER_PROCESS (WM_USER + 7) /* 0x407 */
46
47 // This message is implemented by the broker window which lives in the context of the client
48 #define WM_BROKER_NOTIFICATION (WM_USER + 1) /* 0x401 */
49
50 #define DWORD_ALIGNMENT(offset) \
51 ((((offset) + sizeof(DWORD) - 1) / sizeof(DWORD)) * sizeof(DWORD))
52
53 /* delivery ticket */
54 typedef struct DELITICKET
55 {
56 DWORD dwMagic; /* same as DELITICKET_MAGIC */
57 LONG wEventId; /* event id of SHChangeNotify() */
58 UINT uFlags; /* flags of SHChangeNotify() */
59 DWORD dwTick; /* value of GetTickCount() */
60 DWORD ibOffset1; /* offset to pidl1 */
61 DWORD ibOffset2; /* offset to pidl2 */
62 /* followed by pidl1 and pidl2 */
63 } DELITICKET, *LPDELITICKET;
64
65 /* registration entry */
66 typedef struct REGENTRY
67 {
68 DWORD dwMagic; /* same as REGENTRY_MAGIC */
69 DWORD cbSize; /* the real size of this structure */
70 UINT nRegID; /* the registration ID */
71 HWND hwnd; /* the target window */
72 UINT uMsg; /* the message ID used in notification */
73 INT fSources; /* the source flags */
74 LONG fEvents; /* the event flags */
75 BOOL fRecursive; /* is it recursive? */
76 HWND hwndBroker; /* broker window (if any) */
77 UINT ibPidl; /* offset to the PIDL */
78 /* followed by a PIDL */
79 } REGENTRY, *LPREGENTRY;
80
81 /* handbag */
82 typedef struct HANDBAG
83 {
84 DWORD dwMagic; /* same as HANDBAG_MAGIC */
85 LPITEMIDLIST pidls[2]; /* two PIDLs */
86 LPDELITICKET pTicket; /* the ticket */
87 } HANDBAG, *LPHANDBAG;
88
89 #define DELITICKET_MAGIC 0xDEADFACE
90 #define REGENTRY_MAGIC 0xB0B32D1E
91 #define HANDBAG_MAGIC 0xFACEB00C
92
93 HRESULT CChangeNotifyServer_CreateInstance(REFIID riid, void **ppv);
94
95 #define WORKER_STYLE (WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN)
96 #define WORKER_EXSTYLE WS_EX_TOOLWINDOW
97
98 typedef CWinTraits<WORKER_STYLE, WORKER_EXSTYLE> CWorkerTraits;
99
SHCreateDefaultWorkerWindow(VOID)100 inline HWND SHCreateDefaultWorkerWindow(VOID)
101 {
102 return SHCreateWorkerWindowW(NULL, NULL, WORKER_EXSTYLE, WORKER_STYLE, NULL, 0);
103 }
104