10

I'm using WiX 3.7's Burn/Managed Bootstrapper Application features to create a custom MBA-based installer. For each of the packages in my bundle's chain, when performing a MinorUpdate, I can easily detect which of the package features are already installed to ensure I maintain those feature selections during the upgrade by using these events provided in the WiX base class for the bootstrapper: DetectPackageComplete, DetectMsiFeature, DetectRelatedBundle, DetectRelatedMsiPackage, DetectComplete.

However, during a MajorUpgrade, I'm only seeing a way to determine which package(s) are installed, but am not seeing how to determine which features are installed, as the DetectMsiFeature event does not fire. I tried using the MigrateFeatures flag on the product's configuration, but that doesn't seem to work (or I'm not using it right).

What is the correct way to detect/migrate existing features when performing a MajorUpgrade using a Custom Managed Bootstrapper Application in WiX?


Some file snippets:

Note: I can provide a fully working VS Solution with all code if that is helpful.

Bundle.wxs:
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:bal="http://schemas.microsoft.com/wix/BalExtension">
    <Bundle Name="Bootstrapper1"  Version="1.1.0.0" Manufacturer="Knights Who Say Ni" UpgradeCode="e6fbf160-d1d9-4b38-b293-94d60eae876f" Compressed="yes">    
        <BootstrapperApplicationRef Id="ManagedBootstrapperApplicationHost" >
          <Payload SourceFile="$(var.ManagedBootstrapperApplication.TargetPath)" />
          <!-- other files here -->
        </BootstrapperApplicationRef>
        <Chain>      
          <PackageGroupRef Id="NetFx40Web" />
          <MsiPackage SourceFile="$(var.SetupProject1.TargetPath)" EnableFeatureSelection="yes" Vital="yes"  Compressed="yes" />
        </Chain>
    </Bundle>
</Wix>

Product.wxs:

<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
    <Product Id="*" Name="SetupProject1" Language="1033" Codepage="1252"
           Version="1.1.0.0" Manufacturer="Knights Who Say Ni" 
           UpgradeCode="5fcd463a-3287-4fdf-bf00-d5d74baeccda">

        <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
        <MajorUpgrade AllowSameVersionUpgrades="no" AllowDowngrades="no" MigrateFeatures="yes" DowngradeErrorMessage="Bring me a shrubbery!" />
        <MediaTemplate EmbedCab="yes" />

        <Feature Id="feature_one" Title="Primary Feature" Level="1">      
          <Component Id="CMP_emptyFile1" Guid="{1740AFA6-A98F-482A-B319-A153AA1BEF10}" Directory="INSTALLFOLDER">
            <File Id="file_emptyFile1" Checksum="yes" KeyPath="yes" Source="TextFile1.txt" />
          </Component>      
        </Feature>
        <Feature Id="feature_Two" Title="Optional Feature" Level="2">
          <Component Id="CMP_emptyFile2" Guid="{F0831C98-AF35-4F5E-BE9A-2F5E3ECF893C}" Directory="INSTALLFOLDER">
            <File Id="file_emptyFile2" Checksum="yes" KeyPath="yes" Source="TextFile2.txt"  />
          </Component>
        </Feature>    
    </Product>
</Wix>

CustomBootstrapper.cs

public class CustomBootstrapperApplication : BootstrapperApplication {        
    protected override void Run() {
            DetectPackageComplete += HandlePackageDetected;
            DetectMsiFeature += HandleFeatureDetected;
            DetectRelatedBundle += HandleExistingBundleDetected;
            DetectRelatedMsiPackage += HandleExistingPackageDetected;
            DetectComplete += HandleDetectComplete;
            this.Engine.Detect();
            //blocks here until DetectComplete fires...
    }

    private void HandleExistingPackageDetected(object sender, DetectRelatedMsiPackageEventArgs e) {
        Log(string.Format("Detected Related Package {2} ({1}) at version {3} which is a {0}",
            e.Operation, e.PackageId, e.ProductCode, e.Version));
    }

    private void HandleExistingBundleDetected(object sender, DetectRelatedBundleEventArgs e) {
        Log(string.Format("Detected Related {2} Bundle {0} at version {1} which is a {3}",
            e.ProductCode, e.Version, e.RelationType, e.Operation));
    }

    private void HandleFeatureDetected(object sender, DetectMsiFeatureEventArgs e) {
        Log(string.Format("Feature {0} from Package {1} detected in state {2}",
            e.FeatureId, e.PackageId, e.State));
    }

    private void HandlePackageDetected(object sender, DetectPackageCompleteEventArgs e) {
        Log(string.Format("Package {0} Detected in State {1}",
            e.PackageId, e.State));
    }

    private void HandleDetectComplete(object sender, DetectCompleteEventArgs e)
    { /* release the main thread to continue with work */ }

}

Output on upgrade:

Note that the package and two features were both installed at v1.0.0 and detected in state Absent. The Related Package was detected, but no feature details are included.

Detected Related Upgrade Bundle {5eff0a3c-4b0d-4fd9-875f-05117c07f373) at version 1.0.0.0 which is a MajorUpgrade
Package NetFx4OWeb Detected in State Present
Detected Related Package {540AE32D-75C0-4BF3-A72D-ADBE97FSFF3E} (SetupProject1.msi) at version 1.0.0.0 which is a MajorUpgrade
Feature feature_one from Package SetupProjectl.msi detected in state Absent
Feature feature_Two from Package SetupProjecti .msi detected in state Absent
Package SetupProject1.msi Detected in State Absent
4

2 に答える 2

17

これを推進するために必要なものが得られたので、ボブ・アーンソンの回答を回答としてマークしていますが、この投稿に出くわした他の人のために、機能の状態を収集する方法についてもう少し詳しく説明したいと思いましたWiX が提供するProductInstallationクラス (WiX SDK にある Microsoft.Deployment.WindowsInstaller.dll アセンブリにあります) を使用するため、ネイティブ MSI API を独自に直接呼び出す必要がなくなります。

DetectRelatedMsiPackageイベントに登録できるメソッドの例を次に示します。計画段階で適切な状態を設定できるように、収集した情報を保存する必要があることに注意してください。

private void DetectRelatedMsiPackageHandler(object sender, DetectRelatedMsiPackageEventArgs e)
{
    var existingPackageProductCode = e.ProductCode;
    var actionToBeAppliedToExistingPackage = e.Operation;
    var existingPackageId = e.PackageId;
    var existingPackageVersion = e.Version;

    Log(string.Format("Detected existing related package {0} (product: {1}) at version {2}, which will be {3}",
                      existingPackageId, existingPackageProductCode, existingPackageVersion,
                      actionToBeAppliedToExistingPackage));

    if (actionToBeAppliedToExistingPackage == RelatedOperation.MajorUpgrade)
    {

        //requires reference to WiX Toolset\SDK\Microsoft.Deployment.WindowsInstaller.dll
        var installedPackage = new Microsoft.Deployment.WindowsInstaller.ProductInstallation(existingPackageProductCode);
        if (!installedPackage.IsInstalled) {
            Log(string.Format("Migrating Package {0}, which is not installed, so marking it and it's features as Absent", existingPackageId));
            //TODO: add logic to store state so that during Plan phase can set package with package with product code = existingPackageProductCode to PackageState.Absent
        } else {
            Log(string.Format("Migrating features for MajorUpgrade of Package {0}", existingPackageId));

            foreach (var currentInstallFeature in installedPackage.Features) {                        
                if (currentInstallFeature.State == InstallState.Local) {
                    Log(string.Format("Migrating feature {1} of Package {0} - marking as Present", existingPackageId, currentInstallFeature.FeatureName));
                    //TODO: add logic to store state so that during Plan phase can set package and feature states based on this info
                } else {
                    Log(string.Format("Migrating feature {1} of Package {0} - marking as Absent", existingPackageId, currentInstallFeature.FeatureName));
                    //TODO: add logic to store state so that during Plan phase can set package and feature states based on this info
                }
            }
        }
    }
}
于 2013-07-09T22:42:45.580 に答える
9

DetectMsiFeature は、新しいパッケージの機能の状態を示しています。インストールされていないため、明らかに機能はインストールされていません。DetectRelatedMsiPackage は、(ネイティブ) MSI API 関数 MsiEnumFeatures および MsiGetFeatureState/MsiGetFeatureUsage を使用して、インストールされているバージョンの機能の状態を照会するために必要なデータを提供します。

于 2013-07-09T19:05:44.537 に答える