diff options
| author | Sean Hall <r.sean.hall@gmail.com> | 2021-02-22 16:16:12 -0600 |
|---|---|---|
| committer | Sean Hall <r.sean.hall@gmail.com> | 2021-02-22 20:25:06 -0600 |
| commit | 4f4c85ed66f1b2dfb1bec76d54d7b50c637d5bfa (patch) | |
| tree | 6de8e63ad46626ec457af256d481e81d726f3860 /src | |
| parent | d0d93beac0b79fa9c3d43398813954988afda18f (diff) | |
| download | wix-4f4c85ed66f1b2dfb1bec76d54d7b50c637d5bfa.tar.gz wix-4f4c85ed66f1b2dfb1bec76d54d7b50c637d5bfa.tar.bz2 wix-4f4c85ed66f1b2dfb1bec76d54d7b50c637d5bfa.zip | |
Add patch target for slipstream MSI package even if not installed.
Fixes #3897
Diffstat (limited to 'src')
| -rw-r--r-- | src/engine/core.cpp | 3 | ||||
| -rw-r--r-- | src/engine/detect.cpp | 10 | ||||
| -rw-r--r-- | src/engine/msiengine.cpp | 56 | ||||
| -rw-r--r-- | src/engine/msiengine.h | 3 | ||||
| -rw-r--r-- | src/engine/mspengine.cpp | 196 | ||||
| -rw-r--r-- | src/engine/mspengine.h | 16 | ||||
| -rw-r--r-- | src/engine/package.cpp | 23 | ||||
| -rw-r--r-- | src/engine/package.h | 21 | ||||
| -rw-r--r-- | src/engine/plan.cpp | 4 | ||||
| -rw-r--r-- | src/test/BurnUnitTest/BurnUnitTest.vcxproj | 1 | ||||
| -rw-r--r-- | src/test/BurnUnitTest/PlanTest.cpp | 303 | ||||
| -rw-r--r-- | src/test/BurnUnitTest/TestData/PlanTest/Slipstream_BundleA_manifest.xml | 1 |
12 files changed, 546 insertions, 91 deletions
diff --git a/src/engine/core.cpp b/src/engine/core.cpp index 1a079973..cb7ebbfd 100644 --- a/src/engine/core.cpp +++ b/src/engine/core.cpp | |||
| @@ -351,6 +351,9 @@ extern "C" HRESULT CoreDetect( | |||
| 351 | { | 351 | { |
| 352 | hr = MspEngineDetectInitialize(&pEngineState->packages); | 352 | hr = MspEngineDetectInitialize(&pEngineState->packages); |
| 353 | ExitOnFailure(hr, "Failed to initialize MSP engine detection."); | 353 | ExitOnFailure(hr, "Failed to initialize MSP engine detection."); |
| 354 | |||
| 355 | hr = MsiEngineDetectInitialize(&pEngineState->packages); | ||
| 356 | ExitOnFailure(hr, "Failed to initialize MSI engine detection."); | ||
| 354 | } | 357 | } |
| 355 | 358 | ||
| 356 | for (DWORD i = 0; i < pEngineState->packages.cPackages; ++i) | 359 | for (DWORD i = 0; i < pEngineState->packages.cPackages; ++i) |
diff --git a/src/engine/detect.cpp b/src/engine/detect.cpp index b702306e..9bb58487 100644 --- a/src/engine/detect.cpp +++ b/src/engine/detect.cpp | |||
| @@ -82,6 +82,16 @@ extern "C" void DetectReset( | |||
| 82 | 82 | ||
| 83 | pFeature->currentState = BOOTSTRAPPER_FEATURE_STATE_UNKNOWN; | 83 | pFeature->currentState = BOOTSTRAPPER_FEATURE_STATE_UNKNOWN; |
| 84 | } | 84 | } |
| 85 | |||
| 86 | for (DWORD iSlipstreamMsp = 0; iSlipstreamMsp < pPackage->Msi.cSlipstreamMspPackages; ++iSlipstreamMsp) | ||
| 87 | { | ||
| 88 | BURN_SLIPSTREAM_MSP* pSlipstreamMsp = pPackage->Msi.rgSlipstreamMsps + iSlipstreamMsp; | ||
| 89 | |||
| 90 | pSlipstreamMsp->dwMsiChainedPatchIndex = BURN_PACKAGE_INVALID_PATCH_INDEX; | ||
| 91 | } | ||
| 92 | |||
| 93 | ReleaseNullMem(pPackage->Msi.rgChainedPatches); | ||
| 94 | pPackage->Msi.cChainedPatches = 0; | ||
| 85 | } | 95 | } |
| 86 | else if (BURN_PACKAGE_TYPE_MSP == pPackage->type) | 96 | else if (BURN_PACKAGE_TYPE_MSP == pPackage->type) |
| 87 | { | 97 | { |
diff --git a/src/engine/msiengine.cpp b/src/engine/msiengine.cpp index 801bf9a8..ae105155 100644 --- a/src/engine/msiengine.cpp +++ b/src/engine/msiengine.cpp | |||
| @@ -213,8 +213,8 @@ extern "C" HRESULT MsiEngineParsePackageFromXml( | |||
| 213 | 213 | ||
| 214 | if (cNodes) | 214 | if (cNodes) |
| 215 | { | 215 | { |
| 216 | pPackage->Msi.rgpSlipstreamMspPackages = reinterpret_cast<BURN_PACKAGE**>(MemAlloc(sizeof(BURN_PACKAGE*) * cNodes, TRUE)); | 216 | pPackage->Msi.rgSlipstreamMsps = reinterpret_cast<BURN_SLIPSTREAM_MSP*>(MemAlloc(sizeof(BURN_SLIPSTREAM_MSP) * cNodes, TRUE)); |
| 217 | ExitOnNull(pPackage->Msi.rgpSlipstreamMspPackages, hr, E_OUTOFMEMORY, "Failed to allocate memory for slipstream MSP packages."); | 217 | ExitOnNull(pPackage->Msi.rgSlipstreamMsps, hr, E_OUTOFMEMORY, "Failed to allocate memory for slipstream MSP packages."); |
| 218 | 218 | ||
| 219 | pPackage->Msi.rgsczSlipstreamMspPackageIds = reinterpret_cast<LPWSTR*>(MemAlloc(sizeof(LPWSTR*) * cNodes, TRUE)); | 219 | pPackage->Msi.rgsczSlipstreamMspPackageIds = reinterpret_cast<LPWSTR*>(MemAlloc(sizeof(LPWSTR*) * cNodes, TRUE)); |
| 220 | ExitOnNull(pPackage->Msi.rgsczSlipstreamMspPackageIds, hr, E_OUTOFMEMORY, "Failed to allocate memory for slipstream MSP ids."); | 220 | ExitOnNull(pPackage->Msi.rgsczSlipstreamMspPackageIds, hr, E_OUTOFMEMORY, "Failed to allocate memory for slipstream MSP ids."); |
| @@ -383,15 +383,52 @@ extern "C" void MsiEnginePackageUninitialize( | |||
| 383 | MemFree(pPackage->Msi.rgsczSlipstreamMspPackageIds); | 383 | MemFree(pPackage->Msi.rgsczSlipstreamMspPackageIds); |
| 384 | } | 384 | } |
| 385 | 385 | ||
| 386 | if (pPackage->Msi.rgpSlipstreamMspPackages) | 386 | if (pPackage->Msi.rgSlipstreamMsps) |
| 387 | { | 387 | { |
| 388 | MemFree(pPackage->Msi.rgpSlipstreamMspPackages); | 388 | MemFree(pPackage->Msi.rgSlipstreamMsps); |
| 389 | } | ||
| 390 | |||
| 391 | if (pPackage->Msi.rgChainedPatches) | ||
| 392 | { | ||
| 393 | MemFree(pPackage->Msi.rgChainedPatches); | ||
| 389 | } | 394 | } |
| 390 | 395 | ||
| 391 | // clear struct | 396 | // clear struct |
| 392 | memset(&pPackage->Msi, 0, sizeof(pPackage->Msi)); | 397 | memset(&pPackage->Msi, 0, sizeof(pPackage->Msi)); |
| 393 | } | 398 | } |
| 394 | 399 | ||
| 400 | extern "C" HRESULT MsiEngineDetectInitialize( | ||
| 401 | __in BURN_PACKAGES* pPackages | ||
| 402 | ) | ||
| 403 | { | ||
| 404 | AssertSz(pPackages->cPatchInfo, "MsiEngineDetectInitialize() should only be called if there are MSP packages."); | ||
| 405 | |||
| 406 | HRESULT hr = S_OK; | ||
| 407 | |||
| 408 | // Add target products for slipstream MSIs that weren't detected. | ||
| 409 | for (DWORD iPackage = 0; iPackage < pPackages->cPackages; ++iPackage) | ||
| 410 | { | ||
| 411 | BURN_PACKAGE* pMsiPackage = pPackages->rgPackages + iPackage; | ||
| 412 | if (BURN_PACKAGE_TYPE_MSI == pMsiPackage->type) | ||
| 413 | { | ||
| 414 | for (DWORD j = 0; j < pMsiPackage->Msi.cSlipstreamMspPackages; ++j) | ||
| 415 | { | ||
| 416 | BURN_SLIPSTREAM_MSP* pSlipstreamMsp = pMsiPackage->Msi.rgSlipstreamMsps + j; | ||
| 417 | Assert(pSlipstreamMsp->pMspPackage && BURN_PACKAGE_TYPE_MSP == pSlipstreamMsp->pMspPackage->type); | ||
| 418 | |||
| 419 | if (pSlipstreamMsp->pMspPackage && BURN_PACKAGE_INVALID_PATCH_INDEX == pSlipstreamMsp->dwMsiChainedPatchIndex) | ||
| 420 | { | ||
| 421 | hr = MspEngineAddMissingSlipstreamTarget(pMsiPackage, pSlipstreamMsp); | ||
| 422 | ExitOnFailure(hr, "Failed to add slipstreamed target product code to package: %ls", pSlipstreamMsp->pMspPackage->sczId); | ||
| 423 | } | ||
| 424 | } | ||
| 425 | } | ||
| 426 | } | ||
| 427 | |||
| 428 | LExit: | ||
| 429 | return hr; | ||
| 430 | } | ||
| 431 | |||
| 395 | extern "C" HRESULT MsiEngineDetectPackage( | 432 | extern "C" HRESULT MsiEngineDetectPackage( |
| 396 | __in BURN_PACKAGE* pPackage, | 433 | __in BURN_PACKAGE* pPackage, |
| 397 | __in BURN_USER_EXPERIENCE* pUserExperience | 434 | __in BURN_USER_EXPERIENCE* pUserExperience |
| @@ -971,15 +1008,6 @@ extern "C" HRESULT MsiEnginePlanAddPackage( | |||
| 971 | pAction->msiPackage.dwLoggingAttributes = pLog->dwAttributes; | 1008 | pAction->msiPackage.dwLoggingAttributes = pLog->dwAttributes; |
| 972 | } | 1009 | } |
| 973 | 1010 | ||
| 974 | // Update any slipstream patches' state. | ||
| 975 | for (DWORD i = 0; i < pPackage->Msi.cSlipstreamMspPackages; ++i) | ||
| 976 | { | ||
| 977 | BURN_PACKAGE* pMspPackage = pPackage->Msi.rgpSlipstreamMspPackages[i]; | ||
| 978 | AssertSz(BURN_PACKAGE_TYPE_MSP == pMspPackage->type, "Only MSP packages can be slipstream patches."); | ||
| 979 | |||
| 980 | MspEngineSlipstreamUpdateState(pMspPackage, pPackage->execute, pPackage->rollback); | ||
| 981 | } | ||
| 982 | |||
| 983 | LExit: | 1011 | LExit: |
| 984 | ReleaseMem(rgFeatureActions); | 1012 | ReleaseMem(rgFeatureActions); |
| 985 | ReleaseMem(rgRollbackFeatureActions); | 1013 | ReleaseMem(rgRollbackFeatureActions); |
| @@ -1897,7 +1925,7 @@ static HRESULT ConcatPatchProperty( | |||
| 1897 | { | 1925 | { |
| 1898 | for (DWORD i = 0; i < pPackage->Msi.cSlipstreamMspPackages; ++i) | 1926 | for (DWORD i = 0; i < pPackage->Msi.cSlipstreamMspPackages; ++i) |
| 1899 | { | 1927 | { |
| 1900 | BURN_PACKAGE* pMspPackage = pPackage->Msi.rgpSlipstreamMspPackages[i]; | 1928 | BURN_PACKAGE* pMspPackage = pPackage->Msi.rgSlipstreamMsps[i].pMspPackage; |
| 1901 | AssertSz(BURN_PACKAGE_TYPE_MSP == pMspPackage->type, "Only MSP packages can be slipstream patches."); | 1929 | AssertSz(BURN_PACKAGE_TYPE_MSP == pMspPackage->type, "Only MSP packages can be slipstream patches."); |
| 1902 | 1930 | ||
| 1903 | BOOTSTRAPPER_ACTION_STATE patchExecuteAction = rgSlipstreamPatchActions[i]; | 1931 | BOOTSTRAPPER_ACTION_STATE patchExecuteAction = rgSlipstreamPatchActions[i]; |
diff --git a/src/engine/msiengine.h b/src/engine/msiengine.h index fe742a16..6c7c83e5 100644 --- a/src/engine/msiengine.h +++ b/src/engine/msiengine.h | |||
| @@ -27,6 +27,9 @@ HRESULT MsiEngineParsePropertiesFromXml( | |||
| 27 | void MsiEnginePackageUninitialize( | 27 | void MsiEnginePackageUninitialize( |
| 28 | __in BURN_PACKAGE* pPackage | 28 | __in BURN_PACKAGE* pPackage |
| 29 | ); | 29 | ); |
| 30 | HRESULT MsiEngineDetectInitialize( | ||
| 31 | __in BURN_PACKAGES* pPackages | ||
| 32 | ); | ||
| 30 | HRESULT MsiEngineDetectPackage( | 33 | HRESULT MsiEngineDetectPackage( |
| 31 | __in BURN_PACKAGE* pPackage, | 34 | __in BURN_PACKAGE* pPackage, |
| 32 | __in BURN_USER_EXPERIENCE* pUserExperience | 35 | __in BURN_USER_EXPERIENCE* pUserExperience |
diff --git a/src/engine/mspengine.cpp b/src/engine/mspengine.cpp index 14db27a6..4b7f9a0a 100644 --- a/src/engine/mspengine.cpp +++ b/src/engine/mspengine.cpp | |||
| @@ -30,18 +30,23 @@ static HRESULT AddPossibleTargetProduct( | |||
| 30 | __inout DWORD* pcPossibleTargetProducts | 30 | __inout DWORD* pcPossibleTargetProducts |
| 31 | ); | 31 | ); |
| 32 | static HRESULT AddDetectedTargetProduct( | 32 | static HRESULT AddDetectedTargetProduct( |
| 33 | __in BURN_PACKAGES* pPackages, | ||
| 34 | __in BURN_PACKAGE* pPackage, | 33 | __in BURN_PACKAGE* pPackage, |
| 35 | __in DWORD dwOrder, | 34 | __in DWORD dwOrder, |
| 36 | __in_z LPCWSTR wzProductCode, | 35 | __in_z LPCWSTR wzProductCode, |
| 37 | __in MSIINSTALLCONTEXT context | 36 | __in MSIINSTALLCONTEXT context, |
| 37 | __out DWORD* pdwTargetProductIndex | ||
| 38 | ); | ||
| 39 | static HRESULT AddMsiChainedPatch( | ||
| 40 | __in BURN_PACKAGE* pPackage, | ||
| 41 | __in BURN_PACKAGE* pMspPackage, | ||
| 42 | __in DWORD dwMspTargetProductIndex, | ||
| 43 | __out DWORD* pdwChainedPatchIndex | ||
| 38 | ); | 44 | ); |
| 39 | static void DeterminePatchChainedTarget( | 45 | static HRESULT DeterminePatchChainedTarget( |
| 40 | __in BURN_PACKAGES* pPackages, | 46 | __in BURN_PACKAGES* pPackages, |
| 41 | __in BURN_PACKAGE* pMspPackage, | 47 | __in BURN_PACKAGE* pMspPackage, |
| 42 | __in LPCWSTR wzTargetProductCode, | 48 | __in LPCWSTR wzTargetProductCode, |
| 43 | __out BURN_PACKAGE** ppChainedTargetPackage, | 49 | __in DWORD dwMspTargetProductIndex |
| 44 | __out BOOL* pfSlipstreamed | ||
| 45 | ); | 50 | ); |
| 46 | static HRESULT PlanTargetProduct( | 51 | static HRESULT PlanTargetProduct( |
| 47 | __in BOOTSTRAPPER_DISPLAY display, | 52 | __in BOOTSTRAPPER_DISPLAY display, |
| @@ -159,16 +164,20 @@ extern "C" HRESULT MspEngineDetectInitialize( | |||
| 159 | { | 164 | { |
| 160 | for (DWORD iPatchInfo = 0; iPatchInfo < pPackages->cPatchInfo; ++iPatchInfo) | 165 | for (DWORD iPatchInfo = 0; iPatchInfo < pPackages->cPatchInfo; ++iPatchInfo) |
| 161 | { | 166 | { |
| 162 | if (ERROR_SUCCESS == pPackages->rgPatchInfo[iPatchInfo].uStatus) | 167 | hr = HRESULT_FROM_WIN32(pPackages->rgPatchInfo[iPatchInfo].uStatus); |
| 163 | { | 168 | BURN_PACKAGE* pMspPackage = pPackages->rgPatchInfoToPackage[iPatchInfo]; |
| 164 | BURN_PACKAGE* pMspPackage = pPackages->rgPatchInfoToPackage[iPatchInfo]; | 169 | Assert(BURN_PACKAGE_TYPE_MSP == pMspPackage->type); |
| 165 | Assert(BURN_PACKAGE_TYPE_MSP == pMspPackage->type); | ||
| 166 | 170 | ||
| 171 | if (S_OK == hr) | ||
| 172 | { | ||
| 167 | // Note that we do add superseded and obsolete MSP packages. Package Detect and Plan will sort them out later. | 173 | // Note that we do add superseded and obsolete MSP packages. Package Detect and Plan will sort them out later. |
| 168 | hr = AddDetectedTargetProduct(pPackages, pMspPackage, pPackages->rgPatchInfo[iPatchInfo].dwOrder, pPossibleTargetProduct->wzProductCode, pPossibleTargetProduct->context); | 174 | hr = MspEngineAddDetectedTargetProduct(pPackages, pMspPackage, pPackages->rgPatchInfo[iPatchInfo].dwOrder, pPossibleTargetProduct->wzProductCode, pPossibleTargetProduct->context); |
| 169 | ExitOnFailure(hr, "Failed to add target product code to package: %ls", pMspPackage->sczId); | 175 | ExitOnFailure(hr, "Failed to add target product code to package: %ls", pMspPackage->sczId); |
| 170 | } | 176 | } |
| 171 | // TODO: should we log something for this error case? | 177 | else |
| 178 | { | ||
| 179 | LogStringLine(REPORT_DEBUG, " 0x%x: Patch applicability failed for package: %ls", hr, pMspPackage->sczId); | ||
| 180 | } | ||
| 172 | } | 181 | } |
| 173 | } | 182 | } |
| 174 | else | 183 | else |
| @@ -192,6 +201,54 @@ LExit: | |||
| 192 | return hr; | 201 | return hr; |
| 193 | } | 202 | } |
| 194 | 203 | ||
| 204 | extern "C" HRESULT MspEngineAddDetectedTargetProduct( | ||
| 205 | __in BURN_PACKAGES* pPackages, | ||
| 206 | __in BURN_PACKAGE* pPackage, | ||
| 207 | __in DWORD dwOrder, | ||
| 208 | __in_z LPCWSTR wzProductCode, | ||
| 209 | __in MSIINSTALLCONTEXT context | ||
| 210 | ) | ||
| 211 | { | ||
| 212 | HRESULT hr = S_OK; | ||
| 213 | DWORD dwTargetProductIndex = 0; | ||
| 214 | |||
| 215 | hr = AddDetectedTargetProduct(pPackage, dwOrder, wzProductCode, context, &dwTargetProductIndex); | ||
| 216 | ExitOnFailure(hr, "Failed to add detected target product."); | ||
| 217 | |||
| 218 | hr = DeterminePatchChainedTarget(pPackages, pPackage, wzProductCode, dwTargetProductIndex); | ||
| 219 | ExitOnFailure(hr, "Failed to determine patch chained target."); | ||
| 220 | |||
| 221 | LExit: | ||
| 222 | return hr; | ||
| 223 | } | ||
| 224 | |||
| 225 | extern "C" HRESULT MspEngineAddMissingSlipstreamTarget( | ||
| 226 | __in BURN_PACKAGE* pMsiPackage, | ||
| 227 | __in BURN_SLIPSTREAM_MSP* pSlipstreamMsp | ||
| 228 | ) | ||
| 229 | { | ||
| 230 | HRESULT hr = S_OK; | ||
| 231 | DWORD dwTargetProductIndex = 0; | ||
| 232 | BURN_MSPTARGETPRODUCT* pTargetProduct = NULL; | ||
| 233 | DWORD dwChainedPatchIndex = 0; | ||
| 234 | |||
| 235 | hr = AddDetectedTargetProduct(pSlipstreamMsp->pMspPackage, 0, pMsiPackage->Msi.sczProductCode, pMsiPackage->fPerMachine ? MSIINSTALLCONTEXT_MACHINE : MSIINSTALLCONTEXT_USERUNMANAGED, &dwTargetProductIndex); | ||
| 236 | ExitOnFailure(hr, "Failed to add missing slipstream target."); | ||
| 237 | |||
| 238 | pTargetProduct = pSlipstreamMsp->pMspPackage->Msp.rgTargetProducts + dwTargetProductIndex; | ||
| 239 | pTargetProduct->fSlipstream = TRUE; | ||
| 240 | pTargetProduct->fSlipstreamRequired = TRUE; | ||
| 241 | pTargetProduct->pChainedTargetPackage = pMsiPackage; | ||
| 242 | |||
| 243 | hr = AddMsiChainedPatch(pMsiPackage, pSlipstreamMsp->pMspPackage, dwTargetProductIndex, &dwChainedPatchIndex); | ||
| 244 | ExitOnFailure(hr, "Failed to add chained patch."); | ||
| 245 | |||
| 246 | pSlipstreamMsp->dwMsiChainedPatchIndex = dwChainedPatchIndex; | ||
| 247 | |||
| 248 | LExit: | ||
| 249 | return hr; | ||
| 250 | } | ||
| 251 | |||
| 195 | extern "C" HRESULT MspEngineDetectPackage( | 252 | extern "C" HRESULT MspEngineDetectPackage( |
| 196 | __in BURN_PACKAGE* pPackage, | 253 | __in BURN_PACKAGE* pPackage, |
| 197 | __in BURN_USER_EXPERIENCE* pUserExperience | 254 | __in BURN_USER_EXPERIENCE* pUserExperience |
| @@ -219,7 +276,6 @@ extern "C" HRESULT MspEngineDetectPackage( | |||
| 219 | for (DWORD i = 0; i < pPackage->Msp.cTargetProductCodes; ++i) | 276 | for (DWORD i = 0; i < pPackage->Msp.cTargetProductCodes; ++i) |
| 220 | { | 277 | { |
| 221 | BURN_MSPTARGETPRODUCT* pTargetProduct = pPackage->Msp.rgTargetProducts + i; | 278 | BURN_MSPTARGETPRODUCT* pTargetProduct = pPackage->Msp.rgTargetProducts + i; |
| 222 | BOOL fInstalled = FALSE; | ||
| 223 | 279 | ||
| 224 | hr = WiuGetPatchInfoEx(pPackage->Msp.sczPatchCode, pTargetProduct->wzTargetProductCode, NULL, pTargetProduct->context, INSTALLPROPERTY_PATCHSTATE, &sczState); | 280 | hr = WiuGetPatchInfoEx(pPackage->Msp.sczPatchCode, pTargetProduct->wzTargetProductCode, NULL, pTargetProduct->context, INSTALLPROPERTY_PATCHSTATE, &sczState); |
| 225 | if (SUCCEEDED(hr)) | 281 | if (SUCCEEDED(hr)) |
| @@ -227,17 +283,17 @@ extern "C" HRESULT MspEngineDetectPackage( | |||
| 227 | switch (*sczState) | 283 | switch (*sczState) |
| 228 | { | 284 | { |
| 229 | case '1': | 285 | case '1': |
| 230 | fInstalled = TRUE; | 286 | pTargetProduct->fInstalled = TRUE; |
| 231 | pTargetProduct->patchPackageState = BOOTSTRAPPER_PACKAGE_STATE_PRESENT; | 287 | pTargetProduct->patchPackageState = BOOTSTRAPPER_PACKAGE_STATE_PRESENT; |
| 232 | break; | 288 | break; |
| 233 | 289 | ||
| 234 | case '2': | 290 | case '2': |
| 235 | fInstalled = TRUE; | 291 | pTargetProduct->fInstalled = TRUE; |
| 236 | pTargetProduct->patchPackageState = BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED; | 292 | pTargetProduct->patchPackageState = BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED; |
| 237 | break; | 293 | break; |
| 238 | 294 | ||
| 239 | case '4': | 295 | case '4': |
| 240 | fInstalled = TRUE; | 296 | pTargetProduct->fInstalled = TRUE; |
| 241 | pTargetProduct->patchPackageState = BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE; | 297 | pTargetProduct->patchPackageState = BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE; |
| 242 | break; | 298 | break; |
| 243 | 299 | ||
| @@ -246,7 +302,7 @@ extern "C" HRESULT MspEngineDetectPackage( | |||
| 246 | break; | 302 | break; |
| 247 | } | 303 | } |
| 248 | } | 304 | } |
| 249 | else if (HRESULT_FROM_WIN32(ERROR_UNKNOWN_PATCH) == hr) | 305 | else if (HRESULT_FROM_WIN32(ERROR_UNKNOWN_PATCH) == hr || HRESULT_FROM_WIN32(ERROR_UNKNOWN_PRODUCT) == hr) |
| 250 | { | 306 | { |
| 251 | pTargetProduct->patchPackageState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT; | 307 | pTargetProduct->patchPackageState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT; |
| 252 | hr = S_OK; | 308 | hr = S_OK; |
| @@ -260,9 +316,9 @@ extern "C" HRESULT MspEngineDetectPackage( | |||
| 260 | 316 | ||
| 261 | if (pPackage->fCanAffectRegistration) | 317 | if (pPackage->fCanAffectRegistration) |
| 262 | { | 318 | { |
| 263 | pTargetProduct->registrationState = fInstalled ? BURN_PACKAGE_REGISTRATION_STATE_PRESENT : BURN_PACKAGE_REGISTRATION_STATE_ABSENT; | 319 | pTargetProduct->registrationState = pTargetProduct->fInstalled ? BURN_PACKAGE_REGISTRATION_STATE_PRESENT : BURN_PACKAGE_REGISTRATION_STATE_ABSENT; |
| 264 | 320 | ||
| 265 | if (fInstalled) | 321 | if (pTargetProduct->fInstalled) |
| 266 | { | 322 | { |
| 267 | pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT; | 323 | pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT; |
| 268 | } | 324 | } |
| @@ -290,6 +346,13 @@ extern "C" HRESULT MspEnginePlanInitializePackage( | |||
| 290 | { | 346 | { |
| 291 | BURN_MSPTARGETPRODUCT* pTargetProduct = pPackage->Msp.rgTargetProducts + i; | 347 | BURN_MSPTARGETPRODUCT* pTargetProduct = pPackage->Msp.rgTargetProducts + i; |
| 292 | 348 | ||
| 349 | if (!pTargetProduct->fInstalled && pTargetProduct->fSlipstreamRequired && BOOTSTRAPPER_REQUEST_STATE_PRESENT > pTargetProduct->pChainedTargetPackage->requested) | ||
| 350 | { | ||
| 351 | // There's no way to apply the patch if the target isn't installed. | ||
| 352 | pTargetProduct->defaultRequested = pTargetProduct->requested = BOOTSTRAPPER_REQUEST_STATE_NONE; | ||
| 353 | continue; | ||
| 354 | } | ||
| 355 | |||
| 293 | pTargetProduct->defaultRequested = pTargetProduct->requested = pPackage->requested; | 356 | pTargetProduct->defaultRequested = pTargetProduct->requested = pPackage->requested; |
| 294 | 357 | ||
| 295 | hr = UserExperienceOnPlanPatchTarget(pUserExperience, pPackage->sczId, pTargetProduct->wzTargetProductCode, &pTargetProduct->requested); | 358 | hr = UserExperienceOnPlanPatchTarget(pUserExperience, pPackage->sczId, pTargetProduct->wzTargetProductCode, &pTargetProduct->requested); |
| @@ -637,32 +700,6 @@ LExit: | |||
| 637 | return hr; | 700 | return hr; |
| 638 | } | 701 | } |
| 639 | 702 | ||
| 640 | extern "C" void MspEngineSlipstreamUpdateState( | ||
| 641 | __in BURN_PACKAGE* pPackage, | ||
| 642 | __in BOOTSTRAPPER_ACTION_STATE execute, | ||
| 643 | __in BOOTSTRAPPER_ACTION_STATE rollback | ||
| 644 | ) | ||
| 645 | { | ||
| 646 | Assert(BURN_PACKAGE_TYPE_MSP == pPackage->type); | ||
| 647 | |||
| 648 | // If the dependency manager set our state then that means something else | ||
| 649 | // is dependent on our package. That trumps whatever the slipstream update | ||
| 650 | // state might set. | ||
| 651 | if (!pPackage->fDependencyManagerWasHere) | ||
| 652 | { | ||
| 653 | // The highest aggregate action state found will be returned. | ||
| 654 | if (pPackage->execute < execute) | ||
| 655 | { | ||
| 656 | pPackage->execute = execute; | ||
| 657 | } | ||
| 658 | |||
| 659 | if (pPackage->rollback < rollback) | ||
| 660 | { | ||
| 661 | pPackage->rollback = rollback; | ||
| 662 | } | ||
| 663 | } | ||
| 664 | } | ||
| 665 | |||
| 666 | extern "C" void MspEngineUpdateInstallRegistrationState( | 703 | extern "C" void MspEngineUpdateInstallRegistrationState( |
| 667 | __in BURN_EXECUTE_ACTION* pAction, | 704 | __in BURN_EXECUTE_ACTION* pAction, |
| 668 | __in HRESULT hrExecute, | 705 | __in HRESULT hrExecute, |
| @@ -926,43 +963,68 @@ LExit: | |||
| 926 | } | 963 | } |
| 927 | 964 | ||
| 928 | static HRESULT AddDetectedTargetProduct( | 965 | static HRESULT AddDetectedTargetProduct( |
| 929 | __in BURN_PACKAGES* pPackages, | ||
| 930 | __in BURN_PACKAGE* pPackage, | 966 | __in BURN_PACKAGE* pPackage, |
| 931 | __in DWORD dwOrder, | 967 | __in DWORD dwOrder, |
| 932 | __in_z LPCWSTR wzProductCode, | 968 | __in_z LPCWSTR wzProductCode, |
| 933 | __in MSIINSTALLCONTEXT context | 969 | __in MSIINSTALLCONTEXT context, |
| 970 | __out DWORD* pdwTargetProductIndex | ||
| 934 | ) | 971 | ) |
| 935 | { | 972 | { |
| 936 | HRESULT hr = S_OK; | 973 | HRESULT hr = S_OK; |
| 974 | BURN_MSPTARGETPRODUCT* pTargetProduct = NULL; | ||
| 975 | |||
| 976 | *pdwTargetProductIndex = BURN_PACKAGE_INVALID_PATCH_INDEX; | ||
| 937 | 977 | ||
| 938 | hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pPackage->Msp.rgTargetProducts), pPackage->Msp.cTargetProductCodes + 1, sizeof(BURN_MSPTARGETPRODUCT), 5); | 978 | hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pPackage->Msp.rgTargetProducts), pPackage->Msp.cTargetProductCodes + 1, sizeof(BURN_MSPTARGETPRODUCT), 5); |
| 939 | ExitOnFailure(hr, "Failed to ensure enough target product codes were allocated."); | 979 | ExitOnFailure(hr, "Failed to ensure enough target product codes were allocated."); |
| 940 | 980 | ||
| 941 | hr = ::StringCchCopyW(pPackage->Msp.rgTargetProducts[pPackage->Msp.cTargetProductCodes].wzTargetProductCode, countof(pPackage->Msp.rgTargetProducts[pPackage->Msp.cTargetProductCodes].wzTargetProductCode), wzProductCode); | 981 | pTargetProduct = pPackage->Msp.rgTargetProducts + pPackage->Msp.cTargetProductCodes; |
| 982 | |||
| 983 | hr = ::StringCchCopyW(pTargetProduct->wzTargetProductCode, countof(pTargetProduct->wzTargetProductCode), wzProductCode); | ||
| 942 | ExitOnFailure(hr, "Failed to copy target product code."); | 984 | ExitOnFailure(hr, "Failed to copy target product code."); |
| 943 | 985 | ||
| 944 | DeterminePatchChainedTarget(pPackages, pPackage, wzProductCode, | 986 | pTargetProduct->context = context; |
| 945 | &pPackage->Msp.rgTargetProducts[pPackage->Msp.cTargetProductCodes].pChainedTargetPackage, | 987 | pTargetProduct->dwOrder = dwOrder; |
| 946 | &pPackage->Msp.rgTargetProducts[pPackage->Msp.cTargetProductCodes].fSlipstream); | ||
| 947 | 988 | ||
| 948 | pPackage->Msp.rgTargetProducts[pPackage->Msp.cTargetProductCodes].context = context; | 989 | *pdwTargetProductIndex = pPackage->Msp.cTargetProductCodes; |
| 949 | pPackage->Msp.rgTargetProducts[pPackage->Msp.cTargetProductCodes].dwOrder = dwOrder; | ||
| 950 | ++pPackage->Msp.cTargetProductCodes; | 990 | ++pPackage->Msp.cTargetProductCodes; |
| 951 | 991 | ||
| 952 | LExit: | 992 | LExit: |
| 953 | return hr; | 993 | return hr; |
| 954 | } | 994 | } |
| 955 | 995 | ||
| 956 | static void DeterminePatchChainedTarget( | 996 | static HRESULT AddMsiChainedPatch( |
| 997 | __in BURN_PACKAGE* pPackage, | ||
| 998 | __in BURN_PACKAGE* pMspPackage, | ||
| 999 | __in DWORD dwMspTargetProductIndex, | ||
| 1000 | __out DWORD* pdwChainedPatchIndex | ||
| 1001 | ) | ||
| 1002 | { | ||
| 1003 | HRESULT hr = S_OK; | ||
| 1004 | |||
| 1005 | hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pPackage->Msi.rgChainedPatches), pPackage->Msi.cChainedPatches + 1, sizeof(BURN_CHAINED_PATCH), 5); | ||
| 1006 | ExitOnFailure(hr, "Failed to ensure enough chained patches were allocated."); | ||
| 1007 | |||
| 1008 | BURN_CHAINED_PATCH* pChainedPatch = pPackage->Msi.rgChainedPatches + pPackage->Msi.cChainedPatches; | ||
| 1009 | pChainedPatch->pMspPackage = pMspPackage; | ||
| 1010 | pChainedPatch->dwMspTargetProductIndex = dwMspTargetProductIndex; | ||
| 1011 | |||
| 1012 | *pdwChainedPatchIndex = pPackage->Msi.cChainedPatches; | ||
| 1013 | ++pPackage->Msi.cChainedPatches; | ||
| 1014 | LExit: | ||
| 1015 | return hr; | ||
| 1016 | } | ||
| 1017 | |||
| 1018 | static HRESULT DeterminePatchChainedTarget( | ||
| 957 | __in BURN_PACKAGES* pPackages, | 1019 | __in BURN_PACKAGES* pPackages, |
| 958 | __in BURN_PACKAGE* pMspPackage, | 1020 | __in BURN_PACKAGE* pMspPackage, |
| 959 | __in LPCWSTR wzTargetProductCode, | 1021 | __in LPCWSTR wzTargetProductCode, |
| 960 | __out BURN_PACKAGE** ppChainedTargetPackage, | 1022 | __in DWORD dwMspTargetProductIndex |
| 961 | __out BOOL* pfSlipstreamed | ||
| 962 | ) | 1023 | ) |
| 963 | { | 1024 | { |
| 964 | BURN_PACKAGE* pTargetMsiPackage = NULL; | 1025 | HRESULT hr = S_OK; |
| 965 | BOOL fSlipstreamed = FALSE; | 1026 | DWORD dwChainedPatchIndex = 0; |
| 1027 | BURN_MSPTARGETPRODUCT* pTargetProduct = pMspPackage->Msp.rgTargetProducts + dwMspTargetProductIndex; | ||
| 966 | 1028 | ||
| 967 | for (DWORD iPackage = 0; iPackage < pPackages->cPackages; ++iPackage) | 1029 | for (DWORD iPackage = 0; iPackage < pPackages->cPackages; ++iPackage) |
| 968 | { | 1030 | { |
| @@ -970,15 +1032,19 @@ static void DeterminePatchChainedTarget( | |||
| 970 | 1032 | ||
| 971 | if (BURN_PACKAGE_TYPE_MSI == pPackage->type && CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzTargetProductCode, -1, pPackage->Msi.sczProductCode, -1)) | 1033 | if (BURN_PACKAGE_TYPE_MSI == pPackage->type && CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzTargetProductCode, -1, pPackage->Msi.sczProductCode, -1)) |
| 972 | { | 1034 | { |
| 973 | pTargetMsiPackage = pPackage; | 1035 | pTargetProduct->pChainedTargetPackage = pPackage; |
| 1036 | |||
| 1037 | hr = AddMsiChainedPatch(pPackage, pMspPackage, dwMspTargetProductIndex, &dwChainedPatchIndex); | ||
| 1038 | ExitOnFailure(hr, "Failed to add chained patch."); | ||
| 974 | 1039 | ||
| 975 | for (DWORD j = 0; j < pPackage->Msi.cSlipstreamMspPackages; ++j) | 1040 | for (DWORD j = 0; j < pPackage->Msi.cSlipstreamMspPackages; ++j) |
| 976 | { | 1041 | { |
| 977 | BURN_PACKAGE* pSlipstreamMsp = pPackage->Msi.rgpSlipstreamMspPackages[j]; | 1042 | BURN_SLIPSTREAM_MSP* pSlipstreamMsp = pPackage->Msi.rgSlipstreamMsps + j; |
| 978 | if (pSlipstreamMsp == pMspPackage) | 1043 | if (pSlipstreamMsp->pMspPackage == pMspPackage) |
| 979 | { | 1044 | { |
| 980 | AssertSz(!fSlipstreamed, "An MSP should only show up as a slipstreamed patch in an MSI once."); | 1045 | AssertSz(BURN_PACKAGE_INVALID_PATCH_INDEX == pSlipstreamMsp->dwMsiChainedPatchIndex, "An MSP should only show up as a slipstreamed patch in an MSI once."); |
| 981 | fSlipstreamed = TRUE; | 1046 | pTargetProduct->fSlipstream = TRUE; |
| 1047 | pSlipstreamMsp->dwMsiChainedPatchIndex = dwChainedPatchIndex; | ||
| 982 | break; | 1048 | break; |
| 983 | } | 1049 | } |
| 984 | } | 1050 | } |
| @@ -987,10 +1053,8 @@ static void DeterminePatchChainedTarget( | |||
| 987 | } | 1053 | } |
| 988 | } | 1054 | } |
| 989 | 1055 | ||
| 990 | *ppChainedTargetPackage = pTargetMsiPackage; | 1056 | LExit: |
| 991 | *pfSlipstreamed = fSlipstreamed; | 1057 | return hr; |
| 992 | |||
| 993 | return; | ||
| 994 | } | 1058 | } |
| 995 | 1059 | ||
| 996 | static HRESULT PlanTargetProduct( | 1060 | static HRESULT PlanTargetProduct( |
diff --git a/src/engine/mspengine.h b/src/engine/mspengine.h index 28682169..1530954b 100644 --- a/src/engine/mspengine.h +++ b/src/engine/mspengine.h | |||
| @@ -28,6 +28,17 @@ void MspEnginePackageUninitialize( | |||
| 28 | HRESULT MspEngineDetectInitialize( | 28 | HRESULT MspEngineDetectInitialize( |
| 29 | __in BURN_PACKAGES* pPackages | 29 | __in BURN_PACKAGES* pPackages |
| 30 | ); | 30 | ); |
| 31 | HRESULT MspEngineAddDetectedTargetProduct( | ||
| 32 | __in BURN_PACKAGES* pPackages, | ||
| 33 | __in BURN_PACKAGE* pPackage, | ||
| 34 | __in DWORD dwOrder, | ||
| 35 | __in_z LPCWSTR wzProductCode, | ||
| 36 | __in MSIINSTALLCONTEXT context | ||
| 37 | ); | ||
| 38 | HRESULT MspEngineAddMissingSlipstreamTarget( | ||
| 39 | __in BURN_PACKAGE* pMsiPackage, | ||
| 40 | __in BURN_SLIPSTREAM_MSP* pSlipstreamMsp | ||
| 41 | ); | ||
| 31 | HRESULT MspEngineDetectPackage( | 42 | HRESULT MspEngineDetectPackage( |
| 32 | __in BURN_PACKAGE* pPackage, | 43 | __in BURN_PACKAGE* pPackage, |
| 33 | __in BURN_USER_EXPERIENCE* pUserExperience | 44 | __in BURN_USER_EXPERIENCE* pUserExperience |
| @@ -59,11 +70,6 @@ HRESULT MspEngineExecutePackage( | |||
| 59 | __in LPVOID pvContext, | 70 | __in LPVOID pvContext, |
| 60 | __out BOOTSTRAPPER_APPLY_RESTART* pRestart | 71 | __out BOOTSTRAPPER_APPLY_RESTART* pRestart |
| 61 | ); | 72 | ); |
| 62 | void MspEngineSlipstreamUpdateState( | ||
| 63 | __in BURN_PACKAGE* pMspPackage, | ||
| 64 | __in BOOTSTRAPPER_ACTION_STATE execute, | ||
| 65 | __in BOOTSTRAPPER_ACTION_STATE rollback | ||
| 66 | ); | ||
| 67 | void MspEngineUpdateInstallRegistrationState( | 73 | void MspEngineUpdateInstallRegistrationState( |
| 68 | __in BURN_EXECUTE_ACTION* pAction, | 74 | __in BURN_EXECUTE_ACTION* pAction, |
| 69 | __in HRESULT hrExecute, | 75 | __in HRESULT hrExecute, |
diff --git a/src/engine/package.cpp b/src/engine/package.cpp index bb61cdcd..115866f3 100644 --- a/src/engine/package.cpp +++ b/src/engine/package.cpp | |||
| @@ -282,7 +282,9 @@ extern "C" HRESULT PackagesParseFromXml( | |||
| 282 | { | 282 | { |
| 283 | if (pMsiPackage->Msi.rgsczSlipstreamMspPackageIds[k] && CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pPackage->sczId, -1, pMsiPackage->Msi.rgsczSlipstreamMspPackageIds[k], -1)) | 283 | if (pMsiPackage->Msi.rgsczSlipstreamMspPackageIds[k] && CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pPackage->sczId, -1, pMsiPackage->Msi.rgsczSlipstreamMspPackageIds[k], -1)) |
| 284 | { | 284 | { |
| 285 | pMsiPackage->Msi.rgpSlipstreamMspPackages[k] = pPackage; | 285 | BURN_SLIPSTREAM_MSP* pSlipstreamMsp = pMsiPackage->Msi.rgSlipstreamMsps + k; |
| 286 | pSlipstreamMsp->pMspPackage = pPackage; | ||
| 287 | pSlipstreamMsp->dwMsiChainedPatchIndex = BURN_PACKAGE_INVALID_PATCH_INDEX; | ||
| 286 | 288 | ||
| 287 | ReleaseNullStr(pMsiPackage->Msi.rgsczSlipstreamMspPackageIds[k]); // we don't need the slipstream package id any longer so free it. | 289 | ReleaseNullStr(pMsiPackage->Msi.rgsczSlipstreamMspPackageIds[k]); // we don't need the slipstream package id any longer so free it. |
| 288 | } | 290 | } |
| @@ -295,6 +297,25 @@ extern "C" HRESULT PackagesParseFromXml( | |||
| 295 | 297 | ||
| 296 | AssertSz(pPackages->cPatchInfo == cMspPackages, "Count of packages patch info should be equal to the number of MSP packages."); | 298 | AssertSz(pPackages->cPatchInfo == cMspPackages, "Count of packages patch info should be equal to the number of MSP packages."); |
| 297 | 299 | ||
| 300 | #if DEBUG | ||
| 301 | // Loop through all MSI packages seeing if any of them are missing their slipstream MSP. | ||
| 302 | for (DWORD i = 0; i < pPackages->cPackages; ++i) | ||
| 303 | { | ||
| 304 | BURN_PACKAGE* pPackage = &pPackages->rgPackages[i]; | ||
| 305 | |||
| 306 | if (BURN_PACKAGE_TYPE_MSI == pPackage->type) | ||
| 307 | { | ||
| 308 | for (DWORD k = 0; k < pPackage->Msi.cSlipstreamMspPackages; ++k) | ||
| 309 | { | ||
| 310 | if (pPackage->Msi.rgsczSlipstreamMspPackageIds[k]) | ||
| 311 | { | ||
| 312 | AssertSz(FALSE, "MSI slipstream MSP package doesn't exist."); | ||
| 313 | } | ||
| 314 | } | ||
| 315 | } | ||
| 316 | } | ||
| 317 | #endif | ||
| 318 | |||
| 298 | hr = ParsePatchTargetCode(pPackages, pixnBundle); | 319 | hr = ParsePatchTargetCode(pPackages, pixnBundle); |
| 299 | ExitOnFailure(hr, "Failed to parse target product codes."); | 320 | ExitOnFailure(hr, "Failed to parse target product codes."); |
| 300 | 321 | ||
diff --git a/src/engine/package.h b/src/engine/package.h index 3a243c7d..283afa57 100644 --- a/src/engine/package.h +++ b/src/engine/package.h | |||
| @@ -14,6 +14,8 @@ typedef _BURN_PACKAGE BURN_PACKAGE; | |||
| 14 | 14 | ||
| 15 | // constants | 15 | // constants |
| 16 | 16 | ||
| 17 | const DWORD BURN_PACKAGE_INVALID_PATCH_INDEX = 0x80000000; | ||
| 18 | |||
| 17 | enum BURN_EXE_EXIT_CODE_TYPE | 19 | enum BURN_EXE_EXIT_CODE_TYPE |
| 18 | { | 20 | { |
| 19 | BURN_EXE_EXIT_CODE_TYPE_NONE, | 21 | BURN_EXE_EXIT_CODE_TYPE_NONE, |
| @@ -116,7 +118,9 @@ typedef struct _BURN_MSPTARGETPRODUCT | |||
| 116 | DWORD dwOrder; | 118 | DWORD dwOrder; |
| 117 | WCHAR wzTargetProductCode[39]; | 119 | WCHAR wzTargetProductCode[39]; |
| 118 | BURN_PACKAGE* pChainedTargetPackage; | 120 | BURN_PACKAGE* pChainedTargetPackage; |
| 121 | BOOL fInstalled; | ||
| 119 | BOOL fSlipstream; | 122 | BOOL fSlipstream; |
| 123 | BOOL fSlipstreamRequired; // this means the target product is not present on the machine, but is available in the chain as a slipstream target. | ||
| 120 | 124 | ||
| 121 | BOOTSTRAPPER_PACKAGE_STATE patchPackageState; // only valid after Detect. | 125 | BOOTSTRAPPER_PACKAGE_STATE patchPackageState; // only valid after Detect. |
| 122 | BOOTSTRAPPER_REQUEST_STATE defaultRequested; // only valid during Plan. | 126 | BOOTSTRAPPER_REQUEST_STATE defaultRequested; // only valid during Plan. |
| @@ -172,6 +176,18 @@ typedef struct _BURN_RELATED_MSI | |||
| 172 | DWORD cLanguages; | 176 | DWORD cLanguages; |
| 173 | } BURN_RELATED_MSI; | 177 | } BURN_RELATED_MSI; |
| 174 | 178 | ||
| 179 | typedef struct _BURN_CHAINED_PATCH | ||
| 180 | { | ||
| 181 | BURN_PACKAGE* pMspPackage; | ||
| 182 | DWORD dwMspTargetProductIndex; // index into the Msp.rgTargetProducts | ||
| 183 | } BURN_CHAINED_PATCH; | ||
| 184 | |||
| 185 | typedef struct _BURN_SLIPSTREAM_MSP | ||
| 186 | { | ||
| 187 | BURN_PACKAGE* pMspPackage; | ||
| 188 | DWORD dwMsiChainedPatchIndex; // index into the Msi.rgChainedPatches | ||
| 189 | } BURN_SLIPSTREAM_MSP; | ||
| 190 | |||
| 175 | typedef struct _BURN_PACKAGE_PAYLOAD | 191 | typedef struct _BURN_PACKAGE_PAYLOAD |
| 176 | { | 192 | { |
| 177 | BURN_PAYLOAD* pPayload; | 193 | BURN_PAYLOAD* pPayload; |
| @@ -295,9 +311,12 @@ typedef struct _BURN_PACKAGE | |||
| 295 | BURN_RELATED_MSI* rgRelatedMsis; | 311 | BURN_RELATED_MSI* rgRelatedMsis; |
| 296 | DWORD cRelatedMsis; | 312 | DWORD cRelatedMsis; |
| 297 | 313 | ||
| 298 | _BURN_PACKAGE** rgpSlipstreamMspPackages; | 314 | BURN_SLIPSTREAM_MSP* rgSlipstreamMsps; |
| 299 | LPWSTR* rgsczSlipstreamMspPackageIds; | 315 | LPWSTR* rgsczSlipstreamMspPackageIds; |
| 300 | DWORD cSlipstreamMspPackages; | 316 | DWORD cSlipstreamMspPackages; |
| 317 | |||
| 318 | BURN_CHAINED_PATCH* rgChainedPatches; | ||
| 319 | DWORD cChainedPatches; | ||
| 301 | } Msi; | 320 | } Msi; |
| 302 | struct | 321 | struct |
| 303 | { | 322 | { |
diff --git a/src/engine/plan.cpp b/src/engine/plan.cpp index 95ea0b05..86a07dfb 100644 --- a/src/engine/plan.cpp +++ b/src/engine/plan.cpp | |||
| @@ -2168,7 +2168,7 @@ static HRESULT AddCacheSlipstreamMsps( | |||
| 2168 | 2168 | ||
| 2169 | for (DWORD i = 0; i < pPackage->Msi.cSlipstreamMspPackages; ++i) | 2169 | for (DWORD i = 0; i < pPackage->Msi.cSlipstreamMspPackages; ++i) |
| 2170 | { | 2170 | { |
| 2171 | BURN_PACKAGE* pMspPackage = pPackage->Msi.rgpSlipstreamMspPackages[i]; | 2171 | BURN_PACKAGE* pMspPackage = pPackage->Msi.rgSlipstreamMsps[i].pMspPackage; |
| 2172 | AssertSz(BURN_PACKAGE_TYPE_MSP == pMspPackage->type, "Only MSP packages can be slipstream patches."); | 2172 | AssertSz(BURN_PACKAGE_TYPE_MSP == pMspPackage->type, "Only MSP packages can be slipstream patches."); |
| 2173 | 2173 | ||
| 2174 | hr = AddCachePackageHelper(pPlan, pMspPackage, &hIgnored); | 2174 | hr = AddCachePackageHelper(pPlan, pMspPackage, &hIgnored); |
| @@ -2791,7 +2791,7 @@ static HRESULT FinalizeSlipstreamPatchActions( | |||
| 2791 | { | 2791 | { |
| 2792 | for (DWORD j = 0; j < pPackage->Msi.cSlipstreamMspPackages; ++j) | 2792 | for (DWORD j = 0; j < pPackage->Msi.cSlipstreamMspPackages; ++j) |
| 2793 | { | 2793 | { |
| 2794 | BURN_PACKAGE* pMspPackage = pPackage->Msi.rgpSlipstreamMspPackages[j]; | 2794 | BURN_PACKAGE* pMspPackage = pPackage->Msi.rgSlipstreamMsps[j].pMspPackage; |
| 2795 | AssertSz(BURN_PACKAGE_TYPE_MSP == pMspPackage->type, "Only MSP packages can be slipstream patches."); | 2795 | AssertSz(BURN_PACKAGE_TYPE_MSP == pMspPackage->type, "Only MSP packages can be slipstream patches."); |
| 2796 | 2796 | ||
| 2797 | pAction->msiPackage.rgSlipstreamPatches[j] = fExecute ? pMspPackage->execute : pMspPackage->rollback; | 2797 | pAction->msiPackage.rgSlipstreamPatches[j] = fExecute ? pMspPackage->execute : pMspPackage->rollback; |
diff --git a/src/test/BurnUnitTest/BurnUnitTest.vcxproj b/src/test/BurnUnitTest/BurnUnitTest.vcxproj index 08dc68e7..65f99168 100644 --- a/src/test/BurnUnitTest/BurnUnitTest.vcxproj +++ b/src/test/BurnUnitTest/BurnUnitTest.vcxproj | |||
| @@ -71,6 +71,7 @@ | |||
| 71 | <ItemGroup> | 71 | <ItemGroup> |
| 72 | <None Include="TestData\PlanTest\BasicFunctionality_BundleA_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> | 72 | <None Include="TestData\PlanTest\BasicFunctionality_BundleA_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> |
| 73 | <None Include="TestData\PlanTest\MsiTransaction_BundleAv1_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> | 73 | <None Include="TestData\PlanTest\MsiTransaction_BundleAv1_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> |
| 74 | <None Include="TestData\PlanTest\Slipstream_BundleA_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> | ||
| 74 | </ItemGroup> | 75 | </ItemGroup> |
| 75 | <ItemGroup> | 76 | <ItemGroup> |
| 76 | <Reference Include="System" /> | 77 | <Reference Include="System" /> |
diff --git a/src/test/BurnUnitTest/PlanTest.cpp b/src/test/BurnUnitTest/PlanTest.cpp index 42c11968..820f88c2 100644 --- a/src/test/BurnUnitTest/PlanTest.cpp +++ b/src/test/BurnUnitTest/PlanTest.cpp | |||
| @@ -11,6 +11,7 @@ static HRESULT WINAPI PlanTestBAProc( | |||
| 11 | 11 | ||
| 12 | static LPCWSTR wzMsiTransactionManifestFileName = L"MsiTransaction_BundleAv1_manifest.xml"; | 12 | static LPCWSTR wzMsiTransactionManifestFileName = L"MsiTransaction_BundleAv1_manifest.xml"; |
| 13 | static LPCWSTR wzSingleMsiManifestFileName = L"BasicFunctionality_BundleA_manifest.xml"; | 13 | static LPCWSTR wzSingleMsiManifestFileName = L"BasicFunctionality_BundleA_manifest.xml"; |
| 14 | static LPCWSTR wzSlipstreamManifestFileName = L"Slipstream_BundleA_manifest.xml"; | ||
| 14 | 15 | ||
| 15 | namespace Microsoft | 16 | namespace Microsoft |
| 16 | { | 17 | { |
| @@ -650,6 +651,210 @@ namespace Bootstrapper | |||
| 650 | ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_IGNORED, BURN_PACKAGE_REGISTRATION_STATE_IGNORED); | 651 | ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_IGNORED, BURN_PACKAGE_REGISTRATION_STATE_IGNORED); |
| 651 | } | 652 | } |
| 652 | 653 | ||
| 654 | [Fact] | ||
| 655 | void SlipstreamInstallTest() | ||
| 656 | { | ||
| 657 | HRESULT hr = S_OK; | ||
| 658 | BURN_ENGINE_STATE engineState = { }; | ||
| 659 | BURN_ENGINE_STATE* pEngineState = &engineState; | ||
| 660 | BURN_PLAN* pPlan = &engineState.plan; | ||
| 661 | |||
| 662 | InitializeEngineStateForCorePlan(wzSlipstreamManifestFileName, pEngineState); | ||
| 663 | DetectPermanentPackagesAsPresentAndCached(pEngineState); | ||
| 664 | PlanTestDetectPatchInitialize(pEngineState); | ||
| 665 | |||
| 666 | hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL); | ||
| 667 | NativeAssert::Succeeded(hr, "CorePlan failed"); | ||
| 668 | |||
| 669 | Assert::Equal<DWORD>(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); | ||
| 670 | Assert::Equal<BOOL>(TRUE, pPlan->fPerMachine); | ||
| 671 | Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback); | ||
| 672 | |||
| 673 | BOOL fRollback = FALSE; | ||
| 674 | DWORD dwIndex = 0; | ||
| 675 | DWORD dwPackageStart = 0; | ||
| 676 | ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); | ||
| 677 | dwPackageStart = ValidateCachePackageStart(pPlan, fRollback, dwIndex++, L"PatchA", 4, 1, 20480, FALSE); | ||
| 678 | ValidateCacheAcquirePayload(pPlan, fRollback, dwIndex++, L"PatchA", L"PatchA", FALSE); | ||
| 679 | ValidateCacheCachePayload(pPlan, fRollback, dwIndex++, L"PatchA", L"PatchA", TRUE, FALSE, dwPackageStart); | ||
| 680 | ValidateCachePackageStop(pPlan, fRollback, dwIndex++, L"PatchA", FALSE); | ||
| 681 | ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, FALSE); | ||
| 682 | ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 2); | ||
| 683 | dwPackageStart = ValidateCachePackageStart(pPlan, fRollback, dwIndex++, L"PackageA", 10, 1, 32768, FALSE); | ||
| 684 | ValidateCacheAcquirePayload(pPlan, fRollback, dwIndex++, L"PackageA", L"PackageA", FALSE); | ||
| 685 | ValidateCacheCachePayload(pPlan, fRollback, dwIndex++, L"PackageA", L"PackageA", TRUE, FALSE, dwPackageStart); | ||
| 686 | ValidateCachePackageStop(pPlan, fRollback, dwIndex++, L"PackageA", FALSE); | ||
| 687 | ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, FALSE); | ||
| 688 | Assert::Equal(dwIndex, pPlan->cCacheActions); | ||
| 689 | |||
| 690 | fRollback = TRUE; | ||
| 691 | dwIndex = 0; | ||
| 692 | ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 2); | ||
| 693 | ValidateCacheRollbackPackage(pPlan, fRollback, dwIndex++, L"PackageA", FALSE); | ||
| 694 | Assert::Equal(dwIndex, pPlan->cRollbackCacheActions); | ||
| 695 | |||
| 696 | Assert::Equal(3055111ull, pPlan->qwEstimatedSize); | ||
| 697 | Assert::Equal(53248ull, pPlan->qwCacheSizeTotal); | ||
| 698 | |||
| 699 | fRollback = FALSE; | ||
| 700 | dwIndex = 0; | ||
| 701 | DWORD dwExecuteCheckpointId = 3; | ||
| 702 | BURN_EXECUTE_ACTION* pExecuteAction = NULL; | ||
| 703 | ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); | ||
| 704 | ValidateExecuteWaitSyncpoint(pPlan, fRollback, dwIndex++, pPlan->rgCacheActions[11].syncpoint.hEvent); | ||
| 705 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 706 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 707 | ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_REGISTER); | ||
| 708 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 709 | ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0); | ||
| 710 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 711 | ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", BURN_DEPENDENCY_ACTION_REGISTER); | ||
| 712 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 713 | ValidateExecuteWaitSyncpoint(pPlan, fRollback, dwIndex++, pPlan->rgCacheActions[5].syncpoint.hEvent); | ||
| 714 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 715 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 716 | ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PatchA", BURN_DEPENDENCY_ACTION_REGISTER); | ||
| 717 | pExecuteAction = ValidateDeletedExecuteMspTarget(pPlan, fRollback, dwIndex++, L"PatchA", BOOTSTRAPPER_ACTION_STATE_INSTALL, L"{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}", TRUE, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, TRUE); | ||
| 718 | ValidateExecuteMspTargetPatch(pExecuteAction, 0, L"PatchA"); | ||
| 719 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 720 | ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PatchA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", BURN_DEPENDENCY_ACTION_REGISTER); | ||
| 721 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 722 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 723 | Assert::Equal(dwIndex, pPlan->cExecuteActions); | ||
| 724 | |||
| 725 | fRollback = TRUE; | ||
| 726 | dwIndex = 0; | ||
| 727 | dwExecuteCheckpointId = 3; | ||
| 728 | ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); | ||
| 729 | ValidateExecuteUncachePackage(pPlan, fRollback, dwIndex++, L"PackageA"); | ||
| 730 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 731 | ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_UNREGISTER); | ||
| 732 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 733 | ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0); | ||
| 734 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 735 | ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", BURN_DEPENDENCY_ACTION_UNREGISTER); | ||
| 736 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 737 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 738 | ValidateExecuteUncachePackage(pPlan, fRollback, dwIndex++, L"PatchA"); | ||
| 739 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 740 | ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PatchA", BURN_DEPENDENCY_ACTION_UNREGISTER); | ||
| 741 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 742 | pExecuteAction = ValidateDeletedExecuteMspTarget(pPlan, fRollback, dwIndex++, L"PatchA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, L"{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}", TRUE, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, TRUE); | ||
| 743 | ValidateExecuteMspTargetPatch(pExecuteAction, 0, L"PatchA"); | ||
| 744 | ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PatchA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", BURN_DEPENDENCY_ACTION_UNREGISTER); | ||
| 745 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 746 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 747 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 748 | Assert::Equal(dwIndex, pPlan->cRollbackActions); | ||
| 749 | |||
| 750 | Assert::Equal(2ul, pPlan->cExecutePackagesTotal); | ||
| 751 | Assert::Equal(4ul, pPlan->cOverallProgressTicksTotal); | ||
| 752 | |||
| 753 | dwIndex = 0; | ||
| 754 | Assert::Equal(dwIndex, pPlan->cCleanActions); | ||
| 755 | |||
| 756 | UINT uIndex = 0; | ||
| 757 | ValidatePlannedProvider(pPlan, uIndex++, L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", NULL); | ||
| 758 | Assert::Equal(uIndex, pPlan->cPlannedProviders); | ||
| 759 | |||
| 760 | Assert::Equal(3ul, pEngineState->packages.cPackages); | ||
| 761 | ValidatePermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"NetFx48Web"); | ||
| 762 | ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[1], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT); | ||
| 763 | ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[2], L"PatchA", BURN_PACKAGE_REGISTRATION_STATE_ABSENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT); | ||
| 764 | } | ||
| 765 | |||
| 766 | [Fact] | ||
| 767 | void SlipstreamUninstallTest() | ||
| 768 | { | ||
| 769 | HRESULT hr = S_OK; | ||
| 770 | BURN_ENGINE_STATE engineState = { }; | ||
| 771 | BURN_ENGINE_STATE* pEngineState = &engineState; | ||
| 772 | BURN_PLAN* pPlan = &engineState.plan; | ||
| 773 | |||
| 774 | InitializeEngineStateForCorePlan(wzSlipstreamManifestFileName, pEngineState); | ||
| 775 | DetectPackagesAsPresentAndCached(pEngineState); | ||
| 776 | |||
| 777 | hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL); | ||
| 778 | NativeAssert::Succeeded(hr, "CorePlan failed"); | ||
| 779 | |||
| 780 | Assert::Equal<DWORD>(BOOTSTRAPPER_ACTION_UNINSTALL, pPlan->action); | ||
| 781 | Assert::Equal<BOOL>(TRUE, pPlan->fPerMachine); | ||
| 782 | Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback); | ||
| 783 | |||
| 784 | BOOL fRollback = FALSE; | ||
| 785 | DWORD dwIndex = 0; | ||
| 786 | Assert::Equal(dwIndex, pPlan->cCacheActions); | ||
| 787 | |||
| 788 | fRollback = TRUE; | ||
| 789 | dwIndex = 0; | ||
| 790 | Assert::Equal(dwIndex, pPlan->cRollbackCacheActions); | ||
| 791 | |||
| 792 | Assert::Equal(0ull, pPlan->qwEstimatedSize); | ||
| 793 | Assert::Equal(0ull, pPlan->qwCacheSizeTotal); | ||
| 794 | |||
| 795 | fRollback = FALSE; | ||
| 796 | dwIndex = 0; | ||
| 797 | DWORD dwExecuteCheckpointId = 1; | ||
| 798 | BURN_EXECUTE_ACTION* pExecuteAction = NULL; | ||
| 799 | ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); | ||
| 800 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 801 | ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PatchA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", BURN_DEPENDENCY_ACTION_UNREGISTER); | ||
| 802 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 803 | ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PatchA", BURN_DEPENDENCY_ACTION_UNREGISTER); | ||
| 804 | pExecuteAction = ValidateDeletedExecuteMspTarget(pPlan, fRollback, dwIndex++, L"PatchA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, L"{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}", TRUE, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, TRUE); | ||
| 805 | ValidateExecuteMspTargetPatch(pExecuteAction, 0, L"PatchA"); | ||
| 806 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 807 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 808 | ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", BURN_DEPENDENCY_ACTION_UNREGISTER); | ||
| 809 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 810 | ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_UNREGISTER); | ||
| 811 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 812 | ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0); | ||
| 813 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 814 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 815 | Assert::Equal(dwIndex, pPlan->cExecuteActions); | ||
| 816 | |||
| 817 | fRollback = TRUE; | ||
| 818 | dwIndex = 0; | ||
| 819 | dwExecuteCheckpointId = 1; | ||
| 820 | ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); | ||
| 821 | ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PatchA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", BURN_DEPENDENCY_ACTION_REGISTER); | ||
| 822 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 823 | ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PatchA", BURN_DEPENDENCY_ACTION_REGISTER); | ||
| 824 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 825 | pExecuteAction = ValidateDeletedExecuteMspTarget(pPlan, fRollback, dwIndex++, L"PatchA", BOOTSTRAPPER_ACTION_STATE_INSTALL, L"{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}", TRUE, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, TRUE); | ||
| 826 | ValidateExecuteMspTargetPatch(pExecuteAction, 0, L"PatchA"); | ||
| 827 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 828 | ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", BURN_DEPENDENCY_ACTION_REGISTER); | ||
| 829 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 830 | ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_REGISTER); | ||
| 831 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 832 | ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0); | ||
| 833 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 834 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 835 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
| 836 | Assert::Equal(dwIndex, pPlan->cRollbackActions); | ||
| 837 | |||
| 838 | Assert::Equal(2ul, pPlan->cExecutePackagesTotal); | ||
| 839 | Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal); | ||
| 840 | |||
| 841 | dwIndex = 0; | ||
| 842 | ValidateCleanAction(pPlan, dwIndex++, L"PatchA"); | ||
| 843 | ValidateCleanAction(pPlan, dwIndex++, L"PackageA"); | ||
| 844 | Assert::Equal(dwIndex, pPlan->cCleanActions); | ||
| 845 | |||
| 846 | UINT uIndex = 0; | ||
| 847 | ValidatePlannedProvider(pPlan, uIndex++, L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", NULL); | ||
| 848 | ValidatePlannedProvider(pPlan, uIndex++, L"{0A5113E3-06A5-4CE0-8E83-9EB42F6764A6}", NULL); | ||
| 849 | ValidatePlannedProvider(pPlan, uIndex++, L"{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}", NULL); | ||
| 850 | Assert::Equal(uIndex, pPlan->cPlannedProviders); | ||
| 851 | |||
| 852 | Assert::Equal(3ul, pEngineState->packages.cPackages); | ||
| 853 | ValidatePermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"NetFx48Web"); | ||
| 854 | ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[1], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_ABSENT, BURN_PACKAGE_REGISTRATION_STATE_ABSENT); | ||
| 855 | ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[2], L"PatchA", BURN_PACKAGE_REGISTRATION_STATE_ABSENT, BURN_PACKAGE_REGISTRATION_STATE_ABSENT); | ||
| 856 | } | ||
| 857 | |||
| 653 | private: | 858 | private: |
| 654 | // This doesn't initialize everything, just enough for CorePlan to work. | 859 | // This doesn't initialize everything, just enough for CorePlan to work. |
| 655 | void InitializeEngineStateForCorePlan(LPCWSTR wzManifestFileName, BURN_ENGINE_STATE* pEngineState) | 860 | void InitializeEngineStateForCorePlan(LPCWSTR wzManifestFileName, BURN_ENGINE_STATE* pEngineState) |
| @@ -700,6 +905,30 @@ namespace Bootstrapper | |||
| 700 | pEngineState->fDetected = TRUE; | 905 | pEngineState->fDetected = TRUE; |
| 701 | } | 906 | } |
| 702 | 907 | ||
| 908 | void PlanTestDetectPatchInitialize(BURN_ENGINE_STATE* pEngineState) | ||
| 909 | { | ||
| 910 | HRESULT hr = MsiEngineDetectInitialize(&pEngineState->packages); | ||
| 911 | NativeAssert::Succeeded(hr, "MsiEngineDetectInitialize failed"); | ||
| 912 | |||
| 913 | for (DWORD i = 0; i < pEngineState->packages.cPackages; ++i) | ||
| 914 | { | ||
| 915 | BURN_PACKAGE* pPackage = pEngineState->packages.rgPackages + i; | ||
| 916 | |||
| 917 | if (BURN_PACKAGE_TYPE_MSP == pPackage->type) | ||
| 918 | { | ||
| 919 | for (DWORD j = 0; j < pPackage->Msp.cTargetProductCodes; ++j) | ||
| 920 | { | ||
| 921 | BURN_MSPTARGETPRODUCT* pTargetProduct = pPackage->Msp.rgTargetProducts + j; | ||
| 922 | |||
| 923 | if (BOOTSTRAPPER_PACKAGE_STATE_UNKNOWN == pTargetProduct->patchPackageState) | ||
| 924 | { | ||
| 925 | pTargetProduct->patchPackageState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT; | ||
| 926 | } | ||
| 927 | } | ||
| 928 | } | ||
| 929 | } | ||
| 930 | } | ||
| 931 | |||
| 703 | void DetectAttachedContainerAsAttached(BURN_ENGINE_STATE* pEngineState) | 932 | void DetectAttachedContainerAsAttached(BURN_ENGINE_STATE* pEngineState) |
| 704 | { | 933 | { |
| 705 | for (DWORD i = 0; i < pEngineState->containers.cContainers; ++i) | 934 | for (DWORD i = 0; i < pEngineState->containers.cContainers; ++i) |
| @@ -773,6 +1002,21 @@ namespace Bootstrapper | |||
| 773 | BURN_PACKAGE* pPackage = pEngineState->packages.rgPackages + i; | 1002 | BURN_PACKAGE* pPackage = pEngineState->packages.rgPackages + i; |
| 774 | DetectPackageAsPresentAndCached(pPackage); | 1003 | DetectPackageAsPresentAndCached(pPackage); |
| 775 | DetectPackageDependent(pPackage, pEngineState->registration.sczId); | 1004 | DetectPackageDependent(pPackage, pEngineState->registration.sczId); |
| 1005 | |||
| 1006 | if (BURN_PACKAGE_TYPE_MSI == pPackage->type) | ||
| 1007 | { | ||
| 1008 | for (DWORD j = 0; j < pPackage->Msi.cSlipstreamMspPackages; ++j) | ||
| 1009 | { | ||
| 1010 | pPackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED; | ||
| 1011 | |||
| 1012 | BURN_PACKAGE* pMspPackage = pPackage->Msi.rgSlipstreamMsps[j].pMspPackage; | ||
| 1013 | MspEngineAddDetectedTargetProduct(&pEngineState->packages, pMspPackage, j, pPackage->Msi.sczProductCode, pPackage->fPerMachine ? MSIINSTALLCONTEXT_MACHINE : MSIINSTALLCONTEXT_USERUNMANAGED); | ||
| 1014 | |||
| 1015 | BURN_MSPTARGETPRODUCT* pTargetProduct = pMspPackage->Msp.rgTargetProducts + (pMspPackage->Msp.cTargetProductCodes - 1); | ||
| 1016 | pTargetProduct->patchPackageState = BOOTSTRAPPER_PACKAGE_STATE_PRESENT; | ||
| 1017 | pTargetProduct->registrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT; | ||
| 1018 | } | ||
| 1019 | } | ||
| 776 | } | 1020 | } |
| 777 | } | 1021 | } |
| 778 | 1022 | ||
| @@ -862,7 +1106,23 @@ namespace Bootstrapper | |||
| 862 | { | 1106 | { |
| 863 | BURN_CACHE_ACTION* pAction = ValidateCacheActionExists(pPlan, fRollback, dwIndex); | 1107 | BURN_CACHE_ACTION* pAction = ValidateCacheActionExists(pPlan, fRollback, dwIndex); |
| 864 | Assert::Equal<DWORD>(BURN_CACHE_ACTION_TYPE_ACQUIRE_CONTAINER, pAction->type); | 1108 | Assert::Equal<DWORD>(BURN_CACHE_ACTION_TYPE_ACQUIRE_CONTAINER, pAction->type); |
| 865 | NativeAssert::StringEqual(wzContainerId, pAction->extractContainer.pContainer->sczId); | 1109 | NativeAssert::StringEqual(wzContainerId, pAction->resolveContainer.pContainer->sczId); |
| 1110 | Assert::Equal<BOOL>(fSkipUntilRetried, pAction->fSkipUntilRetried); | ||
| 1111 | } | ||
| 1112 | |||
| 1113 | void ValidateCacheAcquirePayload( | ||
| 1114 | __in BURN_PLAN* pPlan, | ||
| 1115 | __in BOOL fRollback, | ||
| 1116 | __in DWORD dwIndex, | ||
| 1117 | __in LPCWSTR wzPackageId, | ||
| 1118 | __in LPCWSTR wzPayloadId, | ||
| 1119 | __in BOOL fSkipUntilRetried | ||
| 1120 | ) | ||
| 1121 | { | ||
| 1122 | BURN_CACHE_ACTION* pAction = ValidateCacheActionExists(pPlan, fRollback, dwIndex); | ||
| 1123 | Assert::Equal<DWORD>(BURN_CACHE_ACTION_TYPE_ACQUIRE_PAYLOAD, pAction->type); | ||
| 1124 | NativeAssert::StringEqual(wzPackageId, pAction->resolvePayload.pPackage->sczId); | ||
| 1125 | NativeAssert::StringEqual(wzPayloadId, pAction->resolvePayload.pPayload->sczKey); | ||
| 866 | Assert::Equal<BOOL>(fSkipUntilRetried, pAction->fSkipUntilRetried); | 1126 | Assert::Equal<BOOL>(fSkipUntilRetried, pAction->fSkipUntilRetried); |
| 867 | } | 1127 | } |
| 868 | 1128 | ||
| @@ -1063,7 +1323,7 @@ namespace Bootstrapper | |||
| 1063 | __in BURN_PLAN* pPlan, | 1323 | __in BURN_PLAN* pPlan, |
| 1064 | __in BOOL fRollback, | 1324 | __in BOOL fRollback, |
| 1065 | __in DWORD dwIndex, | 1325 | __in DWORD dwIndex, |
| 1066 | __in LPCWSTR wzPackageId, | 1326 | __in_z LPCWSTR wzPackageId, |
| 1067 | __in BOOTSTRAPPER_ACTION_STATE action, | 1327 | __in BOOTSTRAPPER_ACTION_STATE action, |
| 1068 | __in BURN_MSI_PROPERTY actionMsiProperty, | 1328 | __in BURN_MSI_PROPERTY actionMsiProperty, |
| 1069 | __in DWORD uiLevel, | 1329 | __in DWORD uiLevel, |
| @@ -1083,6 +1343,45 @@ namespace Bootstrapper | |||
| 1083 | Assert::Equal<BOOL>(FALSE, pAction->fDeleted); | 1343 | Assert::Equal<BOOL>(FALSE, pAction->fDeleted); |
| 1084 | } | 1344 | } |
| 1085 | 1345 | ||
| 1346 | BURN_EXECUTE_ACTION* ValidateDeletedExecuteMspTarget( | ||
| 1347 | __in BURN_PLAN* pPlan, | ||
| 1348 | __in BOOL fRollback, | ||
| 1349 | __in DWORD dwIndex, | ||
| 1350 | __in_z LPCWSTR wzPackageId, | ||
| 1351 | __in BOOTSTRAPPER_ACTION_STATE action, | ||
| 1352 | __in_z LPCWSTR wzTargetProductCode, | ||
| 1353 | __in BOOL fPerMachineTarget, | ||
| 1354 | __in BURN_MSI_PROPERTY actionMsiProperty, | ||
| 1355 | __in DWORD uiLevel, | ||
| 1356 | __in BOOL fDisableExternalUiHandler, | ||
| 1357 | __in BOOL fDeleted | ||
| 1358 | ) | ||
| 1359 | { | ||
| 1360 | BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex); | ||
| 1361 | Assert::Equal<DWORD>(BURN_EXECUTE_ACTION_TYPE_MSP_TARGET, pAction->type); | ||
| 1362 | NativeAssert::StringEqual(wzPackageId, pAction->mspTarget.pPackage->sczId); | ||
| 1363 | Assert::Equal<DWORD>(action, pAction->mspTarget.action); | ||
| 1364 | NativeAssert::StringEqual(wzTargetProductCode, pAction->mspTarget.sczTargetProductCode); | ||
| 1365 | Assert::Equal<BOOL>(fPerMachineTarget, pAction->mspTarget.fPerMachineTarget); | ||
| 1366 | Assert::Equal<DWORD>(actionMsiProperty, pAction->mspTarget.actionMsiProperty); | ||
| 1367 | Assert::Equal<DWORD>(uiLevel, pAction->mspTarget.uiLevel); | ||
| 1368 | Assert::Equal<BOOL>(fDisableExternalUiHandler, pAction->mspTarget.fDisableExternalUiHandler); | ||
| 1369 | NativeAssert::NotNull(pAction->mspTarget.sczLogPath); | ||
| 1370 | Assert::Equal<BOOL>(fDeleted, pAction->fDeleted); | ||
| 1371 | return pAction; | ||
| 1372 | } | ||
| 1373 | |||
| 1374 | void ValidateExecuteMspTargetPatch( | ||
| 1375 | __in BURN_EXECUTE_ACTION* pAction, | ||
| 1376 | __in DWORD dwIndex, | ||
| 1377 | __in_z LPCWSTR wzPackageId | ||
| 1378 | ) | ||
| 1379 | { | ||
| 1380 | Assert::InRange(dwIndex + 1ul, 1ul, pAction->mspTarget.cOrderedPatches); | ||
| 1381 | BURN_ORDERED_PATCHES* pOrderedPatch = pAction->mspTarget.rgOrderedPatches + dwIndex; | ||
| 1382 | NativeAssert::StringEqual(wzPackageId, pOrderedPatch->pPackage->sczId); | ||
| 1383 | } | ||
| 1384 | |||
| 1086 | void ValidateExecutePackageDependency( | 1385 | void ValidateExecutePackageDependency( |
| 1087 | __in BURN_PLAN* pPlan, | 1386 | __in BURN_PLAN* pPlan, |
| 1088 | __in BOOL fRollback, | 1387 | __in BOOL fRollback, |
diff --git a/src/test/BurnUnitTest/TestData/PlanTest/Slipstream_BundleA_manifest.xml b/src/test/BurnUnitTest/TestData/PlanTest/Slipstream_BundleA_manifest.xml new file mode 100644 index 00000000..4b5cab6f --- /dev/null +++ b/src/test/BurnUnitTest/TestData/PlanTest/Slipstream_BundleA_manifest.xml | |||
| @@ -0,0 +1 @@ | |||
| <?xml version="1.0" encoding="utf-8"?><BurnManifest xmlns="http://wixtoolset.org/schemas/v4/2008/Burn"><Log PathVariable="WixBundleLog" Prefix="~SlipstreamTests_BundleA" Extension=".log" /><RelatedBundle Id="{62C28DAF-A13E-4F55-ACA1-FB843630789C}" Action="Upgrade" /><Variable Id="TestGroupName" Value="SlipstreamTests" Type="string" Hidden="no" Persisted="no" /><Variable Id="WixBundleName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSource" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSourceFolder" Hidden="no" Persisted="yes" /><Variable Id="WixBundleLastUsedSource" Hidden="no" Persisted="yes" /><RegistrySearch Id="NETFRAMEWORK45" Variable="NETFRAMEWORK45" Root="HKLM" Key="SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" Value="Release" Type="value" VariableType="string" /><UX><Payload Id="WixManagedBootstrapperApplicationHost" FilePath="mbahost.dll" FileSize="140288" Hash="4569C53566B1025E243E0C29A96C608BD4019979" Packaging="embedded" SourcePath="u30" /><Payload Id="payO60IVK4ATGzPpMz3rwVbUWl6DyU" FilePath="WixToolset.Mba.Host.config" FileSize="783" Hash="B5BDD5E7179A94C2C817069913CA8C099DF811B9" Packaging="embedded" SourcePath="u0" /><Payload Id="payxj4zDAKL2NVlz4ohp0GvwFHepyI" FilePath="TestBA.dll" FileSize="25088" Hash="DB12DB6565CDBC4E9705204830E421ACEB710129" Packaging="embedded" SourcePath="u1" /><Payload Id="pay1hOSAUC8_D633cD2TXpIXCL30OU" FilePath="mbanative.dll" FileSize="118272" Hash="3A7A20D97B0546A23A025EE5774BE237C14D2957" Packaging="embedded" SourcePath="u2" /><Payload Id="payujy6Izl_BlUNfHt2eI.ADfjYAv4" FilePath="WixToolset.Mba.Core.dll" FileSize="114688" Hash="56BA3EA94BEBF8EB562C914495E1594E74F05DBE" Packaging="embedded" SourcePath="u3" /><Payload Id="payR4EbR4OTDZpPEycWaSSM_gZRBWM" FilePath="mbapreq.thm" FileSize="3599" Hash="8D9797C1E1A50AECB8B85FFCEA6A2A2EF611BD7F" Packaging="embedded" SourcePath="u4" /><Payload Id="paylVCy2Ecl8pHPdJTCQZryUG4T9us" FilePath="mbapreq.png" FileSize="797" Hash="75AE41181581FD6376CA9CA88147011E48BF9A30" Packaging="embedded" SourcePath="u5" /><Payload Id="payTaG4B_lob1aLcKFaOqSSG3MPMpU" FilePath="mbapreq.wxl" FileSize="2237" Hash="068B3C5E27AECE7987EABAA2802C9EB07B39EAF8" Packaging="embedded" SourcePath="u6" /><Payload Id="payZwIGuiezVTitZOoZKxyh2DdRSGs" FilePath="1028\mbapreq.wxl" FileSize="1998" Hash="A989D9B892F497215D81F903591ECB6CD50CFFFC" Packaging="embedded" SourcePath="u7" /><Payload Id="pay.herBWX.LlOh8jLsx24aWdunV_0" FilePath="1029\mbapreq.wxl" FileSize="2428" Hash="E6B8E4B1AA89430EB6A5A1E997CA3D1D2F968285" Packaging="embedded" SourcePath="u8" /><Payload Id="pay8DkMszYsoxxdgX14huLDMYXylQg" FilePath="1030\mbapreq.wxl" FileSize="2256" Hash="612CD2FD0CF3800639385C0BF4D805B24507D356" Packaging="embedded" SourcePath="u9" /><Payload Id="payPaHpoTeOdkW.TK99IDwktNLhTAg" FilePath="1031\mbapreq.wxl" FileSize="2409" Hash="E59A8F11D95AC17FC70BD718706EE36BFA50EF02" Packaging="embedded" SourcePath="u10" /><Payload Id="pay45AtAzterLTMzZgdxxtuYvaiXwU" FilePath="1032\mbapreq.wxl" FileSize="3368" Hash="154E0A658BA7EE59889224A231423634A9725547" Packaging="embedded" SourcePath="u11" /><Payload Id="payA2VEKIqhePyNIEmr14eyH3JoVLc" FilePath="1035\mbapreq.wxl" FileSize="2205" Hash="6AAE55269E42F99A5D88ADD18C433384DEB9E956" Packaging="embedded" SourcePath="u12" /><Payload Id="payvre23ObscjzhcaFIifUAkXMdPa8" FilePath="1036\mbapreq.wxl" FileSize="2276" Hash="7DC74874357F50AE8C4871D8F4DC06B337CF6352" Packaging="embedded" SourcePath="u13" /><Payload Id="paytxUV3vuBbG2c.a9c.d_sZX2x6wA" FilePath="1038\mbapreq.wxl" FileSize="2362" Hash="B60C34DE38E6E48BA0841E8A962C17179FC1B69A" Packaging="embedded" SourcePath="u14" /><Payload Id="payYvMWRK9xelo5.sQn7jRkJIaBp9A" FilePath="1040\mbapreq.wxl" FileSize="2273" Hash="902D231AD6306087F215DEABB7F2AB2F8072C401" Packaging="embedded" SourcePath="u15" /><Payload Id="pay68KKSApyQimbA25t6kSbqhdeH10" FilePath="1041\mbapreq.wxl" FileSize="2518" Hash="4095A1AFCF18C01F7DA51A1A389C2FBBB1A82A12" Packaging="embedded" SourcePath="u16" /><Payload Id="paypiqxaHpYZqx.9eDVjQrj1igLbRY" FilePath="1042\mbapreq.wxl" FileSize="2209" Hash="99CE8B42300EF656E6BD44F01766DC638CB0496F" Packaging="embedded" SourcePath="u17" /><Payload Id="payTO0YwZzxKpbqdrBVUcVRTu3BFe8" FilePath="1043\mbapreq.wxl" FileSize="2282" Hash="87117EE32E0004E25DDCEB1A7D417F3A02856A50" Packaging="embedded" SourcePath="u18" /><Payload Id="payIXg2ldBJukRzhqWolJVOEbTmF34" FilePath="1044\mbapreq.wxl" FileSize="2141" Hash="5AED841C6A870C3A8BAF8A10D00F887A781D0CF0" Packaging="embedded" SourcePath="u19" /><Payload Id="payOHIZbSkIvrpwKkkXI173tv3u3B4" FilePath="1045\mbapreq.wxl" FileSize="2338" Hash="07E37CBC59298F24A5C8C3B8FEB7A45DADF8CD07" Packaging="embedded" SourcePath="u20" /><Payload Id="payQRQ_UZl_R2UtV0xDXB2yeH2bg3E" FilePath="1046\mbapreq.wxl" FileSize="2118" Hash="AEC0CE51E8E335E9B86F1AC7E39CCD172B896582" Packaging="embedded" SourcePath="u21" /><Payload Id="payhrejLLBfc1i27iN._QPhQ4K337I" FilePath="1049\mbapreq.wxl" FileSize="2851" Hash="9628BADB173B171ED85D902634D9AA5D91FE9721" Packaging="embedded" SourcePath="u22" /><Payload Id="payqEzaDNzxB68vGp29jgDcCos6dvg" FilePath="1051\mbapreq.wxl" FileSize="2304" Hash="B584E8C0D7F9B7A1BB70BC00E42BFD35BED5D81D" Packaging="embedded" SourcePath="u23" /><Payload Id="paydz8Vk8xSTyYohgGXTSIxWGXL5.Q" FilePath="1053\mbapreq.wxl" FileSize="2102" Hash="67E93F555DBFEF8508E79F7CA8CE76B881308760" Packaging="embedded" SourcePath="u24" /><Payload Id="pay0HRUZTlbC3taSOffJBsEj92Br8Y" FilePath="1055\mbapreq.wxl" FileSize="2273" Hash="AEB8C90D66942A5CD73EA52A6F2ADD4F7D518A0D" Packaging="embedded" SourcePath="u25" /><Payload Id="payIvUOkc_EMH7laMFehefNolV8hZo" FilePath="1060\mbapreq.wxl" FileSize="2170" Hash="B1D4B71907B8BD82DD8B047404AF10FDBBE5CBA0" Packaging="embedded" SourcePath="u26" /><Payload Id="payLFhOb.rHuk4sW5CYAPMShG0NjGI" FilePath="2052\mbapreq.wxl" FileSize="1953" Hash="C8FB8982EC71C48D6EA021ADD9AAA7BCB0656281" Packaging="embedded" SourcePath="u27" /><Payload Id="payqIKCmERK7Nhxx_nNXvRxdKqKDbI" FilePath="2070\mbapreq.wxl" FileSize="2182" Hash="825F27A543907ED27E815EC67DFD48AF7BF5831E" Packaging="embedded" SourcePath="u28" /><Payload Id="payqeWUzIVaEqjuRXN0z8ECC3Y4tCc" FilePath="3082\mbapreq.wxl" FileSize="2369" Hash="39C07C31077AAFDC0DD208273AA41654CAD80FDD" Packaging="embedded" SourcePath="u29" /><Payload Id="paylfeHEjJSSTnNzY9QMZM2Ye3Ipy4" FilePath="mbapreq.dll" FileSize="245760" Hash="6499FA21D178131DDE13A4EF44ABEC32E91D65D4" Packaging="embedded" SourcePath="u31" /><Payload Id="payDPxs6uy8nbky.R7zhir2RRAfc.c" FilePath="WixToolset.Mba.Host.dll" FileSize="11264" Hash="9E6452891E401EB211DD41550A09FDF98EC0992F" Packaging="embedded" SourcePath="u32" /><Payload Id="uxTxMXPVMXwQrPTMIGa5WGt93w0Ns" FilePath="BootstrapperApplicationData.xml" FileSize="14292" Hash="CDF09A0723F4F33C13670BBAFCFFA7E660E15DFC" Packaging="embedded" SourcePath="u33" /><Payload Id="uxYRbgitOs0K878jn5L_z7LdJ21KI" FilePath="BundleExtensionData.xml" FileSize="252" Hash="86688B13D3364ADB90BBA552F544D4D546AFD63D" Packaging="embedded" SourcePath="u34" /></UX><Payload Id="NetFx48Web" FilePath="redist\ndp48-web.exe" FileSize="1479400" Hash="5A84A8E612E270E27D0061D58DB6B470153BE1F9" DownloadUrl="https://go.microsoft.com/fwlink/?LinkId=2085155" Packaging="external" SourcePath="redist\ndp48-web.exe" /><Payload Id="PackageA" FilePath="PackageAv1.msi" FileSize="32768" Hash="2369B16B7219B3C834DFBC5D2AF8B2EF8803D43D" Packaging="external" SourcePath="PackageAv1.msi" /><Payload Id="PatchA" FilePath="PatchA.msp" FileSize="20480" Hash="FABC6C18E4A778E127E84CDF67F93A291CAEC8BB" Packaging="external" SourcePath="PatchA.msp" /><RollbackBoundary Id="WixDefaultBoundary" Vital="yes" Transaction="no" /><Registration Id="{22D1DDBA-284D-40A7-BD14-95EA07906F21}" ExecutableName="BundleA.exe" PerMachine="yes" Tag="" Version="1.0.0.0" ProviderKey="{22D1DDBA-284D-40A7-BD14-95EA07906F21}"><Arp Register="yes" DisplayName="~SlipstreamTests - BundleA" DisplayVersion="1.0.0.0" /></Registration><Chain><ExePackage Id="NetFx48Web" Cache="yes" CacheId="5A84A8E612E270E27D0061D58DB6B470153BE1F9" InstallSize="1479400" Size="1479400" PerMachine="yes" Permanent="yes" Vital="yes" RollbackBoundaryForward="WixDefaultBoundary" LogPathVariable="NetFx48WebLog" RollbackLogPathVariable="WixBundleRollbackLog_NetFx48Web" DetectCondition="NETFRAMEWORK45 >= 528040" InstallArguments="/q /norestart /ChainingPackage "[WixBundleName]" /log "[NetFx48WebLog].html"" UninstallArguments="/uninstall /q /norestart /ChainingPackage "[WixBundleName]" /log "[NetFx48WebLog].html"" RepairArguments="/q /norestart /repair /ChainingPackage "[WixBundleName]" /log "[NetFx48WebLog].html"" Repairable="yes" Protocol="netfx4"><PayloadRef Id="NetFx48Web" /></ExePackage><MsiPackage Id="PackageA" Cache="yes" CacheId="{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}v1.0.0.0" InstallSize="2103" Size="32768" PerMachine="yes" Permanent="no" Vital="yes" LogPathVariable="WixBundleLog_PackageA" RollbackLogPathVariable="WixBundleRollbackLog_PackageA" ProductCode="{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}" Language="1033" Version="1.0.0.0" UpgradeCode="{DB87BB66-FE5D-4293-81AC-EE313D3F864B}"><MsiProperty Id="ARPSYSTEMCOMPONENT" Value="1" /><MsiProperty Id="MSIFASTINSTALL" Value="7" /><SlipstreamMsp Id="PatchA" /><Provides Key="{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}" Version="1.0.0.0" DisplayName="~SlipstreamTests - PackageA" /><RelatedPackage Id="{DB87BB66-FE5D-4293-81AC-EE313D3F864B}" MaxVersion="1.0.0.0" MaxInclusive="no" OnlyDetect="no" LangInclusive="no"><Language Id="1033" /></RelatedPackage><RelatedPackage Id="{DB87BB66-FE5D-4293-81AC-EE313D3F864B}" MinVersion="1.0.0.0" MinInclusive="no" OnlyDetect="yes" LangInclusive="no"><Language Id="1033" /></RelatedPackage><PayloadRef Id="PackageA" /></MsiPackage><MspPackage Id="PatchA" Cache="yes" CacheId="{0A5113E3-06A5-4CE0-8E83-9EB42F6764A6}" InstallSize="20480" Size="20480" PerMachine="yes" Permanent="no" Vital="yes" RollbackBoundaryBackward="WixDefaultBoundary" LogPathVariable="WixBundleLog_PatchA" RollbackLogPathVariable="WixBundleRollbackLog_PatchA" PatchCode="{0A5113E3-06A5-4CE0-8E83-9EB42F6764A6}" PatchXml="<?xml version="1.0" encoding="utf-16"?><MsiPatch xmlns="http://www.microsoft.com/msi/patch_applicability.xsd" SchemaVersion="1.0.0.0" PatchGUID="{0A5113E3-06A5-4CE0-8E83-9EB42F6764A6}" MinMsiVersion="5" TargetsRTM="true"><TargetProduct MinMsiVersion="500"><TargetProductCode Validate="true">{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}</TargetProductCode><TargetVersion Validate="true" ComparisonType="Equal" ComparisonFilter="MajorMinorUpdate">1.0.0.0</TargetVersion><UpdatedVersion>1.0.1.0</UpdatedVersion><TargetLanguage Validate="false">1033</TargetLanguage><UpdatedLanguages>1033</UpdatedLanguages><UpgradeCode Validate="true">{DB87BB66-FE5D-4293-81AC-EE313D3F864B}</UpgradeCode></TargetProduct><TargetProductCode>{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}</TargetProductCode></MsiPatch>"><Provides Key="{0A5113E3-06A5-4CE0-8E83-9EB42F6764A6}" DisplayName="SlipstreamTests - Patch A" /><PayloadRef Id="PatchA" /></MspPackage></Chain><PatchTargetCode TargetCode="{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}" Product="yes" /></BurnManifest> \ No newline at end of file | |||
