Applying MST transforms to an MSI database

This blog entry provides an example of applying MST transforms to an MSI database using VBScript. It follows on from the previous blog post which provided a tutorial on using inner joins when reading from an MSI database using VBScript.

It forms part 12 of an 17-part series that explores how to use VBScript to manipulate MSI relational databases using the Windows Installer API. Throughout this series of tutorials, we identify the common issues that we encounter and the best practises that we use to overcome them.

For this example I’ve created a sample MST file. Our test MSI has an entry in the Registry table with a primary key of ‘SampleReg’ and a Value of ‘This is an MSI’. To create the transform I used Orca. I opened our test MSI, selected the ‘Transform’ menu option, and scrolled down and clicked ‘New Transform’. I then changed the Value of our ‘SampleReg’ row to be ‘This is an MST’. To create the new transform file, I then selected the ‘Transform’ menu option, and scrolled down and clicked ‘Generate Transform’. By changing this value via a transform, it should enable us to see if the transform has applied.

To start with, copy and paste the following code into your script file:

'create 2 constants - one for when we want to just query the MSI (read) and one for when we want to make changes (write)
Const msiOpenDatabaseModeReadOnly = 0
Const msiOpenDatabaseModeTransact = 1
' Adds a row that already exists.
Const msiTransformErrorAddExistingRow = 1 
' Deletes a row that does not exist.
Const msiTransformErrorDeleteNonExistingRow = 2 
' Adds a table that already exists.
Const msiTransformErrorAddExistingTable = 4 
' Deletes a table that does not exist.
Const msiTransformErrorDeleteNonExistingTable = 8 
' Updates a row that does not exist.
Const msiTransformErrorUpdateNonExistingRow = 16 
' Transform and database code pages do not match and neither has a neutral code page.
Const msiTransformErrorChangeCodePage = 32 
' Creates the temporary _TransformView table.
Const msiTransformErrorViewTransform = 256 
Dim errorCondition : errorCondition = msiTransformErrorChangeCodePage + msiTransformErrorUpdateNonExistingRow + msiTransformErrorDeleteNonExistingTable _
+ msiTransformErrorAddExistingTable + msiTransformErrorDeleteNonExistingRow + msiTransformErrorAddExistingRow
'create WindowsInstaller.Installer object
Dim oInstaller : Set oInstaller = CreateObject("WindowsInstaller.Installer")
'open the MSI (the first argument supplied to the vbscript)
Dim oDatabase : Set oDatabase = oInstaller.OpenDatabase(WScript.Arguments(0),msiOpenDatabaseModeReadOnly) 
Dim sql : sql = "SELECT `Value` FROM `Registry` WHERE `Registry` = 'SampleReg'"
'create a view of the registry we want to see
Dim regView : Set regView = oDatabase.OpenView(sql)
'execute the query
regView.Execute 
'fetch the first row of data (if there is one!)
Dim regRecord : Set regRecord = regView.Fetch
'whilst we've returned a row and therefore regRecord is not Nothing
While Not regRecord Is Nothing
'print out the registry key
wscript.echo "Value from MSI is: " & regRecord.StringData(1)
'go and fetch the next row of data	
Set regRecord = regView.Fetch
Wend
Set regRecord = Nothing
wscript.echo "(...applying MST)"
'apply every transform in the argument list
For i = 1 To Wscript.Arguments.Count - 1
oDatabase.ApplyTransform Wscript.Arguments(i), errorCondition
oDatabase.Commit
Next
sql = "SELECT `Value` FROM `Registry` WHERE `Registry` = 'SampleReg'"
'create a view of the registry we want to see
Set regView = oDatabase.OpenView(sql)
'execute the query
regView.Execute 
'fetch the first row of data (if there is one!)
Set regRecord = regView.Fetch
'whilst we've returned a row and therefore regRecord is not Nothing
While Not regRecord Is Nothing
'print out the registry key
wscript.echo "Value from MST is: " & regRecord.StringData(1)
'go and fetch the next row of data	
Set regRecord = regView.Fetch
Wend
regView.Close
Set regView = Nothing
Set regRecord = Nothing
Set oDatabase = Nothing
Set oInstaller = Nothing

To run it, we need to specify both our MSI file and our MST file:

Open up a Command Prompt
Type: cscript.exe alkaneTestScript.vbs “c:\alkaneMSIs\testMSI.msi” “c:\alkaneMSIs\testMST.mst”

You should see the following result:

The only new part to this script is that we use the ApplyTransform method to apply one (or many!) transforms to our MSI:

'apply every transform in the argument list
For i = 1 To Wscript.Arguments.Count - 1
oDatabase.ApplyTransform Wscript.Arguments(i), 63
oDatabase.Commit
Next

In the excerpt of code above, we loop through the arguments we’ve passed in to the VBCsript (exclusing the first argument – the MSI), we apply the transform to the database and we commit the changes.

Thanks for reading about applying MST transforms to an MSI database using VBScript. Next you can find out how to generate transforms for an MSI database using VBScript.