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