top of page
  • Writer's pictureAshwin Kumar

Generating MSI file using Visual Studio WiX Extension

Updated: Dec 20, 2022

The default Visual Studio Setup Wizard has limitations on the overall size of the project files that need to be compressed into an installable application MSI file. Hence, the alternative option of WiX has been considered and tested successfully to fulfill this requirement. Following are the step-by-step instructions to create an MSI file.


1. Install WiX extension in Visual Studio 2022

a. Open Microsoft Visual Studio 2022 and open an existing project, in order to access the Extensions menu.

b. Select the Manage Extensions option, and choose Visual Studio Marketplace

c. In the Search box at the top-right, type wix as shown below:

d. Select WiX v3 as shown above and click on the Download button that shows up on clicking the option

e. Follow the procedure to complete the installation of the extension


2. Install WiX Toolset

a. Navigate to this page, and select wix311.exe option in order to download the Toolset installer.

b. Once download completes, open Windows feature option by typing Turn Windows features on or off after opening the Windows start menu

c. Make sure that .NET Framework 3.5 (includes .NET 2.0 and 3.0) option is fully checked as below:

d. Open the previously downloaded installer file and follow the procedure to complete the installation.

e. Restart the computer to allow all installations to take full effect.


3. Create an initial WiX project

a. Open Microsoft Visual Studio 2022, and select Create a new project

b. Select Setup Project for WiX v3 as shown below:

c. Mention the project name as required

d. Select an appropriate folder where the project-related files would be created

e. Click Next on all subsequent windows to complete the project creation step


4. Prime the WXS file

a. The above steps would have created a project having a file called product.wxs, which is the core XML file that needs to be modified to allow creation of a customized MSI file

b. Modify the main Product XML element as follows to alter the name of the installer and the company name:

<Product Id="*" Name="<Product>" Language="1033" Version="1.0.0.0" Manufacturer="<Company Name>" UpgradeCode="8e0bfa0f-4770-47ea-80d4-646626bcd0d7">
Note: The value of the Name attribute above is what would show up under the Program Files folder after installation.

c. Modify the MajorUpgrade XML element as follows:

<MajorUpgrade DowngradeErrorMessage="A newer version of <Product> is already installed." />

d. Modify the MediaTemplate XML element as follows:

<MediaTemplate EmbedCab="yes" />
Note: This would ensure that all file cabinet files would be embedded inside the MSI file

e. Ensure that the Feature XML element has title set to the product name as below:

<Feature Id="ProductFeature" Title="<Product>" Level="1">
    <ComponentGroupRef Id="AppFiles" />
    <ComponentRef Id="ApplicationShortcut" />
</Feature>
Note: The Id attribute of the ComponentGroupRef XML element needs to match the Component Group configured in the HEAT command (to come later in this blog)

f. Remove the two Fragment XML sections altogether to leave within the XML file only 1 element (Product) within the Wix element


5. Configuring the source files in the WXS file using HEAT

Note: These steps are required to automate the addition of multiple files to the project, which otherwise becomes extremely cumbersome and time-consuming

a. Open the Windows start menu to Edit Environment Variables, and create System variable called AppSourceDir and make it point to the folder containing all the files to be packaged into the MSI file as below:

b. Restart the computer for the System environment variable to propagate throughout the system

c. Open the folder containing the WiX toolset ('bin' folder) in Windows Explorer. It could be something like this: C:\Program Files (x86)\WiX Toolset v3.11\bin

d. Right click on any vacant space on the right side of the Explorer window, and select Open in Terminal to open Windows PowerShell

e. Format the following command based on instructions given, and execute it in PowerShell:

./heat dir "<Replace this with the full path to the app files to be packaged>" -cg AppFiles -gg -scom -sreg -sfrag -srd -ke -dr INSTALLFOLDER -var env.AppSourceDir -out "<Replace this with the full path to where the setup file needs to be created>"
Note: The path provided in the dir tag must match the path value provided in the AppSourceDir environment variable above. Also, the Component Group name AppFiles mentioned in the command must match the configuration in product.wxs

The path to the out file could be any random file with wxs extension, which would eventually contain the output of the above command, with entries for each file found in the given source directory.


Sample command is as follows:

./heat dir "C:\Data\Work\uncode\www.uncodeit.co\Apps\Live\DemoApp" -cg AppFiles -gg -scom -sreg -sfrag -srd -ke -dr INSTALLFOLDER -var env.AppSourceDir -out "C:\Data\Work\uncode\www.uncodeit.co\source.wxs"

The execution of the above command would create the source.wxs file as mentioned in the above command in the specified path.

f. Open Visual Studio 2022 and open the WiX project created earlier

g. Open the source.wxs file in the same Visual Studio 2022 window by dragging the file from Windows Explorer and dropping it into the Visual Studio window. As can be see from the source.wxs file, there would be multiple entries for files (one each for each file in the source directory) all encapsulated inside two Fragment XML sections.

h. Copy the two Fragment sections from source.wxs and paste them inside product.wxs under the Product XML section

i. Copy the following XML section below the MediaTemplate element inside the Product section:

<Directory Id="TARGETDIR" Name="SourceDir">
    <Directory Id="ProgramFilesFolder">
        <Directory Id="INSTALLFOLDER" Name="<Product>" />
    </Directory>
    <Directory Id="ProgramMenuFolder">
        <Directory Id="ApplicationProgramsFolder" Name="<Product>"/>
    </Directory>
</Directory>

j. Just below the above pasted Directory section, paste the below:

<DirectoryRef Id="ApplicationProgramsFolder">
    <Component
        Id="ApplicationShortcut"
        Guid="<new GUID>">
        <Shortcut Id="ApplicationStartMenuShortcut"
            Name="Product"
            Description="Product Description"
            Target="[#filED338B0C4FAA53F54FD1A30E038EC440]"
            WorkingDirectory="INSTALLFOLDER"/>
        <RemoveFolder
            Id="ApplicationProgramsFolder"
            On="uninstall"/>
        <RegistryValue
            Root="HKCU"
            Key="Software\Company\Product"
            Name="installed"
            Type="integer"
            Value="1"
            KeyPath="yes"/>
    </Component>
</DirectoryRef>
Note: The value in the Guid attribute has to be generated and pasted as the attribute. Use the online GUID generator here, and click on Generate some GUIDs!, and copy the value generated in the Results box, and paste it in the Guid attribute as shown above.
Note: The value in the Target attribute as highlighted above needs to have the value as in the Id attribute of the XML File XML Component point to the main application executable file. Hence, copy the Id attribute content of the File XML element representing the application file and paste it in the Target attribute above. Don't miss out on the '[#' and the trailing ']' in the Target attribute. See below for example of where to pick the ID from:
<Fragment>
    <DirectoryRef Id="INSTALLFOLDER">
        <Component
              Id="cmpEF8304EC6736A7470B2D31DE6BA77139"
              Guid="{AA5A07E8-293B-459C-99B8-EC46CFF3D62A}">
            <File
                Id="filED338B0C4FAA53F54FD1A30E038EC440"
                KeyPath="yes"
                Source="$(env.SourceDir)\DemoApp.exe" />
        </Component>
…
…

k. Ensure that the final formatted XML in product.wxs has a structure as below:

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="DemoApp" Language="1033" Version="1.0.0.0" 
            Manufacturer="DemoCompany"
            UpgradeCode="8e0bfa0f-4770-47ea-80d4-646626bcd0d7">
      <Package InstallerVersion="200" Compressed="yes"
            InstallScope="perMachine" />
      <MajorUpgrade
            DowngradeErrorMessage="A newer version of DemoApp is already      installed." />
      <MediaTemplate EmbedCab="yes" />
      <Directory Id="TARGETDIR" Name="SourceDir">
            <Directory Id="ProgramFilesFolder">
                  <Directory Id="INSTALLFOLDER" Name="DemoApp" />
            </Directory>
            <Directory Id="ProgramMenuFolder">
                  <Directory Id="ApplicationProgramsFolder" 
                        Name="DemoApp"/>
            </Directory>
      </Directory> 
      <DirectoryRef Id="ApplicationProgramsFolder">
            <Component Id="ApplicationShortcut"
                  Guid="c03630a7-fe75-4a60-93aa-09a0762538ee">
                  <Shortcut Id="ApplicationStartMenuShortcut"
                        Name="DemoApp"
                        Description="Demo Application"
                        Target="[#filED338B0C4FAA53F54FD1A30E038EC440]"
                        WorkingDirectory="INSTALLFOLDER"/>
                  <RemoveFolder
                        Id="ApplicationProgramsFolder" On="uninstall"/>
                  <RegistryValue Root="HKCU"
                        Key="Software\DemoCompany\DemoApp"                   
                        Name="installed"
                        Type="integer" Value="1" KeyPath="yes"/>
            </Component>
      </DirectoryRef>
      <Feature Id="ProductFeature" Title="DemoApp" Level="1">
            <ComponentGroupRef Id="AppFiles" />
            <ComponentRef Id="ApplicationShortcut" />
      </Feature>
      <Fragment>…</Fragment>
      <Fragment>…</Fragment>
</Product>
Note: The two Fragment sections above highlighted in red are as pasted from source.wxs

6. Build the project

a. In Visual Studio, select Build menu and select Configuration Manager

b. From the Active solution configuration, select Release, and click on Close

c. From the Build menu, select Build Solution

d. The above should produce a result, after some time, that the build succeeded

e. Now open the project folder of the Visual Studio project, and under the bin/Release folder, you should find the MSI package created.


25 views0 comments
bottom of page