From MSI to WiX, Part 12 – Customizing installation using Transitive components


The main page for the series is here.


 



Introduction


This post is from the same group as Part 6 and 7.


Normally, we use transitive components when our product has system-specific component and depending on system state we want to install one component or the other.  For example, we might have Windows XP-specific dll and Windows Vista-specific dll.  When user upgrades his/her operating system from Windows XP to Windows Vista, we want to uninstall XP version of dll and install Vista version.


For this blog I will be using same task as in Part 6 and 7 – customizing an installation depending on the environment.  Instead of using transforms or custom tables we are going to use transitive components.



Test application


As in part 6, we will be using C# console application as our test application.  Hee is the source code for it:


using System;


using System.Collections.Generic;


using System.Text;


using System.Configuration;


 


namespace ConsoleApp


{


    class Program


    {


        static void Main(string[] args)


        {


            Console.WriteLine(“Key1={0}, Ke2={1}, Key3={2}”,


                 ConfigurationManager.AppSettings[“Key1”],


                 ConfigurationManager.AppSettings[“Key2”],


                 ConfigurationManager.AppSettings[“Key3”]);


 


            Console.ReadLine();


        }


    }


}


Along with executable we will be installing one of the two configuration files. Here is configuration file for Dev environment – Dev.config:


<?xml version=1.0 encoding=utf-8 ?>


<configuration>


  <appSettings>


    <add key=Key1 value=Dev1 />


    <add key=Key2 value=Dev2 />


    <add key=Key3 value=Dev3 />


  </appSettings>


</configuration>


and here is the Test environment version:


<?xml version=1.0 encoding=utf-8 ?>


<configuration>


  <appSettings>


    <add key=Key1 value=Test1 />


    <add key=Key2 value=Test2 />


    <add key=Key3 value=Test3 />


  </appSettings>


</configuration>


WiX source code is really simple:


<?xml version=1.0 encoding=UTF-8?>


<Wix xmlns=http://schemas.microsoft.com/wix/2003/01/wi>


 


  <Product Id={0BD4334D-F9FE-4B70-8070-917288A50B51}


           Name=Minimal Windows Installer Sample


           Language=1033


           Codepage=1252


           Version=1.0.0


           Manufacturer=Acme Corporation


           UpgradeCode={770C5598-A538-4D44-8C2E-B2D94E15CC98}>


 


    <Package Id={E1782FB0-3D87-4B13-88DC-62E11FB72552}


             Description=Minimal Windows Installer Sample


             Comments=This installer database contains the logic and data required to install [ProductName].


             InstallerVersion=200


             Languages=1033


             SummaryCodepage=1252


             Platforms=Intel


             ReadOnly=no


             Compressed=yes


             AdminImage=no


             Keywords=Installer


             ShortNames =no


             Manufacturer=Acme Corporation />


 


    <Media Id=1 Cabinet=CAB001.cab EmbedCab=yes />


 


    <Directory Id=TARGETDIR Name=SourceDir>


      <Directory Id=ProgramFilesFolder>


        <Directory Id=INSTALLDIR Name=Minimal LongName=MinimalInstallation>


 


          <Component Id=ConsoleApp


                     Guid={A77C5B06-132D-4884-8E17-EA10A83C5789}>


            <File Id=ConsoleApp DiskId=1


                  Name=ConsApp.exe LongName=ConsoleApp.exe


                  Source=ConsoleApp\ConsoleApp\bin\Debug\ConsoleApp.exe


                  Vital=yes KeyPath=yes />


          </Component>


 


          <Component Id=Component1


                     Guid={A77C5B06-132D-4884-8E17-EA10A83C812D}


                     Transitive=yes>


            <Condition>%ENVIRONMENT=”Dev”</Condition>


            <File Id=DevConfig DiskId=1


                  Name=App.cnf LongName=ConsoleApp.exe.config


                  Source=Dev.config Vital=yes KeyPath=yes />


          </Component>


          <Component Id=Component2


                     Guid={A77C5B06-132D-4884-8E17-EA10A83C812E}


                     Transitive=yes>


            <Condition>%ENVIRONMENT=”Test”</Condition>


            <File Id=TestConfig DiskId=1


                  Name=App.cnf LongName=ConsoleApp.exe.config


                  Source=Test.config Vital=yes KeyPath=yes />


          </Component>


 


        </Directory>


      </Directory>


    </Directory>


 


    <Feature Id=Feature1


             Title=Feature1 title


             Description=Feature1 description


             Level=1


             ConfigurableDirectory=INSTALLDIR >


      <ComponentRef Id=ConsoleApp />


      <ComponentRef Id=Component1 />


      <ComponentRef Id=Component2 />


    </Feature>


 


  </Product>


</Wix>


What’s new in here is that components Component1 and Component2 have attribute Transitive set to “yes”.  Also, both components have condition on environment variable ENVIRONMENT to be set to either Dev or Test.  Based on the value of this environment variable MSI will determine which component to install.


Let’s test it.  Create environment variable ENVIRONMENT and set its value to Dev.  Compile WiX source and install the application.  Test it to make sure that it shows Dev data in the console window.


Now, change the value of ENVIRONMENT variable to Test.  To uninstall Dev component and install Test component we must do a repair of the installation.  We can repair installation either using Add Remove Programs control panel applet or by issuing the following command from the command window:


msiexec /f Minimal.msi


Run Console.exe again.  Now it should show Test data.



Conclusion


As you can see, we must have type of current environment stored somewhere in the system because repair must know if transitive component needs to be reinstalled or not.  For this sample I chose to use environment variable.  Probably, better solution would be to provide the type of the environment (Dev or Test) through the public property in the command line during initial install.  Condition for transitive components should be based on a property which value is set during AppSearch.  For initial install AppSearch would fail, so we need to add custom action to set property’s value to a value of the property provided in the command line.  We also need to add an element to store the value of environment property in the registry.


 

Comments (2)

  1. Jarek says:

    Can i put condition into feature tag in order to determin which components must be installed? I want to have two feature tags and each with condition on public property. I ask because i had problems with it.

  2. Murali says:

    Hi,

    What the case if I want to uninstall and reinstall always with out any condition?

    Murali