Why does a non-recursive Read­Directory­ChangesW still report files created inside subdirectories?

A customer used the Read­Directory­ChangesW function to monitor a directory for changes, asking for notifications only for changes directly in the directory being monitored (bWatchSubtree = false). But they found that the Read­Directory­ChangesW function reported a change even when they created a file in a subdirectory, rather than in the directory being monitored.

For example, if they asked to monitor the directory C:\dir1, and a file was created at C:\dir1\dir2\file, the Read­Directory­ChangesW function reported a change, even though the file was created in a subdirectory, and the request was for a non-recursive monitor.

What gives?

We saw some time ago that the purpose of the Read­Directory­ChangesW function is to allow you to maintain a local copy of the contents of a directory: The idea is that you make an initial pass over the directory with Find­First­File/Find­Next­File, and then you use the notifications from the Read­Directory­ChangesW function to make incremental updates to your local copy.

And what happened here is that the contents of an enumeration of the C:\dir1 directory did in fact change. What changed is the last-modified date on C:\dir1\dir2!

Comments (11)
  1. I actually guessed this answer before I got to the end of the article. I’ve noticed this in the past on sub-directory dates on my system.

  2. KeyJ says:

    Two questions come to my mind:

    – What if something changes between FindFirstFile() and the first call to ReadDirectoryChangesW()?

    – Why is there no ReadDirectoryChangesA()?

    1. 1) Ideally you should call ReadDirectoryChangesW() first, kick off an update pass manually, then have ReadDirectoryChangesW() kick off the same update pass when it’s called, ideally with some locking mechanism in place to keep it from updating the same data simultaneously (unless your code doesn’t have that particular issue).

      2) I sincerely doubt that ReadDirectoryChanges existed back in the days of FAT. That would’ve required the OS to implement its own polling mechanisms, which would’ve add complexity and consumed precious CPU, especially with DOS compatibility the way it was back then. It looks like this was introduced in Windows XP/2003 (maybe earlier, 2000 timeframe? MSDN isn’t always reliable for describing when functions were actually introduced).

      1. 😑 Why no auto-paragraph detection? Or edit button? Le sigh.

        1. Darran Rowe says:

          There is paragraphs, I can see them perfectly fine for your post.
          The problem seems to be that if you are logged in, your own posts don’t seem to have paragraphs.

      2. Not sure why you’re saying the OS needs to poll to detect changes on FAT volumes, because any changes to FAT volumes came from the OS itself anyway.

        1. True. I think I meant to say “hooking” instead; I didn’t think too deeply into that particular sentence.

      3. JAS says:

        This is a pattern you’ll see everywhere in computer science. If you’re watching incremental updates, begin subscribing BEFORE you make your base copy of whatever is being updated.

  3. Joshua says:

    I thought I read that ReadDirectoryChangesW could have spurious wakeups. Maybe not.

  4. IanBoyd says:

    Is there a shell equivalent of ReadDirectoryChangesW, to monitor an IShellFolder (or an IShellItem of a folder) for changes?

    Not everything in the Shell namespace corresponds to a file system directory. For example: my phone

    1. ranta says:

      SHChangeNotifyRegister looks relevant. It requires a PIDL though, but I suppose you can get that from SHGetIDListFromObject if you have an IShellFolder.

Comments are closed.

Skip to main content