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.