Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / XML

WiX Tricks

4.88/5 (36 votes)
5 Nov 2009CPOL7 min read 138K  
Solutions for WiX problems such as enable disable controls, Custom Actions in C#, running EXE within the installation, and setting icon for MSI and Add/Remove programs.

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.

Enable \ Disable Controls According to Property

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.

XML
<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[CBON <> "1"]]></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[CBON <> "1"]]></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[CBON <> "1"]]></Condition> 
   <Condition Action="enable" CBON = "1"/> 
</Control>
</Dialog>

Running EXE within the Installation

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:

XML
<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.

XML
<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.

Set the Icon for the MSI and Add/Remove Programs

Define an Icon element under the Product element. Make sure the Id for the Icon element ends with '.exe', for example:

XML
<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.

XML
<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.

XML
<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).

Use the Log of Your Installation for Debugging

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:

  1. Event viewer – under Windows Logs -> Application you can find log with the source MSInstaller. In my opinion, these logs were not that helpful.
  2. 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:

C#
session.Log("Begin Custom Action execution");

The logs will appear in the log file as explained here.

Uninstall Programs Manually

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.

Custom Actions in C#

To add custom action in C# to WIX project, using Votive (WiX setup projects for Visual Studio), follow these steps:

  1. 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).
  2. Add a project reference from the WiX project to the custom Action Project.
  3. Add to the WiX file the following definitions:
    1. Add the definition of the custom action and its DLL:
      XML
      <Binary Id="MyCustomAction.dll" SourceFile=
      "$(var.CAProjectName.TargetDir)$(var.CAProjectName.TargetName).CA.dll" />
      <CustomAction Id="MyCustomAction" BinaryKey="MyCustomAction.dll"   
      	DllEntry="CAMethodName" Execute="immediate" />
    2. 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.
      XML
      <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:

C#
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.

Conclusion

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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)