Reputation: 1030
I'm currently have difficulty trying to get an MSI (built with WiX) to patch with an MSP (also built with WiX) in a multi instance scenario using an MST built according to the instructions here:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa367797(v=vs.85).aspx
The transform tool I've built:
Installing an MSI with the transform applied seems to work. I invoke msiexec as such:
msiexec /i <product.msi> TRANSFORMS=<instance.mst> MSINEWINSTANCE=1
However, patching doesn't seem to work. I've tried to apply a patch as described here:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa369528(v=vs.85).aspx
msiexec /p <mypatch.msp> /n {product-code}
The installer immediately exits with a dialog stating "The upgrade patch cannot be installed by the Windows Installer service because the program to upgraded may be missing, or the upgrade patch may update a different version of the program."
The base MSI is installed, and the patch has been built with AllowProductCodeMismatches="yes" on the PatchCreation element in WiX.
How can I get the patch to install?
Edit: After further reading it looks like I'm doing some not good things. I've now stopped changing the UpgradeCode property because it doesn't appear needed, and my instance transforms from my own tooling are much lighter.
I've also looked at @YanSklyarenko 's blog entry for patching - he modified the existing patch to alter the ProductCode the patch applies to. I've tried doing the same with similar code:
// Copy original patch
File.Copy(_patchPath, _newPatchPath, true);
// Update patch target product code
using (var patch = new PatchPackage(_patchPath))
using (var patchForWrite = new Database(_newPatchPath, DatabaseOpenMode.Transact))
{
var originalProductCode = patch.GetTargetProductCodes().First();
var productCode = _newProductCode;
foreach (var transform in patch.GetTransforms())
{
// Extract/update transforms
var tempFileName = Path.GetTempFileName();
var transformFileName = transform + _instanceName;
patch.ExtractTransform(transform, tempFileName);
using (var summaryInfo = new SummaryInfo(tempFileName, true))
{
summaryInfo.RevisionNumber = summaryInfo.RevisionNumber.Replace(originalProductCode, productCodeString);
summaryInfo.Persist();
}
// Write transform to new patch
using (var insertView = patchForWrite.OpenView("INSERT INTO `_Storages` (`Name`,`Data`) VALUES ('{0}', ?)", transformFileName))
{
using (var record = new Record(1))
{
record.SetStream(1, new FileStream(tempFileName, FileMode.Open));
insertView.Execute(record);
patchForWrite.Commit();
}
}
// Add transform to patch properties
patchForWrite.SummaryInfo.LastSavedBy += ";:" + transformFileName;
}
// Update patch properties
patchForWrite.SummaryInfo.Template = patchForWrite.SummaryInfo.Template.Replace(originalProductCode, productCodeString);
patchForWrite.SummaryInfo.Persist();
}
I'm still not having any luck installing the patch and msiexec still quits out before writing any log.
Edit 2: I'm still having no luck. I've tried using WiX instance transforms to install with which works, but the patches still won't apply. My PatchCreation element has TargetProductCode elements for each instance defined, and AllowProductCodeMismatches is still turned on.
Edit 3: Sounds like AllowProductCodeMismatches is an MSIMSP thing to allow jumping between two differenct product codes for creating the patch as opposed to validation. The target product codes must be included in the patch. Unfortunately for me the TargetProductCode elements seem to be ignored.
I’m not one 100% positive here, but I think some of the validations had to do with the generation of the patch based on two images, not the patch application itself (in the old school way of genning a patch with MSIMSP from PCP files). If the two images used in patch transform generation didn’t have the same product code and the ProductID validation was set to no, then you would not get an error. Otherwise, an error would be returned during patch generation letting you know that your inputs might not be valid, etc
Upvotes: 1
Views: 1651
Reputation: 1030
I've managed to get this working. Our original patches are created using the PatchCreation element for various reasons. The transforms created this way are setup with validation that checks the ProductCode and UpgradeCode. In the end I updated my transforms to turn this off instead of changing the ProductCode/UpgradeCode for each transform. So in summary to make a patch apply to a new product code:
The patch is then installed with:
REM This works fine
msiexec /p <patch.msp> /n {<ProductCode>}
This didn't work for me - I get an error from the logs stating that the Windows Installer wasn't able to create a temporary copy of the patch.:
REM DON'T USE THIS!
msiexec /i {<ProductCode>} PATCH=<patch.msp>
Edit: The appropriate validation flags to disable are:
PatchProduct = 0x00020000, // Disables product code matches
PatchUpgradeCode = 0x08000000, // Disables upgrade code matches
PatchMagic = 0x00040000, // Heck knows what this does - but Orca disables this
Upvotes: 1
Reputation: 11013
Creating a patch involves following multiple rules, not just matching the product code. The following MSDN article explains these rules with more details:http://msdn.microsoft.com/en-us/library/aa367850.aspx
As you can also in the article linked by Yan Sklyarenko, the same rules caused him problems in the beginning too.
Upvotes: 1