WIX/MSI - Is it possible to make a package which leaves files that existed prior to installation when you uninstall
I am using WIX to create MSI's which install standard files (no exe, com's, DLL's etc). On some users computers some of the files in the MSI may already exist. During the install this is not a problem as MSI automatically updates files that are older etc. However, during uninstall I hit my problem.
It is easiest to explain with an example:
Joe Bloggs has "file B" on their computer. This file has not been installed by an MSI package and is not being track by the Microsoft Installer system in anyway. It is just a normal file on the computer.Joe Bloggs downloads and installs my package which contains "file A", "file B" and "file C". When he installs my package the Microsoft Installer system checks开发者_如何学Python "file B" and establishes it is identical to the "file B" in my package. It therefore does not replace "file B" but it does mark the MSI component that file B is part of as installed.
Joe Bloggs then decides he does not like my software so uninstalls my package. When he does this all 3 files are removed despite "file B" existing before my package was installed. My investigations have established that this is because the component that contains "file B" is marked as installed. Therefore when you uninstall the package it removes "file B".
This is all a bit technical but hopefully there is a WIX / MSi expert out there that knows a solution.
Thanks
Jim
If the files may already exist on the machine mark Component/@SharedDllRefCount="yes"
Windows installer will then automatically update the reference count if it finds the files already existing.
This is usually done through backup and restore custom actions.
Basically, you write a custom action which can copy some files based on the parameters it receives. You can then use this custom action twice in your installer:
- once during install to copy the original file in a backup folder (usually temp or application data)
- once during uninstall to copy the backup file back in the original location
This is a known "problem" when using MSI and is generally caused by a bad deployment strategy. The lacking reference counting is actually merely a symptom of an error-prone deployment approach.
In almost no case should your installer interfere with files that exist, or are likely to exist, before your installation is run. This includes files you have installed yourself that are reference counted by another of your own installers! Think cohesion & coupling, only one installer should deal with each file.
This general rule normally triggers a response along the lines of "our case is special". Trust me, it isn't. An application should use its own installation folder under Program Files, its own folder under user settings, and its own folder in shared settings. It should never replace or update shared files such as user dictionaries, exclusion lists or similar.
Often such an approach is to facilitate a "developer cruch" where config files need default values for the app to function. Completely unacceptable. The application itself can access shared files, even update them if it has access, but it can not replace the whole file with "default settings" or uninstall the whole file on uninstall. It is an application responsibility to create a running environment in the absence of basic configuration files. The files should then be generated from the applications internal defaults or be copied from read-only default files placed elsewhere.
If you share config files between different installers I would deploy them with a merge module, or simply set the component(s) that contain(s) the file(s) to "shared" and "permanent" and "never replace if already exists". Doing so should be the "easy fix" to the symptom you describe, even if you don't follow the deployment advice I recommend above.
The only way I know would be to hack the registry. If you increment the
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\SharedDLLS\<your dll name>
value after MSI has finished creating it, during uninstall MSI will see that the file is still in use and not remove it. This is pretty hacky, but it would work.
Or you could back the files up to another location, and on uninstall, copy them back.
Let me try to add a better answer than the one I wrote before. It seems I may not have read the question properly. I will try to break this down to a few options:
- It is possible to install files with Windows Installer that are then not tracked by reference counting at all. In other words they are never uninstalled. You do this by blanking out the component GUID containing the file.
- However, in my opinion files that are not tracked by MSI like this are really data files, and should not be dealt with in the normal way. Rather you can install them read-only to a shared location - for example Program Files - and then you can have your application copy them to each user's own data folder. They are then unreferenced by MSI and nothing will ever touch them. A longer discussion of this topic can be found here: http://forum.installsite.net/index.php?showtopic=21552
- saschabeaumont's Component/@SharedDllRefCount="yes" approach should also work (I haven't tested). What this setting does is to increment the legacy style SharedDll ref-counter in the registry (HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\SharedDLLs). As such it is a non-MSI reference feature and I wouldn't rely too much on it personally. MSI reference counting is done in a much more intricate way in HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer and HKCR\Installer among other places. Don't touch anything here directly!
A good rule of thumb with an MSI component, is that once you define a key path (absolute path in the registry or on disk) for a component, Windows Installer thinks it "owns the key path" and will reference count it. If the ref-count is 1 it deletes the key path and anything else that was in the component on uninstall.
精彩评论