How to show dialog or message box during uninstall in WiX? - wix

I'm trying to show a dialog or message box(with yes or no buttons) during uninstall.
I need to set a property with user's choice from my dialog (Yes(true) or No(false)).
This property is important because all the files are going to be deleted if user's answer is "Yes".
I tried to show a custom dialog on uninstall and that didn't work. Custom dialog didn't give me an error. It doesn't even appear in the verbose log.
Here is the custom dialog:
<Dialog Id="ClearAllDataDlg" Width="260" Height="85" Title="[Setup] - [ProductName]" NoMinimize="yes">
<Control Id="No" Type="PushButton" X="132" Y="57" Width="56" Height="17" Default="yes" Cancel="yes" Text="[ButtonText_No]">
<Publish Property="CLEARALLDATA" Value="0" />
<Publish Event="EndDialog" Value="Return">1</Publish>
</Control>
<Control Id="Yes" Type="PushButton" X="72" Y="57" Width="56" Height="17" Text="[ButtonText_Yes]">
<Publish Property="CLEARALLDATA" Value="1" />
<Publish Event="EndDialog" Value="Exit">1</Publish>
</Control>
<Control Id="Text" Type="Text" X="48" Y="15" Width="194" Height="30">
<Text>Do yo want to clear all data including your settings?</Text>
</Control>
<Control Id="Icon" Type="Icon" X="15" Y="15" Width="24" Height="24" ToolTip="Information icon" FixedSize="yes" IconSize="32" Text="[InfoIcon]" />
</Dialog>
and the InstallUISequence:
<Show Dialog="ClearAllDataDlg" Before="CostFinalize">REMOVE ~= "ALL"</Show>
I tried After="MigrateFeatureStates" in the Sequence but that didn't work either.
In another question somebody asked Stopping display of custom dialog boxes in WiX uninstall that is funny because all the other questions are trying to do it's opposite.
I don't want to do this inside of a custom action because i want to block the uninstall progress and wait for the user's answer.
Is there any way to accomplish this?
Any help would be appreciated. Thank you!

I do exactly this in a SDK install we produce. The idea being that if the user has done any actual development inside the SDK install location everything is getting deleted and we want to make sure they save anything they really need.
I didn't create a new dialog for this warning box because a message box is a very well-defined and used concept in all windows products.
In product I added a custom action scheduled before anything actually happens.
<CustomAction Id='CA_UninstallWarning' BinaryKey='SDKCustomActionsDLL' DllEntry='UninstallWarning' Execute='immediate' Return='check' />
<InstallExecuteSequence>
<Custom Action='CA_UninstallWarning' Before='FindRelatedProducts'>NOT UPGRADINGPRODUCTCODE AND REMOVE~="ALL"</Custom>
...
</InstallExecuteSequence>
And in my custom action I have
[CustomAction]
public static ActionResult UninstallWarning(Session session)
{
session.Log("Begin UninstallWarning.");
Record record = new Record();
record.FormatString = session["WarningText"];
MessageResult msgRes = session.Message(InstallMessage.Warning | (InstallMessage)System.Windows.Forms.MessageBoxButtons.OKCancel, record);
session.Log("End UninstallWarning.");
if (msgRes == MessageResult.OK)
{
return ActionResult.Success;
}
return ActionResult.Failure;
}
In your case you can use messageboxbuttons.YesNo instead of OKCancel
With return="check" in your custom action, the installation will stop if you return ActionResult.Failure from the custom action.
I do have this uninstall launching from a wix bootstrapper but the behaviour should be the same.

Related

Wix Progress bar in UI sequence

Can I have a modeless progress bar in UI sequence and get it updated with the custom actions in the UI sequence?
This is the page I have created, the dialog is not getting displayed nor the custom actions are getting called.
Is it possible to do this?
<Fragment>
<UI>
<!-- Progress Text To dispaly Progress Message -->
<ProgressText Action="CA_1">Doing task 1</ProgressText>
<ProgressText Action="CA_2">Doing task 2</ProgressText>
<ProgressText Action="CA_3">Doing task 3</ProgressText>
<Dialog Id="MysqlInstProgressDlg" Width="447" Height="362" Title="Mysql Progress Dialog" NoMinimize="no" Modeless="yes">
<Control Id="InstPrsTxt" Type="Text" X="67" Y="116" Width="372" Height="12" Transparent="yes">
<Text>{\FONT_DESC}</Text>
<Subscribe Event="ActionText" Attribute="Text"></Subscribe>
</Control>
<Control Id="InstPrgs" Type="ProgressBar" X="30" Y="136" Width="397" Height="17" ProgressBlocks="yes" Text="Progress done">
<Subscribe Event="SetProgress" Attribute="Progress" />
</Control>
<Control Id="DownloadBtn" Type="PushButton" X="292" Y="330" Width="66" Height="21" Default="yes">
<Text>{\FONT_DESC}Download</Text>
<Publish Event="DoAction" Value="CA_1" Order="1"><![CDATA[IS_SUCCEED = "true"]]></Publish>
<Publish Event="DoAction" Value="CA_2" Order="2"><![CDATA[IS_SUCCEED = "true"]]></Publish>
<Publish Event="DoAction" Value="CA_3" Order="3"><![CDATA[IS_SUCCEED = "true"]]></Publish>
<Publish Event="EndDialog" Value="Return" Order="4"><![CDATA[IS_SUCCEED = "true"]]></Publish>
<Publish Event="NewDialog" Value="ErrorDlg" Order="5"><![CDATA[(NOT Installed) AND IS_SUCCEED <> "true"]]></Publish>
</Control>
<Control Id="CancelBtn" Type="PushButton" Height="21" Width="66" X="368" Y="330" Cancel="yes" Default="yes">
<Text>{\FONT_DESC}Exit</Text>
<Publish Event="DoAction" Value="InstCancelConfirm_CA" Order="1"><![CDATA[1]]></Publish>
<Publish Event="NewDialog" Value="ErrorDlg" Order="2"><![CDATA[(NOT Installed) AND IS_INTERRUPTED = "true"]]></Publish>
</Control>
</Dialog>
</UI>
</Fragment>
</Wix>
UI Sequence:
<InstallUISequence>
<Show Dialog="InstWelcomeDlg2" Before="MysqlInstProgressDlg"><![CDATA[NOT Installed]]></Show>
<Show Dialog="MysqlInstProgressDlg" Before="ExecuteAction"><![CDATA[NOT Installed]]></Show>
</InstallUISequence>
Managing progress in a Windows Installer install is done in the InstallExecuteSequence, and that's where you can hook into it with this kind of MsiProcessMessage () activity:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa367525(v=vs.85).aspx
where you send INSTALLMESSAGE_PROGRESS messages.
It works this way because there is generally no need for progress or long running custom actions in the UI sequence:
The system should not be changed during the UI sequence because the install can later fail or be canceled, leaving the system changed.
A silent install does not call the UI sequence.
Prerequisites should be installed with a bootstrapper (one of your custom actions seems to be installing SQL).
Actions like populating a database or other configuration are often best done when the app first runs after the install where you are free from the constraints of custom actions, can run in a normal user environment, and more easily re-run if there are issues or more configuration later.
So if you have prerequisites use a bootstrapper, and if you are changing the system put those changes in the execute sequence as deferred custom actions where they can report progress and be undone (with rollback custom actions) if the install fails or is canceled. The short answer is that you can'r get a progress bar like that in the UI sequence.

How to display a dialog box with warning message in Wix installer?

I need to display a warning message while running my installer if a firefox maintenance service is installed.
To achieve this, I added a registry search property, and then added the code for dialog box in wix:
<Property Id="MAINTENANCESERVICEINSTALLED">
<RegistrySearch Id="MSID" Root="HKLM" Key="SOFTWARE\Mozilla\MaintenanceService" Name="Installed" Type="raw"/>
</Property>
<UI>
<Dialog Id="MaintenanceServiceWarningDialog" Width="284" Height="73" Title="Warning" NoMinimize="yes">
<Control Id="Text" Type="Text" X="38" Y="8" Width="240" Height="40" TabSkip="no">
<Text>Firefox Maintenance is installed on your system. Disable it to prevent compatibility issues. Click OK to proceed.</Text>
</Control>
<Control Id="OK" Type="PushButton" X="114" Y="52" Width="56" Height="17" Default="yes" Cancel="yes" Text="OK">
<Publish Event="EndDialog" Value="Return">1</Publish>
</Control>
</Dialog>
<InstallUISequence>
<Show Dialog="MaintenanceServiceWarningDialog" Sequence="1"> <![CDATA[NOT Installed AND MAINTENANCESERVICEINSTALLED]]></Show>
</InstallUISequence>
</UI>
I am using to show the dialog box. The above code is under "Product" tag.
I am getting build issues with this like below. And when I move the UI code to Fragment, the installer does not display anything. Not sure what's wrong.
Your InstallUISequence element is inside the UI element.

WiX Custom Action start with Button

I have a custom action to check the SQL Connection.
Now, it should work with a Control Button, but that's not working.
Custom action works nicely without the button:
Here the wxs-File:
<?xml version="1.0" encoding="UTF-8"?>
<Property Id="SERVERNAME" Value="MSSQL2008R2" />
<Property Id="DATABASENAME" Value="MyDatabase" />
<Property Id="USERNAME" Value="admin" />
<Property Id="PASSWORD" Value="mypassword" />
<Binary Id="CA_SQLTestDLL" SourceFile="$(var.CA_SQLConnectionTest.TargetDir)CA_SQLConnectionTest.CA.dll" />
<CustomAction Id="SQL_Test"
BinaryKey="CA_SQLTestDLL"
DllEntry="ConnectionTest"
Execute="deferred"
Return="check" />
<SetProperty Id="SQL_Test" Value="SERVERNAME=[SERVERNAME];DATABASENAME=[DATABASENAME];USERNAME=[USERNAME];PASSWORD=[PASSWORD]" Sequence="execute" Before="SQL_Test" />
<InstallExecuteSequence>
<Custom Action="SQL_Test" After="InstallInitialize" />
</InstallExecuteSequence>
<UI>
<Dialog Id="SQLServerConnectionTestDlg" Width="370" Height="270" Title="SQL Server connection test">
<Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="!(loc.WixUINext)" />
<Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="!(loc.WixUIBack)" />
<Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="!(loc.WixUICancel)">
<Publish Event="SpawnDialog" Value="CancelDlg">1</Publish>
</Control>
</Dialog>
</UI>
Here is my CustomAction class:
Imports System.Data
Imports System.Data.SqlClient
Public Class CustomActions
<CustomAction()> _
Public Shared Function ConnectionTest(ByVal session As Session) As ActionResult
session.Log("############## Begin CUSTOMACTION ##############")
Dim userName As String
Dim password As String
Dim serverName As String
Dim dataBase As String
serverName = session.CustomActionData("SERVERNAME")
dataBase = session.CustomActionData("DATABASENAME")
userName = session.CustomActionData("USERNAME")
password = session.CustomActionData("PASSWORD")
Dim SqlConn As New SqlConnection
Dim SqlConnStr As String = "Data Source=" + serverName + ";Database=" + dataBase + ";Persist Security Info=True;User ID=" + userName + ";Password=" + password
If SqlConn.State = ConnectionState.Closed Then
SqlConn.ConnectionString = SqlConnStr
Try
SqlConn.Open()
Catch ex As Exception
Return ActionResult.Failure
End Try
End If
session.Log("### SUCCESSFULL ###")
Return ActionResult.Success
End Function
End Class
install.log :
Calling custom action CA_SQLConnectionTest!CA_SQLConnectionTest.CustomActions.ConnectionTest
############## Begin CUSTOMACTION ##############
### SUCCESSFULL ###
Now, I'd like to start the custom action with a button.
So i have to change Execute="deferred" to Execute="immediate" and add a button:
<Control Id="TestConn" Type="PushButton" X="265" Y="205" Width="70" Height="18" Text="&Test Connection">
<Publish Event="DoAction" Value="SQL_Test">1</Publish>
<Publish Property="ERRORMSG" Value="ConnectionTest">ACCEPTED = "1"</Publish>
<Publish Event="SpawnDialog" Value="InvalidDBConnDlg">ACCEPTED = "0"</Publish>
</Control>
<Dialog Id="InvalidDBConnDlg" Width="260" Height="120" Title="MyTester">
<Control Id="OK" Type="PushButton" X="102" Y="90" Width="56" Height="17" Default="yes" Cancel="yes" Text="OK">
<Publish Event="EndDialog" Value="Exit" />
</Control>
<Control Id="Text" Type="Text" X="48" Y="22" Width="194" Height="60" Text="FAILED" />
<Control Id="Icon" Type="Icon" X="15" Y="15" Width="24" Height="24" ToolTip="Information icon" FixedSize="yes" IconSize="32" Text="WixUI_Ico_Info" />
</Dialog>
Now, when i push the button will the setup cancled and i have a fatal error in the log-File:
Action 16:43:20: SQL_Test.
Action start 16:43:20: SQL_Test.
MSI (c) (5C:5C) [16:43:20:236]: Invoking remote custom action. DLL: C:\Users\LOC~1.CRE\AppData\Local\Temp\MSIC08C.tmp, Entrypoint: ConnectionTest
Action ended 16:43:20: SQL_Test. Return value 3.
MSI (c) (5C:20) [16:43:20:404]: Note: 1: 2205 2: 3: Error
MSI (c) (5C:20) [16:43:20:404]: Note: 1: 2228 2: 3: Error 4: SELECT `Message` FROM `Error` WHERE `Error` = 2896
DEBUG: Error 2896: Executing action SQL_Test failed.
The installer has encountered an unexpected error installing this package. This may indicate a problem with this package. The error code is 2896. The arguments are: SQL_Test, ,
Action ended 16:43:20: WelcomeDlg. Return value 3.
MSI (c) (5C:54) [16:43:20:405]: Doing action: FatalError
MSI (c) (5C:54) [16:43:20:405]: Note: 1: 2205 2: 3: ActionText
Action 16:43:20: FatalError.
Action start 16:43:20: FatalError.
Action 16:43:20: FatalError. Dialog created
Action ended 16:43:23: FatalError. Return value 2.
Action ended 16:43:23: INSTALL. Return value 3.
MSI (c) (5C:54) [16:43:23:488]: Destroying RemoteAPI object.
MSI (c) (5C:50) [16:43:23:488]: Custom Action Manager thread ending
Config useLegacyV2RuntimeActivationPolicy is "true"
I use WIX3.10 in Visual Studio 2013
I am not sure what I am doing wrong. But i think it's a problem with the InstallExecuteSequence.
I hope someone can help me, thanks
Well immediate is the correct thing to do, because you can't have deferred custom actions in the UI sequence (so it can't be a problem with the execute sequence as you suspect).
Beyond that, if the code starts and it fails then it's a coding/environmental issue. You should just put message box calls in your code while you're in this debugging stage, check that you have the values, and certainly do more that just trhow away any exception with that try/catch! You're asking what the error might be at the same time that you discard it and return a failure result.
Thanks, you have right, it's not a problem with the execute sequence.
I've narrowed down the problem. When I don't use CustomActionData then works the custom action
userName = session.CustomActionData("USERNAME")
password = session.CustomActionData("PASSWORD")
...
Why I can't not transfer values?
Update:
The command doesnt' work here:
session.CustomActionData("USERNAME")
With the follow command works fine:
session("USERNAME")
CustomActionData cannot be accessed with immediate custom action.
But you can directly access properties using sessions.
try this
userName = session["USERNAME"];
password = session["PASSWORD"];

Inserting Custom Action between Dialogs (InstallUISequence) in WiX

I have two custom dialog boxes (plus the required ones ExitDlg, FatalErrorDlg, etc.), the first one sets a property using an Edit control and the second one shows this property using a Text control. Here is the meaningful code:
<Dialog Id="DialogA" ...>
<Control Id="ControlEdit" Type="Edit" Property="MY_PROPERTY" .../>
<Control Id="ControlNext" Type="PushButton" ...>
<Publish Event="EndDialog" Value="Return" /></Control>
</Dialog>
And then the second dialog:
<Dialog Id="DialogB" ...>
<Control Id="ControlText" Type="Text" Text="[MY_PROPERTY]" .../>
<Control Id="ControlBack" Type="PushButton" ...>
<Publish Event="EndDialog" Value="Return" /></Control>
<Control Id="ControlNext" Type="PushButton" ...>
<Publish Event="EndDialog" Value="Return" /></Control>
</Dialog>
And the action sequence:
<InstallUISequence>
<Show Dialog="DialogA" Before="MyCustomAction" />
<Custom Action="MyCustomAction" Before="DialogB" />
<Show Dialog="DialogB" Before="ExecuteAction" />
</InstallUISequence>
The custom action changes the value of MY_PROPERTY. My problem is how to make the Back button in DialogBget back to DialogA. Using NewDialog is simple, but then I can't get the custom action to be executed between the dialogs, or can I?
edit - 2013-05-02
After the answer from #caveman_dick, I tried to change the DialogA almost like he said, but instead of using EndDialog, I changed to Action="NewDialog" Value="DialogB". But now the Custom Action isn't being called. If I remove the Publish event to go to next dialog, then the CA is called. If I leave as #caveman_dick said, I can't get back to DialogA from DialogB.
edit - 2013-05-02
After searching in book WiX 3.6: A Developer's Guide to Windows Installer XML, I found the following: "if you have more than one Publish event, they must have conditional statements as their inner text. Otherwise, all of the events simply won't be published."
So the answer from #caveman_dick is correct, except that you need to change to the following:
<Publish ...>1</Publish>
Rather than scheduling the custom action in the InstallUISequence you can publish it on the button click:
<Dialog Id="DialogA" ...>
<Control Id="ControlEdit" Type="Edit" Property="MY_PROPERTY" .../>
<Control Id="ControlNext" Type="PushButton" ...>
<Publish Event="DoAction" Value="MyCustomAction">1</Publish>
<Publish Event="EndDialog" Value="Return">1</Publish>
</Control>
</Dialog>
EDIT: The Publish element's condition needs to explicitly evaluate to true to run, so add "1" as the text of the Publish elements.

How to link custom action to control event

I'm studying Wix to build product installer. I've customized the UI successfully but be wondering how to link a custom action to control event (i.e PushButton).
I have 2 projects:
Product.Wix.CustomActions
[CustomAction]
public static ActionResult CustomAction1(Session session)
{
session.Log("Begin CustomAction1");
MessageBox.Show("CustomActions1");
return ActionResult.Success;
}
Product.Wix.Setup (referenced to Product.Wix.CustomActions project). In Setup.wxs, I have declared a custom action:
<Binary Id="CustomActions" SourceFile="..\Product.Wix.CustomActions\bin\Debug\Product.Wix.CustomActions.CA.dll" />
<CustomAction Id='Action1' BinaryKey='CustomActions' DllEntry='CustomAction1' Execute='immediate' Return='check' />
I have a custom dialog with Connect button and wiring to the action as below:
<Control Id="Connect" Type="PushButton" X="325" Y="75" Width="30" Height="17" Text="...">
<Publish Event="DoAction" Value="Action1">1</Publish>
</Control>
It does not work as I expected it should pop-up a message box when clicking on the Connect button.
Am not sure whether MessageBox.Show() will work. Also its better to go with WIX dialogs as you can capture the option selected by user on the popup.
Example
<Control Id="TestConn" Type="PushButton" X="265" Y="205" Width="70" Height="18" Text="&Test Connection">
<Publish Event="DoAction" Value="Action1">1</Publish>
<Publish Property="ERRORMSG" Value="CustomActions1">ACCEPTED = "1"</Publish>
<Publish Event="SpawnDialog" Value="InvalidDBConnDlg">ACCEPTED = "0"</Publish>
</Control>
<Dialog Id="InvalidDBConnDlg" Width="260" Height="120" Title="[ProductName]">
<Control Id="OK" Type="PushButton" X="102" Y="90" Width="56" Height="17" Default="yes" Cancel="yes" Text="OK" />
<Control Id="Text" Type="Text" X="48" Y="22" Width="194" Height="60" Text="[MSGVAR]" />
<Control Id="Icon" Type="Icon" X="15" Y="15" Width="24" Height="24" ToolTip="Information icon" FixedSize="yes" IconSize="32" Text="WixUI_Ico_Info" />
</Dialog>
Custom Action
[CustomAction]
public static ActionResult CustomAction1(Session session)
{
session["MSGVAR"] = "Some Message";
return ActionResult.Success;
}
The log file shows my custom action assemblies could not be loaded properly. The reason is I have unintentionally removed the section:
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" />
</startup>
from the config file. Added it back and everything works now.