How can I write to a file only as long as nobody’s looking?

A customer wanted to know how to detect that the user has opened Notepad to view a particular file. They had come up with method based on polling and sniffing the Notepad title bar, but they found that it consumed a lot of CPU. (They hadn’t noticed yet that it doesn’t localize, and that it can trigger false positives since Notepad shows only the file name and not the full path in the title bar.)

Okay, let’s step back and make sure we understand the problem, because this sounds like the sort of thing where the customer is looking for an answer rather than a solution. After all, why Notepad? What about some other text editor? What about Explorer’s preview pane?

The scenario here is that the program is generating some sort of output file, and they want the program to exit if somebody double-clicks the output file in an attempt to open it in Notepad. The customer wasn’t specifically interested in Notepad, but since that was the most common case, that’s all that they were really interested in.

One option is to open the file in FILE_SHARE_READ mode. This allows other applications to open the file for reading even while you are writing. If, on the other hand, you expect the user to try to edit the output file and save the result, then they will either encounter a sharing violation (if you opened in deny-write mode) or overwrite the changes that the generator program had made in the meantime.

The customer said that they were fine with the program just exiting if somebody tried to look at the output file while it was being generated. In that case, they could use an oplock, specifically a Read-Write oplock. The Read-Write oplock grants you exclusive access to the file, but notifies you if somebody else tries to access the same file, so that you can close your handle and let the other application gain access.

Comments (9)
  1. Dan Bugglin says:

    Still a lot of sticky problems, such as the inability to tell background processes apart from user actions.  Most likely problem is real-time AV scanning the file as soon as its created triggering a false positive.  And of course Explorer will open the file when the user browses to the directory.

    I suspect the problem still has not been properly stated; we peeled away one layer of abstraction, but the question of WHY the program needs to care once the user sees the output file hasn't been answered.

    Perhaps the best way is to simply execute the output file itself; then you KNOW the user is looking at it.  It all depends on what you're trying to do.

  2. Joshua says:

    > And of course Explorer will open the file when the user browses to the directory.

    You could cheat and set FILE_FLAG_OFFLINE. This keeps explorer from issuing spurious open directives.

  3. The customer is retarded.

    Notepad opens files with FILE_SHARE_WRITE|FILE_SHARE_READ, to allow viewing of logs currently being written. The program that writes the log need to allow FILE_SHARE_READ. This will be the least amount of pain.

  4. word! says:

    It would be better if MS always used the Office approach, and created a ~$filename.ext file the filename.ext are opened. That way other applications can watch the file system for the temporary file.

    The simple solution for the customer is to open all files with Word instead of notepad.

  5. John says:

    Yeah, I don't really see the point of what they're trying to do.  It's sort of like Schrodinger's file or something.

  6. So, Raymond, did the customer explain why they wanted such a strange behaviour? Wasn't it the case of easy and impossible (or silly) parts of a solution?

  7. asdbsd says:

    > It would be better if MS always used the Office approach, and created a ~$filename.ext file the filename.ext are opened.

    Can't tell if you're joking, but no, it wouldn't be better. It's not an approach to detecting anything anyway. And I'm not sure what do you mean by MS (so it's okay if Notepads by other companies don't do this?)

  8. Anonymous says:

    Customer has a problem. They solve it by using sharing flags. Now they have two problems.

    I always open with FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE and live with the consequences. Been burned too many times by trying to be more restrictive and running into sharing violations. Sharing violation is a very user-hostile error code. Let the user open the file if they want. Deal with it.

  9. @Anonymous says:

    If you have log files in mind, yes. But if the files are used as a interface between programs (app A is writing it, app B is detecting this and reads it then) then no. As app A, don't allow app B to read the file as long as you haven't closed it. And as app B, open the file without FILE_SHARE_WRITE: You want to read the file in a consistent state, not an incomplete fragment.

    Also, when your app is a database, don't allow all this bad backup applications to read your file. The admins will think all is well when in reality, they have a file with inconsistent data in the backup.

Comments are closed.