Archive: UpgradeDLL macro not foolproof?


UpgradeDLL macro not foolproof?
As appealing as it is to use the version checking logic to avoid "unnecessary" DLL installs, there seems to me to be an easy way for an end-user to get in trouble:

If a user does an uninstall of your app which results in "scheduled" removal of one or more in-use DLLs, and then does a new install of your app (with the same DLL versions) WITHOUT REBOOTING, they will end up not having any of the "in-use" DLLs on their system when they do get around to rebooting!

This happens because the install (after the uninstall) still "sees" the DLLs (which are set to be deleted at the next reboot) and, not detecting a version upgrade, fails to expand/rename any of the DLLs in question... but at the next reboot, these DLLs get deleted!

So it looks to me like the "safe" thing to do is to always bring the "new" DLL in, though you can still try to be friendly and not require a reboot if there are no "in-use" problems. Remember, a cool install package like NSIS is there to make things easy for the user (*and* us), not create new ways for them to get themselves in trouble. :)

In my own case, I have a Shell Extension DLL which implements a property page for my own shortcut type, and whether this DLL will be "in-use" varies across Windows versions... on everything before 2000, just having one of my shortcuts on the desktop is enough to make my DLL always "in-use". On 2000 and XP, I need to actually cause the display of my property page to "lock" my DLL (good ol' Windows Explorer).

As always, corrections/discussion is invited!


You forgot about one thing.

If you extract the DLL using a normal File command, it will still be removed on reboot, because it is on the delete list.

A possibility is to let the uninstaller write a temp file that will be removed on reboot, so you can prevent the installer from starting when the file exists.

If you are using own DLL's with unique file names, you don't have to do all the version checking. But for shared DLL's, you always have to check. Overwriting new DLL's with older versions can break up other applications.


First, thanks for responding, Joost, since this WAS posted to you. :)

"If you extract the DLL using a normal File command, it will still be removed on reboot, because it is on the delete list."

Of course, but then that isn't what one would do - you would bring it in under some other name and RENAME it. The main idea here is to not skip this whole process based just on a version check.

"A possibility is to let the uninstaller write a temp file that will be removed on reboot, so you can prevent the installer from starting when the file exists."

Clearly, one can employ various schemes to work around the fundamental problem(s) with only using a simple version-check scheme, including, say, trying to detect which of your DLLs may be scheduled for removal at the next reboot, but that isn't the point here... the point of view I am trying to support is that we, as developers, should do what we can to not make things difficult for the user, whether the "fault" lies with them or us.

Regarding the possible solution you mention, sure, it could work, but then you will have to tell the user that, no, they CAN'T go through a "normal" uninstall - install sequence without rebooting in between... remember, users are somewhat "conditioned" to doing a reboot at the end of some installs, but are much more rarely told that they have to reboot after an uninstall.

The simple "bring in yourdll.tmp and rename it to yourdll.dll" (which MAY require a reboot to complete) works, and allows for the expected uninstall followed by an install to proceed without ugly surprises. :)

" If you are using own DLL's with unique file names, you don't have to do all the version checking. But for shared DLL's, you always have to check. Overwriting new DLL's with older versions can break up other applications."

Obviously, things get trickier in the "shared DLL" case(s)... and one certainly never wants to overwrite new DLLs with old! That is sort of the definition of the classic "DLL Hell".

So, yes, in the "shared DLL" cases, other mechanisms need to be employed, but that STILL doesn't include just simple version checking... isn't it cool that we can now use (in XP and Server 2003) "Side-By-Side assemblies" to avoid all this? Life will be SO much easier. :)


The problem is not related to UpgradeDLL. If the file is on the delete list for the next reboot, it will always be removed. Rename won't solve the problem, when the DLL is not in use anymore, it will be overwritten directly.

I see no other option than locking the installer until the system has been restarted. I have seen other installer doing this before.

If you can think of a better solution, keep me informed :D


You are right, there is not a problem with UpgradeDLL as such... I have just been trying to shed light on some implicit assumptions in its logic.

So, please let me know if I have any of this wrong:

The model is to always, in the installer, bring in your DLL with a "tmp" name, and then do a "Rename /REBOOTOK ..." to the "real" DLL name, while the uninstaller does a "Delete /REBOOTOK ..." on the DLL when IT runs.

Now, running the uninstaller and the installer back-to-back, we have the following cases:

1) the uninstaller deleted your DLL straight away, since it wasn't "in-use" - in this case, it is NOT on the delete list - it is just gone. When the installer runs, the rename proceeds without conflict and all is well.

2) the uninstaller could NOT delete your DLL, because it was "in-use", and so it is placed on the delete list but is still present. When the installer runs, the rename fails, and is scheduled to happen at the next reboot - AFTER the delete has been processed (it is my understanding that this sequence WILL be maintained).

Am I still missing something? And yes, there is still potential for ugliness if the poor user tries to "stack" things more, by adding yet another uninstall - install sequence, BUT that "shouldn't happen", since they are invited in no uncertain terms to REBOOT at the end of the initial install operation! :)


Right. It should be renamed after deleting, so there is no problem.

If the DLL's are not always in use (no shell extension, normal app that is running), the uninstaller should ask to close the application.


Can't an installer remove a file from the delete list?

Non NSIS Related: According to the Glossary Of Forum Terms, i'm a Regular: 'Someone who lives on the forums. Their diet usually consists of waffles, syrup and Mountain Dew. Reknowned for their general friendliness, regulars are far from being extinct. But please, support their cause by donating generously to the Poor Boy Foundation.'
Poor me! :p


Originally posted by virtlink
Can't an installer remove a file from the delete list?
Well, if you really wanted to mess with the "pending for reboot" file operations (although I would think that is a Bad Idea(tm) ;) , you can check out the documentation of MoveFileEx, which describes where the "pending" file list is stored in both the NT-class versions (the registry) and the 9x-class style (WININIT.INI).

The MoveFileEx description raises another question (possibly for kichik): since MoveFileEx supports [empty] directories, why doesn't RMDir? Is it because the 9x-style of doing things doesn't work for directories (it is not obvious from the doc)? Note that if that isn't the reason, the definition of the remove-directory-at-reboot logic makes the facility useful: the directory only needs to be empty when its turn for deletion comes up, i.e., any files in it have been deleted first.

Ack! I left out a key point in my reply above!

"... since MoveFileEx supports [empty] directories, why doesn't RMDir?"

was supposed to say

"since MoveFileEx supports removing [empty] directories at reboot time, why doesn't RMDir [support the /REBOOTOK switch]?"

Doesn't that make a bit more sense? :)


That is on the TODO list for the next beta version.


Sweeet! :D

Then my uninstallers that need to do a delayed remove of an "in-use" DLL from my app directory could really get rid of everything!


Was going to do it a couple of days ago and got caught up in another thing... Uploaded (source only).