Gareth Oakley
Gareth Oakley

Reputation: 1030

MSI multi-instance installation with patches

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.

http://windows-installer-xml-wix-toolset.687559.n2.nabble.com/Re-Multiple-instance-patches-td1559146.html

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

Answers (2)

Gareth Oakley
Gareth Oakley

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:

  • Update the Template SummaryInfo property and replace the original ProductCode with the instances ProductCode
  • Extract the transforms and replace them with versions disabling the validation for ProductCode and UpgradeCode

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

Bogdan Mitrache
Bogdan Mitrache

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

Related Questions