MSI: How to conditionally change installation failure text? - wix

I have an MSI packages that executes a number of deferred custom actions during product install. If one of custom actions fails, installation ends with standard "Installation was cancelled..." window. This "cancelled" text is very confusing to end user, and i want to modify it in case my custom action fails an i know what is a problem.
I have tried to queue custom action after ExecuteAction but was faced with a problem: this action is executed only on installation success, but not on instllation failure! After that i have tried to queue my custom action to be executed at installation failure by assigning it a sequence number of -3. It is executed - but in server context, so it can't change text that is displayed in client context!
Is it any way to change this text? I need a custom action that is executed in client context (immediate mode) after installation fails.

Did you try to use Error Table?
(add your own error description into this table and return its code)

Take a look at src\ext\UIExtension\wixlib\WixUI_en-us.wxl in WIX source.
Find String ID of your text and add (for example into Product.wxs):
<String Id="STRING_ID_HERE">New text</String>

Related

Wix v4: Run custom action only on install

In wix 3 you could specify a condition inside the custom element.
In wix 4 the same element does not seem to accept inner text anymore. If you try to set a condition the compiler throws a The Custom element contains illegal inner text: 'NOT Installed AND NOT UPGRADINGPRODUCTCODE' error. How would one go ahead and only run the custom action during the installation now?
Condition is an attribute on the Custom element: https://wixtoolset.org/docs/reference/schema/wxs/custom/
I ended up checking the REMOVE parameter inside the custom action itself to check whether it got called during a uninstall and then run the logic accordingly.
var isUninstall = session["REMOVE"] == "ALL";
The only problem with that solution is that this way I cant make sure that the custom action logic does not run on patches as well.
Pro Tip: WiX's v3 to v4 code converter is really good. Author what you know in v3 and then convert it v4 and diff the before and after to quickly learn new changes in v4.

custom action returns failure, but msi still returns 0

I'm attempting to modify some inherited code. I have a custom action that was hardcoded to return success. I have it run before LaunchConditions. If there was a failure, it would set a value to be false, and that would force an error message.
<Condition Message='The application cannot be installed while Office is open.'>
<![CDATA[DEPENDENT_PROCESSES_CLOSED = "true"]]>
</Condition>
I'm not sure how this stops the install. Outside of the property declaration, I can't find any other references to DEPENDENT_PROCESSES_CLOSED.
Edit: Turns out a Condition in the product by definition stops the install
The main problem with this setup is the msi would always return 0. I want the msi to return a failure code, 1603, if it fails. I tried changing the custom action to return ActionResult.Failure if the dependent processes are running. While this stops the install, and tells the user the install failed, this resulted in two problems.
1) The conditional message no longer shows.
2) The msi still returns 0.
What do I need to do to have the custom action's error code be returned by the msi? How do I display the conditional message?

Wix Installation - Using Burn to have Managed UI & Displaying Same Progress Text as Built In dialogs

I am using Wix Burn to install per-requisites of our project, I have used ManagedBootstrapperApplicationHost to have custom UI, I have been following project available from Wix Source code to create my Managed WPF application..
Now the problem is the Progress (Message) it shows that doesn't match the progress message we have using inbuilt UI - WixStandardBootstrapperApplication.RtfLicense
Basically I am using following code from the Wix source
private void ExecuteMsiMessage(object sender, ExecuteMsiMessageEventArgs e)
{
lock (this)
{
this.Message = e.Message;
e.Result = this.root.Canceled ? Result.Cancel : Result.Ok;
}
}
How can I have the same display as the normal Progress dialog has.. Do I have to individually set Message from other methods like PlanPackage etc..
The wixstdba does not show the action data progress messages today. There was someone talking about adding the feature on the wix-devs mailing list but that has not happened yet. It's simply a matter of adding code like you have in the managed case to the wixstdba (that doesn't have it yet).
If you just want to display the name of the package being installed the way the wixstdba does it, then you'll want to handle the Engine.OnCachePackageBegin() and Engine.ExecutePackageBegin() callbacks. Those callbacks tell you when a package begins to be downloaded and then installed respectively. As part of the args to those callbacks you'll be provided the package id.
To get the friendly display name, you can read the BootstrapperApplicationData.xml that is automatically included next to your Bootstrapper Application .dll. In there are WixPackageProperties elements that provide lots of information about the packages in the bundle, including the DisplayName.
--- Sorry, the following is an answer to a question that wasn't asked. ---
The Engine.ExecuteMsiMessage() callback is called when the Windows Installer displays a message (like action data or a request to prompt the user for input). Progress is provided via a three different callbacks.
You can get the overall progress via the Engine.Progress callback. This is a very coarse grained progress that essentially moves as each package is cached and executed.
You can get the overall and individual package progress via the Engine.CacheAcquireProgress. This progress moves as each package is downloaded/copied and verified to be placed in the Package Cache.
You can get the overall and individual package progress via the Engine.ExecuteProgress callback. This progress moves as each package is installed/repaired/uninstalled.
So the Engine.Progress shows you the total overall progress and is very easy to use for a single progress bar but the progress bar will not move very smoothly. You can get a smoother overall progress by adding the Engine.CacheAcquireProgress to the Engine.ExecuteProgress. Note: that will give you a progress bar that goes to 200.
You can see how the WixBA handles all this in the src\Setup\WixBA\ProgressViewModel.cs file.

How to remove Custom Eventlog on uninstall?

In my current assignment I am having a requirement where I need to create custom eventlog during installation and uninstall this custom eventlog during uninstallation.
I am able to create custom eventlog during installation, but I am not able delete it during uninstallation. I could not find any documentation on how to delete the custom eventlog.
Can somebody please let me know is it possible or not? If possible, please guide me on how to achieve it.
I suppose you're trying to achieve this with <util:EventSource /> element. If that's the case, then the component hosting that event source should regulate its install / uninstall behavior.
If a component is scheduled for the installation, the event source will be created. If a component is to be uninstalled, it removes the event source altogether. At least, this is the way most elements work when placing inside the component.
If that's not the case, edit your question to add more details and some code, as I mentioned in the comment above.

How can I get the return code from a CustomAction?

I have the following CustomAction in my project:
<CustomAction Id="InstallDriver"
Return="check"
Execute="deferred"
Impersonate="no"
FileKey="FileDriverInst"
ExeCommand="-install" />
<InstallExecuteSequence>
<Custom Action="InstallDriver" Before="InstallServices" />
</InstallExecuteSequence>
The program that installs the driver produces useful return codes, for example if the installation failed because the system needs to be restarted following a previous driver uninstall.
Currently if anything other than success is returned, I get a dialog saying 'A program run as part of the setup did not finish as expected.' and the installation fails. This is not optimal.
How can I get and handle return codes?
Windows Installer doesn't support handling custom action return values.
For an EXE custom action a non-zero return value is interpreted as an error and the installation stops. Only a win32 DLL or VBScript custom action can change the installation behavior through its return code, but it's still very limited.
If you want to reboot the machine after install, you can set the REBOOT property.
Added as an "answer" by request:
Your whole design is not optimal. It's out of process to Windows Installer and isn't declarative. There are better patterns for installing drivers.
That's simply the way MSI handles EXE calls. You'd have to write your own custom actions to wrap the EXE call and then interpret the failure reason. To me this just adds yet another failure point.
You can't get a return code from a CustomAction, but in a round about way you can set what that return code would be on a property. That might as well be the same thing as getting the return code.
You have to get it within the script/dll your custom action is performing. Otherwise, the return code only shows up in the log.
For example, if you have property like
<Property="MyCode" Secure="yes">
Then within VBScript (or Jscript) you can get the value of that property like this:
VBScript
Session.Property("MyCode")
Initially, it is null. You can set it in VBScript like this:
If someCondition = 4 Then
Session.Property("MyCode") = "4" // For a return code of 4
End If
Once back in your WiX .wxs file, if you look at the value of your property, it is now 4. You could even use it in CDATA tags.
For example, only spawn a dialog if MyCode is equal to 4.
<Publish Dialog="SpawnDialog" ...><![CDATA[ MyCode = 4 ]]></Publish>