ReactOS  0.4.15-dev-1150-g593bcce
CChangeNotifyServer.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 #include "shelldesktop.h"
8 #include "shlwapi_undoc.h"
9 #include "CDirectoryWatcher.h"
10 #include <assert.h> // for assert
11 
13 
15 
16 // notification target item
17 struct ITEM
18 {
19  UINT nRegID; // The registration ID.
20  DWORD dwUserPID; // The user PID; that is the process ID of the target window.
21  HANDLE hRegEntry; // The registration entry.
22  HWND hwndBroker; // Client broker window (if any).
23  CDirectoryWatcher *pDirWatch; // for filesystem notification
24 };
25 
26 typedef CWinTraits <
30 
32 // CChangeNotifyServer
33 //
34 // CChangeNotifyServer implements a window that handles all shell change notifications.
35 // It runs in the context of explorer and specifically in the thread of the shell desktop.
36 // Shell change notification api exported from shell32 forwards all their calls
37 // to this window where all processing takes place.
38 
40  public CWindowImpl<CChangeNotifyServer, CWindow, CChangeNotifyServerTraits>,
41  public CComObjectRootEx<CComMultiThreadModelNoCS>,
42  public IOleWindow
43 {
44 public:
46  virtual ~CChangeNotifyServer();
48 
49  // *** IOleWindow methods ***
50  virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *lphwnd);
52 
53  // Message handlers
54  LRESULT OnRegister(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
59  LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
60 
62 
66  END_COM_MAP()
67 
68  DECLARE_WND_CLASS_EX(L"WorkerW", 0, 0)
69 
77  END_MSG_MAP()
78 
79 private:
82 
83  BOOL AddItem(UINT nRegID, DWORD dwUserPID, HANDLE hRegEntry, HWND hwndBroker,
84  CDirectoryWatcher *pDirWatch);
85  BOOL RemoveItemsByRegID(UINT nRegID, DWORD dwOwnerPID);
86  void RemoveItemsByProcess(DWORD dwOwnerPID, DWORD dwUserPID);
87  void DestroyItem(ITEM& item, DWORD dwOwnerPID, HWND *phwndBroker);
88 
90  BOOL DeliverNotification(HANDLE hTicket, DWORD dwOwnerPID);
91  BOOL ShouldNotify(LPDELITICKET pTicket, LPREGENTRY pRegEntry);
92 };
93 
95  : m_nNextRegID(INVALID_REG_ID)
96 {
97 }
98 
100 {
101 }
102 
103 BOOL CChangeNotifyServer::AddItem(UINT nRegID, DWORD dwUserPID, HANDLE hRegEntry,
104  HWND hwndBroker, CDirectoryWatcher *pDirWatch)
105 {
106  // find the empty room
107  for (INT i = 0; i < m_items.GetSize(); ++i)
108  {
109  if (m_items[i].nRegID == INVALID_REG_ID)
110  {
111  // found the room, populate it
112  m_items[i].nRegID = nRegID;
113  m_items[i].dwUserPID = dwUserPID;
114  m_items[i].hRegEntry = hRegEntry;
115  m_items[i].hwndBroker = hwndBroker;
116  m_items[i].pDirWatch = pDirWatch;
117  return TRUE;
118  }
119  }
120 
121  // no empty room found
122  ITEM item = { nRegID, dwUserPID, hRegEntry, hwndBroker, pDirWatch };
123  m_items.Add(item);
124  return TRUE;
125 }
126 
127 void CChangeNotifyServer::DestroyItem(ITEM& item, DWORD dwOwnerPID, HWND *phwndBroker)
128 {
129  // destroy broker if any and if first time
130  HWND hwndBroker = item.hwndBroker;
131  item.hwndBroker = NULL;
132  if (hwndBroker && hwndBroker != *phwndBroker)
133  {
134  ::DestroyWindow(hwndBroker);
135  *phwndBroker = hwndBroker;
136  }
137 
138  // request termination of pDirWatch if any
139  CDirectoryWatcher *pDirWatch = item.pDirWatch;
140  item.pDirWatch = NULL;
141  if (pDirWatch)
142  pDirWatch->RequestTermination();
143 
144  // free
145  SHFreeShared(item.hRegEntry, dwOwnerPID);
146  item.nRegID = INVALID_REG_ID;
147  item.dwUserPID = 0;
148  item.hRegEntry = NULL;
149  item.hwndBroker = NULL;
150  item.pDirWatch = NULL;
151 }
152 
154 {
155  BOOL bFound = FALSE;
156  HWND hwndBroker = NULL;
157  assert(nRegID != INVALID_REG_ID);
158  for (INT i = 0; i < m_items.GetSize(); ++i)
159  {
160  if (m_items[i].nRegID == nRegID)
161  {
162  bFound = TRUE;
163  DestroyItem(m_items[i], dwOwnerPID, &hwndBroker);
164  }
165  }
166  return bFound;
167 }
168 
170 {
171  HWND hwndBroker = NULL;
172  assert(dwUserPID != 0);
173  for (INT i = 0; i < m_items.GetSize(); ++i)
174  {
175  if (m_items[i].dwUserPID == dwUserPID)
176  {
177  DestroyItem(m_items[i], dwOwnerPID, &hwndBroker);
178  }
179  }
180 }
181 
182 // create a CDirectoryWatcher from a REGENTRY
183 static CDirectoryWatcher *
185 {
186  if (pRegEntry->ibPidl == 0)
187  return NULL;
188 
189  // get the path
191  LPITEMIDLIST pidl = (LPITEMIDLIST)((LPBYTE)pRegEntry + pRegEntry->ibPidl);
193  return NULL;
194 
195  // create a CDirectoryWatcher
196  CDirectoryWatcher *pDirectoryWatcher = CDirectoryWatcher::Create(szPath, pRegEntry->fRecursive);
197  if (pDirectoryWatcher == NULL)
198  return NULL;
199 
200  return pDirectoryWatcher;
201 }
202 
203 // Message CN_REGISTER: Register the registration entry.
204 // wParam: The handle of registration entry.
205 // lParam: The owner PID of registration entry.
206 // return: TRUE if successful.
208 {
209  TRACE("OnRegister(%p, %u, %p, %p)\n", m_hWnd, uMsg, wParam, lParam);
210 
211  // lock the registration entry
212  HANDLE hRegEntry = (HANDLE)wParam;
213  DWORD dwOwnerPID = (DWORD)lParam;
214  LPREGENTRY pRegEntry = (LPREGENTRY)SHLockSharedEx(hRegEntry, dwOwnerPID, TRUE);
215  if (pRegEntry == NULL || pRegEntry->dwMagic != REGENTRY_MAGIC)
216  {
217  ERR("pRegEntry is invalid\n");
218  SHUnlockShared(pRegEntry);
219  return FALSE;
220  }
221 
222  // update registration ID if necessary
223  if (pRegEntry->nRegID == INVALID_REG_ID)
224  pRegEntry->nRegID = GetNextRegID();
225 
226  TRACE("pRegEntry->nRegID: %u\n", pRegEntry->nRegID);
227 
228  // get the user PID; that is the process ID of the target window
229  DWORD dwUserPID;
230  GetWindowThreadProcessId(pRegEntry->hwnd, &dwUserPID);
231 
232  // get broker if any
233  HWND hwndBroker = pRegEntry->hwndBroker;
234 
235  // clone the registration entry
236  HANDLE hNewEntry = SHAllocShared(pRegEntry, pRegEntry->cbSize, dwOwnerPID);
237  if (hNewEntry == NULL)
238  {
239  ERR("Out of memory\n");
240  pRegEntry->nRegID = INVALID_REG_ID;
241  SHUnlockShared(pRegEntry);
242  return FALSE;
243  }
244 
245  // create a directory watch if necessary
246  CDirectoryWatcher *pDirWatch = NULL;
247  if (pRegEntry->ibPidl && (pRegEntry->fSources & SHCNRF_InterruptLevel))
248  {
249  pDirWatch = CreateDirectoryWatcherFromRegEntry(pRegEntry);
250  if (pDirWatch && !pDirWatch->RequestAddWatcher())
251  {
252  ERR("RequestAddWatcher failed: %u\n", pRegEntry->nRegID);
253  pRegEntry->nRegID = INVALID_REG_ID;
254  SHUnlockShared(pRegEntry);
255  delete pDirWatch;
256  return FALSE;
257  }
258  }
259 
260  // unlock the registry entry
261  SHUnlockShared(pRegEntry);
262 
263  // add an ITEM
264  return AddItem(m_nNextRegID, dwUserPID, hNewEntry, hwndBroker, pDirWatch);
265 }
266 
267 // Message CN_UNREGISTER: Unregister registration entries.
268 // wParam: The registration ID.
269 // lParam: Ignored.
270 // return: TRUE if successful.
272 {
273  TRACE("OnUnRegister(%p, %u, %p, %p)\n", m_hWnd, uMsg, wParam, lParam);
274 
275  // validate registration ID
276  UINT nRegID = (UINT)wParam;
277  if (nRegID == INVALID_REG_ID)
278  {
279  ERR("INVALID_REG_ID\n");
280  return FALSE;
281  }
282 
283  // remove it
284  DWORD dwOwnerPID;
285  GetWindowThreadProcessId(m_hWnd, &dwOwnerPID);
286  return RemoveItemsByRegID(nRegID, dwOwnerPID);
287 }
288 
289 // Message CN_DELIVER_NOTIFICATION: Perform a delivery.
290 // wParam: The handle of delivery ticket.
291 // lParam: The owner PID of delivery ticket.
292 // return: TRUE if necessary.
294 {
295  TRACE("OnDeliverNotification(%p, %u, %p, %p)\n", m_hWnd, uMsg, wParam, lParam);
296 
297  HANDLE hTicket = (HANDLE)wParam;
298  DWORD dwOwnerPID = (DWORD)lParam;
299 
300  // do delivery
301  BOOL ret = DeliverNotification(hTicket, dwOwnerPID);
302 
303  // free the ticket
304  SHFreeShared(hTicket, dwOwnerPID);
305  return ret;
306 }
307 
308 // Message CN_SUSPEND_RESUME: Suspend or resume the change notification.
309 // (specification is unknown)
311 {
312  TRACE("OnSuspendResume\n");
313 
314  // FIXME
315  return FALSE;
316 }
317 
318 // Message CN_UNREGISTER_PROCESS: Remove registration entries by PID.
319 // wParam: The user PID.
320 // lParam: Ignored.
321 // return: Zero.
323 {
324  DWORD dwOwnerPID, dwUserPID = (DWORD)wParam;
325  GetWindowThreadProcessId(m_hWnd, &dwOwnerPID);
326  RemoveItemsByProcess(dwOwnerPID, dwUserPID);
327  return 0;
328 }
329 
331 {
333  return 0;
334 }
335 
336 // get next valid registration ID
338 {
339  m_nNextRegID++;
341  m_nNextRegID++;
342  return m_nNextRegID;
343 }
344 
345 // This function is called from CChangeNotifyServer::OnDeliverNotification.
346 // The function notifies to the registration entries that should be notified.
348 {
349  TRACE("DeliverNotification(%p, %p, 0x%lx)\n", m_hWnd, hTicket, dwOwnerPID);
350 
351  // lock the delivery ticket
352  LPDELITICKET pTicket = (LPDELITICKET)SHLockSharedEx(hTicket, dwOwnerPID, FALSE);
353  if (pTicket == NULL || pTicket->dwMagic != DELITICKET_MAGIC)
354  {
355  ERR("pTicket is invalid\n");
356  SHUnlockShared(pTicket);
357  return FALSE;
358  }
359 
360  // for all items
361  for (INT i = 0; i < m_items.GetSize(); ++i)
362  {
363  // validate the item
364  if (m_items[i].nRegID == INVALID_REG_ID)
365  continue;
366 
367  HANDLE hRegEntry = m_items[i].hRegEntry;
368  if (hRegEntry == NULL)
369  continue;
370 
371  // lock the registration entry
372  LPREGENTRY pRegEntry = (LPREGENTRY)SHLockSharedEx(hRegEntry, dwOwnerPID, FALSE);
373  if (pRegEntry == NULL || pRegEntry->dwMagic != REGENTRY_MAGIC)
374  {
375  ERR("pRegEntry is invalid\n");
376  SHUnlockShared(pRegEntry);
377  continue;
378  }
379 
380  // should we notify for it?
381  BOOL bNotify = ShouldNotify(pTicket, pRegEntry);
382  if (bNotify)
383  {
384  // do notify
385  TRACE("Notifying: %p, 0x%x, %p, %lu\n",
386  pRegEntry->hwnd, pRegEntry->uMsg, hTicket, dwOwnerPID);
387  SendMessageW(pRegEntry->hwnd, pRegEntry->uMsg, (WPARAM)hTicket, dwOwnerPID);
388  TRACE("GetLastError(): %ld\n", ::GetLastError());
389  }
390 
391  // unlock the registration entry
392  SHUnlockShared(pRegEntry);
393  }
394 
395  // unlock the ticket
396  SHUnlockShared(pTicket);
397 
398  return TRUE;
399 }
400 
402 {
403 #define RETURN(x) do { \
404  TRACE("ShouldNotify return %d\n", (x)); \
405  return (x); \
406 } while (0)
407 
408  if (pTicket->wEventId & SHCNE_INTERRUPT)
409  {
410  if (!(pRegEntry->fSources & SHCNRF_InterruptLevel))
411  RETURN(FALSE);
412  if (!pRegEntry->ibPidl)
413  RETURN(FALSE);
414  }
415  else
416  {
417  if (!(pRegEntry->fSources & SHCNRF_ShellLevel))
418  RETURN(FALSE);
419  }
420 
421  if (!(pTicket->wEventId & pRegEntry->fEvents))
422  RETURN(FALSE);
423 
424  LPITEMIDLIST pidl = NULL, pidl1 = NULL, pidl2 = NULL;
425  if (pRegEntry->ibPidl)
426  pidl = (LPITEMIDLIST)((LPBYTE)pRegEntry + pRegEntry->ibPidl);
427  if (pTicket->ibOffset1)
428  pidl1 = (LPITEMIDLIST)((LPBYTE)pTicket + pTicket->ibOffset1);
429  if (pTicket->ibOffset2)
430  pidl2 = (LPITEMIDLIST)((LPBYTE)pTicket + pTicket->ibOffset2);
431 
432  if (pidl == NULL || (pTicket->wEventId & SHCNE_GLOBALEVENTS))
433  RETURN(TRUE);
434 
435  if (pRegEntry->fRecursive)
436  {
437  if (ILIsParent(pidl, pidl1, FALSE) ||
438  (pidl2 && ILIsParent(pidl, pidl2, FALSE)))
439  {
440  RETURN(TRUE);
441  }
442  }
443  else
444  {
445  if (ILIsEqual(pidl, pidl1) ||
446  ILIsParent(pidl, pidl1, TRUE) ||
447  (pidl2 && ILIsParent(pidl, pidl2, TRUE)))
448  {
449  RETURN(TRUE);
450  }
451  }
452 
453  RETURN(FALSE);
454 #undef RETURN
455 }
456 
458 {
459  if (!phwnd)
460  return E_INVALIDARG;
461  *phwnd = m_hWnd;
462  return S_OK;
463 }
464 
466 {
467  return E_NOTIMPL;
468 }
469 
471 {
472  // This is called by CChangeNotifyServer_CreateInstance right after instantiation.
473  // Create the window of the server here.
474  Create(0);
475  if (!m_hWnd)
476  return E_FAIL;
477  return S_OK;
478 }
479 
481 {
482  return ShellObjectCreatorInit<CChangeNotifyServer>(riid, ppv);
483 }
#define WS_CLIPSIBLINGS
Definition: pedump.c:618
BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath)
Definition: path.c:1702
LRESULT OnRemoveByPID(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
#define SHCNE_GLOBALEVENTS
Definition: shlobj.h:1752
#define REFIID
Definition: guiddef.h:118
PVOID WINAPI SHLockSharedEx(HANDLE hData, DWORD dwProcessId, BOOL bWriteAccess)
LRESULT OnUnRegister(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
HRESULT CChangeNotifyServer_CreateInstance(REFIID riid, void **ppv)
#define TRUE
Definition: types.h:120
REFIID riid
Definition: precomp.h:44
_In_ BOOLEAN Create
Definition: pstypes.h:519
BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath)
Definition: pidl.c:1294
#define DECLARE_WND_CLASS_EX(WndClassName, style, bkgnd)
Definition: atlwin.h:1886
#define SHCNE_INTERRUPT
Definition: shlobj.h:1754
REFIID LPVOID * ppv
Definition: atlbase.h:39
#define DELITICKET_MAGIC
#define assert(x)
Definition: debug.h:53
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1044
#define DECLARE_NOT_AGGREGATABLE(x)
Definition: atlcom.h:611
LRESULT OnRegister(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
BOOL WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
Definition: pidl.c:535
UINT_PTR WPARAM
Definition: windef.h:207
CSimpleArray< ITEM > m_items
#define REGENTRY_MAGIC
#define WS_CLIPCHILDREN
Definition: pedump.c:619
#define E_FAIL
Definition: ddrawi.h:102
BOOL WINAPI DestroyWindow(_In_ HWND)
#define WS_EX_TOOLWINDOW
Definition: winuser.h:404
#define DWORD
Definition: nt_native.h:44
CDirectoryWatcher * pDirWatch
int32_t INT
Definition: typedefs.h:58
WPARAM wParam
Definition: combotst.c:138
#define RETURN(x)
BOOL AddItem(UINT nRegID, DWORD dwUserPID, HANDLE hRegEntry, HWND hwndBroker, CDirectoryWatcher *pDirWatch)
LRESULT OnSuspendResume(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
static CDirectoryWatcher * CreateDirectoryWatcherFromRegEntry(LPREGENTRY pRegEntry)
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
#define INVALID_REG_ID
unsigned char * LPBYTE
Definition: typedefs.h:53
#define CN_REGISTER
#define FALSE
Definition: types.h:117
void RemoveItemsByProcess(DWORD dwOwnerPID, DWORD dwUserPID)
unsigned int BOOL
Definition: ntddk_ex.h:94
BOOL RemoveItemsByRegID(UINT nRegID, DWORD dwOwnerPID)
DWORD WINAPI GetWindowThreadProcessId(HWND, PDWORD)
#define E_INVALIDARG
Definition: ddrawi.h:101
#define SHCNRF_InterruptLevel
Definition: shlobj.h:1774
smooth NULL
Definition: ftsmooth.c:416
#define CN_UNREGISTER_PROCESS
LONG_PTR LPARAM
Definition: windef.h:208
CWinTraits< WS_POPUP|WS_CLIPSIBLINGS|WS_CLIPCHILDREN, WS_EX_TOOLWINDOW > CChangeNotifyServerTraits
static void RequestAllWatchersTermination()
MESSAGE_HANDLER(CN_UNREGISTER_PROCESS, OnRemoveByPID)
#define WM_DESTROY
Definition: winuser.h:1591
virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode)
static CDirectoryWatcher * Create(LPCWSTR pszDirectoryPath, BOOL fSubTree)
#define BEGIN_COM_MAP(x)
Definition: atlcom.h:541
#define TRACE(s)
Definition: solgame.cpp:4
virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *lphwnd)
LRESULT OnDeliverNotification(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
HANDLE WINAPI SHAllocShared(LPCVOID lpvData, DWORD dwSize, DWORD dwProcId)
Definition: ordinal.c:162
__wchar_t WCHAR
Definition: xmlstorage.h:180
LONG HRESULT
Definition: typedefs.h:79
#define END_MSG_MAP()
Definition: atlwin.h:1799
#define MAX_PATH
Definition: compat.h:34
#define WINAPI
Definition: msvc.h:6
#define SHCNRF_ShellLevel
Definition: shlobj.h:1775
#define STDMETHODCALLTYPE
Definition: bdasup.h:9
PVOID HANDLE
Definition: typedefs.h:73
unsigned long DWORD
Definition: ntddk_ex.h:95
BOOL WINAPI SHFreeShared(HANDLE hShared, DWORD dwProcId)
Definition: ordinal.c:308
int ret
static const WCHAR L[]
Definition: oid.c:1250
#define CN_DELIVER_NOTIFICATION
BOOL ShouldNotify(LPDELITICKET pTicket, LPREGENTRY pRegEntry)
HANDLE hRegEntry
#define ERR(fmt,...)
Definition: debug.h:110
#define CN_UNREGISTER
BOOL WINAPI ILIsParent(LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidlChild, BOOL bImmediate)
Definition: pidl.c:592
#define S_OK
Definition: intsafe.h:51
static ATOM item
Definition: dde.c:856
LPCWSTR szPath
Definition: env.c:35
BOOL DeliverNotification(HANDLE hTicket, DWORD dwOwnerPID)
#define COM_INTERFACE_ENTRY_IID(iid, x)
Definition: atlcom.h:561
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define E_NOTIMPL
Definition: ddrawi.h:99
#define WS_POPUP
Definition: pedump.c:616
unsigned int UINT
Definition: ndis.h:50
struct DELITICKET * LPDELITICKET
#define BEGIN_MSG_MAP(theClass)
Definition: atlwin.h:1780
#define DECLARE_PROTECT_FINAL_CONSTRUCT()
Definition: atlcom.h:639
WINE_DEFAULT_DEBUG_CHANNEL(shcn)
const GUID IID_IOleWindow
BOOL WINAPI SHUnlockShared(LPVOID lpView)
Definition: ordinal.c:288
#define END_COM_MAP()
Definition: atlcom.h:552
LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
LONG_PTR LRESULT
Definition: windef.h:209
void DestroyItem(ITEM &item, DWORD dwOwnerPID, HWND *phwndBroker)
ITEMIDLIST UNALIGNED * LPITEMIDLIST
Definition: shtypes.idl:41
LPARAM lParam
Definition: combotst.c:139
struct REGENTRY * LPREGENTRY
#define CN_SUSPEND_RESUME