In the previous post we’ve taken a look at the WiX solution/project structure and project properties. We’re still playing with our super SuperForm application and today we’ll take a look at the general parts of the main wxs file, SuperForm.wxs, and the wxi include file. For wxs file we’ll just go over the general description of what each part does in the code comments. The more detailed descriptions will be in future posts about features themselves.
WXI include file
Include files are exactly what their name implies. To include a wxi file into the wxs file you have to put the wxi at the beginning of each .wxs file you wish to include it in. If you’ve ever worked with C++ you can think of the include files as .h files. For example if you include SuperFormVariables.wxi into the SuperForm.wxs, the variables in the wxi won’t be seen in FilesFragment.wxs or RegistryFragment.wxs. You’d have to include it manually into those two wxs files too.
For preprocessor variable $(var.VariableName) to be seen by every file in the project you have to include them in the WiX project properties->Build->“Define preprocessor variables” textbox.
This is why I’ve chosen not to go this route because in multi developer teams not everyone has the same directory structure and having a single variable would mean each developer would have to checkout the wixproj file to edit the variable. This is pretty much unacceptable by my standards. This is why we’ve added a System Environment variable named SuperFormFilesDir as is shown in the previous Wix Tutorial post. Because the FilesFragment.wxs is autogenerated on every project build we don’t want to change it manually each time by adding the include wxi at the beginning of the file. This way we couldn’t recreate it in each pre-build event.
<?xml version="1.0" encoding="utf-8"?>
Versioning. These have to be changed for upgrades.
It's not enough to just include newer files.
<?define MajorVersion="1" ?>
<?define MinorVersion="0" ?>
<?define BuildVersion="0" ?>
<!-- Revision is NOT used by WiX in the upgrade procedure -->
<?define Revision="0" ?>
<!-- Full version number to display -->
<?define VersionNumber="$(var.MajorVersion).$(var.MinorVersion).$(var.BuildVersion).$(var.Revision)" ?>
Upgrade code HAS to be the same for all updates.
Once you've chosen it don't change it.
<?define UpgradeCode="YOUR-GUID-HERE" ?>
Path to the resources directory. resources don't really need to be included
in the project structure but I like to include them for for clarity
<?define ResourcesDir="$(var.ProjectDir)\Resources" ?>
The name of your application exe file. This will be used to kill the process when updating
and creating the desktop shortcut
<?define ExeProcessName="SuperForm.MainApp.exe" ?>
For now there’s no way to tell WiX in Visual Studio to have a wxi include file available to the whole project, so you have to include it in each file separately.
Only variables set in “Define preprocessor variables” or System Environment variables are accessible to the whole project for now.
The main WXS file: SuperForm.wxs
We’ll only take a look at the general structure of the main SuperForm.wxs and not its the details. We’ll cover the details in future posts. The code comments should provide plenty info about what each part does in general.
Basically there are 5 major parts. The update part, the conditions and actions part, the UI install sequence, the directory structure and the features we want to include.
<?xml version="1.0" encoding="UTF-8"?>
<!-- Add xmlns:util namespace definition to be able to use stuff from WixUtilExtension dll-->
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<!-- This is how we include wxi files -->
<?include $(sys.CURRENTDIR)Includes\SuperFormVariables.wxi ?>
Id="*" is to enable upgrading. * means that the product ID will be autogenerated on each build.
Name is made of localized product name and version number.
<Product Id="*" Name="!(loc.ProductName) $(var.VersionNumber)" Language="!(loc.LANG)" Version="$(var.VersionNumber)" Manufacturer="!(loc.ManufacturerName)" UpgradeCode="$(var.UpgradeCode)">
<!-- Define the minimum supported installer version (3.0) and that the install should be done for the whole machine not just the current user -->
<Package InstallerVersion="300" Compressed="yes" InstallScope="perMachine"/>
<Media Id="1" Cabinet="media1.cab" EmbedCab="yes" />
<!-- Upgrade settings. This will be explained in more detail in a future post -->
<UpgradeVersion OnlyDetect="yes" Minimum="$(var.VersionNumber)" IncludeMinimum="no" Property="NEWER_VERSION_FOUND" />
<UpgradeVersion Minimum="0.0.0.0" IncludeMinimum="yes" Maximum="$(var.VersionNumber)" IncludeMaximum="no" Property="OLDER_VERSION_FOUND" />
<!-- Reference the global NETFRAMEWORK35 property to check if it exists -->
Startup conditions that checks if .Net Framework 3.5 is installed or if
we're running the OS higher than Windows XP SP2.
If not the installation is aborted.
By doing the (Installed OR ...) property means that this condition will only
be evaluated if the app is being installed and not on uninstall or changing
<![CDATA[Installed OR NETFRAMEWORK35]]>
<![CDATA[Installed OR ((VersionNT >= 501 AND ServicePackLevel >= 2) OR (VersionNT >= 502))]]>
This custom action in the InstallExecuteSequence is needed to
stop silent install (passing /qb to msiexec) from going around it.
<CustomAction Id="NewerVersionFound" Error="!(loc.SuperFormNewerVersionInstalled)" />
<!-- Check for newer versions with FindRelatedProducts and execute the custom action after it -->
<Custom Action="NewerVersionFound" After="FindRelatedProducts">
<!-- Remove the previous versions of the product -->
<!-- WixCloseApplications is a built in custom action that uses util:CloseApplication below -->
<Custom Action="WixCloseApplications" Before="InstallInitialize" />
<!-- This will ask the user to close the SuperForm app if it's running while upgrading -->
<util:CloseApplication Id="CloseSuperForm" CloseMessage="no" Description="!(loc.MustCloseSuperForm)"
ElevatedCloseMessage="no" RebootPrompt="no" Target="$(var.ExeProcessName)" />
<!-- Use the built in WixUI_InstallDir GUI -->
<UIRef Id="WixUI_InstallDir" />
<!-- These dialog references are needed for CloseApplication above to work correctly -->
<DialogRef Id="FilesInUse" />
<DialogRef Id="MsiRMFilesInUse" />
<!-- Here we'll add the GUI logic for installation and updating in a future post-->
<!-- Set the icon to show next to the program name in Add/Remove programs -->
<Icon Id="SuperFormIcon.ico" SourceFile="$(var.ResourcesDir)\Exclam.ico" />
<Property Id="ARPPRODUCTICON" Value="SuperFormIcon.ico" />
<!-- Installer UI custom pictures. File names are made up. Add path to your pics. –>
<WixVariable Id="WixUIDialogBmp" Value="MyAppLogo.jpg" />
<WixVariable Id="WixUIBannerBmp" Value="installBanner.jpg" />
<!-- the default directory structure -->
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="INSTALLLOCATION" Name="!(loc.ProductName)" />
Set the default install location to the value of
INSTALLLOCATION (usually c:\Program Files\YourProductName)
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLLOCATION" />
<!-- Set the components defined in our fragment files that will be used for our feature -->
<Feature Id="SuperFormFeature" Title="!(loc.ProductName)" Level="1">
<ComponentGroupRef Id="SuperFormFiles" />
<ComponentRef Id="cmpVersionInRegistry" />
<ComponentRef Id="cmpIsThisUpdateInRegistry" />
For more info on what certain attributes mean you should look into the WiX Documentation.
WiX 3 tutorial by Mladen Prajdić navigation