Adding and Customizing Dialogs in WiX 3
How to add a user interface, optionally create a shortcut on the desktop, and conditionally launch your app after installation
So you've downloaded WiX 3, you've gone through Lesson One of Gábor DEÁK JAHN's excellent WiX tutorial, and you've got files getting installed and uninstalled. You're ready to add an interface, but Lesson Two of the tutorial is written for WiX version 2, and the instructions don't seem to be working.
Maybe you've searched the web and found a way to get a user interface showing up, but can't figure out how to add a checkbox to perform an optional action. This page will hopefully answer that for you.
Adding support for a user interface
If you are using the Visual Studio integration, right-click on the "References" folder of your setup project and add the WixUIExtension.dll file as a reference. You should also go to your project's properties (right-click the project name in the Solution Explorer and select "Properties"), go to the "Linker" tab, and in the edit control next to "Cultures:" enter "en-US" (without the quotes).
If you are using the WiX command line, you'll need to specify the following on the light.exe command line:
-cultures:en-US -ext WixUIExtension.dll
If light.exe can't find it, you may need to specify the path to the WixUIExtension.dll.
Selecting a user interface
WiX 3 provides five basic user interface styles: WixUI_Mondo
, WixUI_FeatureTree
, WixUI_InstallDir
, WixUI_Minimal
, and WixUI_Advanced
. Information on the differences between these is easy to find and is included with the WiX help file. This example will focus on the WixUI_Installer
set of dialogs, but can be adapted to the other styles easily. To add the WixUI_Installer
user interface (or WiX dialog set) to your setup, add the following elements on the main installation level of the setup file (inside the the <Wix>...</Wix>
element block):
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR"/>
<UIRef Id="WixUI_InstallDir" />
|
Note the <Property>
element. That is necessary only for the WixUI_InstallDir
user interface, and the INSTALLDIR
value should be replaced with the ID of the <Directory>
element where your main application will get installed.
After adding the <UIRef>
element and linking with the WixUIExtension
library, your setup program should have the selected user interface.
If you run into problems building the setup with Visual Studio, make sure you've specified the culture in the linker settings. Also try right-clicking the project name and selecting "Rebuild All". If you're still having problems, try shutting down and restarting Visual Studio, re-opening the setup project, and Rebuilding All again. If you're still running into problems, the WiX SourceForge page has some great supportive mailing lists you can search or join.
Adding a checkbox to conditionally install a desktop shortcut
Customizing a dialog by adding a checkbox is not much more complicated. This example will use the WixUI_InstallDir
user interface, and will add a checkbox to the dialog that gives the user a chance to change the installation directory. Extending this example to customize another dialog in another dialog series should be straightforward.
Don't worry - you won't have to recompile WiX, but you will need to download the source code for the build of WiX that you are using. For this example, you'll need to copy two files out of the WiX source tree into your own setup project directory: WixUI_InstallDir.wxs and InstallDirDlg.wxs. Once in your own directory, rename these files MyWixUI_InstallDir.wxs and MyInstallDirDlg.wxs respectively.
First, you'll need a property that indicates whether or not to place a shortcut on the desktop. Add the following code to your setup file, at the same level as the <UIRef>
element (it's important that the property name be in all caps - this signifies that it's a global property):
<Property Id="INSTALLDESKTOPSHORTCUT" Value="1" /> |
You'll also need a component section to conditionally place the shortcut depending on the value of the INSTALLDESKTOPSHORTCUT
property. If you already have an individual component that installs the shortcut, you can simply add the conditional. Otherwise, your code might look as follows (replace the highlighted sections with what fits for your installation):
<Directory Id="DesktopFolder" Name="Desktop"> <Component Id="DesktopShortcut" Guid="YOUR-GUID-HERE"> <Condition>INSTALLDESKTOPSHORTCUT</Condition> <RegistryKey Root="HKCU" Key="YourAppKey\PossibleSubKey" Action="createAndRemoveOnUninstall"> <RegistryValue Name="AnyValueName" Value="1" Type="integer" KeyPath="yes"/> </RegistryKey> <Shortcut Id="DesktopShortcut" Directory="DesktopFolder" Name="ShortcutName" ShortName="ShrtName" Icon="YourApp.exe" Target="[#YourAppExeId]"/> </Component> </Directory> |
Of course, you'll also need to add a corresponding <ComponentRef>
element inside your application's <Feature>
element.
You'll now have a shortcut that gets installed based on the value of the INSTALLDESKTOPSHORTCUT
property. Now we need to add the checkbox to the directory dialog. Load up your copy of MyInstallDirDlg.wxs and make the following changes:
<?xml version="1.0" encoding="UTF-8"?> <!-- Copyright (c) Microsoft Corporation. All rights reserved. --> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> <Fragment> <UI> <Dialog Id="MyInstallDirDlg" Width="370" Height="270" Title="!(loc.InstallDirDlg_Title)"> . . . <Control Id="FolderLabel" Type="Text" X="20" Y="60" Width="290" Height="30" Text="!(loc.InstallDirDlgFolderLabel)" /> <Control Id="Folder" Type="PathEdit" X="20" Y="100" Width="320" Height="18" Property="WIXUI_INSTALLDIR" Indirect="yes" /> <Control Id="ChangeFolder" Type="PushButton" X="20" Y="120" Width="56" Height="17" Text="!(loc.InstallDirDlgChange)" /> <Control Id="DesktopShortcutCheckBox" Type="CheckBox" X="20" Y="160" Width="290" Height="17" Property="INSTALLDESKTOPSHORTCUT" CheckBoxValue="1" Text="Create a shortcut for this program on the desktop." /> </Dialog> </UI> </Fragment> </Wix> |
Two more changes are necessary. You need to change your MyWixUI_InstallDir.wxs file to use the new MyInstallDirDlg. Load up your copy of MyWixUI_InstallDir.wxs and make the following changes:
<?xml version="1.0" encoding="UTF-8"?> <!-- Copyright (c) Microsoft Corporation. All rights reserved. --> <!-- First-time install dialog sequence: Maintenance dialog sequence: - WixUI_WelcomeDlg - WixUI_MaintenanceWelcomeDlg - WixUI_LicenseAgreementDlg - WixUI_MaintenanceTypeDlg - WixUI_InstallDirDlg - WixUI_InstallDirDlg - WixUI_VerifyReadyDlg - WixUI_VerifyReadyDlg - WixUI_DiskCostDlg --> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> <Fragment> <UI Id="MyWixUI_InstallDir"> . . . <Publish Dialog="LicenseAgreementDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg">1</Publish> <Publish Dialog="LicenseAgreementDlg" Control="Next" Event="NewDialog" Value="MyInstallDirDlg">LicenseAccepted = "1"</Publish> <Publish Dialog="MyInstallDirDlg" Control="Back" Event="NewDialog" Value="LicenseAgreementDlg">1</Publish> <Publish Dialog="MyInstallDirDlg" Control="Next" Event="SetTargetPath" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish> <Publish Dialog="MyInstallDirDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg" Order="2">1</Publish> <Publish Dialog="MyInstallDirDlg" Control="ChangeFolder" Property="_BrowseProperty" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish> <Publish Dialog="MyInstallDirDlg" Control="ChangeFolder" Event="SpawnDialog" Value="BrowseDlg" Order="2">1</Publish> <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MyInstallDirDlg" Order="1">NOT Installed</Publish> <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg" Order="2">Installed</Publish> . . . </UI> <UIRef Id="WixUI_Common" /> </Fragment> </Wix> |
You'll also need to update the <UIRef>
element you previously added on the main installation level of the setup file (inside the <Wix>...</Wix>
element block) so it points to your new dialog:
<UIRef Id="MyWixUI_InstallDir" />
|
Now add the MyWixUI_InstallDir.wxs and MyInstallDirDlg.wxs files to your setup project, compile it, and your new install directory dialog should look as follows:
And the desktop shortcut will only be added if the checkbox is checked!
Conditionally launching the application after installation
There are two ways to add a checkbox to the final page of an installation in order to conditionally launch an application. The first is supported in WiX 3 without needing any changes to the original dialogs, but it has a major limitation.
The final dialog box (ExitDialog
) has an optional checkbox that can be displayed, and the property tied to this checkbox can be used to conditionally launch the application. The following entries in the setup file will add this checkbox (again, replace the entries in yellow with your own):
<CustomAction Id="StartAppOnExit" FileKey="YourAppExeId" ExeCommand="" Execute="immediate" Impersonate="yes" Return="asyncNoWait" /> <Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT" Value="Launch Sample App 1.0 when setup exits." /> <UI> <Publish Dialog="ExitDialog" Control="Finish" Order="1" Event="DoAction" Value="StartAppOnExit">WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT</Publish> </UI> |
The above code will add the following checkbox to the ExitDialog
:
Note the gray background behind the checkbox. Unfortunately there's no easy way to fix this, without fixing it in the WiX source code. Because the control's background uses the default dialog background color, changing the background image for the dialog to match won't really solve anything. It would still look out of place on different versions of Windows that use other default background colors, and on the machines of users that change their Windows color scheme.
The other method of adding a checkbox and conditionally launching an application after setup is to create a new checkbox control like we did for the desktop shortcut. If you added a checkbox for the desktop shortcut, then you already have a copy of WixUI_InstallDir.wxs in your setup project named MyWixUI_InstallDir.wxs. You'll also need to copy ExitDialog.wxs into your project directory and rename it MyExitDialog.wxs. Then make the following changes to the file:
<?xml version="1.0" encoding="UTF-8"?> <!-- Copyright (c) Microsoft Corporation. All rights reserved. --> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> <Fragment> <UI> <Dialog Id="MyExitDialog" Width="370" Height="270" Title="!(loc.ExitDialog_Title)"> <Control Id="Finish" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Cancel="yes" Text="!(loc.WixUIFinish)" /> <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Disabled="yes" Text="!(loc.WixUICancel)" /> <Control Id="Bitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="234" TabSkip="no" Text="!(loc.ExitDialogBitmap)" /> <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Disabled="yes" Text="!(loc.WixUIBack)" /> <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" /> <Control Id="Description" Type="Text" X="135" Y="70" Width="220" Height="20" Transparent="yes" NoPrefix="yes" Text="!(loc.ExitDialogDescription)" /> <Control Id="Title" Type="Text" X="135" Y="20" Width="220" Height="60" Transparent="yes" NoPrefix="yes" Text="!(loc.ExitDialogTitle)" /> <Control Id="OptionalText" Type="Text" X="135" Y="100" Width="220" Height="80" Transparent="yes" NoPrefix="yes" Hidden="yes" Text="[WIXUI_EXITDIALOGOPTIONALTEXT]"> <Condition Action="show">WIXUI_EXITDIALOGOPTIONALTEXT AND NOT Installed</Condition> </Control> <Control Id="OptionalCheckBox" Type="CheckBox" X="135" Y="190" Width="220" Height="40" Hidden="yes" Property="WIXUI_EXITDIALOGOPTIONALCHECKBOX" CheckBoxValue="1" Text="[WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT]"> <Condition Action="show">WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT AND NOT Installed</Condition> </Control> <Control Id="LaunchCheckBox" Type="CheckBox" X="10" Y="243" Width="170" Height="17" Property="LAUNCHAPPONEXIT" Hidden="yes" CheckBoxValue="1" Text="Launch Sample App 1.0 when setup exits."> <Condition Action="show">NOT Installed</Condition> </Control> </Dialog> <InstallUISequence> <Show Dialog="MyExitDialog" OnExit="success" /> </InstallUISequence> <AdminUISequence> <Show Dialog="MyExitDialog" OnExit="success" /> </AdminUISequence> </UI> </Fragment> </Wix> |
You'll also need to make the following change to your MyWixUI_InstallDir.wxs file:
.
.
.
<Publish Dialog="MyExitDialog" Control="Finish" Event="EndDialog" Value="Return" Order="999">1</Publish>
.
.
.
|
Add the new MyExitDialog.wxs file to your project, and instead of the above gray checkbox on a white background, you'll end up with the following:
Finally, to get the application to actually launch you'll need to add code similar to the previous option, replacing the highlighted pieces with what makes sense for your setup:
<CustomAction Id="LaunchApplication" FileKey="YourAppExeId" ExeCommand="" Execute="immediate" Impersonate="yes" Return="asyncNoWait" />
<UI>
<Publish Dialog="MyExitDialog" Control="Finish" Order="1" Event="DoAction" Value="LaunchApplication">LAUNCHAPPONEXIT</Publish>
</UI>
|
That's it!
Hopefully these instructions will be useful to someone. I know it took a very long, frustrating day before I pieced enough information together to figure all this out. Again, if you run into any problems that haven't been covered here, the WiX SourceForge page has excellent email lists, the archives of which are searchable and provide a wealth of tips from users who have probably run into whatever it is you're having problems with. On the off chance you can't find what you're looking for in the archives, you can always join!