.

Introduction

FindFirstChangeNotification

ReadDirectoryChangesW

FindFirstChangeNotification

ReadDirectoryChangesW

ReadDirectoryChangesW

GetOverlappedResult: this requires an event object for each directory you'd like to monitor. .

this requires an event object for each directory you'd like to monitor. Using a completion routine: this requires that you provide a completion function (completion routine) that would be called by the system whenever a change occurs. .

this requires that you provide a completion function (completion routine) that would be called by the system whenever a change occurs. Using IO completion ports: in this method we associate handles of directories to be monitored with a completion port much like we associate it with sockets. This I think is more scalable/efficient than the two other methods and that's what we are implementing here.

Using the Code

#include "FileSysMon.h" ..... CFileSysMon myFileSysMon; if (!myFileSysMon.Init()) { MessageBox(0, _T("Initialization Error"), NULL, MB_ICONERROR); return 0; } if (myFileSysMon.AddPath(_T("c:\\FolderToMonitor")) != E_FILESYSMON_SUCCESS) MessageBox(hWnd, _T("Error adding file to monitoring list"), NULL, MB_ICONERROR); VECCHANGES vecChanges; while (myFileSysMon.GetQueuedStatus(vecChanges, INFINITE) == E_FILESYSMON_SUCCESS) //INFINITE or a timeout value in milliseconds { //vecChanges.at(i).strFilePath //if ((vecChanges.at(i).dwAction & FILE_ACTION_ADDED) == FILE_ACTION_ADDED) //if ((vecChanges.at(i).dwAction & FILE_ACTION_REMOVED) == FILE_ACTION_REMOVED) //if ((vecChanges.at(i).dwAction & FILE_ACTION_MODIFIED) == FILE_ACTION_MODIFIED) //if ((vecChanges.at(i).dwAction & FILE_ACTION_RENAMED_OLD_NAME) == FILE_ACTION_RENAMED_OLD_NAME) //if ((vecChanges.at(i).dwAction & FILE_ACTION_RENAMED_NEW_NAME) == FILE_ACTION_RENAMED_NEW_NAME) ..... }

How Does It Work

CreateIOCompletionPort

if (!(m_hIOCP = CreateIoCompletionPort( (HANDLE)INVALID_HANDLE_VALUE, NULL, 0, nThreads))) { m_nLastError = GetLastError(); return false; }

CreateIOCompletionPort

if (CreateIoCompletionPort(pDir->hFile, m_hIOCP, (ULONG_PTR) pDir->hFile, 0) == NULL) { m_nLastError = GetLastError(); CloseHandle(pDir->hFile); delete pDir; return E_FILESYSMON_ERRORADDTOIOCP; }

ReadDirectoryChangesW

if (!ReadDirectoryChangesW(pDir->hFile, pDir->pBuff, MAX_BUFF_SIZE * sizeof(FILE_NOTIFY_INFORMATION), bSubTree, dwNotifyFilters, &dwBytesReturned, &pDir->ol, NULL)) { m_nLastError = GetLastError(); CloseHandle(pDir->hFile); delete pDir; return E_FILESYSMON_ERRORREADDIR; }

if (!GetQueuedCompletionStatus(m_hIOCP, &dwBytesXFered, &ulKey, &pOl, dwTimeOut)) { if ((m_nLastError = GetLastError()) == WAIT_TIMEOUT) return E_FILESYSMON_NOCHANGE; return E_FILESYSMON_ERRORDEQUE; }

History

There are 3 main methods for monitoring the file system on a Windows machine. Kernel mode filesystem drivers, theAPI and theAPI. If the main purpose of your application is not monitoring the file system or bypassing/overriding file system IO operations then Kernel mode file system drivers would be too much unnecessary work.is a good alternative but it tells you that a change took place but not which file was changed or how (added, modified, removed..etc.)on the other hand, when called asynchronously, is reasonably efficient and provides detailed info on which file changed and how.There are also 3 approaches to usingasynchronously:First we create a completion port usingThen we associate each directory we would like to monitor with that completion port also usingAnd we callon the directory handle:Then we query the completion port for status messages:

13 JAN 11: first release.

.