root/honeybow/trunk/mwwatcher/src/DelayedDirectoryChangeHandler.h

Revision 670, 14.1 kB (checked in by chengyu, 2 years ago)

honeybow sensor mwwatcher component first public release.

Line 
1 // DelayedDirectoryChangeHandler.h
2 //
3 // Interface for the CDelayedDirectoryChangeHandler2 class
4 // Copyright (C) 2001. Wes Jones (wesj@hotmail.com)
5 //
6 // This code is free for use under the following conditions:
7 //
8 //      1. You may not claim authorship of this code.
9 //      2. You may not sell or distrubute this code without author's permission.
10 //      3. You are not permitted to sell this code in it's compiled, non-compiled, executable,
11 //         or any other form.
12 //      4. Executable code excepted in the case that it is not sold separately from an application
13 //         which uses this it. This means you can use this code for your applications as you
14 //         see fit, but this code may not be sold in any form to others for use in their applications.
15 //      5. This copyright notice may not be removed.
16 //      6. Sell this code as part of a 'Programmer's Library' is stricly prohibited.
17 //
18 // If you'd like to pay me to turn this into an ActiveX/COM object so you can use it in
19 // a Visual Basic application, feel free to contact me with an offer, and I will create
20 // it for you. Otherwise, here is the source code, and you may make your own ActiveX/COM
21 // object, providing that it is not sold separately.
22 //
23 // No guarantees or warranties are expressed or implied.
24 // This code may contain bugs.
25 //
26 // Warning: May contain matter. If this should come into contact with anti-matter,
27 // a violent explosion may occur.
28 //
29 // Please let me know of any bugs, bug fixes, or enhancements made to this code.
30 // If you have ideas for this, and/or tips or admonitions, I would be glad to hear them.
31 //
32 // See notes at top of DirectoryChanges.cpp modification history and more info.
33 //
34 ////////////////////////////////////////////////////////////////////////////////////////
35 //
36 //      You needn't worry about the classes in this file.
37 //      they are implementation classes used to help CDirectoryChangeWatcher work.
38 //
39
40 #if !defined(AFX_DELAYEDDIRECTORYCHANGEHANDLER_H__F20EC22B_1C79_403E_B43C_938F95723D45__INCLUDED_)
41 #define AFX_DELAYEDDIRECTORYCHANGEHANDLER_H__F20EC22B_1C79_403E_B43C_938F95723D45__INCLUDED_
42
43 #if _MSC_VER > 1000
44 #pragma once
45 #endif // _MSC_VER > 1000
46
47 //classes declrared in other files:
48 class CDirectoryChangeWatcher;
49 class CDirectoryChangeHandler;
50 //classes declared in this file:
51 class CDirChangeNotification;
52 class CDelayedDirectoryChangeHandler;
53
54 class CDelayedNotificationWindow;
55 class CDelayedNotificationThread;
56
57 /*******************************************************************
58         The classes in this file implement methods to ensure that file change
59         notifications are fired in a thread other than the worker thread used
60         by CDirectoryChangeWatcher.
61
62         Dispatching the notifications in to a different thread improves the performance
63         of CDirectoryChangeWatcher so that it can process more notifications faster
64         and notifications aren't 'lost'.
65
66
67         There are two methods of dispatching functions to another thread.
68
69                 1)  One is to use the message pump associated w/ the main thread by posting notifications
70                         to a hidden window. This is implemented w/ the class CDelayedNotificationWindow.
71
72                 2)      The other is to create a worker thread that implements a message pump.  This is
73                         implemented w/ the class CDelayedNotificationThread.
74
75
76         If your app uses a GUI then it has a already has message pump. 
77         You can make sure that CDelayedNotificationWindow is used in this case.
78         The advantage here being that there is one less worker thread used in your program.
79
80         If your app is a command line app or otherwise doesn't have a GUI,
81         then you will want to make sure that you are using the CDelayedNotificationThread
82         to dispatch notifications to another thread.
83
84         This is determined by a flag passed is passed to the constructor of CDirecotryChangeWatcher
85
86 ********************************************************************/
87
88 class CDelayedNotifier
89 //
90 //      Abstract base class for ensuring notifications are fired in a thread
91 //
92 //
93 {
94 public:
95         virtual ~CDelayedNotifier(){}
96         virtual void PostNotification(CDirChangeNotification * pNotification) = 0;
97
98 };
99
100 class CDelayedNotificationWindow : public CDelayedNotifier
101 //
102 //      A class that implements a
103 //      there will always be only one of the actual windows
104 //      in existance.
105 //
106 {
107 public:
108                 CDelayedNotificationWindow(){  AddRef(); }
109                 virtual ~CDelayedNotificationWindow(){ Release(); }
110                
111
112                 void PostNotification(CDirChangeNotification * pNotification);
113 private:
114                 long AddRef();          //      the window handle is reference counted
115                 long Release();         //
116
117                 static long s_nRefCnt;
118                 static HWND s_hWnd; //there's only one window no matter how many instances of this class there are.... this means that all notifications are handled by the same thread.
119                 static BOOL s_bRegisterWindow;
120                 BOOL RegisterWindowClass(LPCTSTR szClassName);
121                 BOOL CreateNotificationWindow();
122 };
123
124 class CDelayedNotificationThread : public CDelayedNotifier
125 //
126 //      Class that implements a worker thread w/ a message pump.
127 //      CDirectoryChangeWatcher posts notifications to this thread, where they are dispatched.
128 //      This thread executes CDirectoryChangeHandler notifications.
129 //
130 {
131 public:
132         CDelayedNotificationThread()
133                 :m_hThreadStartEvent(NULL)
134         {
135                 m_hThreadStartEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
136                 ASSERT( m_hThreadStartEvent );
137                 AddRef();
138         }
139         virtual ~CDelayedNotificationThread()
140         {
141                 Release();
142                 if( m_hThreadStartEvent )
143                         CloseHandle(m_hThreadStartEvent), m_hThreadStartEvent = NULL;
144         }
145
146         void PostNotification(CDirChangeNotification * pNotification);
147
148 private:
149         long AddRef();                                  // The thread handle is reference
150         long Release();                                 // counted so that only one thread is used
151                                                                         // so that there's only one worker thread(performing this functino)
152         static long             s_nRefCnt;              // no matter how many directories are being watched
153         static HANDLE   s_hThread;              //     
154         static DWORD    s_dwThreadID;   // 
155                                                                                 
156         static UINT __stdcall ThreadFunc(LPVOID lpvThis);
157
158         bool StartThread();
159         bool StopThread();
160
161         BOOL WaitForThreadStartup(){ return WaitForSingleObject(m_hThreadStartEvent, INFINITE) == WAIT_OBJECT_0; };
162         BOOL SignalThreadStartup(){ return SetEvent( m_hThreadStartEvent ) ; }
163
164         HANDLE m_hThreadStartEvent;//signals that the worker thread has started. this fixes a bug condition.
165                 
166 };
167
168
169 class CDirChangeNotification
170 //
171 //       A class to help dispatch the change notifications to the main thread.
172 //
173 //       This class holds the data in memory until the notification can be dispatched.(ie: this is the time between when the notification is posted, and the clients notification code is called).
174 //
175 //
176 {
177 private:
178         CDirChangeNotification();//not implemented
179 public:
180         explicit CDirChangeNotification(CDelayedDirectoryChangeHandler * pDelayedHandler, DWORD dwPartialPathOffset);
181         ~CDirChangeNotification();
182
183         //
184         //
185         void PostOn_FileAdded(LPCTSTR szFileName);
186         void PostOn_FileRemoved(LPCTSTR szFileName);
187         void PostOn_FileNameChanged(LPCTSTR szOldName, LPCTSTR szNewName);
188         void PostOn_FileModified(LPCTSTR szFileName);
189         void PostOn_ReadDirectoryChangesError(DWORD dwError, LPCTSTR szDirectoryName);
190         void PostOn_WatchStarted(DWORD dwError, LPCTSTR szDirectoryName);
191         void PostOn_WatchStopped(LPCTSTR szDirectoryName);
192         void PostOn_FileUploaded(LPCTSTR szFileName);
193
194         void DispatchNotificationFunction();
195
196
197         enum eFunctionToDispatch{       eFunctionNotDefined = -1,
198                                                                 eOn_FileAdded           = FILE_ACTION_ADDED,
199                                                                 eOn_FileRemoved         = FILE_ACTION_REMOVED,
200                                                                 eOn_FileModified        = FILE_ACTION_MODIFIED,
201                                                                 eOn_FileNameChanged     = FILE_ACTION_RENAMED_OLD_NAME,
202                                                                 eOn_ReadDirectoryChangesError,
203                                                                 eOn_WatchStarted,
204                                                                 eOn_WatchStopped,
205                                                                 eOn_FileUploaded
206         };     
207 protected:
208         void PostNotification();
209        
210 private:
211         friend class CDelayedDirectoryChangeHandler;
212         CDelayedDirectoryChangeHandler * m_pDelayedHandler;
213
214         //
215         //      Members to help implement DispatchNotificationFunction
216         //
217         //
218
219         eFunctionToDispatch m_eFunctionToDispatch;
220         //Notification Data:
221         TCHAR * m_szFileName1;//<-- is the szFileName parameter to On_FileAdded(),On_FileRemoved,On_FileModified(), and is szOldFileName to On_FileNameChanged(). Is also strDirectoryName to On_ReadDirectoryChangesError(), On_WatchStarted(), and On_WatchStopped()
222         TCHAR * m_szFileName2;//<-- is the szNewFileName parameter to On_FileNameChanged()
223         DWORD m_dwError;          //<-- is the dwError parameter to On_WatchStarted(), and On_ReadDirectoryChangesError()
224         //
225
226         DWORD m_dwPartialPathOffset;//helps support FILTERS_CHECK_PARTIAL_PATH...not passed to any functions other than may be used during tests in CDelayedDirectoryChangeHandler::NotifyClientOfFileChange()
227
228
229         friend class CDirChangeNotification;
230         friend class CDirectoryChangeWatcher;
231         friend DWORD GetPathOffsetBasedOnFilterFlags(CDirChangeNotification*,DWORD);//a friend function
232 };
233
234
235 //////////////////////////////////////////////////////////////////////////
236 //
237 //      This class makes it so that a file change notification is executed in the
238 //      context of the main thread, and not the worker thread.
239 //
240 //
241 //      It works by creating a hidden window.  When it receieves a notification
242 //      via one of the On_Filexxx() functions, a message is posted to this window.
243 //      when the message is handled, the notification is fired again in the context
244 //      of the main thread, or whichever thread that called CDirectoryChangeWatcher::WatchDirectory()
245 //
246 //
247 /////////////////////////////////////////////////////////////////////////////
248 //      Note this code wants to use PathMatchSpec()
249 //      which is only supported on WINNT 4.0 w/ Internet Explorer 4.0 and above.
250 //      PathMatchSpec is fully supported on Win2000/XP.
251 //
252 //      For the case of WINNT 4.0 w/out IE 4.0, we'll use a simpler function.
253 //      some functionality is lost, but such is the price.
254 //
255
256 typedef BOOL (STDAPICALLTYPE * FUNC_PatternMatchSpec)(LPCTSTR pszFile, LPCTSTR pszSpec);
257
258 class CDelayedDirectoryChangeHandler : public CDirectoryChangeHandler
259 //
260 //      Decorates an instance of a CDirectoryChangeHandler object.
261 //      Intercepts notification function calls and posts them to
262 //      another thread through a method implemented by a class derived from
263 //      CDelayedNotifier
264 //     
265 //
266 //      This class implements dispatching the notifications to a thread
267 //      other than CDirectoryChangeWatcher::MonitorDirectoryChanges()
268 //
269 //      Also supports the include and exclude filters for each directory
270 //
271 {
272 private:
273         CDelayedDirectoryChangeHandler();//not implemented.
274 public:
275         CDelayedDirectoryChangeHandler( CDirectoryChangeHandler * pRealHandler, bool bAppHasGUI, LPCTSTR szIncludeFilter, LPCTSTR szExcludeFilter, DWORD dwFilterFlags);
276         virtual ~CDelayedDirectoryChangeHandler();
277
278        
279         CDirectoryChangeHandler * GetRealChangeHandler()const { return m_pRealHandler; }
280         CDirectoryChangeHandler * & GetRealChangeHandler(){ return m_pRealHandler; }//FYI: PCLint will give a warning that this exposes a private/protected member& defeats encapsulation. 
281
282         void PostNotification(CDirChangeNotification * pNotification);
283         void DispatchNotificationFunction(CDirChangeNotification * pNotification);
284
285
286 protected:
287         //These functions are called when the directory to watch has had a change made to it
288         void On_FileAdded(const CString & strFileName);
289         void On_FileRemoved(const CString & strFileName);
290         void On_FileModified(const CString & strFileName);
291         void On_FileNameChanged(const CString & strOldFileName, const CString & strNewFileName);
292         void On_ReadDirectoryChangesError(DWORD dwError, const CString & strDirectoryName);
293
294         void On_WatchStarted(DWORD dwError, const CString & strDirectoryName);
295         void On_WatchStopped(const CString & strDirectoryName);
296        
297         void On_FileUploaded(const CString & strFileName);
298
299         void SetChangedDirectoryName(const CString & strChangedDirName);
300         const CString & GetChangedDirectoryName()const;
301
302         BOOL WaitForOnWatchStoppedDispatched();//see comments in .cpp
303
304
305         bool NotifyClientOfFileChange(CDirChangeNotification * pNot);
306
307         bool IncludeThisNotification(LPCTSTR szFileName);       //      based on file name.
308         bool ExcludeThisNotification(LPCTSTR szFileName);       //      Allows us to filter notifications
309                                                                                                                 //
310         
311        
312
313         CDirChangeNotification * GetNotificationObject();
314         void DisposeOfNotification(CDirChangeNotification * pNotification);
315
316         CDelayedNotifier * m_pDelayNotifier;
317         CDirectoryChangeHandler * m_pRealHandler;       
318
319                                                 // m_bAppHasGUI:
320                                                 //   This flag, if set to true, indicates that the app has a message
321         bool m_bAppHasGUI;      //       pump, and that functions are dispatched to the main thread.
322                                                 //   Otherwise, functions are dispatched to a separate worker thread.
323                                                 //
324         DWORD m_dwFilterFlags;
325
326         DWORD m_dwPartialPathOffset; //helps support FILTERS_CHECK_PARTIAL_PATH
327         void SetPartialPathOffset(const CString & strWatchedDirName);
328
329         friend class CDirectoryChangeWatcher;
330         friend class CDirectoryChangeWatcher::CDirWatchInfo;
331
332 private:
333         HANDLE m_hWatchStoppedDispatchedEvent;//supports WaitForOnWatchStoppedDispatched()
334
335         TCHAR * m_szIncludeFilter;              //      Supports the include
336         TCHAR * m_szExcludeFilter;              //      & exclude filters
337
338         //
339         //      Load PathMatchSpec dynamically because it's only supported if IE 4.0 or greater is
340         //      installed.
341         static HMODULE s_hShlwapi_dll;//for the PathMatchSpec() function
342         static BOOL s_bShlwapi_dllExists;//if on NT4.0 w/out IE 4.0 or greater, this'll be false
343         static long s_nRefCnt_hShlwapi;
344         static FUNC_PatternMatchSpec s_fpPatternMatchSpec;
345
346         BOOL _PathMatchSpec(LPCTSTR szPath, LPCTSTR szPattern);
347         BOOL InitializePathMatchFunc(LPCTSTR szIncludeFilter, LPCTSTR szExcludeFilter);
348         BOOL InitializePatterns(LPCTSTR szIncludeFilter, LPCTSTR szExcludeFilter);
349         void UninitializePathMatchFunc();
350
351         bool UsesRealPathMatchSpec() const;//are we using PathMatchSpec() or wildcmp()?
352
353         //note: if the PathMatchSpec function isn't found, wildcmp() is used instead.
354         //
355         //      to support multiple file specs separated by a semi-colon,
356         //      the include and exclude filters that are passed into the
357         //      the constructor are parsed into separate strings
358         //      which are all checked in a loop.
359         //
360         int m_nNumIncludeFilterSpecs;
361         int m_nNumExcludeFilterSpecs;
362
363
364 };
365
366
367
368
369 #endif // !defined(AFX_DELAYEDDIRECTORYCHANGEHANDLER_H__F20EC22B_1C79_403E_B43C_938F95723D45__INCLUDED_)
Note: See TracBrowser for help on using the browser.