ReadDirectoryChangesW is evil

I have some code that uses ReadDirectoryChangesW() to monitor when files are modified, renamed, or deleted. I’ve gotten a few bugs from our testers saying that the right thing isn’t happening, but I’ve been unable to repro them.

Today, I finally got a repro, and figured out the cause.

If you read the docs for ReadDirectoryChangesW(), you’ll find that the file change information is passed back in a FILE_NOTIFY_INFORMATION structure. In the docs for the FileName field, there’s a single line that says:

If there is both a short and long name for the file, the function will return one of these names, but it is unspecified which one.

For the youngsters, in ancient times, all DOS (and windows) filenames were short. You got 8 characters for filename, a period, and then 3 for the extension, giving you the “8.3” format for filenames. When long filenames were introduced, you needed a way to not break every app in existence, so a mapping was developed that took a long filename and gave you a unique short filename for a given directory. If you’ve ever seen a name like “graph2~1.jpg”, that’s a short filename.

Short filenames really aren’t seen much these days, but apparently they’re still alive and well in some places. And the bad part is that not only is it unspecified whether it will return a short or long name, the one that it returns isn’t invariant for a single file. In my case, if you renamed a file, you got a notification with the long filename, where if you deleted the file, you got a notification with the short filename. For some files… 

For other files, you got the long filename in both cases, which was why I was having so much trouble getting a repro.

That behavior is evil.

The fix is to store both the long and short names in my list of files to watch, so I can detect both cases.

Maybe Ray can tell me why things work this way.

Comments (5)

  1. G. Diggity Doo says:

    I have one word for you : FileSystemWatcher. OK, its not a word but it is a .NET BCL class.

  2. Jason Bock says:


    You’re assuming Eric has the ability to use the .NET Framework. Maybe he doesn’t have that option…

  3. M Knight says:

    GetFullPathName sounds like what you want.

    Especially if you get the odd case of mixed short & long names in the directory structure when handling files.

  4. G.,

    Jason is correct. Ironically, all the code I’m writing for work is "old school" – native C++, WTL, and Win32.


    GetFullPathName doesn’t work if the file is already deleted, which is the situation I’m in.

  5. Simon Steele says:

    We had exactly the same problem and opted for the same solution.

    Unfortunately, FileSystemWatcher suffers from the same problems (we were writing a .NET app). Smells like a leaky abstraction!