我们正在将安装程序从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安装程序。
<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),因此无法像上面所述那样直接使用解决方案。
问题是:我们如何以稳健的方式处理此升级?目前我们没有可行的解决方案。
我可以考虑一些选项,但想看看人们是否有更好的答案,关于哪个选项最佳的建议,或者建议如何实施这些列出的方法之一:
关于卸载旧的perUser安装。如果与最初用于每用户安装的用户相比,登录的用户不同,那么可能会出现问题?这里有任何我们应该注意的问题吗?
更新
我尝试过使用CustomAction的方法,我使用升级代码调用MsiEnumRelatedProducts
来查看我们软件的先前版本是否已安装,然后调用
msiexec /X {PRODUCT-CODE-FOUND-USING-MsiEnumRelatedProducts} \q
卸载旧版本。但是,这不起作用,因为MSI似乎使用Mutex锁来确保一次只能执行一次MSI操作。
答案 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>