Is it possible to read MSI properties from MSI files in chain before detect phase in bootstrapper?

StackOverflow https://stackoverflow.com/questions/19800430

  •  04-07-2022
  •  | 
  •  

Question

In "Bundle.wxs" I have a "chain" with "MsiPackages" which contain "InstallConditions". In order for the user to decide which packages he/she wants installed/upgraded I would like to display properties found in them.

For instance, I want to read the property "ProductName" and "ProductVersion" in the "Property" table of every MSI in the chain and display it to the user next to a checkbox for every MSI in the chain. The checkbox is wired to the burn variable used in "InstallConditions".

But the problem is, it doesn't seem like I have access to the MSI files before the "Apply" step. They are not extracted from the Bootstrapper Application EXE before this step. So, my question is, Is there a way to load these values programatically in order to display them to the user before the Apply step? I could use variables and populate them myself with the values but this information is already in the MSI so this seems inefficient.

Is there a way to do this? Thanks for the help.

<Bundle>

    <Variable Name="InstallProduct1" Type="string" Value="true" />
    <Variable Name="ProductName1" Type="string" Value="My Product 1"/> <!-- Better way? -->
    <Variable Name="ProductVersion1" Type="version" Value="1.2.3.4"/> <!-- Better way? -->

    <Chain>
              <MsiPackage SourceFile="my_product_1.msi"
                          InstallCondition="InstallProduct1">
              </MsiPackage>
    </Chain>

</Bundle>
Was it helpful?

Solution

WiX does generate a BootstrapperApplicationData.xml file which includes a lot of the information used to build the exe and is included in the files available at runtime. You can parse that file at runtime in order to access that metadata. Since the file, along with all of our assemblies and .msi files, are placed in a randomly-name temp folder, we can’t know ahead of time where the file will live, so we must use our assembly’s path to find it. You can then parse the XML to get the metadata.

I have a blog post with additional details here: https://www.wrightfully.com/part-3-of-writing-your-own-net-based-installer-with-wix-context-data/

In my case, I use the tag instead of '', so have some of the info available to me may not be there for you, so your experience may vary. I would suggest running a makeshift installer in debug mode and setting a breakpoint to inspect the contents of the XML in order to get a full list of what’s available.

Here’s an example of how I get data from the file in my ManagedBootstrapperApplication (c#). Note: in this example, my domain objects are MBAPrereqPackage, BundlePackage and PackageFeature, each of which take an XML node object in their constructor and further parse the data into the object’s properties.

const  XNamespace ManifestNamespace = ( XNamespace) “http://schemas.microsoft.com/wix/2010/BootstrapperApplicationData” ;

public void Initialize()
{

    //
    // parse the ApplicationData to find included packages and features
    //
    var bundleManifestData = this.ApplicationData;
    var bundleDisplayName = bundleManifestData 
                              .Element(ManifestNamespace + “WixBundleProperties“ )
                              .Attribute( “DisplayName“)
                              .Value;

    var mbaPrereqs = bundleManifestData.Descendants(ManifestNamespace + “WixMbaPrereqInformation“)
                                       .Select(x => new MBAPrereqPackage(x))
                                       .ToList();

    //
    //exclude the MBA prereq packages, such as the .Net 4 installer
    //
    var pkgs = bundleManifestData.Descendants(ManifestNamespace + “WixPackageProperties“)
                                 .Select(x => new BundlePackage(x))
                                 .Where(pkg => !mbaPrereqs.Any(preReq => preReq.PackageId == pkg.Id));

    //
    // Add the packages to a collection of BundlePackages
    //
    BundlePackages.AddRange(pkgs);

    //
    // check for features and associate them with their parent packages
    //
    var featureNodes = bundleManifestData.Descendants(ManifestNamespace + “WixPackageFeatureInfo“);
    foreach ( var featureNode in featureNodes)
    {
       var feature = new PackageFeature(featureNode);
       var parentPkg = BundlePackages.First(pkg => pkg.Id == feature.PackageId);
       parentPkg.AllFeatures.Add(feature);
       feature.Package = parentPkg;
    }
}

/// 
/// Fetch BootstrapperApplicationData.xml and parse into XDocument.
/// 
public XElement ApplicationData
{
    get
    {
        var workingFolder = Path.GetDirectoryName(this.GetType().Assembly.Location);
        var bootstrapperDataFilePath = Path.Combine(workingFolder, “BootstrapperApplicationData.xml”);

        using (var reader = new StreamReader(bootstrapperDataFilePath))
        {
            var xml = reader.ReadToEnd();
            var xDoc = XDocument.Parse(xml);
            return xDoc.Element(ManifestNamespace + “BootstrapperApplicationData“);                   
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top