Click here to Skip to main content
14,028,405 members
Click here to Skip to main content
Add your own
alternative version


358 bookmarked
Posted 31 Jan 2001

CDirectoryChangeWatcher - ReadDirectoryChangesW all wrapped up

, 11 May 2002
Rate this:
Please Sign up or sign in to vote.
This class wraps up ReadDirectoryChangesW.

DirWatcher Sample App Screenshot


This code wraps up the Win32 API function ReadDirectoryChangesW so that your application only has to worry about responding to the events that take place when a file or directory is added, removed, modified, or renamed.

This code will only work on Windows NT, Windows 2000, or Windows XP, and the directory you wish to watch must also reside on a WindowsNT, Windows 2000, or Windows XP computer.

The Classes

There are two classes that must be used together to watch a directory, they are: CDirectoryChangeWatcher and CDirectoryChangeHandler.

About CDirectoryChangeWatcher:

The class CDirectoryChangeWatcher does all the grunt work of watching a directory.  It creates a worker thread that is waiting for directory changes to take place via its use of the ReadDirectoryChangesW Win32 API function.   Multiple directories can be watched with a single instance of CDirectoryChangeWatcher, and directories can be added and removed from the watch at any time.  

When file change notifications are received, CDirectoryChangeWatcher 'dispatches' these notifications to your application via the the class CDirectoryChangeHandler(see below).

About CDirectoryChangeHandler:

The class CDirectoryChangeHandler receives notifications about file changes from CDirectoryChangeHandler.  You need to derive a class from CDirectoryChangeHandler in order for your application to handle the file change notifications.  
A single instance of a CDirectoryChangeHandler derived class can be used to handle notifications for multiple directory watches at the same time, or you may specify different CDirectoryChangeHandler derived classes for each watched directory.

The Interfaces

The following is the public interface of CDirectoryChangeWatcher:

class CDirectoryChangeWatcher{
   enum	{  //options for determining the behavior of the filter tests.
           FILTERS_DONT_USE_FILTERS     = 1, 
  CDirectoryChangeWatcher(bool bAppHasGUI = true, 
                          DWORD dwFilterFlags = FILTERS_DEFAULT_BEHAVIOR);
  virtual ~CDirectoryChangeWatcher();//dtor
  DWORD	WatchDirectory( const CString & strDirToWatch, 
			DWORD dwChangesToWatchFor, 
			CDirectoryChangeHandler * pChangeHandler, 
			BOOL bWatchSubDirs = FALSE,
			LPCTSTR szIncludeFilter = NULL,
			LPCTSTR szExcludeFilter = NULL);

  BOOL IsWatchingDirectory(const CString & strDirName)const;
  int  NumWatchedDirectories()const; 

  BOOL UnwatchDirectory(const CString & strDirToStopWatching);
  BOOL UnwatchAllDirectories();

  DWORD	SetFilterFlags(DWORD dwFilterFlags);
  DWORD GetFilterFlags() const;


The class CDirectoryChangeHandler has the following interface:

class CDirectoryChangeHandler{
   BOOL UnwatchDirectory(); 
  //override these functions:	
   //Notification related:
   virtual void On_FileAdded(const CString & strFileName);
   virtual void On_FileRemoved(const CString & strFileName);
   virtual void On_FileModified(const CString & strFileName);
   virtual void On_FileNameChanged(const CString & strOldFileName, 
                                   const CString & strNewFileName);
   virtual void On_ReadDirectoryChangesError(DWORD dwError);
   virtual void On_WatchStarted(DWORD dwError, const CString & strDirectoryName);
   virtual void On_WatchStopped(const CString & strDirectoryName);
   //Filter related:
   virtual bool On_FilterNotification(DWORD dwNotifyAction,
                                      LPCTSTR szFileName, LPCTSTR szNewFileName);

To handle the events that happen when a file or directory is added, deleted, modified, or renamed, create a class derived from CDirectoryChangeHandler that does all of the things that you want to do when these events happen.

The Notifications

There are 7 notifications that you can receive when using these classes.

CDirectoryChangeHandler function
Notification Description
Flag(s) required to receive notification--
(dwChangesToWatchFor parameter
Watch Started
A directory watch has been started because 
was called.
Watch Stopped
A directory watch has been stopped because 
was called.

Can also be called when CDirectoryChangeHandler's desctructor is called and there are 1 or more directories being watched at that time.
** See the comments in DirectoryChanges.h near the On_WatchStopped function to avoid RTFM errors which can occur under certain circumstances.**
Directory Watch Error
An error occurred while watching a directory. In this condition, the watch is stopped automatically.  You will not receive the On_WatchStopped notification.
File Added
A file was added to a watched directory (newly created, or copied into that directory).
File Removed
A file was deleted, or removed from the watched directory(ie: sent to the recycle bin, moved to another directory, or deleted)
File Name Changed
A file's name has been changed in the watched directory.  The parameters to this notification are the old file name, and the new file name.
File Modified
A file was modified in some manner in a watched directory.  Things that can cause you to receive this notification include changes to a file's last accessed, last modified, or created timestamps. Other changes, such as a change to a file's attributes, size, or security descriptor can also trigger this notification.

The Filters

One of the new features to this class is the ability to filter out notifications so that you can receive notifications only for files that you want to receive notifications about.  This feature enables you receive file notifications only for files you wish to know about based on the name of the changed file, or based on a function that you implement.  

Without a filter, you will receive notifications for any and all file changes, as specified by the combination of flags passed as the dwChangesToWatchFor parameter to the CDirectoryChangeWatcher::WatchDirectory function(which is the default by the way).

There are 3 types of filters: An Include Filter, an Exclude Filter, and a programmer implemented virtual function which can decide whether or not the appropriate CDirectoryChangeHandler::On_Filexxxxx() function is called.

The Include, Exclude filters:

The Include and Exclude filters are string parameters that are passed to CDirectoryChangeWatcher::WatchDirectory when a directory watch is started.  The filter is a pattern which can contain the DOS wildcard characters * and ?.   Multiple patterns can be specified by separating each pattern with a semi-colon (;).

The following are examples of valid pattern strings that can be used to filter notifications:

    "*.txt"   <-- specifies only a single file pattern.
    "*.txt;*.tmp;myfile???.txt;MySubFolder???\*.doc"  <-- specifies multiple file patterns.

Note that the supporting code for these string filters uses the PathMatchSpec Win32 API function to determine a pattern match. PathMatchSpec is implemented in shlwapi.dll version 4.71 or later. If you are running on NT4.0, and Internet Explorer 4.0 is not installed, a modified version of wildcmp is used instead.

What does the Include Filter mean?

The Include filter is used to tell CDirectoryChangeWatcher that you wish to receive notifications ONLY for files that match a certain pattern. All other file notifications are implicitly excluded because the file name does not match the 'Include Filter' pattern. ie: If you pass an 'Include Filter' of "*.txt", you will only receive notifications(File Added, File Removed, etc) for files with names that end with ".txt".  You will not be notified of changes to any other files.

Note: It's better to specify a NULL or empty string, than to specify an Include Filter of "*.*".

What does the Exclude Filter mean?

With the Exclude Filter, you can choose to tell CDirectoryChangeWatcher to explicitly ignore notifications for changes to files based on the name of the changed file.  For example, you can choose to ignore changes to .log files in a watched directory. To do so, you would specify an Exclude Filter of "*.log"

The Include and Exclude Filters are a powerful way of customizing the notifications that you wish to receive.  To test your pattern strings, there is a dialog provided as part of the sample application.  Press the "Test Filter Patterns..." button on the Sample App.

The Programmer Defined Filter:

You can also override the function : virtual bool CDirectoryChangeHandler::On_FilterNotification() . If On_FilterNotification returns true(the default), you will receive the notification.  If On_FilterNotification returns false, the file notification is ignored.  See the comments in the source code for more information about this function.

Filter Options

There are several options related to how CDirectoryChangeWatcher works with filters.  

Filter Flag
Flag Description
Specifies that the string filters for the Include and Exclude filter are not checked.  All notifications are sent unless 
returns false.
Specifies that CDirectoryChangeHandler::On_FilterNotification() is not tested. If the File name passes the test against the Include and Exclude filter, the notification is passed on.
Specifies that NO filter tests are to be performed.  The Include and Exclude filters are not tested, and CDirectoryChangeHandler::On_FilterNotification() is not called.  This is a combination of FILTERS_DONT_USE_FILTERS and FILTERS_DONT_USE_HANDLER_FILTER flags.
FILTERS_NO_WATCHSTART_NOTIFICATION CDirectoryChangeHandler::On_WatchStarted won't be called
FILTERS_NO_WATCHSTOP_NOTIFICATION CDirectoryChangeHandler::On_WatchStopped won't be called
FILTERS_NO_STARTSTOP_NOTIFICATION CDirectoryChangeHandler::On_WatchStarted and CDirectoryChangeHandler::On_WatchStopped won't be called. Is a combination of FILTERS_NO_WATCHSTART_NOTIFICATION and FILTERS_NO_WATCHSTOP_NOTIFICATION.
Specifies that CDirectoryChangeHandler::On_FilterNotification() is to be called BEFORE the file name is tested against the Include and Exclude filter patterns.  The default is that CDirectoryChangeHandler::On_FilterNotification() is tested AFTER only if the file name matches the patterns used that may have been specified as Include or Exclude Filters.
Specifies that the entire file name and path is to be tested against the Include and Exclude Filter pattern.
Specifies that only a portion of the file path and name are to be tested against the Include and Exclude Filter.  The portion of the path checked is the part of the path following the watched folder name.  

For example, if you are watching "C:\Temp" (and are also watching subfolders) and a file named "C:\Temp\SomeFolder\SomeFileName.txt" is changed, the portion of the file name that is checked against the Include and Exclude filters is "SomeFolder\SomeFileName.txt"
Specifies that only the file name part of the file path is to be checked against the Include and Exclude filter.
Specifies the 'default' filter handling behaviour.
Currently, it's only set to FILTERS_CHECK_FILE_NAME_ONLY.

This implies that the Include/Exclude Filters are tested before On_FilterNotification, and that On_WatchStarted and On_WatchStopped are called.

To specify these options, see the constructor of CDirectoryChangeWatcher , or use the function CDirectoryChangeWatcher::SetFilterFlags() .

Note that the Filter Flags are used for the next call to CDirectoryChangeWatcher::WatchDirectory and that calling CDirectoryChangeWatcher::SetFilterFlags() will have no effect on any currently watched directories.

The sample app includes a dialog which allows you to test this out:

Thread Safety, and Message Pumps.

While CDirectoryChangeWatcher uses a worker thread to get the job done, all notifications are called in the context of the main thread . The 'main' thread is the thread that first calls CDirectoryChangeWatcher::WatchDirectory . CDirectoryChangeWatcher uses a hidden notification window to dispatch notifications from the worker thread to the main thread. Because it uses a window, the calling application must have a message pump implemented somewhere in the program's 'main' thread.

Console Applications

For console applications, or applications/threads without a message pump, CDirectoryChangeWatcher can still be used. Just pass false as the value of the bAppHasGUI parameter to the constructor of CDirectoryChangeWatcher . Instead of using a hidden notification window, CDirectoryChangeWatcher uses an additional worker thread. Note that when you pass false as the value of bAppHasGUI parameter to the constructor of CDirectoryChangeWatcher , that all CDirectoryChangeHandler functions are called within the context of a worker thread, and NOT the main thread.

CDirectoryChangeWatcher watcher(false); //safe to use in a console app.
				//Note: CDirectoryChangeHandler functions are called 
				// 	in a worker thread.

A Sample:

class CMyDirectoryChangeHandler : public CDirectoryChangeHandler
      	virtual ~CMyDirectoryChangeHandler(){}

       	void On_FileNameChanged(const CString & strOldFileName, const CString & strNewFileName)
             MessageBox(NULL, _T("The file ") + strOldFileName + _T(" was renamed to: ") + 
       	bool On_FilterNotification(DWORD dwNotifyAction, LPCTSTR szFileName, LPCTSTR szNewFileName)
            // This programmer defined filter will only cause notifications
            // that a file name was changed to be sent.
		if( dwNotifyAction == FILE_ACTION_RENAMED_OLD_NAME ) 
                   return true;
              	return false;

        CDirectoryChangeWatcher watcher;
        CMyDirectoryChangeHandler MyChangeHandler;
                                 FALSE, //<-- watch sub directories? 
                                 NULL, //<-- Include Filter
                    		 NULL);//<-- Exclude Filter


was based on the FWatch example program in the SDK and uses an I/O completion port so that there will only be one worker thread (per instance of CDirectoryChangeWatcher ) for any number of watched directories.

When using this source code in your application, you only need to use CDirectoryChangeWatcher and class(es) derived from CDirectoryChangeHandler.  Any other classes in these source files are used to implement CDirectoryChangeWatcher.

Download the sample or source code for more details.


  • CDirectoryChangeWatcher is based on the FWatch sample in the SDK.
  • The sample application uses CFolderDialog by Armen Hakobyan.
  • CDirectoryChangeWatcher uses a modified version of wildcmp by Jack Handy

Feel free to email me with bugs, bug fixes, tips, comments, accolades, or admonitions at


This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


About the Author

Wes Jones
Web Developer
United States United States
No Biography provided

You may also be interested in...

Comments and Discussions

GeneralRe: Locked Directory [modified] Pin
Wes Jones5-Nov-06 15:40
memberWes Jones5-Nov-06 15:40 
GeneralReadDirectoryChangesW Pin
Klempie3-Oct-05 8:09
memberKlempie3-Oct-05 8:09 
GeneralRe: ReadDirectoryChangesW Pin
Wes Jones3-Oct-05 12:35
memberWes Jones3-Oct-05 12:35 
GeneralRe: ReadDirectoryChangesW Pin
Klempie3-Oct-05 21:08
memberKlempie3-Oct-05 21:08 
Generalgiving error in afxtempl.h Pin
gauri_ag20-Sep-05 4:34
membergauri_ag20-Sep-05 4:34 
GeneralRe: giving error in afxtempl.h Pin
Wes Jones20-Sep-05 5:35
memberWes Jones20-Sep-05 5:35 
GeneralRe: giving error in afxtempl.h Pin
gauri_ag20-Sep-05 19:07
membergauri_ag20-Sep-05 19:07 
GeneralRe: giving error in afxtempl.h Pin
Jeffgosurfing2-Aug-07 8:08
memberJeffgosurfing2-Aug-07 8:08 
Generalvery nice Pin
T1TAN13-Sep-05 0:14
memberT1TAN13-Sep-05 0:14 
GeneralCatch deletion before On_FileRemoved Pin
mousse_225-Jul-05 4:54
membermousse_225-Jul-05 4:54 
GeneralRe: Catch deletion before On_FileRemoved Pin
Wes Jones25-Jul-05 8:20
memberWes Jones25-Jul-05 8:20 
GeneralAbout FileCopy Pin
piceleri2-Jun-05 4:32
memberpiceleri2-Jun-05 4:32 
GeneralRe: About FileCopy Pin
Wes Jones2-Jun-05 6:05
memberWes Jones2-Jun-05 6:05 
GeneralFile Lose When Monitoring Pin
KW-Rix21-Apr-05 15:39
memberKW-Rix21-Apr-05 15:39 
GeneralRe: File Lose When Monitoring Pin
Wes Jones22-Apr-05 6:40
memberWes Jones22-Apr-05 6:40 
GeneralFile Modified Pin
BoscoBill19-Apr-05 9:33
memberBoscoBill19-Apr-05 9:33 
GeneralRe: File Modified Pin
Wes Jones22-Apr-05 6:38
memberWes Jones22-Apr-05 6:38 
GeneralRe: File Modified Pin
BoscoBill22-Apr-05 7:02
memberBoscoBill22-Apr-05 7:02 
GeneralRe: File Modified Pin
Wes Jones29-Apr-05 8:44
memberWes Jones29-Apr-05 8:44 
GeneralRe: File Modified Pin
BoscoBill2-May-05 8:36
memberBoscoBill2-May-05 8:36 
GeneralThe device cannot be stopped Pin
cliff hunger2-Apr-05 10:05
susscliff hunger2-Apr-05 10:05 
GeneralRe: The device cannot be stopped Pin
Wes Jones8-Apr-05 6:33
memberWes Jones8-Apr-05 6:33 
GeneralRe: The device cannot be stopped Pin
SongZhenwei8-Apr-05 14:35
memberSongZhenwei8-Apr-05 14:35 
Questionhow can i get who change the file? Pin
feiyuntan24-Mar-05 2:00
memberfeiyuntan24-Mar-05 2:00 
AnswerRe: how can i get who change the file? Pin
Wes Jones24-Mar-05 6:32
memberWes Jones24-Mar-05 6:32 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web06 | 2.8.190419.4 | Last Updated 12 May 2002
Article Copyright 2001 by Wes Jones
Everything else Copyright © CodeProject, 1999-2019
Layout: fixed | fluid