首页 文章

如何使用InstallScope = perMachine处理从具有ALLUSERS = false的* .vdproj安装程序到WiX安装程序的转换

提问于
浏览
1

我们正在将安装程序从Visual Studio Installer项目(* .vdproj)升级到WiX安装程序 . 从我们的用户角度来看,我们希望尽可能无缝地进行此转换 . 即如果他们的软件版本是使用* .vdproj版本中的MSI安装的,那么使用WiX版本中的MSI进行的v2.0安装应该覆盖/删除旧版本并继续正常运行 .

我们遇到的问题是原始的* .vdproj安装程序将软件安装为“ALLUSERS = false”,而现在使用WiX我们想使用InstallScope =“perMachine”(即“ALLUSERS = true”) .

我们使用自举的WiX安装程序,其中链中的第一个元素处理.Net Framework安装(如果需要),第二个元素是我们产品的MSI安装程序 .

这是我们第一次尝试升级代码的样子[1] [2]

<MajorUpgrade DowngradeErrorMessage="A newer version of ... is already installed." />

<Upgrade  Id="{UPGRADE-CODE-OF-OLD-INSTALLER}">
    <UpgradeVersion OnlyDetect="no" Property="OTHER_STUFF_FOUND" Minimum="0.0.0" />
</Upgrade>

如果我们在新的WiX安装程序中设置InstallScope =“perUser”,那么这将按预期工作,但是如果我们设置InstallScope =“perMachine”,则卸载失败并记录此错误:

MSI (c) (04:10) [23:18:49:626]: FindRelatedProducts: current install is per-machine.  Related install for product '{PRODUCT-CODE-OF-OLD-INSTALLER}' is per-user.  Skipping...

经过一些研究后,我们了解到这是一个已知问题,并且由于Microsoft安装程序阻止了上下文切换(即从perUser到perMachine),因此无法像上面所述那样简单地解决问题 .

问题是:我们如何以稳健的方式处理此升级?目前我们没有可行的解决方案 .

我可以想到几个选项,但想看看人们是否有更好的答案,关于哪个选项最好的建议,或者关于如何实施这些列出的方法之一的建议:

  • 使用自定义操作手动卸载旧软件或向用户发出警告,以手动卸载旧版本并终止安装 . 如果我们知道旧安装程序的升级代码,我们应该能够搜索注册表以查看是否安装了旧软件?当我看着re

  • 我可以使用另一个以InstallScope = "perUser"运行的WiX MSI安装程序,并且全权负责删除旧安装吗?

  • 我找到了这个解决方案[3],但是因为我们使用的是Bootstrapped安装程序,我们的MSI项目中的标签没有被执行所以它对我们不起作用 .

  • 将我们的新WiX安装程序更改为"perUser"并在未来的某个时间处理此问题(不是理想的解决方案)

关于卸载旧的perUser安装 . 如果与最初用于每用户安装的用户相比,登录的用户不同,那么可能会出现问题?这里有什么问题我们应该注意吗?

UPDATE

我已经尝试使用CustomAction的方法,我使用升级代码调用 MsiEnumRelatedProducts 以查看我们的软件的先前版本是否已安装,然后调用

msiexec /X {PRODUCT-CODE-FOUND-USING-MsiEnumRelatedProducts} \q

卸载旧版本 . 但是,这不起作用,因为MSI似乎使用Mutex锁来确保一次只能执行一个MSI操作 .

1 回答

  • 1

    我会回答我自己的问题 .

    最后,我使用以下代码创建了一个CustomInstallerAction:

    public class CustomActions
    {
        [CustomAction]
        public static ActionResult CustomAction1(Session session)
        {
            session.Log("Begin CustomAction1");
    
            StringBuilder sbProductCode = new StringBuilder(39);
            uint iIndex = 0;
    
            try
            {
                while (0 == MsiEnumRelatedProducts("YOUR MSI GUID HERE", 0, iIndex++, sbProductCode))
                {
                    session.Message(InstallMessage.Error, new Record(1) { FormatString = "Setup has detected a version of the software from 2016 or earlier.  Please manually uninstall this version using the Control Panel before installing this new version." });
    
                    return ActionResult.UserExit;
                }
            }
            catch (Exception ex)
            {
                session.Log("2: " + ex.ToString());
            }
            return ActionResult.Success;
        }
    
    
        public static string EnumRelatedProducts(string UpgradeCode, uint Index)
        {
            StringBuilder ProductCode = new StringBuilder();
            UInt32 rc = MsiEnumRelatedProducts(UpgradeCode, 0, Index, ProductCode);
            Console.WriteLine("Returned");
            if (rc != 0)
            {
                return string.Empty;
            }
    
            return ProductCode.ToString();
        }
    
        [DllImport("msi.dll")]
        private static extern uint MsiEnumRelatedProducts(
             string lpUpgradeCode,
             uint dwReserved,
             uint lProductIndex,
             StringBuilder lpProductBuf);
    
    }
    

    并在WiX安装程序中添加以下内容:

    <Binary Id="****" src="..\***\bin\$(var.Configuration)\***.CustomInstallerAction.CA.dll" />
    
    <CustomAction Id="RemoveVDPROJVersions" Return="check" Execute="immediate" BinaryKey="***.CustomInstallerAction.CA.dll" DllEntry="CustomAction1" />
    
    <InstallExecuteSequence>
      <Custom Action="RemoveVDPROJVersions" Before="LaunchConditions">
        NOT Installed AND NOT REMOVE
      </Custom>
    </InstallExecuteSequence>
    

相关问题