如何使用WiX Burn MBA捆绑包在MajorUpgrade期间检测当前安装的function?

我正在使用WiX 3.7的Burn / Managed Bootstrapper应用程序function来创建基于MBA的自定义安装程序。 对于我的bundle链中的每个软件包,在执行MinorUpdate时,我可以轻松检测已经安装了哪些软件包function,以确保在升级期间通过使用WiX基类中为引导程序提供的这些事件来保留这些function选择: DetectPackageCompleteDetectMsiFeatureDetectRelatedBundleDetectRelatedMsiPackageDetectComplete

但是, 在MajorUpgrade期间,我只看到一种方法来确定安装了哪些软件包,但是没有看到如何确定安装了哪些function,因为DetectMsiFeature事件不会触发。 我尝试在产品的配置上使用MigrateFeatures标志,但这似乎不起作用(或者我没有正确使用它)。

在WiX中使用自定义托管引导程序应用程序执行MajorUpgrade时检测/迁移现有function的正确方法是什么?


一些文件片段:

注意:如果有帮助的话,我可以提供一个包含所有代码的完全可用的VS解决方案。

Bundle.wxs:

             

Product.wxs:

                  

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 */ } } 

升级输出:

请注意,程序包和两个function都安装在v1.0.0中,并在状态为Absent时检测到。 检测到相关包,但未包含任何function详细信息。

检测到相关升级捆绑包{5eff0a3c-4b0d-4fd9-875f-05117c07f373)版本1.0.0.0,这是一个MajorUpgrade
在状态存在中检测到包NetFx4OWeb
检测到相关软件包{540AE32D-75C0-4BF3-A72D-ADBE97FSFF3E}(SetupProject1.msi)版本1.0.0.0,这是一个MajorUpgrade
来自Package SetupProjectl.msi的functionfeature_one在状态Absent中检测到
来自Package SetupProjecti .msi的functionfeature_Two在状态Absent中检测到
程序包SetupProject1.msi在状态缺席时检测到

DetectMsiFeature告诉您新包的function状态; 它没有安装,所以显然function不是。 DetectRelatedMsiPackage为您提供使用(本机)MSI API函数MsiEnumFeatures和MsiGetFeatureState / MsiGetFeatureUsage查询已安装版本的function状态所需的数据。

我将Bob Arnson的回答标记为答案,因为它给了我推动这一点所需要的东西,但对于遇到这篇文章的其他人,我想我会更详细地介绍一下如何收集function状态使用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 } } } } } 
Interesting Posts