Get feature installation cost prior to installatio

2019-08-22 03:12发布

问题:

We're making a custom boostrapper / external UI for our installation.

We want to provide a "Custom Installation" dialog (like in MSI) to allow the user to choose feature(s) they want to install or remove.

Currently, we are able to read the features (and other feature details like description) from the MSI database itself (by running an SQL query on the Feature table).

However, we also want to display the cost of installing a feature. Windows Installer "Custom Installation" dialog is capable of doing this.

I think we can mimic the behavior by doing the following:

  1. Pick a Feature that you want to get the cost
  2. Using the FeatureComponents table, get the Component associated with the feature from 1
  3. Using the File table, add the FileSize of the files associated with the component identified in 2
  4. The sum from 3 is the cost of the feature installation

Question:

  1. Is there an API (either from DTF or MSI.DLL) that we can use to get the cost of a feature PRIOR to installation? (There is a FeatureInfo.GetCost method in DTF but you can't use that directly. The product must be installed first before you can call FeatureInfo.GetCost from ProductInstallation)
  2. If there is no API, is the procedure given above appropriate or correct to calculate the cost of a feature installation?

Thanks! :)

UPDATE # 1

I think there's a way to get the cost of a feature installation through the API even PRIOR to starting installation. Here's how I did it:

Installer.SetInternalUI(InstallUIOptions.Silent);

Session s = Installer.OpenPackage(@"C:\a.msi", false);

foreach (FeatureInfo info in s.Features)
{
    MessageBox.Show(info.Name);
    MessageBox.Show(info.GetCost(false, false, InstallState.Unknown).ToString());
}
s.Close();

calling info.name successfully returns the name of the feature. However, calling info.GetCost will return an InvalidHandlerException with a message: "selection manager not initialized".

Here's where I'm currently at.

Update #2:

I was getting the InvalidHandlerException because I am not invoking the needed file costing routines before I call info.GetCost. Here's my modified code:

  Installer.SetInternalUI(InstallUIOptions.Silent);

  Session s = Installer.OpenPackage(@"C:\1.msi", false);
  s["ROOTDRIVE"] = @"C:\";
  s.DoAction("CostInitialize");
  s.DoAction("FileCost");
  s.DoAction("CostFinalize");

  foreach (FeatureInfo info in s.Features)
  {
       long cost = info.GetCost(false, false, InstallState.Local);
       MessageBox.Show(info.Title + " " + cost);
  }
  s.Close();

I am no longer getting the InvalidHandlerException but all file cost being returned is -1099511627776.

回答1:

This isn't the answer you are looking for but I would suggest pre-calculating the sizes of the features at build time and using a precalculated table during install. This is what we do in Burn in WiX v3.6. It is much faster and much more stable.



回答2:

Yes, there is an API. You need to get an MSI Session by calling OpenPackage. By doing so, you will have access to the Feature list which will give you access to the GetCost method.

1 Gotcha: You need to perform 4 standard actions before calculating the cost: CostInitialize, FileCost, CostFinalize and InstallValidate.

    Installer.SetInternalUI(InstallUIOptions.Silent);

    Session s = Installer.OpenPackage(@"C:\1.msi", false);
    s.DoAction("CostInitialize");
    s.DoAction("FileCost");
    s.DoAction("CostFinalize");
    s.DoAction("InstallValidate");

    foreach (FeatureInfo info in s.Features)
    {
        long cost = info.GetCost(false, false, InstallState.Local);
        MessageBox.Show(info.Title + " " + cost);
    }
    s.Close();