The installer I'm writing using WiX 3.0 uses a RegistryValue element to modify an existing registry value (originally written by our main product). I'm trying to figure out a way to restore the registry value when the user uninstalls my utility. I'd like to avoid using a custom action, but that might be the only recourse? TIA.
I did this. The registry value in question was the application associated to a file extension, but it could be any registry value.
My first idea was to use a "custom action" for install and uninstall to preserve and restore, respectively, the associated regy state. This seemed simple enough.
I created a setup project in VS2008 and built the CA's as javascript files. The "on install" script grabbed the existing regy value and stashed it into a well-known place. The "on uninstall" script would look in the well-known place, and then put the value found there, back in the original location. Easy, right?
There were two problems:
the script that ran during install, to preserve the pre-existing registry value, runs AFTER the registry has already been updated with the values for the newly installed thing. So it preserved the new setting instead of the setting that was there before the MSI ran. Not useful.
The script that runs during uninstall, runs AFTER the registry values, and in fact the entire directory subtree,
have been deleted. Including the stashed value. So it had lost its state.
To solve that I wrote another script that re-orders the custom actions so they run at the proper times.
There's actually one more twist. Obviously, the "Restore" script (on uninstall) won't work if it is run after the registry entries for the app have been deleted. I can't remember now, why... but I also determined that this script could not run before that. Somehow that wasn't working either.
So, I modified the MSI to run the restore script twice. In phase 1, it transfers the stashed value to a "parking lot" in the registry. Then the application's Keys and Values in the registry get deleted, but the parking lot remains. In phase 2, outside the transactional protection, the restore script retrieves the state from the parking lot, restores the file association, and then deletes the parking lot.
I can't remember exactly why I needed to do this in 2 steps, but I remember fighting with it for a while before coming up with that solution.
The way it works in development:
- set the
on install
andon uninstall
CA's in the VS project - build the VS Setup project
- run the post-processing script that modifies the MSI.
When using the MSI, it's a little more complicated than I originally thought but it works.
If you are using WiX, you may have more control over the time and ordering of the steps, so may not need that post-processing step.
Finally, you said you wanted to avoid a CA. To me, CA's are avoided because they are painful to produce in C++, and producing them in .NET is often inappropriate. But, it's pretty simple to use Javascript for CA's. Some people think script is the wrong tool for the CA job. I think that's wrongheaded. I think script is a very good tool for this purpose. And once you can accept script as a good tool, then you don't need to hold your nose about creating a custom CA.
The registry table is incapable of writing a registry value during an uninstall so it is correct that this must be done via custom action. I am of the opinion that using script is bad. Whether you choose to listen is up to you. I can tell you that just the other day I was called into to trouble shoot a situation where some wrote a vbscript CA that was failing because the file system object had been unregistered as part of a security lockdown process.
I suggest C++ or C#/DTF depending on your needs.