如何使用InstallScope = perMachine

时间:2016-10-24 22:48:06

标签: .net wix

我们正在将安装程序从Visual Studio Installer项目(* .vdproj)升级到WiX安装程序。从我们的用户角度来看,我们希望尽可能无缝地进行此转换。即如果他们的软件版本1.0是使用* .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),因此无法像上面所述那样直接使用解决方案。

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

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

  1. 使用自定义操作手动卸载旧软件或向用户发出警告,以手动卸载旧版本并终止安装。如果我们知道旧安装程序的升级代码,我们应该能够搜索注册表以查看是否安装了旧软件?当我查看了重新
  2. 我可以安装另一个以InstallScope =“perUser”运行的WiX MSI安装程序,并且全权负责删除旧安装吗?
  3. 我找到了这个解决方案[3],但是因为我们使用的是Bootstrapped安装程序,我们的MSI项目中的标签没有被执行,所以它对我们不起作用。
  4. 将我们的新WiX安装程序更改为“perUser”并在未来某个时间处理此问题(不是理想的解决方案)
  5. 关于卸载旧的perUser安装。如果与最初用于每用户安装的用户相比,登录的用户不同,那么可能会出现问题?这里有任何我们应该注意的问题吗?

    更新

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

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

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

1 个答案:

答案 0 :(得分: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>
相关问题