How To Add Custom Actions in WiX Toolset
We have a list of Wix-related articles meant to help developers navigate through the tool in a seamless way. From implementing upgrades with WiX to embedding CAB options in MSI - you can find a lot of helpful materials on our main WiX page.
This article is all about Custom Actions in the Windows Installer XML Toolset (WiX), and by the end of it, you should be able to add any Custom Actions using the tool. Let's go through it together.
Unlike other packaging tools, Windows Installer XML Toolset (WiX) doesn't have a GUI – it builds the Windows Installer package based on the information defined within the WiX source file (XML based).
When it comes to Custom Actions, there are two elements that are connected to each other, and you will have to keep both of them in mind when defining your XML. These two elements are:
1. The Custom Action element – which comes with various attributes that correspond to different Custom Action types.
2. The Sequences element - which could be any of these: AdminExecuteSequence, AdminUISequence, AdvertiseExecuteSequence, InstallExecuteSequence or InstallUISequence and is used to schedule a Custom Action within the corresponding table in the MSI. It also allows setting the condition for determining if a Custom Action gets executed or not.
How To Add a Custom Action to Your Package Using WiX Toolset?
Let’s suppose you want to add two Custom Actions to your MSI package with the following characteristics:
- One Custom Action to create a file at the time the package gets installed.
- Another Custom Action to remove the same file at the time the package gets uninstalled.
In the following example, we will show you how to add a Custom Action to your MSI package using the WiX Toolset. We will also go through the most common conditions used for Custom Actions.
First, we must define our Custom Action element:
<CustomAction Id="CreateFileCA" BinaryKey="CreateFile.vbs" Execute="deferred" VBScriptCall='' Impersonate="no" Return="check"/> <CustomAction Id="DeleteFileCA" BinaryKey="DeleteFile.vbs" Execute="deferred" VBScriptCall='' Impersonate="no" Return="check"/>
As you can see, the BinaryKey attribute contains a reference to a Binary element. This is because I opted for my Custom Action source code to be stored in the Binary table. The next step in our example is to define the Binary element.
<Binary Id="CreateFile.vbs" SourceFile="CreateFile.vbs"/> <Binary Id="DeleteFile.vbs" SourceFile="DeleteFile.vbs"/>
Now that our Custom Action element is defined, we can set the corresponding InstallExecuteSequence element.
<InstallExecuteSequence> <Custom Action='CreateFileCA' Before='InstallFinalize'>NOT Installed</Custom> <Custom Action='DeleteFileCA' Before='CreateFolders'>Installed AND ( REMOVE = "ALL" OR AI_INSTALL_MODE = "Remove" ) AND NOT UPGRADINGPRODUCTCODE</Custom> </InstallExecuteSequence>
The inner text of a Custom element specifies the condition of the Custom Action.
The complete listing for the WiX source file is as follows:
<?xml version="1.0" encoding="UTF-8"?> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> <Product Id="{2D00166E-A14A-4F24-B94F-3D5E9ED21D65}" Name="MyApp" Language="1033" Version="1.0.0.0" Manufacturer="MyCompany" UpgradeCode="{8F800905-91E8-4234-AD80-A485F156FE1B}"> <Package InstallerVersion="400" Compressed="yes" InstallScope="perMachine" /> <Media Id='1' Cabinet='MyAppCAB.cab' EmbedCab='yes' /> <Directory Id='TARGETDIR' Name='SourceDir'> <Directory Id='ProgramFilesFolder'> <Directory Id='MyCompany' Name='MyCompany'> <Directory Id='INSTALLDIR' Name='MyApp'> <Component Id='MyComponent' Guid='{2D00166E-AAAA-4F24-B94F-3D5E9ED21D65}'> <File Id="Readme" Name="Readme.txt" DiskId="1" Source="Readme.txt"/> </Component> </Directory> </Directory> </Directory> </Directory> <Feature Id='MyFeature' Title='My 1st Feature' Level='1'> <ComponentRef Id='MyComponent' /> </Feature> <Binary Id="CreateFile.vbs" SourceFile="CreateFile.vbs"/> <Binary Id="DeleteFile.vbs" SourceFile="DeleteFile.vbs"/> <CustomAction Id="CreateFileCA" BinaryKey="CreateFile.vbs" Execute="deferred" VBScriptCall='' Impersonate="no" Return="check"/> <CustomAction Id="DeleteFileCA" BinaryKey="DeleteFile.vbs" Execute="deferred" VBScriptCall='' Impersonate="no" Return="check"/> <InstallExecuteSequence> <Custom Action='CreateFileCA' Before='InstallFinalize'>NOT Installed</Custom> <Custom Action='DeleteFileCA' Before='CreateFolders'>Installed AND ( REMOVE = "ALL" OR AI_INSTALL_MODE = "Remove" ) AND NOT UPGRADINGPRODUCTCODE</Custom> </InstallExecuteSequence> </Product> </Wix>
How to Set Custom Action Conditions?
Conditions are set depending on your specific needs and can be easily customized to a great extent. They can include references to installer properties, environment variables, installation folders, state/action of a component/feature, etc.
Below, you can find a list of the most common conditions:
- NOT Installed – evaluates to TRUE during the MSI installation only
- NOT Installed OR REINSTALL – evaluates to TRUE during the MSI installation and repair
- REMOVE = "ALL" – evaluates to TRUE during the MSI uninstallation and upgrade
- (REMOVE = "ALL") AND NOT UPGRADINGPRODUCTCODE – evaluates to TRUE during the MSI uninstallation only
Compile and Build the MSI Package Containing the Custom Actions
After following the previous steps and taking notes of what each condition is and how to add Custom Actions in WiX, we have reached the final step of this process: Building the MSI package.
To do this, we have to:
1. Pre-process and compile the WiX source file (.wxs) into an object file (.wixobj) by running the following command:
candle <path to wsx file>
2. Process the object file (.wixobj) and build the Windows Installer package (.msi) by running the following command:
light <path to wixobj file> –out <path to msi file>
And that’s it. Your MSI package is now built.
How Do Custom Actions Work in Advanced Installer
Now, with your project completely configured you can build your setup package directly from Visual Studio or Azure DevOps.
Windows Installer comes with a lot of Standard Actions which are enough to install and configure the application. However, there are scenarios where developers or IT Pros need to extend the standard capabilities offered by Windows Installer and include Custom Actions.
As you can see, WiX does not have any GUI and is purely based on the information defined within the WiX source file (XML) which can be a bit difficult.
On the other hand, tools like Advanced Installer come with a dedicated GUI for adding a Custom Action which makes the job a lot easier and straightforward.
If you want to give it a try, you can check it out for free through the Advanced Installer 30-day full-feature trial and have a look at our Custom Actions page. Additionally, Advanced Installer comes with a list of predefined Custom Action which you can use.