aboutsummaryrefslogtreecommitdiff
path: root/src/engine
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2021-02-22 16:16:12 -0600
committerSean Hall <r.sean.hall@gmail.com>2021-02-22 20:25:06 -0600
commit4f4c85ed66f1b2dfb1bec76d54d7b50c637d5bfa (patch)
tree6de8e63ad46626ec457af256d481e81d726f3860 /src/engine
parentd0d93beac0b79fa9c3d43398813954988afda18f (diff)
downloadwix-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/engine')
-rw-r--r--src/engine/core.cpp3
-rw-r--r--src/engine/detect.cpp10
-rw-r--r--src/engine/msiengine.cpp56
-rw-r--r--src/engine/msiengine.h3
-rw-r--r--src/engine/mspengine.cpp196
-rw-r--r--src/engine/mspengine.h16
-rw-r--r--src/engine/package.cpp23
-rw-r--r--src/engine/package.h21
-rw-r--r--src/engine/plan.cpp4
9 files changed, 243 insertions, 89 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
400extern "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
428LExit:
429 return hr;
430}
431
395extern "C" HRESULT MsiEngineDetectPackage( 432extern "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
983LExit: 1011LExit:
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(
27void MsiEnginePackageUninitialize( 27void MsiEnginePackageUninitialize(
28 __in BURN_PACKAGE* pPackage 28 __in BURN_PACKAGE* pPackage
29 ); 29 );
30HRESULT MsiEngineDetectInitialize(
31 __in BURN_PACKAGES* pPackages
32 );
30HRESULT MsiEngineDetectPackage( 33HRESULT 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 );
32static HRESULT AddDetectedTargetProduct( 32static 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 );
39static HRESULT AddMsiChainedPatch(
40 __in BURN_PACKAGE* pPackage,
41 __in BURN_PACKAGE* pMspPackage,
42 __in DWORD dwMspTargetProductIndex,
43 __out DWORD* pdwChainedPatchIndex
38 ); 44 );
39static void DeterminePatchChainedTarget( 45static 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 );
46static HRESULT PlanTargetProduct( 51static 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
204extern "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
221LExit:
222 return hr;
223}
224
225extern "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
248LExit:
249 return hr;
250}
251
195extern "C" HRESULT MspEngineDetectPackage( 252extern "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
640extern "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
666extern "C" void MspEngineUpdateInstallRegistrationState( 703extern "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
928static HRESULT AddDetectedTargetProduct( 965static 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
952LExit: 992LExit:
953 return hr; 993 return hr;
954} 994}
955 995
956static void DeterminePatchChainedTarget( 996static 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;
1014LExit:
1015 return hr;
1016}
1017
1018static 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; 1056LExit:
991 *pfSlipstreamed = fSlipstreamed; 1057 return hr;
992
993 return;
994} 1058}
995 1059
996static HRESULT PlanTargetProduct( 1060static 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(
28HRESULT MspEngineDetectInitialize( 28HRESULT MspEngineDetectInitialize(
29 __in BURN_PACKAGES* pPackages 29 __in BURN_PACKAGES* pPackages
30 ); 30 );
31HRESULT 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 );
38HRESULT MspEngineAddMissingSlipstreamTarget(
39 __in BURN_PACKAGE* pMsiPackage,
40 __in BURN_SLIPSTREAM_MSP* pSlipstreamMsp
41 );
31HRESULT MspEngineDetectPackage( 42HRESULT 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 );
62void MspEngineSlipstreamUpdateState(
63 __in BURN_PACKAGE* pMspPackage,
64 __in BOOTSTRAPPER_ACTION_STATE execute,
65 __in BOOTSTRAPPER_ACTION_STATE rollback
66 );
67void MspEngineUpdateInstallRegistrationState( 73void 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
17const DWORD BURN_PACKAGE_INVALID_PATCH_INDEX = 0x80000000;
18
17enum BURN_EXE_EXIT_CODE_TYPE 19enum 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
179typedef struct _BURN_CHAINED_PATCH
180{
181 BURN_PACKAGE* pMspPackage;
182 DWORD dwMspTargetProductIndex; // index into the Msp.rgTargetProducts
183} BURN_CHAINED_PATCH;
184
185typedef struct _BURN_SLIPSTREAM_MSP
186{
187 BURN_PACKAGE* pMspPackage;
188 DWORD dwMsiChainedPatchIndex; // index into the Msi.rgChainedPatches
189} BURN_SLIPSTREAM_MSP;
190
175typedef struct _BURN_PACKAGE_PAYLOAD 191typedef 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;