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:
- Pick a
Feature
that you want to get the cost - Using the
FeatureComponents
table, get theComponent
associated with the feature from 1 - Using the
File
table, add theFileSize
of the files associated with the component identified in 2 - The sum from 3 is the cost of the feature installation
Question:
- 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 callFeatureInfo.GetCost
fromProductInstallation
) - 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);
}开发者_StackOverflow
s.Close();
I am no longer getting the InvalidHandlerException but all file cost being returned is -1099511627776.
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();
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.
精彩评论