Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

337 lines
11 KiB

  1. // private declarations for scnotify.cpp
  2. typedef struct
  3. {
  4. DWORD dwSig;
  5. UINT uCmd;
  6. ULONG ulID;
  7. ULONG ulHwnd;
  8. UINT uMsg;
  9. DWORD fSources;
  10. LONG lEvents;
  11. BOOL fRecursive;
  12. UINT uidlRegister;
  13. } CHANGEREGISTER;
  14. typedef struct
  15. {
  16. DWORD dwSig;
  17. DWORD cbSize;
  18. LONG lEvent;
  19. UINT uFlags;
  20. DWORD dwEventTime;
  21. UINT uidlMain;
  22. UINT uidlExtra;
  23. } CHANGEEVENT;
  24. typedef struct
  25. {
  26. DWORD dwSig;
  27. LPITEMIDLIST pidlMain;
  28. LPITEMIDLIST pidlExtra;
  29. CHANGEEVENT *pce;
  30. } CHANGELOCK;
  31. HANDLE SHChangeNotification_Create(LONG lEvent, UINT uFlags, LPCITEMIDLIST pidlMain, LPCITEMIDLIST pidlExtra, DWORD dwProcId, DWORD dwEventTime);
  32. class CNotifyEvent;
  33. class CCollapsingClient;
  34. class CRegisteredClient;
  35. class CInterruptSource;
  36. class CAnyAlias;
  37. //
  38. // this is the global object g_pscn
  39. // its lifetime is tied to the SCNotify thread and window.
  40. // if the thread or window dies, then the object is destroyed
  41. //
  42. class CChangeNotify
  43. {
  44. public: // methods
  45. CNotifyEvent *GetEvent(LONG lEvent, LPCITEMIDLIST pidl, LPCITEMIDLIST pidlExtra, DWORD dwEventTime, UINT uEventFlags);
  46. BOOL AddClient(IDLDATAF flags, LPCITEMIDLIST pidl, BOOL *pfInterrupt, BOOL fRecursive, CCollapsingClient *pclient);
  47. HRESULT RemoveClient(LPCITEMIDLIST pidl, BOOL fInterrupt, CCollapsingClient *pclient);
  48. BOOL AddInterruptSource(LPCITEMIDLIST pidlClient, BOOL fRecursive);
  49. void ReleaseInterruptSource(LPCITEMIDLIST pidlClient);
  50. void AddAlias(LPCITEMIDLIST pidlReal, LPCITEMIDLIST pidlAlias, DWORD dwEventTime);
  51. void AddSpecialAlias(int csidlReal, int csidlAlias);
  52. void UpdateSpecialAlias(int csidlAlias);
  53. void NotifyEvent(LONG lEvent, UINT uFlags, LPCITEMIDLIST pidl, LPCITEMIDLIST pidlExtra, DWORD dwEventTime);
  54. void PendingCallbacks(BOOL fAdd);
  55. void SetFlush(int idt);
  56. static DWORD WINAPI ThreadProc(void *pv);
  57. static DWORD WINAPI ThreadStartUp(void *pv);
  58. static LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  59. protected: // methods
  60. BOOL _OnChangeRegistration(HANDLE hChangeRegistration, DWORD dwProcId);
  61. LRESULT _OnNotifyEvent(HANDLE hChange, DWORD dwProcId);
  62. LRESULT _OnSuspendResume(HANDLE hChange, DWORD dwProcId);
  63. void _OnDeviceBroadcast(ULONG_PTR code, DEV_BROADCAST_HANDLE *pbhnd);
  64. ULONG _RegisterClient(HWND hwnd, int fSources, LONG fEvents, UINT wMsg, SHChangeNotifyEntry *pfsne);
  65. BOOL _DeregisterClient(CRegisteredClient *pclient);
  66. BOOL _DeregisterClientByID(ULONG ulID);
  67. BOOL _DeregisterClientsByWindow(HWND hwnd);
  68. void _FreshenClients(void);
  69. BOOL _InitTree(CIDLTree **pptree);
  70. BOOL _AddToClients(LONG lEvent, LPCITEMIDLIST pidl, LPCITEMIDLIST pidlExtra, DWORD dwEventTime, UINT uEventFlags);
  71. void _MatchAndNotify(LPCITEMIDLIST pidl, CNotifyEvent *pne, BOOL fFromExtra);
  72. void _AddGlobalEvent(CNotifyEvent *pne);
  73. CInterruptSource *_InsertInterruptSource(LPCITEMIDLIST pidl, BOOL fRecursive);
  74. DWORD _GetInterruptEvents(HANDLE *ahEvents, DWORD cEvents);
  75. void _ResetRelatedInterrupts(LPCITEMIDLIST pidl);
  76. void _FlushInterrupts();
  77. void _Flush(BOOL fShouldWait);
  78. void _WaitForCallbacks(void);
  79. BOOL _SuspendResume(BOOL fSuspend, BOOL fRecursive, LPCITEMIDLIST pidl);
  80. BOOL _HandleMessages(void);
  81. void _MessagePump(void);
  82. void _SignalInterrupt(HANDLE hEvent);
  83. void _FreshenUp(void);
  84. CAnyAlias *_FindAlias(LPCITEMIDLIST pidlReal, LPCITEMIDLIST pidlAlias);
  85. CAnyAlias *_FindSpecialAlias(int csidlReal, int csidlAlias);
  86. void _CheckAliasRollover(void);
  87. void _FreshenAliases(void);
  88. BOOL _InsertAlias(CLinkedNode<CAnyAlias> *p);
  89. void _ActivateAliases(LPCITEMIDLIST pidl, BOOL fActivate);
  90. protected: // members
  91. CIDLTree *_ptreeClients;
  92. CIDLTree *_ptreeInterrupts;
  93. CIDLTree *_ptreeAliases;
  94. CLinkedList<CInterruptSource> _listInterrupts;
  95. CLinkedList<CRegisteredClient> _listClients;
  96. CLinkedList<CAnyAlias> _listAliases;
  97. LONG _cFlushing;
  98. LONG _cCallbacks;
  99. HANDLE _hCallbackEvent;
  100. };
  101. typedef struct _MSGEVENT
  102. {
  103. HANDLE hChange;
  104. DWORD dwProcId;
  105. } MSGEVENT;
  106. //
  107. // LIFETIME - based on clients holding references
  108. // Each event can have multiple references
  109. // each CRegisteredClient has a DPA that points to a list
  110. // of events that the client will want to know.
  111. // the first time an event is used, it is added
  112. // to the ptreeEvents, so that it may be reused.
  113. // when the last client stops using the event, then
  114. // it is removed from the tree.
  115. //
  116. class CNotifyEvent
  117. {
  118. public:
  119. STDMETHOD_(ULONG, AddRef)();
  120. STDMETHOD_(ULONG, Release)();
  121. MSGEVENT *GetNotification(DWORD dwProcId)
  122. {
  123. MSGEVENT *pme = new MSGEVENT;
  124. if (pme)
  125. {
  126. pme->dwProcId = dwProcId;
  127. pme->hChange = SHChangeNotification_Create((lEvent & ~SHCNE_INTERRUPT), // clients should never see the SHCNE_INTERRUPT flag
  128. 0,
  129. pidl,
  130. pidlExtra,
  131. dwProcId,
  132. dwEventTime);
  133. if (!pme->hChange)
  134. {
  135. delete pme;
  136. pme = NULL;
  137. }
  138. }
  139. return pme;
  140. }
  141. BOOL Init(LPCITEMIDLIST pidlIn, LPCITEMIDLIST pidlExtraIn);
  142. LONG lEvent;
  143. LPITEMIDLIST pidl;
  144. LPITEMIDLIST pidlExtra;
  145. DWORD dwEventTime;
  146. UINT uEventFlags;
  147. protected:
  148. LONG _cRef;
  149. static CNotifyEvent *Create(LONG lEvent, LPCITEMIDLIST pidl, LPCITEMIDLIST pidlExtra, DWORD dwEventTime, UINT uEventFlags);
  150. CNotifyEvent(LONG lEventIn, DWORD dwEventTimeIn, UINT uEventFlagsIn)
  151. : lEvent(lEventIn), dwEventTime(dwEventTimeIn), uEventFlags(uEventFlagsIn), _cRef(1) {}
  152. ~CNotifyEvent() { ILFree(pidl); ILFree(pidlExtra); }
  153. // so CSCN can set fUsed;
  154. friend class CChangeNotify;
  155. friend class CRegisteredClient;
  156. };
  157. class CCollapsingClient
  158. {
  159. public: // methods
  160. void Notify(CNotifyEvent *pne, BOOL fFromExtra);
  161. BOOL Flush(BOOL fNeedsCallbackEvent);
  162. BOOL Init(LPCITEMIDLIST pidl, BOOL fRecursive);
  163. CCollapsingClient();
  164. protected:
  165. virtual ~CCollapsingClient();
  166. virtual BOOL _WantsEvent(LONG lEvent) = 0;
  167. virtual void _SendNotification(CNotifyEvent *pne, BOOL fNeedsCallbackEvent, SENDASYNCPROC pfncb) = 0;
  168. virtual BOOL _IsValidClient() = 0;
  169. virtual BOOL _CheckUpdatingSelf() = 0;
  170. LPITEMIDLIST _pidl;
  171. LONG _fEvents;
  172. HWND _hwnd;
  173. BOOL _fUpdatingSelf;
  174. BOOL _fRecursive;
  175. private:
  176. BOOL _Flush(BOOL fNeedsCallbackEvent);
  177. BOOL _CanCollapse(LONG lEvent);
  178. BOOL _IsDupe(CNotifyEvent *pne);
  179. BOOL _AddEvent(CNotifyEvent *pne, BOOL fFromExtra);
  180. CDPA<CNotifyEvent> _dpaPendingEvents;
  181. int _iUpdatingSelfIndex;
  182. int _cEvents;
  183. };
  184. //
  185. // LIFETIME - based on client registration
  186. // when an SCN client calls Register, we create
  187. // a corresponding object that lives
  188. // as long as the client window is valid
  189. // or until Deregister is called.
  190. // references are kept in ptreeClients and in
  191. // the pclientFirst list. when a client is
  192. // removed from the list, it is also removed
  193. // from the tree.
  194. //
  195. class CRegisteredClient : public CCollapsingClient
  196. {
  197. public: // methods
  198. CRegisteredClient();
  199. ~CRegisteredClient();
  200. BOOL Init(HWND hwnd, int fSources, LONG fEvents, UINT wMsg, SHChangeNotifyEntry *pfsne);
  201. protected: // methods
  202. void _SendNotification(CNotifyEvent *pne, BOOL fNeedsCallbackEvent, SENDASYNCPROC pfncb);
  203. BOOL _WantsEvent(LONG lEvent);
  204. BOOL _IsValidClient() { return (!_fDeadClient); }
  205. BOOL _CheckUpdatingSelf() { return _fUpdatingSelf; }
  206. protected: // members
  207. ULONG _ulID;
  208. BOOL _fDeadClient;
  209. BOOL _fInterrupt;
  210. private: // members
  211. DWORD _dwProcId;
  212. int _fSources;
  213. UINT _wMsg;
  214. friend class CChangeNotify;
  215. };
  216. class CAnyAlias : public CCollapsingClient
  217. {
  218. public: // methods
  219. void Activate(BOOL fActivate);
  220. BOOL Remove();
  221. BOOL Init(LPCITEMIDLIST pidlReal, LPCITEMIDLIST pidlAlias);
  222. BOOL InitSpecial(int csidlReal, int csidlAlias);
  223. BOOL IsAlias(LPCITEMIDLIST pidlReal, LPCITEMIDLIST pidlAlias);
  224. BOOL IsSpecial(int csidlReal, int csidlAlias);
  225. ~CAnyAlias();
  226. protected:
  227. BOOL _CustomTranslate();
  228. void _SendNotification(CNotifyEvent *pne, BOOL fNeedsCallbackEvent, SENDASYNCPROC pfncb);
  229. BOOL _WantsEvent(LONG lEvent);
  230. BOOL _IsValidClient() { return TRUE; }
  231. BOOL _CheckUpdatingSelf() { return FALSE; }
  232. BOOL _OkayToNotifyTranslatedEvent(CNotifyEvent *pne, LONG lEvent, LPCITEMIDLIST pidl, LPCITEMIDLIST pidlExtra);
  233. private:
  234. LONG _cActivated;
  235. LPITEMIDLIST _pidlAlias;
  236. ITranslateShellChangeNotify *_ptscn;
  237. DWORD _dwTime;
  238. BOOL _fRemove;
  239. BOOL _fInterrupt;
  240. BOOL _fCheckedCustom;
  241. BOOL _fSpecial;
  242. int _csidlReal;
  243. int _csidlAlias;
  244. friend class CChangeNotify;
  245. };
  246. //
  247. // LIFETIME - based on client registration
  248. // when an SCN client calls Register, we may create
  249. // a corresponding object that lives
  250. // as long as the client window is valid
  251. // or until Deregister is called.
  252. // references are kept in ptreeClients and in
  253. // the pclientFirst list. when a client is
  254. // removed from the list, it is also removed
  255. // from the tree.
  256. //
  257. class CInterruptSource
  258. {
  259. public: // methods
  260. BOOL Init(LPCITEMIDLIST pidl, BOOL fRecursive);
  261. void Reset(BOOL fSignal);
  262. BOOL GetEvent(HANDLE *phEvent);
  263. void Suspend(BOOL fSuspend);
  264. BOOL SuspendDevice(BOOL fSuspend, HDEVNOTIFY hPNP);
  265. BOOL Flush(void);
  266. ~CInterruptSource();
  267. protected: // methods
  268. void _Reset(BOOL fDeviceNotify);
  269. protected: // members
  270. LPITEMIDLIST pidl; // this is SHARED with the fs registered client structure.
  271. DWORD cClients; // how many clients are interested in this. (ref counts)
  272. private:
  273. typedef enum
  274. {
  275. NO_SIGNAL = 0,
  276. SH_SIGNAL,
  277. FS_SIGNAL
  278. } SIGNAL_STATE;
  279. BOOL _fRecursive; // is this a recursive interrupt client?
  280. HANDLE _hEvent;
  281. // cRecursive clients
  282. LONG _cSuspend; // suspended for extended fileops
  283. SIGNAL_STATE _ssSignal; // FS has signaled us with an event on this directory
  284. HDEVNOTIFY _hPNP; // PnP handle to warn us about drives coming and going
  285. HDEVNOTIFY _hSuspended; // suspended PnP handle
  286. friend class CChangeNotify;
  287. };