Home » Win32 » ReadDirectoryChangesW

ReadDirectoryChangesW

Just find a attractive API unexpectedly, ReadDirectoryChangesW can be used to watch a directory. Whenever there occurs an operation on/inside it, we can get notified with information of the operation which file/subdirectory is on, and even their names. Someone on the CodeProject has already attached a wrapped library to do the same thing, with calling ReadDirectoryChangesW under the hood. 🙂

After survey the MSDN, I also found another 3 API group used to watch a directory: FindFirstChangeNotification, FindNextChangeNotification, and FindCloseChangeNotification. The shorti coming of these 3 APIs is that they seem not be able to get the enough information on what happened there.

Below is the simplest demo code used to watch a directory, I use it in a synchronous way. (Some advanced usage of it will involve IO Completion Routine, but since it is too small here, I don’t think IO Completion is suitable for my demo code here).

#include "stdafx.h"
#include "windows.h"

void DumpChangesInfo(const PFILE_NOTIFY_INFORMATION fni);
void StartWatchDirectory(const TCHAR * strDirectoryName);

int _tmain(int argc, _TCHAR* argv[])
{
 if (argc != 2)
  return 0;
 StartWatchDirectory(argv[1]);
 return 0;
}

void StartWatchDirectory(const TCHAR * strDirectoryName)
{
 HANDLE hDirectory;

 hDirectory = CreateFile(
  strDirectoryName,               // Directory name/path
  FILE_LIST_DIRECTORY | FILE_TRAVERSE | GENERIC_READ, // Desired Access
  FILE_SHARE_WRITE | FILE_SHARE_READ,       // File shared mode
  NULL,
  OPEN_EXISTING,
  FILE_FLAG_BACKUP_SEMANTICS,          // Flags and Attributes
  NULL
  );

 if (hDirectory == INVALID_HANDLE_VALUE)
 {
  printf("Error Code[%d]: Open Directory Failed…\n", GetLastError());
  return;
 }

 BYTE buffer[1024] = { 0 }; // hardcode the length of the buffer, ReadDirectoryChangesW may return 0 in dwBytesRet.

 BOOL bResult = FALSE;
 FILE_NOTIFY_INFORMATION * fni = NULL;
 DWORD dwBufferLen = 0;
 DWORD dwBytesRet = 0;
 DWORD dwNotifyFilter =
  FILE_NOTIFY_CHANGE_FILE_NAME |
  FILE_NOTIFY_CHANGE_DIR_NAME |
  FILE_NOTIFY_CHANGE_ATTRIBUTES |
  FILE_NOTIFY_CHANGE_SIZE  |
  FILE_NOTIFY_CHANGE_LAST_WRITE |
  FILE_NOTIFY_CHANGE_LAST_ACCESS |
  FILE_NOTIFY_CHANGE_CREATION |
  FILE_NOTIFY_CHANGE_SECURITY; // Notify for every operations

 printf("Directory Changes is starting…\n");

 do
 {
  ZeroMemory(&buffer, 1024);
  bResult = ReadDirectoryChangesW(
   hDirectory,     // Directory handle
   (LPVOID)&buffer,   // Buffer
   1024,       // Length of the buffer
   TRUE,       // If watch sub directory
   dwNotifyFilter,    // NotifyFilter
   &dwBytesRet,    // Number of Byte returned
   NULL,       // OVERLAPPED structure
   NULL       // IO Completion Routine
   );

  if (bResult == 0)
  {
   printf("Error Code[%d]: Read Directory Changes Failed…\n", GetLastError());
   break;
  }
  fni = (PFILE_NOTIFY_INFORMATION)&buffer;
  DumpChangesInfo(fni);
 } while(bResult);

 printf("Directory Watcher is shutting down…\n");
 CloseHandle(hDirectory);
}

void DumpChangesInfo(const PFILE_NOTIFY_INFORMATION fni)
{
 // FileNameLength returned in PFILE_NOTIFY_INFORMATION is a WCHAR * without ‘0\’ as its termination.
 WCHAR * strFileName = (WCHAR * )malloc(fni->FileNameLength + sizeof(WCHAR));
 wcscpy(strFileName, fni->FileName);
 strFileName[fni->FileNameLength/sizeof(WCHAR)] = _T(”);

 TCHAR strAction[20];
 memset(&strAction, ”, 20 * sizeof(TCHAR));
 switch (fni->Action)
 {
 case FILE_ACTION_ADDED:
  _tcscpy(strAction, _T("ADD"));
  break;
 case FILE_ACTION_REMOVED:
  _tcscpy(strAction, _T("REMOVED"));
  break;
 case FILE_ACTION_MODIFIED:
  _tcscpy(strAction, _T("MODIFIED"));
  break;
 case FILE_ACTION_RENAMED_OLD_NAME:
  _tcscpy(strAction, _T("RENAMED"));
  break;
 case FILE_ACTION_RENAMED_NEW_NAME:
  _tcscpy(strAction, _T("RENAMED"));
  break;
 }

 _tprintf(_T("\tFile/Directory:\t%s -> %s\n"), strFileName, strAction);
 free(strFileName);
}

[Update] Just a minute ago,  I found another guy posted a more object-oriented sample code >”<
http://blog.vckbase.com/bruceteen/articles/229.html

One thought on “ReadDirectoryChangesW

  1. Wow, I was wondering how Windows Media Player watched a media folder changes to update its media content, it maybe also use this ReadDirectoryChanges to do that.
     
    Helpful.

Leave a comment