Introduction
WiX is an installer language based on XML, a toolset that builds Windows installation packages MSIs from XML files. It is quite easy to configure an MSI using WiX as it is powerful and flexible. WiX solved a lot of problems such as having a web application deployment together with regular Windows application.
In this article, I'll present a few tips and tricks when programming using WIX. I gathered these tricks after creating installers using WiX. For each problem, a solution was found after long experimenting or searching deep in the web. Some of the tricks are “how to’s” for WiX and others such as ‘Use the Log of Your Installation for Debugging’ and ‘Uninstall Programs Manually‘ help while debugging MSI the WiX result.
In order to control the visibility of UI controls in dialogs, disable control or enable them, a property and conditions with disable\enable actions should be used. The following is an example of a checkbox called “EnableCheckBox
” that is used to control the visibility of other controls, a label (“FolderLabel
”) a Path text box ( “Folder
”) and the “Next” button. When the check box is checked, the controls are enabled and when it is unchecked they are disabled. The starting state of the checkbox is unchecked.
The way to do it is to set Property
attribute for the checkbox and use the same property in the conditions of the other controls.
Pay attention that the property should have to be declared separately using a property
element if it is used only in the same dialog context.
<Dialog Id="Dlg">
<Control Id="EnableCheckBox" Property="CBON" Type="CheckBox" X="20"
Y="150" Width="290" Height="30" Text="!(loc.EnableCheckBox)" CheckBoxValue="1" />
<Control Id="Next" Type="PushButton" X="236" Y="243" Width="56"
Height="17" Default="yes" Text="!(loc.WixUINext)">
<Publish Event="NewDialog" Value="VerifyReadyDlg" Order="2" />
<Condition Action="disable"><![CDATA[</Condition>
<Condition Action="enable" CBON = "1"/>
</Control>
<Control Id="FolderLabel" Type="Text" X="35" Y="100" Width="290"
Height="30" NoPrefix="yes" Text="!(loc.InstallDirDlgFolderLabel)">
<Condition Action="disable"><![CDATA[</Condition>
<Condition Action="enable" CBON = "1"/>
</Control>
<Control Id="Folder" Type="PathEdit" X="35" Y="140" Width="320"
Height="18" Property="INSTALL_DIR" Indirect="yes">
<Condition Action="disable"><![CDATA[</Condition>
<Condition Action="enable" CBON = "1"/>
</Control>
</Dialog>
Many Installers run another program as part of the installation process. To run an executable, use a Custom Action with a FileKey
attribute which is the executable. In order to provide parameters to the executable, use the attribute ExeCommand
. For example:
<CustomAction Id="StartAppOnExit" FileKey="Executable.exe"
ExeCommand="param1" Execute="immediate" Return="asyncNoWait" />
The call for this action is done from InstallExecuteSequence
element. There we should specify when we want it to run.
<InstallExecuteSequence>
<Custom Action='StartAppOnExit' After='InstallFinalize' />
</InstallExecuteSequence>
The custom element is responsible for calling the custom action. To determine when the custom action will be called, use only one of these attributes: After
, Before
, OnExit
or Sequence
. In the example above, we used the ‘After
’ attribute for which we provide the name of the standard or custom action (in this case a standard action called 'InstallFinalize
') after which this action should be performed. For more information, read here.
Define an Icon
element under the Product
element. Make sure the Id for the Icon
element ends with '.exe', for example:
<Icon Id="IconName.exe" SourceFile="..\Icons\IconName.ico" />
Define a property called ARPPRODUCTICON
and provide the id of the Icon
as the value, see example below. This property specifies a foreign key to the Icon
table, which is the primary icon for the Windows Installer package.
<Property Id="ARPPRODUCTICON" Value="'IconName.exe" />
Define a property called ALLUSERS
and set it to 1
. Read more about why it should be one here.
<Property Id="ALLUSERS" Value="1" />
Pay Attention
Icons should always have Id with suffix ".exe" and should be defined under the Product
element – it would not work otherwise! (Even if the icon is used in other places).
The log of the installation is one of the common ways to track the process of the installation. It is helpful for debugging purposes especially when trying to debug properties values and launch conditions. Logs can be found in two main places:
- Event viewer – under Windows Logs -> Application you can find log with the source MSInstaller. In my opinion, these logs were not that helpful.
- A dedicated log file - To obtain a log of an installation, use the command line
msiexec
tool: msiexec /I MySetup.msi /l*v <LogFile>
You can read more about the /l
switch here or simply by calling msiexec /?
.
For example, properties value will be logged like this:
Property(S): INSTALLDIR = c:\Program Files (x86)\Company\Product\
Even properties that are private
(not set by the user).
As most of the installation is done automatically by built-in functions, the only place you will want to log your own messages is in your custom actions. When using Votive WiX custom action project, it is easy! Use the Log
function of the Session
object. For example:
session.Log("Begin Custom Action execution");
The logs will appear in the log file as explained here.
Many times during Installer development, a bug is revealed during the uninstall process which leads to the unfortunate situation of having a product installed without being able to uninstall it…
To solve this problem, here are steps to uninstall programs manually from a Windows XP. These steps are not providing a full uninstall process but enable you to run the install and uninstall again. Be aware that these steps may not remove everything associated with the application and can impact other applications on the computer. I suggest that in case of uncertainty, prepare a backup before performing these steps. Notice that not all steps are relevant for your application.
- Open
regedit
and navigate to HKEY_LOCAL_MACHINE\SOFTWARE and find the application folder and delete it. - Open
regedit
and navigate to HKEY_CURRENT_USER\SOFTWARE and find the application folder and delete it. - To remove the application entry from Add/Remove Programs (if present), open
regedit
and navigate to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall and find the application folder and delete it. - If your applications have Services attached to it, navigate to HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services, locate and delete the service.
To add custom action in C# to WIX project, using Votive (WiX setup projects for Visual Studio), follow these steps:
- Add a WIX project of type “C# Custom Action Project” to the solution of the WIX project. Within this project, write your custom action code. This project output is 2 DLLs, one a regular class library DLL and the other has WiX information added to it. Its suffix is “CA.Dll”. We’ll use the latter for referencing the custom action. (Further on how to pass parameters to it and how to log from it).
- Add a project reference from the WiX project to the custom Action Project.
- Add to the WiX file the following definitions:
- Add the definition of the custom action and its DLL:
<Binary Id="MyCustomAction.dll" SourceFile=
"$(var.CAProjectName.TargetDir)$(var.CAProjectName.TargetName).CA.dll" />
<CustomAction Id="MyCustomAction" BinaryKey="MyCustomAction.dll"
DllEntry="CAMethodName" Execute="immediate" />
- The call for this action is done from
InstallExecuteSequence
element. There we should specify when we want it to run. The custom element is responsible for calling the custom action. To determine when the custom action will be called, use only one of these attributes: After
, Before
, OnExit
or Sequence
. In the example above, we used the ‘After
’ attribute for which we provide the name of the standard or custom action (in this case a standard action called 'InstallFinalize
') after which this action should be performed. For more information, read here.
<InstallExecuteSequence>
<Custom Action='StartAppOnExit' After='InstallFinalize' />
</InstallExecuteSequence>
Tip
If you want to debug your custom action code instead of attaching the msiexec
process, I suggest to use the Debugger.Break()
function under “System.Diagnostics
” namespace. That way when running the MSI, a popup will be presented asking if you want to “Debug the program”. Click on this option and then choose the Visual Studio instance on which the custom action project is open on. The execution will stop at the break call (if not press F10) and you can start debugging.
Passing Parameters to C# Custom Action
All the properties that are defined under ‘Product
’ element are passed to the custom action code by session
object. For example:
String propertyValue = Session[PropertyName] ;
Yet there is one exception to this rule and it is deferred custom action. When is a custom action is considered deferred? When it changes the system directly or calls a system service. For more information regarding these cases, see this link.
I have found WiX to be a very strong technology, which solves installer problems in a friendly way. We have covered solutions for frequently occurring problems. Hopefully, I managed to make your work with WiX easier.
History
- 5th November, 2009: Initial post