Click here to Skip to main content
15,881,281 members
Articles / Desktop Programming / MFC
Article

How to get a notification if change occurs in a specified directory

Rate me:
Please Sign up or sign in to vote.
4.39/5 (27 votes)
3 Aug 20032 min read 169.8K   9.2K   47   16
This article discusses how to handle file system notification events.

Sample Image - DirCheck.gif

Introduction

Sometimes, its is very important to monitor events, occurring in some directory. For example, if new file was saved in a specified directory, the application must to do something.

Background

File system notification events can be obtained by the Win32 API function FindFirstChangeNotification (look more in detail in the MSDN). This function creates a change notification handle and sets up initial change notification filter conditions. A wait on a notification handle succeeds when a change matching the filter conditions occurs in the specified directory or subtree. After the wait has been satisfied, the application can respond to this condition and continue monitoring the directory, by calling the FindNextChangeNotification function and the appropriate wait function. When the handle is no longer needed, it can be closed by using the FindCloseChangeNotification function.

The classes

CNotifyDirCheck class holds notification events in the work thread and parse file tree for finding a new (changed) file. User must override the Action function of the base class or implement own notification callback. This callback has the following prototype:

UINT DefaultNotificationCallback(
CFileInformation fiObject,  //file (directory) information object
EFileAction       faAction,  //notification event type
LPVOID           lpData );  //user's data pointer

If the callback succeeds, the return value is 0. If the callback failed, the return value must be an error number (>0). Samples of the callback and virtual function Action exists in the code of the class CNotifyDirCheck.

Class CFileInformation is a useful API wrapping class that is developed to make file manipulation and to obtain information about files and directories in a simpler and easier way.

How to Use

  1. Create an object of CNotifyDirCheck.
  2. Create notification callback or override virtual function Action.
  3. Select directory.
  4. Add the user’s data pointer (if needed).
  5. Call method Run to start notification thread.
  6. Call method Stop to stop notification thread (or this method will be called in destructor).
CNotifyDirCheck m_ndc;
…
UINT DirCallback(...) {...}
...
m_ndc.SetDirectory( m_dir );//root directory
m_ndc.SetData( this );//user’s data
m_ndc.SetActionCallback( DirCallback );//user’s callback
…
m_ndc.Run();//start workthread
...
m_ndc.Stop();//stop workthread

Conclusion

I would like to mention thanks to CodeProject authors for many great ideas and useful source code. I'd be glad if somebody uses my class. Please let me know of any bugs that you have found and I will fix them in a future release.

References

  1. MSDN
  2. CodeProject - Files & Folders

License

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


Written By
Software Developer (Senior) Elmo Motion Control
Israel Israel
Software developer since 1992

Comments and Discussions

 
QuestionUnicode support Pin
Bruff20-Apr-19 6:52
Bruff20-Apr-19 6:52 
QuestionBig folder Pin
meocon3572-Apr-15 13:55
meocon3572-Apr-15 13:55 
QuestionLicense? Pin
dripfeed5-Mar-13 23:20
dripfeed5-Mar-13 23:20 
GeneralMultiple Notifications Pin
DoGuy10-Oct-05 3:31
DoGuy10-Oct-05 3:31 
Hi,

Here is a little modification that permit multiple notifications for these classes.

1) Add a new CfileInformation funtion in FileInformation.h
EFileAction CFileInformation::CompareFiles(P_FI_List oldList, P_FI_List newList, P_FI_List outList);


2) Add in FileInformation.cpp
EFileAction CFileInformation::CompareFiles( P_FI_List oldList,
P_FI_List newList,
P_FI_List outList
)
{
EFileAction faType = faNone;

POSITION newListPos = NULL;
POSITION oldListPos = NULL;

CFileInformation *newFI = NULL;
CFileInformation *oldFI = NULL;

int nNew = newList->GetCount();
int nOld = oldList->GetCount();

outList->RemoveAll();

if (nOld == nNew)
{
newListPos = newList->GetHeadPosition();
oldListPos = oldList->GetHeadPosition();
while (oldListPos != NULL && newListPos != NULL)
{
oldFI = oldList->GetNext( oldListPos);
newFI = newList->GetNext( newListPos);

if (*oldFI != *newFI)
{
outList->AddTail( newFI);
faType = faChange;
}
}
}

else if (nOld > nNew)
{
BOOL isFind;

oldListPos = oldList->GetHeadPosition();
while (oldListPos != NULL)
{
oldFI = oldList->GetNext( oldListPos);

isFind = TRUE;

newListPos = newList->GetHeadPosition();
while (newListPos != NULL)
{
newFI = newList->GetNext( newListPos);

if (*oldFI == *newFI)
{
isFind = FALSE;
break;
}
}

if (isFind)
{
outList->AddTail( oldFI);
faType = faDelete;
}
}
}

else if (nOld < nNew)
{
BOOL isFind;

newListPos = newList->GetHeadPosition();
while (newListPos != NULL)
{
newFI = newList->GetNext( newListPos);

isFind = TRUE;

oldListPos = oldList->GetHeadPosition();
while (oldListPos != NULL)
{
oldFI = oldList->GetNext( oldListPos);

if (*oldFI == *newFI)
{
isFind = FALSE;
break;
}
}

if (isFind)
{
outList->AddTail(newFI);
faType = faCreate;
}
}
}

return(faType);
}

3) Modify the UINT NotifyDirThread( LPVOID pParam) in NotifyDirCheck.cpp like this:

UINT NotifyDirThread( LPVOID pParam)
{
BOOL bStop = FALSE;

HANDLE hDir = NULL;

CNotifyDirCheck *pNDC = (CNotifyDirCheck *)pParam;

FI_List newFIL,
oldFIL;

FI_List fileList;

EFileAction faAction;

CFileInformation fi;


if (pNDC == NULL)
return( 0);

hDir = FindFirstChangeNotification( pNDC->GetDirectory(),
TRUE,
FILE_NOTIFY_CHANGE_FILE_NAME |
FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_SIZE |
FILE_NOTIFY_CHANGE_LAST_WRITE |
FILE_NOTIFY_CHANGE_ATTRIBUTES
);

if (hDir == INVALID_HANDLE_VALUE)
{
ErrorMessage( _T( "FindFirstChangeNotification"));
return( 0);
}

while( pNDC->IsRun())
{
CFileInformation::RemoveFiles( &oldFIL);
CFileInformation::EnumFiles( pNDC->GetDirectory(), &oldFIL);

bStop = FALSE;

while( WaitForSingleObject( hDir, WAIT_TIMEOUT) != WAIT_OBJECT_0)
{
if (!pNDC->IsRun())
{
bStop = TRUE;//to end
break;
}
}

if (bStop)
break;//to end

Sleep( WAIT_TIMEOUT);

CFileInformation::RemoveFiles( &newFIL);
CFileInformation::EnumFiles( pNDC->GetDirectory(), &newFIL);

// Sleep( WAIT_TIMEOUT);

// faAction = CFileInformation::CompareFiles( &oldFIL, &newFIL, fi);
faAction = CFileInformation::CompareFiles( &oldFIL, &newFIL, &fileList);

if (!IS_NOTACT_FILE( faAction))
{
NOTIFICATION_CALLBACK_PTR ncpAction = pNDC->GetActionCallback();

POSITION fileListPos = NULL;

fileListPos = fileList.GetHeadPosition();

while (fileListPos)
{
fi = fileList.GetAt( fileListPos);

if (ncpAction) //call user's callback
bStop = (ncpAction( fi, faAction, pNDC->GetData()) > 0);

else //call user's virtual function
bStop = (pNDC->Action( fi, faAction) > 0);

if (bStop)
break;//to end

fileList.GetNext( fileListPos);
}
}

if (FindNextChangeNotification( hDir) == 0)
{
ErrorMessage( _T( "FindNextChangeNotification"));
return( 0);
}
}

//end point of notification thread
CFileInformation::RemoveFiles( &newFIL);
CFileInformation::RemoveFiles( &oldFIL);

return FindCloseChangeNotification( hDir);
}



With these 2 modifications, your NotificationCallback( CFileInformation fiObject, EFileAction faAction, LPVOID lpData) will be call for all files ADDED, ROMOVED or MODIFIED in one notification.

Dominique Guy.
dguy@axalto.com
GeneralRe: Multiple Notifications Nice Job Pin
bruno leclerc2-Feb-06 23:58
bruno leclerc2-Feb-06 23:58 
GeneralRe: Multiple Notifications Nice Job Pin
acjohnson5517-Jul-06 12:17
acjohnson5517-Jul-06 12:17 
GeneralMultiple notifications Pin
Madhu Reddy9-Mar-05 1:23
Madhu Reddy9-Mar-05 1:23 
Generalsome bug... Pin
boy061212-May-04 20:35
boy061212-May-04 20:35 
GeneralGreat help! Pin
mr.axe6-Oct-03 8:39
mr.axe6-Oct-03 8:39 
GeneralHello Monster! Pin
SUMIGOR13-Aug-03 8:53
SUMIGOR13-Aug-03 8:53 
GeneralRe: Hello Monster! Pin
jukov23-Aug-03 21:01
jukov23-Aug-03 21:01 
QuestionIs this better? Pin
Anonymous4-Aug-03 7:35
Anonymous4-Aug-03 7:35 
AnswerRe: Is this better? Pin
vcplusplus5-Aug-03 10:14
vcplusplus5-Aug-03 10:14 
GeneralRe: Is this better? Pin
Member 215474313-Oct-05 17:15
Member 215474313-Oct-05 17:15 
GeneralERROR N50 Pin
vcplusplus4-Aug-03 6:54
vcplusplus4-Aug-03 6:54 
GeneralRe: ERROR N50 Pin
jukov6-Aug-03 21:49
jukov6-Aug-03 21:49 

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.