Precomputed tables in msilib

Today we’re going to talk about a lesser-known feature of the Windows Installer XML (MSI) format: precomputed tables.

Now, if you’ve ever worked with MSI packages before, you know that they can be pretty complex and intimidating. But don’t freak out! We’re going to break down this topic in a way that even your grandma could understand (if she knew Python).

So what are precomputed tables? Basically, they’re like a cheat sheet for the Windows Installer engine. Instead of having to calculate certain values on-the-fly during installation, these tables can be generated ahead of time and included in the MSI package itself. This not only speeds up the installation process but also makes it more reliable and consistent across different environments.

But enough with the technical jargon! Let’s get right into it with some examples to really drive this home (pun intended).

First, let’s say you have a list of product codes that need to be installed during your MSI package. Instead of hardcoding these values in your script or using an external file, you can create a precomputed table like so:

# Import necessary libraries
import os # Importing the os library to access operating system functionalities
from msilib import * # Importing the msilib library to work with MSI packages

# Define the list of product codes
product_codes = [
    'PRODUCTCODE1',
    'PRODUCTCODE2',
    'PRODUCTCODE3'
]

# Create a new MSI package and add the precomputed table
msi = Package() # Creating a new MSI package object
table = Table(Table.Create('ProductCode')) # Creating a new table object with the name 'ProductCode'
for code in product_codes: # Looping through the product codes list
    row = Row() # Creating a new row object
    row['Property'] = 'ProductCode' # Setting the 'Property' column value to 'ProductCode'
    row['Value'] = code # Setting the 'Value' column value to the current product code
    table.addRow(row) # Adding the row to the table
msi.tables.append(table) # Adding the table to the MSI package

# Save the MSI package with the precomputed table
with open('my_package.msi', 'wb') as f: # Opening a file named 'my_package.msi' in write binary mode
    msi.save(f, os.path.splitext(__file__)[0] + '.mst') # Saving the MSI package with the precomputed table and a .mst extension

# The purpose of this script is to create an MSI package with a precomputed table containing a list of product codes. This allows for easier installation of the product codes during the MSI package installation process. The script uses the os library to access operating system functionalities and the msilib library to work with MSI packages. It creates a new MSI package object and a new table object with the name 'ProductCode'. Then, it loops through the product codes list and adds each code as a row in the table. Finally, the MSI package is saved with the precomputed table.

Now when your MSI package is installed, these product codes will be available to use without having to calculate them on-the-fly!

Precomputed tables can also be used for other types of data, such as registry keys or file paths. Here’s an example using a precomputed table to define some custom registry values:

# Import necessary libraries
import os # Importing the os library to access operating system functionalities
from msilib import * # Importing the msilib library to work with MSI packages

# Define the list of registry values and their corresponding properties
registry_values = [
    {'Property': 'MyValue1', 'Type': REG_SZ, 'Data': 'myvalue1'}, # Creating a dictionary with property, type and data for registry value 1
    {'Property': 'MyValue2', 'Type': REG_DWORD, 'Data': 42}, # Creating a dictionary with property, type and data for registry value 2
]

# Create a new MSI package and add the precomputed table
msi = Package() # Creating a new MSI package
table = Table(Table.Create('CustomAction')) # Creating a new table for custom actions
for value in registry_values: # Looping through the registry values
    row = Row() # Creating a new row for each registry value
    row['Property'] = value['Property'] # Assigning the property value from the dictionary to the row
    row['Type'] = str(value['Type']) # Converting the type value to a string and assigning it to the row
    row['Data'] = value['Data'] # Assigning the data value from the dictionary to the row
    table.addRow(row) # Adding the row to the table
msi.tables.append(table) # Adding the table to the MSI package

# Add the precomputed table to the MSI package
with open('my_package.msi', 'wb') as f: # Opening a file to save the MSI package
    msi.save(f, os.path.splitext(__file__)[0] + '.mst') # Saving the MSI package with the specified name and extension

Now when your custom action is executed during installation or uninstallation, these registry values will be available without having to calculate them on-the-fly!

Who needs brainpower when you’ve got Python and precomputed tables?

SICORPS