From MSI to WiX, Part 7 – Customizing installation using Transforms


The main page for the series is here.


 



Introduction


In previous blog we were using custom tables to store the data for different environments.  Now, we will be using transforms to customize installation.  In order to create a Transform we need a base installation database and extended installation database.  Transform is the difference between base and extended installation databases.



Creating Base Installation Database


First, we need to create a Base installation which does not any customization data.  Here is modified source Wix file from previous blog:


<?xml version=1.0 encoding=UTF-8?>
<
Wix xmlns=http://schemas.microsoft.com/wix/2003/01/wi>


    <Product Id={1EFFDCD2-4B4B-439E-8296-651795EE02D9}
                  Name=Minimal Windows Installer Sample
                  Language=1033
                  Codepage=1252
                  Version=1.0.0
                  Manufacturer=Acme Corporation
                  UpgradeCode={15F9543C-1C8D-45D6-B587-86E65F914F20}>


        <Package Id={????????-????-????-????-????????????}
                        Description=Minimal Windows Installer Sample
                        Comments=This installer database contains the logic and data required to install Minimal Windows Installer Sample.
                        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 CompressionLevel=high EmbedCab=yes />


        <Directory Id=TARGETDIR Name=SourceDir>
            <
Directory Id=ProgramFilesFolder>
                <
Directory Id=INSTALLDIR Name=Minimal LongName=MinimalInstallation>


                    <Component Id=Component1
                                       Guid={A77C5B06-132D-4884-8E17-EA10A83C812D}>


                        <File Id=ConsoleApp DiskId=1 Name=ConsApp.exe Source=ConsoleApp.exe Vital=yes KeyPath=yes />


                        <File Id=ConsoleApp.exe.config DiskId=1 Name=ConsApp.exc LongName=ConsoleApp.exe.config
                                Vital=yes Source=ConsoleApp.exe.config />


                        <XmlFile Id=SetKey1
                                     Action=setValue
                                     ElementPath=//appSettings/add[\[]@key=’Key1′[\]]/@value
                                     Value=[KEY1]
                                     File=[INSTALLDIR]ConsoleApp.exe.config />
                        <
XmlFile Id=SetKey2
                                     Action=setValue
                                     ElementPath=//appSettings/add[\[]@key=’Key2′[\]]/@value
                                     Value=[KEY2]
                                     File=[INSTALLDIR]ConsoleApp.exe.config />
                        <
XmlFile Id=SetKey3
                                     Action=setValue
                                     ElementPath=//appSettings/add[\[]@key=’Key3′[\]]/@value
                                     Value=[KEY3]
                                     File=[INSTALLDIR]ConsoleApp.exe.config />


                    </Component>


                </Directory>
            </
Directory>
        </
Directory>


        <Feature Id=Feature1
                      Title=Feature1 title
                      Description=Feature1 description
                      Level=1
                      ConfigurableDirectory=INSTALLDIR >
            <
ComponentRef Id=Component1 />
        </
Feature>


    </Product>
</
Wix>


Here are commands to build Minimal.msi:


candle.exe Minimal.wxs
light.exe -out Minimal.msi Minimal.wixobj



Creating extended database using Orca


Create a copy of Minimal.msi and rename it to MinimalTest.msi.  This will be our extended installation database for the test environment.  Open MinimalTest.msi using Orca, click on Property table in the Tables window on the left.  Add three new properties to the Property table:















Property Value
KEY1 Test1
KEY2 Test2
KEY3 Test3

Save the installation database.


Now we need to generate a transform which will have just the difference between bae and extended database.  To do that, we need to run this command (MsiTran.exe will be installed on your machine if you installed the Platform SDK/Windows Installer SDK):


MsiTran -g Minimal.msi MinimalTest.msi Test.mst


To install the product use this command:


msiexec /i Minimal.msi TRANSFORMS=Test.mst


Same procedure should be executed for any additional environment.



Automating the process of creating transforms


We can use Windows Installer Automation Interface to automate the process of cretaing transforms.  Here is the script which creates both Test.mst and Dev.mst:


Option Explicit


 


Const msiOpenDatabaseModeReadOnly = 0


Const msiOpenDatabaseModeTransact = 1


Const msiViewModifyAssign = 3


Const msiTransformErrorNone = 0


Const msiTransformValidationNone = 0


 


On Error Resume Next


 


Dim installer : Set installer = Nothing


 


Dim Devs


Set Devs = CreateObject(“Scripting.Dictionary”)


Devs.Add “KEY1”, “Dev1”


Devs.Add “KEY2”, “Dev2”


Devs.Add “KEY3”, “Dev3”


CreateTransform “Dev”, Devs


 


Dim Test


Set Test = CreateObject(“Scripting.Dictionary”)


Test.Add “KEY1”, “Test1”


Test.Add “KEY2”, “Test2”


Test.Add “KEY3”, “Test3”


CreateTransform “Test”, Test


 


Wscript.Quit 0


 


Sub CreateTransform(TransformName, Values)


    ‘ Create a copy of base database


    Dim fso


    Set fso = CreateObject(“Scripting.FileSystemObject”) : CheckError


    fso.CopyFile “Minimal.msi”, TransformName & “.msi” : CheckError


    Set fso = Nothing


 


    ‘ Add additional properties to the copy


    Dim database


    Dim view


    Dim record


 


    Set installer = Wscript.CreateObject(“WindowsInstaller.Installer”) : CheckError


    Set database = installer.OpenDatabase(TransformName & “.msi”, msiOpenDatabaseModeTransact) : CheckError


 


    Set view = database.OpenView(“SELECT `Property`,`Value` FROM Property”) : CheckError


    view.Execute : CheckError


 


    Dim keys : keys = Values.Keys


    dim items : items = Values.Items


    Dim i


    For i = 0 To Values.Count – 1


        Set record = installer.CreateRecord(2)


        record.StringData(1) = keys(i)


        record.StringData(2) = items(i)


        view.Modify msiViewModifyAssign, record : CheckError


    Next


 


    view.Close


    Set view = Nothing


    database.Commit : CheckError


    Set database = Nothing


   


    ‘ Create a Transform


    Dim database1 : Set database1 = installer.OpenDatabase(“Minimal.msi”, msiOpenDatabaseModeReadOnly) : CheckError


    Dim database2 : Set database2 = installer.OpenDatabase(TransformName & “.msi”, msiOpenDatabaseModeReadOnly) : CheckError


    Dim transform : transform = TransformName & “.mst”


    database2.GenerateTransform database1, transform : CheckError


    database2.CreateTransformSummaryInfo database1, transform, msiTransformErrorNone, msiTransformValidationNone : CheckError


    Set database1 = Nothing


    Set database2 = Nothing


 


    Set installer = Nothing


End Sub


 


Sub CheckError


    If Err = 0 Then Exit Sub


 


    Dim message, errRec


    message = Err.Source & ” “ & Hex(Err) & “: “ & Err.Description


    If Not installer Is Nothing Then


        Set errRec = installer.LastErrorRecord


        If Not errRec Is Nothing Then message = message & vbNewLine & errRec.FormatText


    End If


    Wscript.Echo message


    Wscript.Quit 2


End Sub



Embedding Transforms into installer database


Instead of shipping installer database and a separate transform file to a customer we can embed the Transform to an installer database and ship just one file.  In fact, we can embed multiple transforms in the database.  Here is the fragment of updated version of Transforms generating script from previous section:


‘ Create a Transform


Dim database1 : Set database1 = installer.OpenDatabase(“Minimal.msi”, msiOpenDatabaseModeReadOnly) : CheckError


Dim database2 : Set database2 = installer.OpenDatabase(TransformName & “.msi”, msiOpenDatabaseModeReadOnly) : CheckError


Dim transform : transform = TransformName & “.mst”


database2.GenerateTransform database1, transform : CheckError


database2.CreateTransformSummaryInfo database1, transform, msiTransformErrorNone, msiTransformValidationNone : CheckError


Set database1 = Nothing


Set database2 = Nothing


 


‘ Embed Transform into the database


Set database = installer.OpenDatabase(“Minimal.msi”, msiOpenDatabaseModeTransact) : CheckError


Set view = database.OpenView(“SELECT `Name`,`Data` FROM _Storages”) : CheckError


view.Execute : CheckError


Set record = installer.CreateRecord(2)


record.StringData(1) = TransformName


record.SetStream 2, TransformName & “.mst” : CheckError


view.Modify msiViewModifyAssign, record : CheckError


database.Commit : CheckError


Set database = Nothing


The command line to install the product applying the Transform will look like this:


msiexec /i Minimal.msi TRANSFORMS=:Dev


or


msiexec /i Minimal.msi TRANSFORMS=:Test



 

Comments (4)

  1. kunal rai says:

    Hi sir,

    I have a question?I have to create a msi which is having a same product but having three button through which we can install three separate instance of same product.The product contains three windows service one asp web project one windows utility.Could you please help me for making this successful.

    Thanks.

  2. ikunalrai says:

    Hi sir,

    I have a question?I have to create a msi which is having a same product but having three button through which we can install three separate instance of same product.The product contains three windows service one asp web project one windows utility.Could you please help me for making this successful.

  3. Pratap says:

    Hi,

    Is there a wix 2.0 tool to create the transforms? I see that torch tool does the work in Wix 3.0, but I want to see if it can be done with Wix 2.0 tools.

    -Pratap.