InstalledFileAction exiting with an error leaves MSI application in Control Panel

Apr 21, 2015 at 3:25 PM
I have a custom executable that I'm launching as an InstalledFileAction, and the executable is returning an exit error code (non zero). This part is fine, I know why the error code is returned however the MSI still shows the application as installed in Control Panel. That should not be since the install failed.
I can certainly fix the error inside my custom executable however I also want to handle any other unexpected errors, and not leave a partially installed application in Control Panel. I hope I'm making sense :)

This is how the executbale is being called:
new InstalledFileAction(@"MySetup.exe", "[INSTALL_ARGS]", Return.check, When.After, Step.InstallFinalize, Condition.NOT_BeingRemoved); //install or repair

I also tried "When.Before, Step.InstallFinalize" and the above issue is not happening, but the MySetup.exe is not even called, because apparently the file is not yet copied to the target directory at this stage.

Any ideas?

Thanks Oleg for the 2 other fixes from yesterday (files starting with a numeric, and the INSTALLDIR that was not removed in some cases). They both appear to work now.
Apr 21, 2015 at 7:11 PM
Answering my own question (I think)...
It looks that "When.After, Step.InstallExecute" does the trick.
I arrived at the conclusion that "When.After, Step.InstallFinalize" should probably never be used to call an executable as part of the install.
This does not look to be related to Wix# at all, but maybe just the way Wix handles things...
Apr 24, 2015 at 3:30 AM
You are right.
I have updated the codebase. Now InstalledFileAction defaults are set to "When.After, Step.InstallExecute".
And Compiler now emits warning if the defaults are changed.

Txs.
Apr 24, 2015 at 5:07 PM
Well yes and no :)
I just discovered that when you RE-install something on "When.After, Step.InstallExecute", the MSI does not repair files that are missing.
It does repair any missing files on "When.After, Step.InstallFinalize" but this has the drawback mentioned earlier (that is - if the install fails, it leaves the entry in Control Panel).
Still trying to figure this out...
Apr 28, 2015 at 3:32 PM
Edited Apr 28, 2015 at 6:46 PM
Oleg, do you have an example in Wix# for this scenario?

1) MSI copies files to a directory. One of these files being "Setup.exe". Another one being "ntrights.exe".
2) MSI then runs a ManagedAction to run "Setup.exe" which in turns calls "ntrights.exe"
3) The "ntrights.exe" file then gets deleted by "Setup.exe" (for security reasons)

...
Later on, MSI is repaired, and the above steps should execute without errors.

The problem I'm having is that the repair fails because the "ntrights.exe" file is missing.
Shouldn't the MSI extract / copy the "ntrights.exe" file again on repair?

Thanks!
Apr 29, 2015 at 1:44 PM
I do have a solution for you, but I really want to discourage you from using it. :)

Solution:
  • Add your ntrights.exe to your project as Binary not as File
  • Have your managed custom action executed during both install and repair. You can have it at any step. Even Before InstallInitialize.
  • In the managed CA extract ntrights.exe from MSI int a temp dir, run and delete it.
Have a look at 'Simplified Bootstrapper' sample. It does exactly that.

Architectural considerations:
Your all problems (in fact everything described in this thread) are caused by the fact that you are trying to push your setup to do something that it's not design to do - Configuration.
Do you remember the fundamental design principle "Separation of concerns"? Apply it to your problem. Setup (any setup) is concerned about deploying of the files. Full stop. Configuration is not part of the setup but a part of the application initialization stage. That is why MS introduced a great deployment guideline (as part of the Vista application certification). This guideline requires the applications to configure the user profile on the first start of the installed application but not at the installation. The benefits are enormous:
  • No need to have a complicated setup UI as no need to interact with the user after the last file is deployed. The user interaction is delegated to the application executable. You can still start the app (in config mode) at the last step of the installation.
  • Simple path for reconfiguration of the application. Start it at any time in the config mode without resorting to the "Repair", which effectively installs the product again for no real reason.
  • App upgrade is incredibly simple. Upgrade binaries and the app itself will pick the prev app settings if present.
  • Licencing, target system validation all becomes very straight forward.
  • ...
The deployment solution designed this way becomes something that I would call a "Lean Setup". The latest Wix# dev effort is going towards this direction.

If you agree with this concept than you can completely remove your ntrights.exe form the setup and embed it as a resource in your app. And on the first start extract ntrights.exe in the temp folder, run...... you know the drill.

Good luck.
Apr 30, 2015 at 2:58 PM
Thanks Oleg, but I would rather use the native/built-in MSI repair functionality so it works with all my deployed files, not just the "ntrights.exe" file.

About the suggestion to execute the managed custom action during both install and repair before InstallInitialize, this is not working because the files are not copied yet at this stage... unless I'm doing it incorrectly? This is the action that I use:

new ManagedAction("MySetupExeAction", "MyExternalDll.dll", Return.check, When.Before, Step.InstallInitialize, Condition.NOT_BeingRemoved, Sequence.InstallExecuteSequence);

If I change the above to use Step.InstallExecute, the action is executed normally.

I guess I'll keep looking for a solution to address the repairs. Incidentally, I have also tried:
        Compiler.WixSourceGenerated += document =>
                                       document.Descendants("File")
                                               .ForEach(e => e.SetAttributeValue("KeyPath", "yes"));
and:
        WixSharp.Property reinstallMode = new Property("REINSTALLMODE", "vamus");
        properties.Add(reinstallMode);
and using:
MsiExec.exe /fvamus "{xxxxxxxxxxxxxxxxxxxxx}" /quiet /norestart /l*vx ".\Test repair.log"

...but repairs still do not work.
My custom action executable does get called, but is failing because the "ntrights.exe" is not re-extracted by the MSI.

I'll let you know if I find a solution to this. Likewise if you know... :)
May 1, 2015 at 2:16 AM
...but I would rather use the native/built-in MSI repair functionality so it works with all my deployed files, not just the "ntrights.exe" file.
I expected this answer :)
This is exactly the problem. Repair means 'redeploy' and your ntrights.exe has nothing to do with the deployment (I guess it is some kind of OS user right configuration). Thus you cannot reconfigure/update the user rights unless you reinstall the all files. This is the reason you never configure user account as part of the email client installation. You can auto-start the "add account" wizard after the install but you never do the actual account configuration from the install/repair activity.

If you try to get your application "certified for Windows Vista+" you would have real problems because of the deployment strategy you chosen.

Anyway, enough of this. This discussion is purely theoretical. You will choose the approach you think is the most appropriate for the situation. :)

... this is not working because the files are not copied yet at this stage...
Why? I suggested "Add your ntrights.exe to your project as Binary not as File". Meaning it is never-ever going to be installed. "In the managed CA extract ntrights.exe from MSI" means you need to extract the file from the database (msi) not to find it among installed files. 'Simplified Bootstrapper' sample does exactly that. It shows how execute the file which is embedded into msi but is not destined to be installed.