There is no standard way to accomplish it, because multi-MSI transactions are not supported by WiX.
I found a workaround that works for me. I use Custom Bootstrapper Application, so I can handle failure event in C# code. If you use WiX Standard Bootstrapper Application (WiXStdBA) it will not help you.
If update failed, I call previous bundle installer from Windows Package Cache in silent repair mode. It restores previous state.
Next code expresses the idea:
Bootstrapper.PlanRelatedBundle += (o, e) => { PreviousBundleId = e.BundleId; };
Bootstrapper.ApplyComplete += OnApplyComplete;
private void OnApplyComplete(object sender, ApplyCompleteEventArgs e)
{
bool updateFailed = e.Status != 0 && _model.InstallationMode == InstallationMode.Update;
if (updateFailed)
{
var registryKey = string.Format("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{0}", VersionManager.PreviousBundleId);
RegistryKey key = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(registryKey)
?? RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(registryKey);
if (key != null)
{
string path = key.GetValue("BundleCachePath").ToString();
var proc = new Process();
proc.StartInfo.FileName = path;
proc.StartInfo.Arguments = "-silent -repair";
proc.Start();
proc.WaitForExit();
}
}
}