A common problem that you, as a developer, may run into on Windows is the need to replace a file that is in use. This commonly happens with installations and upgrades, but can of course also happen in general use.
In earlier versions of Windows, when most users worked in full administrator mode, the MoveFileEx function with the MOVEFILE_DELAY_UNTIL_REBOOT flag was suggested by Microsoft as a great approach for updating files that were in use. This flag would, as it sounds, allow you to schedule the move or deletion of a file at a time when it was (pretty much) guaranteed to succeed.
For example:
// This will delete c:\temp\coolcorelibrary.dll on the next reboot
MoveFileEx(“c:\\temp\\coolcorelibrary.dll”, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
Nowadays, of course, this flag does not work unless you are running in the context of an administrative user. That’s great, you think, this will still work for my install or upgrade program.
But don’t trust that feeling of security. Things are never as easy as they seem. I first realised that this was a problem when researching issues occasionally reported by some of our Keyman Desktop users.
Take this scenario:
- A user, Joe, decides to uninstall your awesome app CoolCoreProgram.
- The uninstaller finds that a critical file (let’s call it coolcorelibrary.dll) is in use and can’t delete it
- Installer calls a MoveFileEx with MOVEFILE_DELAY_UNTIL_REBOOT to schedule deletion of coolcorelibrary.dll.
-
Would you click Restart Now? Why not leave it till later? The uninstall completes and presents Joe with the dreaded “Hey, you need to restart Windows now” dialog.
- Poor unhappy Joe swears and cancels the restart, and continues his work. He can’t see any good reason to restart Windows…
- A short while later, Joe realises that he actually loves CoolCoreProgram and so he downloads and reinstalls the latest, greatest version (now with extra shiny!)
- Shortly thereafter, Joe finishes up for the day and turns off his computer.
- The next morning, after Joe starts up his computer, Windows notes its instructions from the previous day, and obediently deletes coolcorelibrary.dll.
- And now Joe is now really, really unhappy when he tries to start CoolCoreProgram and he gets a bizarre coolcorelibrary.dll missing error.
Who is Joe going to blame? Is it his fault for not restarting? Is it yours for using cool APIs such as MoveFileEx? Or is it a woeful confluence of unintended consequences?
This is probably one of the simplest scenarios in which this problem can crop up. Things get much worse when you talk about shared libraries, fonts, or other resources which may be in use by the system, or multi-user systems.
Some reasons I have encountered for files in use:
- Program is still running (duh!)
- System has locked the file (common with fonts, hook libraries)
- Antivirus or security software is scanning the file
- Another application is trying to update the file (i.e. don’t run multiple installers at once)
One possible fix would be to check and update the registry key
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations for listed file before creating or updating them. But that’s a big performance and reliability hit. I can’t say that solution sits well with me.
Another idea is to block further install and upgrade tasks until Joe actually does restart his computer, for example with a registry setting or a RunOnce entry. But that’s going to make Joe hate me even more than he already does!
Some scenarios can be fixed with the Windows Installer automatic repair functionality. But that assumes access to the original source files is always possible. So that’s not a general solution.
I don’t really have a good general solution to this problem. Any ideas?