aboutsummaryrefslogtreecommitdiff
path: root/src/burn
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2022-01-14 21:37:24 -0600
committerSean Hall <r.sean.hall@gmail.com>2022-01-16 10:30:28 -0600
commitda1d1376953ef1c9afb32d5eee02b785e52e372e (patch)
tree0df8550960259d7b13f5cd90f04d21b5576f16b7 /src/burn
parentabe316b80fae80eba54b0b79e76b6362105fa098 (diff)
downloadwix-da1d1376953ef1c9afb32d5eee02b785e52e372e.tar.gz
wix-da1d1376953ef1c9afb32d5eee02b785e52e372e.tar.bz2
wix-da1d1376953ef1c9afb32d5eee02b785e52e372e.zip
Remove orphan compatible MSI packages.
Reimplements #3190
Diffstat (limited to 'src/burn')
-rw-r--r--src/burn/engine/apply.cpp162
-rw-r--r--src/burn/engine/core.cpp8
-rw-r--r--src/burn/engine/dependency.cpp123
-rw-r--r--src/burn/engine/dependency.h5
-rw-r--r--src/burn/engine/detect.cpp2
-rw-r--r--src/burn/engine/elevation.cpp303
-rw-r--r--src/burn/engine/elevation.h17
-rw-r--r--src/burn/engine/engine.mc23
-rw-r--r--src/burn/engine/logging.cpp43
-rw-r--r--src/burn/engine/logging.h7
-rw-r--r--src/burn/engine/msiengine.cpp181
-rw-r--r--src/burn/engine/msiengine.h14
-rw-r--r--src/burn/engine/package.cpp25
-rw-r--r--src/burn/engine/package.h34
-rw-r--r--src/burn/engine/plan.cpp83
-rw-r--r--src/burn/engine/plan.h10
-rw-r--r--src/burn/engine/registration.cpp4
-rw-r--r--src/burn/engine/userexperience.cpp118
-rw-r--r--src/burn/engine/userexperience.h26
-rw-r--r--src/burn/test/BurnUnitTest/PlanTest.cpp133
20 files changed, 1252 insertions, 69 deletions
diff --git a/src/burn/engine/apply.cpp b/src/burn/engine/apply.cpp
index 99884234..6bf3020c 100644
--- a/src/burn/engine/apply.cpp
+++ b/src/burn/engine/apply.cpp
@@ -60,7 +60,7 @@ typedef struct _BURN_EXECUTE_CONTEXT
60 BURN_USER_EXPERIENCE* pUX; 60 BURN_USER_EXPERIENCE* pUX;
61 BURN_APPLY_CONTEXT* pApplyContext; 61 BURN_APPLY_CONTEXT* pApplyContext;
62 BOOL fRollback; 62 BOOL fRollback;
63 BURN_PACKAGE* pExecutingPackage; 63 LPCWSTR wzExecutingPackageId;
64 DWORD cExecutedPackages; 64 DWORD cExecutedPackages;
65 DWORD cExecutePackagesTotal; 65 DWORD cExecutePackagesTotal;
66} BURN_EXECUTE_CONTEXT; 66} BURN_EXECUTE_CONTEXT;
@@ -278,6 +278,19 @@ static void ResetTransactionRegistrationState(
278 __in BURN_ENGINE_STATE* pEngineState, 278 __in BURN_ENGINE_STATE* pEngineState,
279 __in BOOL fCommit 279 __in BOOL fCommit
280 ); 280 );
281static HRESULT ExecuteUninstallMsiCompatiblePackage(
282 __in BURN_ENGINE_STATE* pEngineState,
283 __in BURN_EXECUTE_ACTION* pExecuteAction,
284 __in BURN_EXECUTE_CONTEXT* pContext,
285 __out BOOL* pfRetry,
286 __out BOOL* pfSuspend,
287 __out BOOTSTRAPPER_APPLY_RESTART* pRestart
288 );
289static HRESULT CleanCompatiblePackage(
290 __in BURN_CACHE* pCache,
291 __in HANDLE hElevatedPipe,
292 __in BURN_PACKAGE* pPackage
293 );
281static HRESULT CleanPackage( 294static HRESULT CleanPackage(
282 __in BURN_CACHE* pCache, 295 __in BURN_CACHE* pCache,
283 __in HANDLE hElevatedPipe, 296 __in HANDLE hElevatedPipe,
@@ -300,7 +313,8 @@ static HRESULT ReportOverallProgressTicks(
300static HRESULT ExecutePackageComplete( 313static HRESULT ExecutePackageComplete(
301 __in BURN_USER_EXPERIENCE* pUX, 314 __in BURN_USER_EXPERIENCE* pUX,
302 __in BURN_VARIABLES* pVariables, 315 __in BURN_VARIABLES* pVariables,
303 __in BURN_PACKAGE* pPackage, 316 __in LPCWSTR wzPackageId,
317 __in BOOL fPackageVital,
304 __in HRESULT hrOverall, 318 __in HRESULT hrOverall,
305 __in HRESULT hrExecute, 319 __in HRESULT hrExecute,
306 __in BOOL fRollback, 320 __in BOOL fRollback,
@@ -808,7 +822,20 @@ extern "C" void ApplyClean(
808 BURN_CLEAN_ACTION* pCleanAction = pPlan->rgCleanActions + i; 822 BURN_CLEAN_ACTION* pCleanAction = pPlan->rgCleanActions + i;
809 BURN_PACKAGE* pPackage = pCleanAction->pPackage; 823 BURN_PACKAGE* pPackage = pCleanAction->pPackage;
810 824
811 hr = CleanPackage(pPlan->pCache, hPipe, pPackage); 825 switch (pCleanAction->type)
826 {
827 case BURN_CLEAN_ACTION_TYPE_COMPATIBLE_PACKAGE:
828 hr = CleanCompatiblePackage(pPlan->pCache, hPipe, pPackage);
829 break;
830
831 case BURN_CLEAN_ACTION_TYPE_PACKAGE:
832 hr = CleanPackage(pPlan->pCache, hPipe, pPackage);
833 break;
834
835 default:
836 AssertSz(FALSE, "Unknown clean action.");
837 break;
838 }
812 } 839 }
813} 840}
814 841
@@ -2350,6 +2377,11 @@ static HRESULT DoExecuteAction(
2350 ExitOnFailure(hr, "Failed to execute commit MSI transaction action."); 2377 ExitOnFailure(hr, "Failed to execute commit MSI transaction action.");
2351 break; 2378 break;
2352 2379
2380 case BURN_EXECUTE_ACTION_TYPE_UNINSTALL_MSI_COMPATIBLE_PACKAGE:
2381 hr = ExecuteUninstallMsiCompatiblePackage(pEngineState, pExecuteAction, pContext, &fRetry, pfSuspend, &restart);
2382 ExitOnFailure(hr, "Failed to execute uninstall MSI compatible package.");
2383 break;
2384
2353 default: 2385 default:
2354 hr = E_UNEXPECTED; 2386 hr = E_UNEXPECTED;
2355 ExitOnFailure(hr, "Invalid execute action."); 2387 ExitOnFailure(hr, "Invalid execute action.");
@@ -2509,7 +2541,7 @@ static HRESULT ExecuteRelatedBundle(
2509 } 2541 }
2510 2542
2511 Assert(pContext->fRollback == fRollback); 2543 Assert(pContext->fRollback == fRollback);
2512 pContext->pExecutingPackage = pPackage; 2544 pContext->wzExecutingPackageId = pPackage->sczId;
2513 fBeginCalled = TRUE; 2545 fBeginCalled = TRUE;
2514 2546
2515 // Send package execute begin to BA. 2547 // Send package execute begin to BA.
@@ -2550,7 +2582,7 @@ static HRESULT ExecuteRelatedBundle(
2550LExit: 2582LExit:
2551 if (fBeginCalled) 2583 if (fBeginCalled)
2552 { 2584 {
2553 hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend); 2585 hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage->sczId, pPackage->fVital, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
2554 } 2586 }
2555 2587
2556 return hr; 2588 return hr;
@@ -2581,7 +2613,7 @@ static HRESULT ExecuteExePackage(
2581 } 2613 }
2582 2614
2583 Assert(pContext->fRollback == fRollback); 2615 Assert(pContext->fRollback == fRollback);
2584 pContext->pExecutingPackage = pPackage; 2616 pContext->wzExecutingPackageId = pPackage->sczId;
2585 fBeginCalled = TRUE; 2617 fBeginCalled = TRUE;
2586 2618
2587 // Send package execute begin to BA. 2619 // Send package execute begin to BA.
@@ -2629,7 +2661,7 @@ LExit:
2629 2661
2630 if (fBeginCalled) 2662 if (fBeginCalled)
2631 { 2663 {
2632 hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend); 2664 hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage->sczId, pPackage->fVital, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
2633 } 2665 }
2634 2666
2635 return hr; 2667 return hr;
@@ -2659,7 +2691,7 @@ static HRESULT ExecuteMsiPackage(
2659 } 2691 }
2660 2692
2661 Assert(pContext->fRollback == fRollback); 2693 Assert(pContext->fRollback == fRollback);
2662 pContext->pExecutingPackage = pPackage; 2694 pContext->wzExecutingPackageId = pPackage->sczId;
2663 fBeginCalled = TRUE; 2695 fBeginCalled = TRUE;
2664 2696
2665 // Send package execute begin to BA. 2697 // Send package execute begin to BA.
@@ -2693,7 +2725,7 @@ LExit:
2693 2725
2694 if (fBeginCalled) 2726 if (fBeginCalled)
2695 { 2727 {
2696 hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend); 2728 hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage->sczId, pPackage->fVital, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
2697 } 2729 }
2698 2730
2699 return hr; 2731 return hr;
@@ -2723,7 +2755,7 @@ static HRESULT ExecuteMspPackage(
2723 } 2755 }
2724 2756
2725 Assert(pContext->fRollback == fRollback); 2757 Assert(pContext->fRollback == fRollback);
2726 pContext->pExecutingPackage = pPackage; 2758 pContext->wzExecutingPackageId = pPackage->sczId;
2727 fBeginCalled = TRUE; 2759 fBeginCalled = TRUE;
2728 2760
2729 // Send package execute begin to BA. 2761 // Send package execute begin to BA.
@@ -2766,7 +2798,7 @@ LExit:
2766 2798
2767 if (fBeginCalled) 2799 if (fBeginCalled)
2768 { 2800 {
2769 hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend); 2801 hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage->sczId, pPackage->fVital, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
2770 } 2802 }
2771 2803
2772 return hr; 2804 return hr;
@@ -2798,7 +2830,7 @@ static HRESULT ExecuteMsuPackage(
2798 } 2830 }
2799 2831
2800 Assert(pContext->fRollback == fRollback); 2832 Assert(pContext->fRollback == fRollback);
2801 pContext->pExecutingPackage = pPackage; 2833 pContext->wzExecutingPackageId = pPackage->sczId;
2802 fBeginCalled = TRUE; 2834 fBeginCalled = TRUE;
2803 2835
2804 // Send package execute begin to BA. 2836 // Send package execute begin to BA.
@@ -2846,7 +2878,7 @@ LExit:
2846 2878
2847 if (fBeginCalled) 2879 if (fBeginCalled)
2848 { 2880 {
2849 hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend); 2881 hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage->sczId, pPackage->fVital, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
2850 } 2882 }
2851 2883
2852 return hr; 2884 return hr;
@@ -3110,6 +3142,79 @@ static void ResetTransactionRegistrationState(
3110 } 3142 }
3111} 3143}
3112 3144
3145static HRESULT ExecuteUninstallMsiCompatiblePackage(
3146 __in BURN_ENGINE_STATE* pEngineState,
3147 __in BURN_EXECUTE_ACTION* pExecuteAction,
3148 __in BURN_EXECUTE_CONTEXT* pContext,
3149 __out BOOL* pfRetry,
3150 __out BOOL* pfSuspend,
3151 __out BOOTSTRAPPER_APPLY_RESTART* pRestart
3152 )
3153{
3154 HRESULT hr = S_OK;
3155 HRESULT hrExecute = S_OK;
3156 BOOL fRollback = FALSE;
3157 BOOTSTRAPPER_ACTION_STATE action = BOOTSTRAPPER_ACTION_STATE_UNINSTALL;
3158 INSTALLUILEVEL uiLevel = INSTALLUILEVEL_NONE;
3159 BOOL fDisableExternalUiHandler = FALSE;
3160 BOOL fBeginCalled = FALSE;
3161 BURN_PACKAGE* pParentPackage = pExecuteAction->uninstallMsiCompatiblePackage.pParentPackage;
3162
3163 Assert(pContext->fRollback == fRollback);
3164 pContext->wzExecutingPackageId = pParentPackage->compatiblePackage.compatibleEntry.sczId;
3165 fBeginCalled = TRUE;
3166
3167 // Send package execute begin to BA.
3168 hr = UserExperienceOnExecutePackageBegin(&pEngineState->userExperience, pContext->wzExecutingPackageId, !fRollback, action, uiLevel, fDisableExternalUiHandler);
3169 ExitOnRootFailure(hr, "BA aborted execute MSI compatible package begin.");
3170
3171 // execute package
3172 if (pParentPackage->fPerMachine)
3173 {
3174 hrExecute = ElevationUninstallMsiCompatiblePackage(pEngineState->companionConnection.hPipe, pEngineState->userExperience.hwndApply, pExecuteAction, &pEngineState->variables, fRollback, MsiExecuteMessageHandler, pContext, pRestart);
3175 ExitOnFailure(hrExecute, "Failed to uninstall per-machine MSI compatible package.");
3176 }
3177 else
3178 {
3179 hrExecute = MsiEngineUninstallCompatiblePackage(pEngineState->userExperience.hwndApply, pExecuteAction, pContext->pCache, &pEngineState->variables, fRollback, MsiExecuteMessageHandler, pContext, pRestart);
3180 ExitOnFailure(hrExecute, "Failed to uninstall per-user MSI compatible package.");
3181 }
3182
3183 pContext->cExecutedPackages += fRollback ? -1 : 1;
3184
3185 hr = ReportOverallProgressTicks(&pEngineState->userExperience, fRollback, pEngineState->plan.cOverallProgressTicksTotal, pContext->pApplyContext);
3186 ExitOnRootFailure(hr, "BA aborted MSI compatible package execute progress.");
3187
3188LExit:
3189
3190 if (fBeginCalled)
3191 {
3192 hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pContext->wzExecutingPackageId, FALSE, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
3193 }
3194
3195 return hr;
3196}
3197
3198static HRESULT CleanCompatiblePackage(
3199 __in BURN_CACHE* pCache,
3200 __in HANDLE hElevatedPipe,
3201 __in BURN_PACKAGE* pPackage
3202 )
3203{
3204 HRESULT hr = S_OK;
3205
3206 if (pPackage->fPerMachine)
3207 {
3208 hr = ElevationCleanCompatiblePackage(hElevatedPipe, pPackage);
3209 }
3210 else
3211 {
3212 hr = CacheRemovePackage(pCache, FALSE, pPackage->compatiblePackage.compatibleEntry.sczId, pPackage->compatiblePackage.sczCacheId);
3213 }
3214
3215 return hr;
3216}
3217
3113static HRESULT CleanPackage( 3218static HRESULT CleanPackage(
3114 __in BURN_CACHE* pCache, 3219 __in BURN_CACHE* pCache,
3115 __in HANDLE hElevatedPipe, 3220 __in HANDLE hElevatedPipe,
@@ -3150,16 +3255,16 @@ static int GenericExecuteMessageHandler(
3150 case GENERIC_EXECUTE_MESSAGE_PROGRESS: 3255 case GENERIC_EXECUTE_MESSAGE_PROGRESS:
3151 { 3256 {
3152 DWORD dwOverallProgress = pContext->cExecutePackagesTotal ? (pContext->cExecutedPackages * 100 + pMessage->progress.dwPercentage) / (pContext->cExecutePackagesTotal) : 0; 3257 DWORD dwOverallProgress = pContext->cExecutePackagesTotal ? (pContext->cExecutedPackages * 100 + pMessage->progress.dwPercentage) / (pContext->cExecutePackagesTotal) : 0;
3153 UserExperienceOnExecuteProgress(pContext->pUX, pContext->pExecutingPackage->sczId, pMessage->progress.dwPercentage, dwOverallProgress, &nResult); // ignore return value. 3258 UserExperienceOnExecuteProgress(pContext->pUX, pContext->wzExecutingPackageId, pMessage->progress.dwPercentage, dwOverallProgress, &nResult); // ignore return value.
3154 } 3259 }
3155 break; 3260 break;
3156 3261
3157 case GENERIC_EXECUTE_MESSAGE_ERROR: 3262 case GENERIC_EXECUTE_MESSAGE_ERROR:
3158 UserExperienceOnError(pContext->pUX, BOOTSTRAPPER_ERROR_TYPE_EXE_PACKAGE, pContext->pExecutingPackage->sczId, pMessage->error.dwErrorCode, pMessage->error.wzMessage, pMessage->dwUIHint, 0, NULL, &nResult); // ignore return value. 3263 UserExperienceOnError(pContext->pUX, BOOTSTRAPPER_ERROR_TYPE_EXE_PACKAGE, pContext->wzExecutingPackageId, pMessage->error.dwErrorCode, pMessage->error.wzMessage, pMessage->dwUIHint, 0, NULL, &nResult); // ignore return value.
3159 break; 3264 break;
3160 3265
3161 case GENERIC_EXECUTE_MESSAGE_NETFX_FILES_IN_USE: 3266 case GENERIC_EXECUTE_MESSAGE_NETFX_FILES_IN_USE:
3162 UserExperienceOnExecuteFilesInUse(pContext->pUX, pContext->pExecutingPackage->sczId, pMessage->filesInUse.cFiles, pMessage->filesInUse.rgwzFiles, BOOTSTRAPPER_FILES_IN_USE_TYPE_NETFX, &nResult); // ignore return value. 3267 UserExperienceOnExecuteFilesInUse(pContext->pUX, pContext->wzExecutingPackageId, pMessage->filesInUse.cFiles, pMessage->filesInUse.rgwzFiles, BOOTSTRAPPER_FILES_IN_USE_TYPE_NETFX, &nResult); // ignore return value.
3163 fPassthrough = TRUE; 3268 fPassthrough = TRUE;
3164 break; 3269 break;
3165 } 3270 }
@@ -3188,25 +3293,25 @@ static int MsiExecuteMessageHandler(
3188 case WIU_MSI_EXECUTE_MESSAGE_PROGRESS: 3293 case WIU_MSI_EXECUTE_MESSAGE_PROGRESS:
3189 { 3294 {
3190 DWORD dwOverallProgress = pContext->cExecutePackagesTotal ? (pContext->cExecutedPackages * 100 + pMessage->progress.dwPercentage) / (pContext->cExecutePackagesTotal) : 0; 3295 DWORD dwOverallProgress = pContext->cExecutePackagesTotal ? (pContext->cExecutedPackages * 100 + pMessage->progress.dwPercentage) / (pContext->cExecutePackagesTotal) : 0;
3191 UserExperienceOnExecuteProgress(pContext->pUX, pContext->pExecutingPackage->sczId, pMessage->progress.dwPercentage, dwOverallProgress, &nResult); // ignore return value. 3296 UserExperienceOnExecuteProgress(pContext->pUX, pContext->wzExecutingPackageId, pMessage->progress.dwPercentage, dwOverallProgress, &nResult); // ignore return value.
3192 } 3297 }
3193 break; 3298 break;
3194 3299
3195 case WIU_MSI_EXECUTE_MESSAGE_ERROR: 3300 case WIU_MSI_EXECUTE_MESSAGE_ERROR:
3196 nResult = pMessage->nResultRecommendation; 3301 nResult = pMessage->nResultRecommendation;
3197 UserExperienceOnError(pContext->pUX, BOOTSTRAPPER_ERROR_TYPE_WINDOWS_INSTALLER, pContext->pExecutingPackage->sczId, pMessage->error.dwErrorCode, pMessage->error.wzMessage, pMessage->dwUIHint, pMessage->cData, pMessage->rgwzData, &nResult); // ignore return value. 3302 UserExperienceOnError(pContext->pUX, BOOTSTRAPPER_ERROR_TYPE_WINDOWS_INSTALLER, pContext->wzExecutingPackageId, pMessage->error.dwErrorCode, pMessage->error.wzMessage, pMessage->dwUIHint, pMessage->cData, pMessage->rgwzData, &nResult); // ignore return value.
3198 break; 3303 break;
3199 3304
3200 case WIU_MSI_EXECUTE_MESSAGE_MSI_MESSAGE: 3305 case WIU_MSI_EXECUTE_MESSAGE_MSI_MESSAGE:
3201 nResult = pMessage->nResultRecommendation; 3306 nResult = pMessage->nResultRecommendation;
3202 UserExperienceOnExecuteMsiMessage(pContext->pUX, pContext->pExecutingPackage->sczId, pMessage->msiMessage.mt, pMessage->dwUIHint, pMessage->msiMessage.wzMessage, pMessage->cData, pMessage->rgwzData, &nResult); // ignore return value. 3307 UserExperienceOnExecuteMsiMessage(pContext->pUX, pContext->wzExecutingPackageId, pMessage->msiMessage.mt, pMessage->dwUIHint, pMessage->msiMessage.wzMessage, pMessage->cData, pMessage->rgwzData, &nResult); // ignore return value.
3203 break; 3308 break;
3204 3309
3205 case WIU_MSI_EXECUTE_MESSAGE_MSI_RM_FILES_IN_USE: 3310 case WIU_MSI_EXECUTE_MESSAGE_MSI_RM_FILES_IN_USE:
3206 fRestartManager = TRUE; 3311 fRestartManager = TRUE;
3207 __fallthrough; 3312 __fallthrough;
3208 case WIU_MSI_EXECUTE_MESSAGE_MSI_FILES_IN_USE: 3313 case WIU_MSI_EXECUTE_MESSAGE_MSI_FILES_IN_USE:
3209 UserExperienceOnExecuteFilesInUse(pContext->pUX, pContext->pExecutingPackage->sczId, pMessage->msiFilesInUse.cFiles, pMessage->msiFilesInUse.rgwzFiles, fRestartManager ? BOOTSTRAPPER_FILES_IN_USE_TYPE_MSI_RM : BOOTSTRAPPER_FILES_IN_USE_TYPE_MSI, &nResult); // ignore return value. 3314 UserExperienceOnExecuteFilesInUse(pContext->pUX, pContext->wzExecutingPackageId, pMessage->msiFilesInUse.cFiles, pMessage->msiFilesInUse.rgwzFiles, fRestartManager ? BOOTSTRAPPER_FILES_IN_USE_TYPE_MSI_RM : BOOTSTRAPPER_FILES_IN_USE_TYPE_MSI, &nResult); // ignore return value.
3210 fPassthrough = TRUE; 3315 fPassthrough = TRUE;
3211 break; 3316 break;
3212 } 3317 }
@@ -3246,7 +3351,8 @@ static HRESULT ReportOverallProgressTicks(
3246static HRESULT ExecutePackageComplete( 3351static HRESULT ExecutePackageComplete(
3247 __in BURN_USER_EXPERIENCE* pUX, 3352 __in BURN_USER_EXPERIENCE* pUX,
3248 __in BURN_VARIABLES* pVariables, 3353 __in BURN_VARIABLES* pVariables,
3249 __in BURN_PACKAGE* pPackage, 3354 __in LPCWSTR wzPackageId,
3355 __in BOOL fPackageVital,
3250 __in HRESULT hrOverall, 3356 __in HRESULT hrOverall,
3251 __in HRESULT hrExecute, 3357 __in HRESULT hrExecute,
3252 __in BOOL fRollback, 3358 __in BOOL fRollback,
@@ -3256,10 +3362,10 @@ static HRESULT ExecutePackageComplete(
3256 ) 3362 )
3257{ 3363{
3258 HRESULT hr = FAILED(hrOverall) ? hrOverall : hrExecute; // if the overall function failed use that otherwise use the execution result. 3364 HRESULT hr = FAILED(hrOverall) ? hrOverall : hrExecute; // if the overall function failed use that otherwise use the execution result.
3259 BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION executePackageCompleteAction = FAILED(hrOverall) || SUCCEEDED(hrExecute) || pPackage->fVital ? BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION_NONE : BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION_IGNORE; 3365 BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION executePackageCompleteAction = FAILED(hrOverall) || SUCCEEDED(hrExecute) || fPackageVital ? BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION_NONE : BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION_IGNORE;
3260 3366
3261 // Send package execute complete to BA. 3367 // Send package execute complete to BA.
3262 UserExperienceOnExecutePackageComplete(pUX, pPackage->sczId, hr, *pRestart, &executePackageCompleteAction); 3368 UserExperienceOnExecutePackageComplete(pUX, wzPackageId, hr, *pRestart, &executePackageCompleteAction);
3263 if (BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION_RESTART == executePackageCompleteAction) 3369 if (BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION_RESTART == executePackageCompleteAction)
3264 { 3370 {
3265 *pRestart = BOOTSTRAPPER_APPLY_RESTART_INITIATED; 3371 *pRestart = BOOTSTRAPPER_APPLY_RESTART_INITIATED;
@@ -3271,23 +3377,23 @@ static HRESULT ExecutePackageComplete(
3271 if (BOOTSTRAPPER_APPLY_RESTART_INITIATED == *pRestart) 3377 if (BOOTSTRAPPER_APPLY_RESTART_INITIATED == *pRestart)
3272 { 3378 {
3273 // Best effort to set the forced restart package variable. 3379 // Best effort to set the forced restart package variable.
3274 VariableSetString(pVariables, BURN_BUNDLE_FORCED_RESTART_PACKAGE, pPackage->sczId, TRUE, FALSE); 3380 VariableSetString(pVariables, BURN_BUNDLE_FORCED_RESTART_PACKAGE, wzPackageId, TRUE, FALSE);
3275 } 3381 }
3276 3382
3277 // If we're retrying, leave a message in the log file and say everything is okay. 3383 // If we're retrying, leave a message in the log file and say everything is okay.
3278 if (*pfRetry) 3384 if (*pfRetry)
3279 { 3385 {
3280 LogId(REPORT_STANDARD, MSG_APPLY_RETRYING_PACKAGE, pPackage->sczId, hrExecute); 3386 LogId(REPORT_STANDARD, MSG_APPLY_RETRYING_PACKAGE, wzPackageId, hrExecute);
3281 hr = S_OK; 3387 hr = S_OK;
3282 } 3388 }
3283 else if (SUCCEEDED(hrOverall) && FAILED(hrExecute) && BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION_IGNORE == executePackageCompleteAction && !pPackage->fVital) // If we *only* failed to execute and the BA ignored this *not-vital* package, say everything is okay. 3389 else if (SUCCEEDED(hrOverall) && FAILED(hrExecute) && BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION_IGNORE == executePackageCompleteAction && !fPackageVital) // If we *only* failed to execute and the BA ignored this *not-vital* package, say everything is okay.
3284 { 3390 {
3285 LogId(REPORT_STANDARD, MSG_APPLY_CONTINUING_NONVITAL_PACKAGE, pPackage->sczId, hrExecute); 3391 LogId(REPORT_STANDARD, MSG_APPLY_CONTINUING_NONVITAL_PACKAGE, wzPackageId, hrExecute);
3286 hr = S_OK; 3392 hr = S_OK;
3287 } 3393 }
3288 else 3394 else
3289 { 3395 {
3290 LogId(REPORT_STANDARD, MSG_APPLY_COMPLETED_PACKAGE, LoggingRollbackOrExecute(fRollback), pPackage->sczId, hr, LoggingRestartToString(*pRestart)); 3396 LogId(REPORT_STANDARD, MSG_APPLY_COMPLETED_PACKAGE, LoggingRollbackOrExecute(fRollback), wzPackageId, hr, LoggingRestartToString(*pRestart));
3291 } 3397 }
3292 3398
3293 return hr; 3399 return hr;
diff --git a/src/burn/engine/core.cpp b/src/burn/engine/core.cpp
index d70810f2..7f7a915e 100644
--- a/src/burn/engine/core.cpp
+++ b/src/burn/engine/core.cpp
@@ -389,6 +389,7 @@ extern "C" HRESULT CoreDetect(
389 pPackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_UNKNOWN; 389 pPackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_UNKNOWN;
390 pPackage->cacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN; 390 pPackage->cacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN;
391 pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN; 391 pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN;
392 pPackage->compatiblePackage.fDetected = FALSE;
392 } 393 }
393 } 394 }
394 395
@@ -2240,7 +2241,7 @@ static void LogPackages(
2240 } 2241 }
2241 2242
2242 LogId(REPORT_STANDARD, MSG_PLANNED_PACKAGE, pPackage->sczId, LoggingPackageStateToString(pPackage->currentState), LoggingRequestStateToString(pPackage->defaultRequested), LoggingRequestStateToString(pPackage->requested), LoggingActionStateToString(pPackage->execute), LoggingActionStateToString(pPackage->rollback), LoggingCacheTypeToString(pPackage->authoredCacheType), LoggingCacheTypeToString(pPackage->cacheType), LoggingBoolToString(pPackage->fPlannedCache), LoggingBoolToString(pPackage->fPlannedUncache), LoggingDependencyActionToString(pPackage->dependencyExecute), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->expectedInstallRegistrationState), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->expectedCacheRegistrationState)); 2243 LogId(REPORT_STANDARD, MSG_PLANNED_PACKAGE, pPackage->sczId, LoggingPackageStateToString(pPackage->currentState), LoggingRequestStateToString(pPackage->defaultRequested), LoggingRequestStateToString(pPackage->requested), LoggingActionStateToString(pPackage->execute), LoggingActionStateToString(pPackage->rollback), LoggingCacheTypeToString(pPackage->authoredCacheType), LoggingCacheTypeToString(pPackage->cacheType), LoggingBoolToString(pPackage->fPlannedCache), LoggingBoolToString(pPackage->fPlannedUncache), LoggingDependencyActionToString(pPackage->dependencyExecute), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->expectedInstallRegistrationState), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->expectedCacheRegistrationState));
2243 2244
2244 if (BURN_PACKAGE_TYPE_MSI == pPackage->type) 2245 if (BURN_PACKAGE_TYPE_MSI == pPackage->type)
2245 { 2246 {
2246 if (pPackage->Msi.cFeatures) 2247 if (pPackage->Msi.cFeatures)
@@ -2266,6 +2267,11 @@ static void LogPackages(
2266 LogId(REPORT_STANDARD, MSG_PLANNED_SLIPSTREAMED_MSP_TARGET, pSlipstreamMsp->pMspPackage->sczId, LoggingActionStateToString(pSlipstreamMsp->execute), LoggingActionStateToString(pSlipstreamMsp->rollback)); 2267 LogId(REPORT_STANDARD, MSG_PLANNED_SLIPSTREAMED_MSP_TARGET, pSlipstreamMsp->pMspPackage->sczId, LoggingActionStateToString(pSlipstreamMsp->execute), LoggingActionStateToString(pSlipstreamMsp->rollback));
2267 } 2268 }
2268 } 2269 }
2270
2271 if (pPackage->compatiblePackage.fRemove)
2272 {
2273 LogId(REPORT_STANDARD, MSG_PLANNED_ORPHAN_PACKAGE_FROM_PROVIDER, pPackage->sczId, pPackage->compatiblePackage.compatibleEntry.sczId, pPackage->Msi.sczProductCode);
2274 }
2269 } 2275 }
2270 else if (BURN_PACKAGE_TYPE_MSP == pPackage->type && pPackage->Msp.cTargetProductCodes) 2276 else if (BURN_PACKAGE_TYPE_MSP == pPackage->type && pPackage->Msp.cTargetProductCodes)
2271 { 2277 {
diff --git a/src/burn/engine/dependency.cpp b/src/burn/engine/dependency.cpp
index 5d7e1a94..6ee95935 100644
--- a/src/burn/engine/dependency.cpp
+++ b/src/burn/engine/dependency.cpp
@@ -54,6 +54,10 @@ static HRESULT AddPackageDependencyActions(
54 __in const BURN_DEPENDENCY_ACTION dependencyRollbackAction 54 __in const BURN_DEPENDENCY_ACTION dependencyRollbackAction
55 ); 55 );
56 56
57static LPCWSTR GetPackageProviderId(
58 __in const BURN_PACKAGE* pPackage
59 );
60
57static HRESULT RegisterPackageProvider( 61static HRESULT RegisterPackageProvider(
58 __in const BURN_PACKAGE* pPackage 62 __in const BURN_PACKAGE* pPackage
59 ); 63 );
@@ -299,6 +303,9 @@ extern "C" HRESULT DependencyDetectChainPackage(
299 hr = DetectPackageDependents(pPackage, pRegistration); 303 hr = DetectPackageDependents(pPackage, pRegistration);
300 ExitOnFailure(hr, "Failed to detect dependents for package '%ls'", pPackage->sczId); 304 ExitOnFailure(hr, "Failed to detect dependents for package '%ls'", pPackage->sczId);
301 305
306 hr = DependencyDetectCompatibleEntry(pPackage, pRegistration);
307 ExitOnFailure(hr, "Failed to detect compatible package for package '%ls'", pPackage->sczId);
308
302LExit: 309LExit:
303 return hr; 310 return hr;
304} 311}
@@ -396,6 +403,8 @@ extern "C" HRESULT DependencyPlanPackageBegin(
396 STRINGDICT_HANDLE sdIgnoredDependents = NULL; 403 STRINGDICT_HANDLE sdIgnoredDependents = NULL;
397 BURN_DEPENDENCY_ACTION dependencyExecuteAction = BURN_DEPENDENCY_ACTION_NONE; 404 BURN_DEPENDENCY_ACTION dependencyExecuteAction = BURN_DEPENDENCY_ACTION_NONE;
398 BURN_DEPENDENCY_ACTION dependencyRollbackAction = BURN_DEPENDENCY_ACTION_NONE; 405 BURN_DEPENDENCY_ACTION dependencyRollbackAction = BURN_DEPENDENCY_ACTION_NONE;
406 BOOL fDependentBlocksUninstall = FALSE;
407 BOOL fAttemptingUninstall = BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pPackage->execute || pPackage->compatiblePackage.fRemove;
399 408
400 pPackage->dependencyExecute = BURN_DEPENDENCY_ACTION_NONE; 409 pPackage->dependencyExecute = BURN_DEPENDENCY_ACTION_NONE;
401 pPackage->dependencyRollback = BURN_DEPENDENCY_ACTION_NONE; 410 pPackage->dependencyRollback = BURN_DEPENDENCY_ACTION_NONE;
@@ -415,7 +424,7 @@ extern "C" HRESULT DependencyPlanPackageBegin(
415 } 424 }
416 425
417 // If we're uninstalling the package, check if any dependents are registered. 426 // If we're uninstalling the package, check if any dependents are registered.
418 if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pPackage->execute) 427 if (fAttemptingUninstall)
419 { 428 {
420 // Build up a list of dependents to ignore, including the current bundle. 429 // Build up a list of dependents to ignore, including the current bundle.
421 hr = GetIgnoredDependents(pPackage, pPlan, &sdIgnoredDependents); 430 hr = GetIgnoredDependents(pPackage, pPlan, &sdIgnoredDependents);
@@ -444,9 +453,9 @@ extern "C" HRESULT DependencyPlanPackageBegin(
444 { 453 {
445 hr = S_OK; 454 hr = S_OK;
446 455
447 if (!pPackage->fDependencyManagerWasHere) 456 if (!fDependentBlocksUninstall)
448 { 457 {
449 pPackage->fDependencyManagerWasHere = TRUE; 458 fDependentBlocksUninstall = TRUE;
450 459
451 LogId(REPORT_STANDARD, MSG_DEPENDENCY_PACKAGE_HASDEPENDENTS, pPackage->sczId); 460 LogId(REPORT_STANDARD, MSG_DEPENDENCY_PACKAGE_HASDEPENDENTS, pPackage->sczId);
452 } 461 }
@@ -459,14 +468,20 @@ extern "C" HRESULT DependencyPlanPackageBegin(
459 } 468 }
460 } 469 }
461 470
471 if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pPackage->execute)
472 {
473 pPackage->fDependencyManagerWasHere = fDependentBlocksUninstall;
474 }
475
462 // Calculate the dependency actions before the package itself is planned. 476 // Calculate the dependency actions before the package itself is planned.
463 CalculateDependencyActionStates(pPackage, pPlan->action, &dependencyExecuteAction, &dependencyRollbackAction); 477 CalculateDependencyActionStates(pPackage, pPlan->action, &dependencyExecuteAction, &dependencyRollbackAction);
464 478
465 // If dependents were found, change the action to not uninstall the package. 479 // If dependents were found, change the action to not uninstall the package.
466 if (pPackage->fDependencyManagerWasHere) 480 if (fDependentBlocksUninstall)
467 { 481 {
468 pPackage->execute = BOOTSTRAPPER_ACTION_STATE_NONE; 482 pPackage->execute = BOOTSTRAPPER_ACTION_STATE_NONE;
469 pPackage->rollback = BOOTSTRAPPER_ACTION_STATE_NONE; 483 pPackage->rollback = BOOTSTRAPPER_ACTION_STATE_NONE;
484 pPackage->compatiblePackage.fRemove = FALSE;
470 } 485 }
471 else 486 else
472 { 487 {
@@ -494,7 +509,7 @@ extern "C" HRESULT DependencyPlanPackageBegin(
494 } 509 }
495 510
496 // If the package will be removed, add its providers to the growing list in the plan. 511 // If the package will be removed, add its providers to the growing list in the plan.
497 if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pPackage->execute) 512 if (fAttemptingUninstall)
498 { 513 {
499 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i) 514 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
500 { 515 {
@@ -739,6 +754,73 @@ extern "C" void DependencyUnregisterBundle(
739 } 754 }
740} 755}
741 756
757extern "C" HRESULT DependencyDetectCompatibleEntry(
758 __in BURN_PACKAGE* pPackage,
759 __in BURN_REGISTRATION* pRegistration
760 )
761{
762 HRESULT hr = S_OK;
763 LPWSTR sczId = NULL;
764 LPWSTR sczName = NULL;
765 LPWSTR sczVersion = NULL;
766 LPCWSTR wzPackageProviderId = GetPackageProviderId(pPackage);
767 HKEY hkHive = pRegistration->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
768
769 switch (pPackage->type)
770 {
771 case BURN_PACKAGE_TYPE_MSI:
772 // Only MSI packages can handle compatible entries.
773 break;
774 default:
775 ExitFunction();
776 }
777
778 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
779 {
780 BURN_DEPENDENCY_PROVIDER* pProvider = &pPackage->rgDependencyProviders[i];
781
782 hr = DepGetProviderInformation(hkHive, pProvider->sczKey, &sczId, &sczName, &sczVersion);
783 if (E_NOTFOUND == hr)
784 {
785 hr = S_OK;
786 continue;
787 }
788 ExitOnFailure(hr, "Failed to get provider information for compatible package: %ls", pProvider->sczKey);
789
790 // Make sure the compatible package is not the package itself.
791 if (!wzPackageProviderId)
792 {
793 if (!sczId)
794 {
795 continue;
796 }
797 }
798 else if (sczId && CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, wzPackageProviderId, -1, sczId, -1))
799 {
800 continue;
801 }
802
803 pPackage->compatiblePackage.fDetected = TRUE;
804
805 hr = StrAllocString(&pPackage->compatiblePackage.compatibleEntry.sczProviderKey, pProvider->sczKey, 0);
806 ExitOnFailure(hr, "Failed to copy provider key for compatible entry.");
807
808 pPackage->compatiblePackage.compatibleEntry.sczId = sczId;
809 sczId = NULL;
810
811 pPackage->compatiblePackage.compatibleEntry.sczName = sczName;
812 sczName = NULL;
813
814 pPackage->compatiblePackage.compatibleEntry.sczVersion = sczVersion;
815 sczVersion = NULL;
816
817 break;
818 }
819
820LExit:
821 return hr;
822}
823
742// internal functions 824// internal functions
743 825
744 826
@@ -1170,24 +1252,35 @@ LExit:
1170 return hr; 1252 return hr;
1171} 1253}
1172 1254
1255static LPCWSTR GetPackageProviderId(
1256 __in const BURN_PACKAGE* pPackage
1257 )
1258{
1259 LPCWSTR wzId = NULL;
1260
1261 switch (pPackage->type)
1262 {
1263 case BURN_PACKAGE_TYPE_MSI:
1264 wzId = pPackage->Msi.sczProductCode;
1265 break;
1266 case BURN_PACKAGE_TYPE_MSP:
1267 wzId = pPackage->Msp.sczPatchCode;
1268 break;
1269 }
1270
1271 return wzId;
1272}
1273
1173static HRESULT RegisterPackageProvider( 1274static HRESULT RegisterPackageProvider(
1174 __in const BURN_PACKAGE* pPackage 1275 __in const BURN_PACKAGE* pPackage
1175 ) 1276 )
1176{ 1277{
1177 HRESULT hr = S_OK; 1278 HRESULT hr = S_OK;
1178 LPWSTR wzId = NULL;
1179 HKEY hkRoot = pPackage->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1180 1279
1181 if (pPackage->rgDependencyProviders) 1280 if (pPackage->rgDependencyProviders)
1182 { 1281 {
1183 if (BURN_PACKAGE_TYPE_MSI == pPackage->type) 1282 HKEY hkRoot = pPackage->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1184 { 1283 LPCWSTR wzId = GetPackageProviderId(pPackage);
1185 wzId = pPackage->Msi.sczProductCode;
1186 }
1187 else if (BURN_PACKAGE_TYPE_MSP == pPackage->type)
1188 {
1189 wzId = pPackage->Msp.sczPatchCode;
1190 }
1191 1284
1192 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i) 1285 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
1193 { 1286 {
diff --git a/src/burn/engine/dependency.h b/src/burn/engine/dependency.h
index 8d7344eb..41718066 100644
--- a/src/burn/engine/dependency.h
+++ b/src/burn/engine/dependency.h
@@ -191,6 +191,11 @@ void DependencyUnregisterBundle(
191 __in const BURN_PACKAGES* pPackages 191 __in const BURN_PACKAGES* pPackages
192 ); 192 );
193 193
194HRESULT DependencyDetectCompatibleEntry(
195 __in BURN_PACKAGE* pPackage,
196 __in BURN_REGISTRATION* pRegistration
197 );
198
194#if defined(__cplusplus) 199#if defined(__cplusplus)
195} 200}
196#endif 201#endif
diff --git a/src/burn/engine/detect.cpp b/src/burn/engine/detect.cpp
index be828366..37b034ae 100644
--- a/src/burn/engine/detect.cpp
+++ b/src/burn/engine/detect.cpp
@@ -98,6 +98,8 @@ extern "C" void DetectReset(
98 pProvider->rgDependents = NULL; 98 pProvider->rgDependents = NULL;
99 pProvider->cDependents = 0; 99 pProvider->cDependents = 0;
100 } 100 }
101
102 PackageUninitializeCompatible(&pPackage->compatiblePackage);
101 } 103 }
102 104
103 for (DWORD iPatchInfo = 0; iPatchInfo < pPackages->cPatchInfo; ++iPatchInfo) 105 for (DWORD iPatchInfo = 0; iPatchInfo < pPackages->cPatchInfo; ++iPatchInfo)
diff --git a/src/burn/engine/elevation.cpp b/src/burn/engine/elevation.cpp
index 221d8b6d..9ebba7c5 100644
--- a/src/burn/engine/elevation.cpp
+++ b/src/burn/engine/elevation.cpp
@@ -32,6 +32,8 @@ typedef enum _BURN_ELEVATION_MESSAGE_TYPE
32 BURN_ELEVATION_MESSAGE_TYPE_BEGIN_MSI_TRANSACTION, 32 BURN_ELEVATION_MESSAGE_TYPE_BEGIN_MSI_TRANSACTION,
33 BURN_ELEVATION_MESSAGE_TYPE_COMMIT_MSI_TRANSACTION, 33 BURN_ELEVATION_MESSAGE_TYPE_COMMIT_MSI_TRANSACTION,
34 BURN_ELEVATION_MESSAGE_TYPE_ROLLBACK_MSI_TRANSACTION, 34 BURN_ELEVATION_MESSAGE_TYPE_ROLLBACK_MSI_TRANSACTION,
35 BURN_ELEVATION_MESSAGE_TYPE_UNINSTALL_MSI_COMPATIBLE_PACKAGE,
36 BURN_ELEVATION_MESSAGE_TYPE_CLEAN_COMPATIBLE_PACKAGE,
35 37
36 BURN_ELEVATION_MESSAGE_TYPE_APPLY_INITIALIZE_PAUSE_AU_BEGIN, 38 BURN_ELEVATION_MESSAGE_TYPE_APPLY_INITIALIZE_PAUSE_AU_BEGIN,
37 BURN_ELEVATION_MESSAGE_TYPE_APPLY_INITIALIZE_PAUSE_AU_COMPLETE, 39 BURN_ELEVATION_MESSAGE_TYPE_APPLY_INITIALIZE_PAUSE_AU_COMPLETE,
@@ -168,11 +170,16 @@ static HRESULT OnApplyInitialize(
168 __in HANDLE hPipe, 170 __in HANDLE hPipe,
169 __in BURN_VARIABLES* pVariables, 171 __in BURN_VARIABLES* pVariables,
170 __in BURN_REGISTRATION* pRegistration, 172 __in BURN_REGISTRATION* pRegistration,
173 __in BURN_PACKAGES* pPackages,
171 __in HANDLE* phLock, 174 __in HANDLE* phLock,
172 __in BOOL* pfDisabledWindowsUpdate, 175 __in BOOL* pfDisabledWindowsUpdate,
173 __in BYTE* pbData, 176 __in BYTE* pbData,
174 __in SIZE_T cbData 177 __in SIZE_T cbData
175 ); 178 );
179static HRESULT ElevatedProcessDetect(
180 __in BURN_REGISTRATION* pRegistration,
181 __in BURN_PACKAGES* pPackages
182 );
176static HRESULT OnApplyUninitialize( 183static HRESULT OnApplyUninitialize(
177 __in HANDLE* phLock 184 __in HANDLE* phLock
178 ); 185 );
@@ -271,6 +278,14 @@ static HRESULT OnExecuteMsuPackage(
271 __in BYTE* pbData, 278 __in BYTE* pbData,
272 __in SIZE_T cbData 279 __in SIZE_T cbData
273 ); 280 );
281static HRESULT OnUninstallMsiCompatiblePackage(
282 __in HANDLE hPipe,
283 __in BURN_CACHE* pCache,
284 __in BURN_PACKAGES* pPackages,
285 __in BURN_VARIABLES* pVariables,
286 __in BYTE* pbData,
287 __in SIZE_T cbData
288 );
274static HRESULT OnExecutePackageProviderAction( 289static HRESULT OnExecutePackageProviderAction(
275 __in BURN_PACKAGES* pPackages, 290 __in BURN_PACKAGES* pPackages,
276 __in BURN_RELATED_BUNDLES* pRelatedBundles, 291 __in BURN_RELATED_BUNDLES* pRelatedBundles,
@@ -306,6 +321,12 @@ static int MsiExecuteMessageHandler(
306 __in WIU_MSI_EXECUTE_MESSAGE* pMessage, 321 __in WIU_MSI_EXECUTE_MESSAGE* pMessage,
307 __in_opt LPVOID pvContext 322 __in_opt LPVOID pvContext
308 ); 323 );
324static HRESULT OnCleanCompatiblePackage(
325 __in BURN_CACHE* pCache,
326 __in BURN_PACKAGES* pPackages,
327 __in BYTE* pbData,
328 __in SIZE_T cbData
329 );
309static HRESULT OnCleanPackage( 330static HRESULT OnCleanPackage(
310 __in BURN_CACHE* pCache, 331 __in BURN_CACHE* pCache,
311 __in BURN_PACKAGES* pPackages, 332 __in BURN_PACKAGES* pPackages,
@@ -1230,6 +1251,58 @@ LExit:
1230 return hr; 1251 return hr;
1231} 1252}
1232 1253
1254extern "C" HRESULT ElevationUninstallMsiCompatiblePackage(
1255 __in HANDLE hPipe,
1256 __in_opt HWND hwndParent,
1257 __in BURN_EXECUTE_ACTION* pExecuteAction,
1258 __in BURN_VARIABLES* pVariables,
1259 __in BOOL fRollback,
1260 __in PFN_MSIEXECUTEMESSAGEHANDLER pfnMessageHandler,
1261 __in LPVOID pvContext,
1262 __out BOOTSTRAPPER_APPLY_RESTART* pRestart
1263 )
1264{
1265 HRESULT hr = S_OK;
1266 BYTE* pbData = NULL;
1267 SIZE_T cbData = 0;
1268 BURN_ELEVATION_MSI_MESSAGE_CONTEXT context = { };
1269 DWORD dwResult = 0;
1270
1271 // serialize message data
1272 hr = BuffWriteNumber(&pbData, &cbData, (DWORD)fRollback);
1273 ExitOnFailure(hr, "Failed to write rollback flag to message buffer.");
1274
1275 hr = BuffWriteString(&pbData, &cbData, pExecuteAction->uninstallMsiCompatiblePackage.pParentPackage->sczId);
1276 ExitOnFailure(hr, "Failed to write package id to message buffer.");
1277
1278 hr = BuffWriteString(&pbData, &cbData, pExecuteAction->uninstallMsiCompatiblePackage.pParentPackage->compatiblePackage.compatibleEntry.sczId);
1279 ExitOnFailure(hr, "Failed to write compatible package id to message buffer.");
1280
1281 hr = BuffWritePointer(&pbData, &cbData, (DWORD_PTR)hwndParent);
1282 ExitOnFailure(hr, "Failed to write parent hwnd to message buffer.");
1283
1284 hr = BuffWriteString(&pbData, &cbData, pExecuteAction->uninstallMsiCompatiblePackage.sczLogPath);
1285 ExitOnFailure(hr, "Failed to write package log to message buffer.");
1286
1287 hr = VariableSerialize(pVariables, FALSE, &pbData, &cbData);
1288 ExitOnFailure(hr, "Failed to write variables.");
1289
1290
1291 // send message
1292 context.pfnMessageHandler = pfnMessageHandler;
1293 context.pvContext = pvContext;
1294
1295 hr = PipeSendMessage(hPipe, BURN_ELEVATION_MESSAGE_TYPE_UNINSTALL_MSI_COMPATIBLE_PACKAGE, pbData, cbData, ProcessMsiPackageMessages, &context, &dwResult);
1296 ExitOnFailure(hr, "Failed to send BURN_ELEVATION_MESSAGE_TYPE_UNINSTALL_MSI_COMPATIBLE_PACKAGE message to per-machine process.");
1297
1298 hr = ProcessResult(dwResult, pRestart);
1299
1300LExit:
1301 ReleaseBuffer(pbData);
1302
1303 return hr;
1304}
1305
1233extern "C" HRESULT ElevationExecutePackageProviderAction( 1306extern "C" HRESULT ElevationExecutePackageProviderAction(
1234 __in HANDLE hPipe, 1307 __in HANDLE hPipe,
1235 __in BURN_EXECUTE_ACTION* pExecuteAction 1308 __in BURN_EXECUTE_ACTION* pExecuteAction
@@ -1295,6 +1368,35 @@ LExit:
1295 return hr; 1368 return hr;
1296} 1369}
1297 1370
1371extern "C" HRESULT ElevationCleanCompatiblePackage(
1372 __in HANDLE hPipe,
1373 __in BURN_PACKAGE* pPackage
1374 )
1375{
1376 HRESULT hr = S_OK;
1377 BYTE* pbData = NULL;
1378 SIZE_T cbData = 0;
1379 DWORD dwResult = 0;
1380
1381 // serialize message data
1382 hr = BuffWriteString(&pbData, &cbData, pPackage->sczId);
1383 ExitOnFailure(hr, "Failed to write clean package id to message buffer.");
1384
1385 hr = BuffWriteString(&pbData, &cbData, pPackage->compatiblePackage.compatibleEntry.sczId);
1386 ExitOnFailure(hr, "Failed to write compatible package id to message buffer.");
1387
1388 // send message
1389 hr = PipeSendMessage(hPipe, BURN_ELEVATION_MESSAGE_TYPE_CLEAN_COMPATIBLE_PACKAGE, pbData, cbData, NULL, NULL, &dwResult);
1390 ExitOnFailure(hr, "Failed to send BURN_ELEVATION_MESSAGE_TYPE_CLEAN_COMPATIBLE_PACKAGE message to per-machine process.");
1391
1392 hr = (HRESULT)dwResult;
1393
1394LExit:
1395 ReleaseBuffer(pbData);
1396
1397 return hr;
1398}
1399
1298/******************************************************************* 1400/*******************************************************************
1299 ElevationCleanPackage - 1401 ElevationCleanPackage -
1300 1402
@@ -1940,7 +2042,7 @@ static HRESULT ProcessElevatedChildMessage(
1940 break; 2042 break;
1941 2043
1942 case BURN_ELEVATION_MESSAGE_TYPE_APPLY_INITIALIZE: 2044 case BURN_ELEVATION_MESSAGE_TYPE_APPLY_INITIALIZE:
1943 hrResult = OnApplyInitialize(pContext->hPipe, pContext->pVariables, pContext->pRegistration, pContext->phLock, pContext->pfDisabledAutomaticUpdates, (BYTE*)pMsg->pvData, pMsg->cbData); 2045 hrResult = OnApplyInitialize(pContext->hPipe, pContext->pVariables, pContext->pRegistration, pContext->pPackages, pContext->phLock, pContext->pfDisabledAutomaticUpdates, (BYTE*)pMsg->pvData, pMsg->cbData);
1944 break; 2046 break;
1945 2047
1946 case BURN_ELEVATION_MESSAGE_TYPE_APPLY_UNINITIALIZE: 2048 case BURN_ELEVATION_MESSAGE_TYPE_APPLY_UNINITIALIZE:
@@ -2003,6 +2105,14 @@ static HRESULT ProcessElevatedChildMessage(
2003 hrResult = OnLaunchApprovedExe(pContext->hPipe, pContext->pApprovedExes, pContext->pCache, pContext->pVariables, (BYTE*)pMsg->pvData, pMsg->cbData); 2105 hrResult = OnLaunchApprovedExe(pContext->hPipe, pContext->pApprovedExes, pContext->pCache, pContext->pVariables, (BYTE*)pMsg->pvData, pMsg->cbData);
2004 break; 2106 break;
2005 2107
2108 case BURN_ELEVATION_MESSAGE_TYPE_UNINSTALL_MSI_COMPATIBLE_PACKAGE:
2109 hrResult = OnUninstallMsiCompatiblePackage(pContext->hPipe, pContext->pCache, pContext->pPackages, pContext->pVariables, (BYTE*)pMsg->pvData, pMsg->cbData);
2110 break;
2111
2112 case BURN_ELEVATION_MESSAGE_TYPE_CLEAN_COMPATIBLE_PACKAGE:
2113 hrResult = OnCleanCompatiblePackage(pContext->pCache, pContext->pPackages, (BYTE*)pMsg->pvData, pMsg->cbData);
2114 break;
2115
2006 default: 2116 default:
2007 hr = E_INVALIDARG; 2117 hr = E_INVALIDARG;
2008 ExitOnRootFailure(hr, "Unexpected elevated message sent to child process, msg: %u", pMsg->dwMessage); 2118 ExitOnRootFailure(hr, "Unexpected elevated message sent to child process, msg: %u", pMsg->dwMessage);
@@ -2082,6 +2192,7 @@ static HRESULT OnApplyInitialize(
2082 __in HANDLE hPipe, 2192 __in HANDLE hPipe,
2083 __in BURN_VARIABLES* pVariables, 2193 __in BURN_VARIABLES* pVariables,
2084 __in BURN_REGISTRATION* pRegistration, 2194 __in BURN_REGISTRATION* pRegistration,
2195 __in BURN_PACKAGES* pPackages,
2085 __in HANDLE* phLock, 2196 __in HANDLE* phLock,
2086 __in BOOL* pfDisabledWindowsUpdate, 2197 __in BOOL* pfDisabledWindowsUpdate,
2087 __in BYTE* pbData, 2198 __in BYTE* pbData,
@@ -2113,11 +2224,9 @@ static HRESULT OnApplyInitialize(
2113 hr = ApplyLock(TRUE, phLock); 2224 hr = ApplyLock(TRUE, phLock);
2114 ExitOnFailure(hr, "Failed to acquire lock due to setup in other session."); 2225 ExitOnFailure(hr, "Failed to acquire lock due to setup in other session.");
2115 2226
2116 // Reset and reload the related bundles. 2227 // Detect.
2117 RelatedBundlesUninitialize(&pRegistration->relatedBundles); 2228 hr = ElevatedProcessDetect(pRegistration, pPackages);
2118 2229 ExitOnFailure(hr, "Failed to run detection in elevated process.");
2119 hr = RelatedBundlesInitializeForScope(TRUE, pRegistration, &pRegistration->relatedBundles);
2120 ExitOnFailure(hr, "Failed to initialize per-machine related bundles.");
2121 2230
2122 // Attempt to pause AU with best effort. 2231 // Attempt to pause AU with best effort.
2123 if (BURN_AU_PAUSE_ACTION_IFELEVATED == dwAUAction || BURN_AU_PAUSE_ACTION_IFELEVATED_NORESUME == dwAUAction) 2232 if (BURN_AU_PAUSE_ACTION_IFELEVATED == dwAUAction || BURN_AU_PAUSE_ACTION_IFELEVATED_NORESUME == dwAUAction)
@@ -2187,6 +2296,39 @@ LExit:
2187 return hr; 2296 return hr;
2188} 2297}
2189 2298
2299static HRESULT ElevatedProcessDetect(
2300 __in BURN_REGISTRATION* pRegistration,
2301 __in BURN_PACKAGES* pPackages
2302 )
2303{
2304 HRESULT hr = S_OK;
2305
2306 DetectReset(pRegistration, pPackages);
2307
2308 hr = RelatedBundlesInitializeForScope(TRUE, pRegistration, &pRegistration->relatedBundles);
2309 ExitOnFailure(hr, "Failed to initialize per-machine related bundles.");
2310
2311 for (DWORD i = 0; i < pPackages->cPackages; ++i)
2312 {
2313 BURN_PACKAGE* pPackage = pPackages->rgPackages + i;
2314
2315 hr = DependencyDetectCompatibleEntry(pPackage, pRegistration);
2316 ExitOnFailure(hr, "Failed to detect per-machine compatible entry for package: %ls", pPackage->sczId);
2317
2318 switch (pPackage->type)
2319 {
2320 case BURN_PACKAGE_TYPE_MSI:
2321 hr = MsiEngineDetectCompatiblePackage(pPackage);
2322 ExitOnFailure(hr, "Failed to detect per-machine compatible package for package: %ls", pPackage->sczId);
2323
2324 break;
2325 }
2326 }
2327
2328LExit:
2329 return hr;
2330}
2331
2190static HRESULT OnApplyUninitialize( 2332static HRESULT OnApplyUninitialize(
2191 __in HANDLE* phLock 2333 __in HANDLE* phLock
2192 ) 2334 )
@@ -2659,6 +2801,11 @@ static HRESULT OnExecuteExePackage(
2659 hr = PackageFindById(pPackages, sczPackage, &executeAction.exePackage.pPackage); 2801 hr = PackageFindById(pPackages, sczPackage, &executeAction.exePackage.pPackage);
2660 ExitOnFailure(hr, "Failed to find package: %ls", sczPackage); 2802 ExitOnFailure(hr, "Failed to find package: %ls", sczPackage);
2661 2803
2804 if (BURN_PACKAGE_TYPE_EXE != executeAction.exePackage.pPackage->type)
2805 {
2806 ExitWithRootFailure(hr, E_INVALIDARG, "Package is not an EXE package: %ls", sczPackage);
2807 }
2808
2662 // Execute EXE package. 2809 // Execute EXE package.
2663 hr = ExeEngineExecutePackage(&executeAction, pCache, pVariables, static_cast<BOOL>(dwRollback), GenericExecuteMessageHandler, hPipe, &exeRestart); 2810 hr = ExeEngineExecutePackage(&executeAction, pCache, pVariables, static_cast<BOOL>(dwRollback), GenericExecuteMessageHandler, hPipe, &exeRestart);
2664 ExitOnFailure(hr, "Failed to execute EXE package."); 2811 ExitOnFailure(hr, "Failed to execute EXE package.");
@@ -2760,6 +2907,11 @@ static HRESULT OnExecuteMsiPackage(
2760 hr = VariableDeserialize(pVariables, FALSE, pbData, cbData, &iData); 2907 hr = VariableDeserialize(pVariables, FALSE, pbData, cbData, &iData);
2761 ExitOnFailure(hr, "Failed to read variables."); 2908 ExitOnFailure(hr, "Failed to read variables.");
2762 2909
2910 if (BURN_PACKAGE_TYPE_MSI != executeAction.msiPackage.pPackage->type)
2911 {
2912 ExitWithRootFailure(hr, E_INVALIDARG, "Package is not an MSI package: %ls", sczPackage);
2913 }
2914
2763 // Execute MSI package. 2915 // Execute MSI package.
2764 hr = MsiEngineExecutePackage(hwndParent, &executeAction, pCache, pVariables, fRollback, MsiExecuteMessageHandler, hPipe, &msiRestart); 2916 hr = MsiEngineExecutePackage(hwndParent, &executeAction, pCache, pVariables, fRollback, MsiExecuteMessageHandler, hPipe, &msiRestart);
2765 ExitOnFailure(hr, "Failed to execute MSI package."); 2917 ExitOnFailure(hr, "Failed to execute MSI package.");
@@ -2859,6 +3011,11 @@ static HRESULT OnExecuteMspPackage(
2859 hr = BuffReadNumber(pbData, cbData, &iData, (DWORD*)&fRollback); 3011 hr = BuffReadNumber(pbData, cbData, &iData, (DWORD*)&fRollback);
2860 ExitOnFailure(hr, "Failed to read rollback flag."); 3012 ExitOnFailure(hr, "Failed to read rollback flag.");
2861 3013
3014 if (BURN_PACKAGE_TYPE_MSP != executeAction.mspTarget.pPackage->type)
3015 {
3016 ExitWithRootFailure(hr, E_INVALIDARG, "Package is not an MSP package: %ls", sczPackage);
3017 }
3018
2862 // Execute MSP package. 3019 // Execute MSP package.
2863 hr = MspEngineExecutePackage(hwndParent, &executeAction, pCache, pVariables, fRollback, MsiExecuteMessageHandler, hPipe, &restart); 3020 hr = MspEngineExecutePackage(hwndParent, &executeAction, pCache, pVariables, fRollback, MsiExecuteMessageHandler, hPipe, &restart);
2864 ExitOnFailure(hr, "Failed to execute MSP package."); 3021 ExitOnFailure(hr, "Failed to execute MSP package.");
@@ -2920,6 +3077,11 @@ static HRESULT OnExecuteMsuPackage(
2920 hr = PackageFindById(pPackages, sczPackage, &executeAction.msuPackage.pPackage); 3077 hr = PackageFindById(pPackages, sczPackage, &executeAction.msuPackage.pPackage);
2921 ExitOnFailure(hr, "Failed to find package: %ls", sczPackage); 3078 ExitOnFailure(hr, "Failed to find package: %ls", sczPackage);
2922 3079
3080 if (BURN_PACKAGE_TYPE_MSU != executeAction.msuPackage.pPackage->type)
3081 {
3082 ExitWithRootFailure(hr, E_INVALIDARG, "Package is not an MSU package: %ls", sczPackage);
3083 }
3084
2923 // execute MSU package 3085 // execute MSU package
2924 hr = MsuEngineExecutePackage(&executeAction, pCache, pVariables, static_cast<BOOL>(dwRollback), static_cast<BOOL>(dwStopWusaService), GenericExecuteMessageHandler, hPipe, &restart); 3086 hr = MsuEngineExecutePackage(&executeAction, pCache, pVariables, static_cast<BOOL>(dwRollback), static_cast<BOOL>(dwStopWusaService), GenericExecuteMessageHandler, hPipe, &restart);
2925 ExitOnFailure(hr, "Failed to execute MSU package."); 3087 ExitOnFailure(hr, "Failed to execute MSU package.");
@@ -2943,6 +3105,88 @@ LExit:
2943 return hr; 3105 return hr;
2944} 3106}
2945 3107
3108static HRESULT OnUninstallMsiCompatiblePackage(
3109 __in HANDLE hPipe,
3110 __in BURN_CACHE* pCache,
3111 __in BURN_PACKAGES* pPackages,
3112 __in BURN_VARIABLES* pVariables,
3113 __in BYTE* pbData,
3114 __in SIZE_T cbData
3115 )
3116{
3117 HRESULT hr = S_OK;
3118 SIZE_T iData = 0;
3119 LPWSTR sczPackageId = NULL;
3120 LPWSTR sczCompatiblePackageId = NULL;
3121 HWND hwndParent = NULL;
3122 BOOL fRollback = 0;
3123 BURN_EXECUTE_ACTION executeAction = { };
3124 BURN_PACKAGE* pPackage = NULL;
3125 BURN_COMPATIBLE_PACKAGE* pCompatiblePackage = NULL;
3126 BOOTSTRAPPER_APPLY_RESTART msiRestart = BOOTSTRAPPER_APPLY_RESTART_NONE;
3127
3128 executeAction.type = BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE;
3129
3130 // Deserialize message data.
3131 hr = BuffReadNumber(pbData, cbData, &iData, (DWORD*)&fRollback);
3132 ExitOnFailure(hr, "Failed to read rollback flag.");
3133
3134 hr = BuffReadString(pbData, cbData, &iData, &sczPackageId);
3135 ExitOnFailure(hr, "Failed to read MSI package id.");
3136
3137 hr = BuffReadString(pbData, cbData, &iData, &sczCompatiblePackageId);
3138 ExitOnFailure(hr, "Failed to read MSI compatible package id.");
3139
3140 hr = BuffReadPointer(pbData, cbData, &iData, (DWORD_PTR*)&hwndParent);
3141 ExitOnFailure(hr, "Failed to read parent hwnd.");
3142
3143 hr = BuffReadString(pbData, cbData, &iData, &executeAction.uninstallMsiCompatiblePackage.sczLogPath);
3144 ExitOnFailure(hr, "Failed to read package log.");
3145
3146 hr = VariableDeserialize(pVariables, FALSE, pbData, cbData, &iData);
3147 ExitOnFailure(hr, "Failed to read variables.");
3148
3149 hr = PackageFindById(pPackages, sczPackageId, &pPackage);
3150 ExitOnFailure(hr, "Failed to find package: %ls", sczPackageId);
3151
3152 executeAction.uninstallMsiCompatiblePackage.pParentPackage = pPackage;
3153 pCompatiblePackage = &pPackage->compatiblePackage;
3154
3155 if (!pCompatiblePackage->fDetected || BURN_PACKAGE_TYPE_MSI != pCompatiblePackage->type || !pCompatiblePackage->compatibleEntry.sczId)
3156 {
3157 ExitWithRootFailure(hr, E_INVALIDARG, "Package '%ls' has no compatible MSI package", sczPackageId);
3158 }
3159
3160 if (!sczCompatiblePackageId || !*sczCompatiblePackageId ||
3161 CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pCompatiblePackage->compatibleEntry.sczId, -1, sczCompatiblePackageId, -1))
3162 {
3163 ExitWithRootFailure(hr, E_INVALIDARG, "Package '%ls' has no compatible package with id: %ls", sczPackageId, sczCompatiblePackageId);
3164 }
3165
3166 // Uninstall MSI compatible package.
3167 hr = MsiEngineUninstallCompatiblePackage(hwndParent, &executeAction, pCache, pVariables, fRollback, MsiExecuteMessageHandler, hPipe, &msiRestart);
3168 ExitOnFailure(hr, "Failed to execute MSI package.");
3169
3170LExit:
3171 ReleaseStr(sczPackageId);
3172 ReleaseStr(sczCompatiblePackageId);
3173 PlanUninitializeExecuteAction(&executeAction);
3174
3175 if (SUCCEEDED(hr))
3176 {
3177 if (BOOTSTRAPPER_APPLY_RESTART_REQUIRED == msiRestart)
3178 {
3179 hr = HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED);
3180 }
3181 else if (BOOTSTRAPPER_APPLY_RESTART_INITIATED == msiRestart)
3182 {
3183 hr = HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_INITIATED);
3184 }
3185 }
3186
3187 return hr;
3188}
3189
2946static HRESULT OnExecutePackageProviderAction( 3190static HRESULT OnExecutePackageProviderAction(
2947 __in BURN_PACKAGES* pPackages, 3191 __in BURN_PACKAGES* pPackages,
2948 __in BURN_RELATED_BUNDLES* pRelatedBundles, 3192 __in BURN_RELATED_BUNDLES* pRelatedBundles,
@@ -3258,6 +3502,53 @@ LExit:
3258 return nResult; 3502 return nResult;
3259} 3503}
3260 3504
3505static HRESULT OnCleanCompatiblePackage(
3506 __in BURN_CACHE* pCache,
3507 __in BURN_PACKAGES* pPackages,
3508 __in BYTE* pbData,
3509 __in SIZE_T cbData
3510 )
3511{
3512 HRESULT hr = S_OK;
3513 SIZE_T iData = 0;
3514 LPWSTR sczPackageId = NULL;
3515 LPWSTR sczCompatiblePackageId = NULL;
3516 BURN_PACKAGE* pPackage = NULL;
3517 BURN_COMPATIBLE_PACKAGE* pCompatiblePackage = NULL;
3518
3519 // Deserialize message data.
3520 hr = BuffReadString(pbData, cbData, &iData, &sczPackageId);
3521 ExitOnFailure(hr, "Failed to read package id.");
3522
3523 hr = BuffReadString(pbData, cbData, &iData, &sczCompatiblePackageId);
3524 ExitOnFailure(hr, "Failed to read compatible package id.");
3525
3526 hr = PackageFindById(pPackages, sczPackageId, &pPackage);
3527 ExitOnFailure(hr, "Failed to find package: %ls", sczPackageId);
3528
3529 pCompatiblePackage = &pPackage->compatiblePackage;
3530
3531 if (!pCompatiblePackage->fDetected || !pCompatiblePackage->compatibleEntry.sczId || !pCompatiblePackage->sczCacheId || !*pCompatiblePackage->sczCacheId)
3532 {
3533 ExitWithRootFailure(hr, E_INVALIDARG, "Package '%ls' has no compatible package to clean.", sczPackageId);
3534 }
3535
3536 if (!sczCompatiblePackageId || !*sczCompatiblePackageId ||
3537 CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pCompatiblePackage->compatibleEntry.sczId, -1, sczCompatiblePackageId, -1))
3538 {
3539 ExitWithRootFailure(hr, E_INVALIDARG, "Package '%ls' has no compatible package with id: %ls", sczPackageId, sczCompatiblePackageId);
3540 }
3541
3542 // Remove the package from the cache.
3543 hr = CacheRemovePackage(pCache, TRUE, pCompatiblePackage->compatibleEntry.sczId, pCompatiblePackage->sczCacheId);
3544 ExitOnFailure(hr, "Failed to remove from cache compatible package: %ls", pCompatiblePackage->compatibleEntry.sczId);
3545
3546LExit:
3547 ReleaseStr(sczPackageId);
3548 ReleaseStr(sczCompatiblePackageId);
3549 return hr;
3550}
3551
3261static HRESULT OnCleanPackage( 3552static HRESULT OnCleanPackage(
3262 __in BURN_CACHE* pCache, 3553 __in BURN_CACHE* pCache,
3263 __in BURN_PACKAGES* pPackages, 3554 __in BURN_PACKAGES* pPackages,
diff --git a/src/burn/engine/elevation.h b/src/burn/engine/elevation.h
index 0e63c687..b4d0ca83 100644
--- a/src/burn/engine/elevation.h
+++ b/src/burn/engine/elevation.h
@@ -127,6 +127,16 @@ HRESULT ElevationExecuteMsuPackage(
127 __in LPVOID pvContext, 127 __in LPVOID pvContext,
128 __out BOOTSTRAPPER_APPLY_RESTART* pRestart 128 __out BOOTSTRAPPER_APPLY_RESTART* pRestart
129 ); 129 );
130HRESULT ElevationUninstallMsiCompatiblePackage(
131 __in HANDLE hPipe,
132 __in_opt HWND hwndParent,
133 __in BURN_EXECUTE_ACTION* pExecuteAction,
134 __in BURN_VARIABLES* pVariables,
135 __in BOOL fRollback,
136 __in PFN_MSIEXECUTEMESSAGEHANDLER pfnMessageHandler,
137 __in LPVOID pvContext,
138 __out BOOTSTRAPPER_APPLY_RESTART* pRestart
139 );
130HRESULT ElevationExecutePackageProviderAction( 140HRESULT ElevationExecutePackageProviderAction(
131 __in HANDLE hPipe, 141 __in HANDLE hPipe,
132 __in BURN_EXECUTE_ACTION* pExecuteAction 142 __in BURN_EXECUTE_ACTION* pExecuteAction
@@ -135,12 +145,9 @@ HRESULT ElevationExecutePackageDependencyAction(
135 __in HANDLE hPipe, 145 __in HANDLE hPipe,
136 __in BURN_EXECUTE_ACTION* pExecuteAction 146 __in BURN_EXECUTE_ACTION* pExecuteAction
137 ); 147 );
138HRESULT ElevationLaunchElevatedChild( 148HRESULT ElevationCleanCompatiblePackage(
139 __in HANDLE hPipe, 149 __in HANDLE hPipe,
140 __in BURN_PACKAGE* pPackage, 150 __in BURN_PACKAGE* pPackage
141 __in LPCWSTR wzPipeName,
142 __in LPCWSTR wzPipeToken,
143 __out DWORD* pdwChildPid
144 ); 151 );
145HRESULT ElevationCleanPackage( 152HRESULT ElevationCleanPackage(
146 __in HANDLE hPipe, 153 __in HANDLE hPipe,
diff --git a/src/burn/engine/engine.mc b/src/burn/engine/engine.mc
index 5c1b0b69..6ce11564 100644
--- a/src/burn/engine/engine.mc
+++ b/src/burn/engine/engine.mc
@@ -262,6 +262,13 @@ Detected forward compatible bundle: %1!ls!, type: %2!hs!, scope: %3!hs!, version
262. 262.
263 263
264MessageId=108 264MessageId=108
265Severity=Success
266SymbolicName=MSG_DETECTED_COMPATIBLE_PACKAGE_FROM_PROVIDER
267Language=English
268Detected compatible package: %1!ls!, provider: %2!ls!, installed: %3!ls!, version: %4!ls!, chained: %5!ls!
269.
270
271MessageId=109
265Severity=Warning 272Severity=Warning
266SymbolicName=MSG_DETECT_RELATED_BUNDLE_NOT_CACHED 273SymbolicName=MSG_DETECT_RELATED_BUNDLE_NOT_CACHED
267Language=English 274Language=English
@@ -429,6 +436,13 @@ Language=English
429Plan skipped related bundle: %1!ls!, type: %2!hs!, because it was previously scheduled. 436Plan skipped related bundle: %1!ls!, type: %2!hs!, because it was previously scheduled.
430. 437.
431 438
439MessageId=215
440Severity=Success
441SymbolicName=MSG_PLANNED_ORPHAN_PACKAGE_FROM_PROVIDER
442Language=English
443Will remove orphan package: %1!ls!, installed: %2!ls!, chained: %3!ls!
444.
445
432MessageId=216 446MessageId=216
433Severity=Success 447Severity=Success
434SymbolicName=MSG_PLAN_SKIPPED_RELATED_BUNDLE_EMBEDDED_BUNDLE_NEWER 448SymbolicName=MSG_PLAN_SKIPPED_RELATED_BUNDLE_EMBEDDED_BUNDLE_NEWER
@@ -604,7 +618,6 @@ Language=English
604Failed to layout container: %2!ls! to layout directory: %3!ls!, error: %1!ls!. 618Failed to layout container: %2!ls! to layout directory: %3!ls!, error: %1!ls!.
605. 619.
606 620
607
608MessageId=317 621MessageId=317
609Severity=Error 622Severity=Error
610SymbolicName=MSG_FAILED_LAYOUT_PAYLOAD 623SymbolicName=MSG_FAILED_LAYOUT_PAYLOAD
@@ -927,7 +940,6 @@ Language=English
927Calculating whether to keep registration 940Calculating whether to keep registration
928. 941.
929 942
930
931MessageId=374 943MessageId=374
932Severity=Success 944Severity=Success
933SymbolicName=MSG_POST_APPLY_PACKAGE 945SymbolicName=MSG_POST_APPLY_PACKAGE
@@ -1005,6 +1017,13 @@ Language=English
1005Skipping the rest of non-vital rollback boundary, id: %1!ls! 1017Skipping the rest of non-vital rollback boundary, id: %1!ls!
1006. 1018.
1007 1019
1020MessageId=390
1021Severity=Success
1022SymbolicName=MSG_APPLYING_ORPHAN_COMPATIBLE_PACKAGE
1023Language=English
1024Applying %1!hs! compatible package: %2!ls!, parent package: %3!ls!, action: %4!hs!, arguments: '%5!ls!'
1025.
1026
1008MessageId=399 1027MessageId=399
1009Severity=Success 1028Severity=Success
1010SymbolicName=MSG_APPLY_COMPLETE 1029SymbolicName=MSG_APPLY_COMPLETE
diff --git a/src/burn/engine/logging.cpp b/src/burn/engine/logging.cpp
index 1e436f68..7c048523 100644
--- a/src/burn/engine/logging.cpp
+++ b/src/burn/engine/logging.cpp
@@ -227,6 +227,49 @@ extern "C" void LoggingIncrementPackageSequence()
227 ++vdwPackageSequence; 227 ++vdwPackageSequence;
228} 228}
229 229
230extern "C" HRESULT LoggingSetCompatiblePackageVariable(
231 __in BURN_PACKAGE* pPackage,
232 __in BURN_LOGGING* pLog,
233 __in BURN_VARIABLES* pVariables,
234 __out_opt LPWSTR* psczLogPath
235 )
236{
237 HRESULT hr = S_OK;
238 LPWSTR sczLogPathVariable = NULL;
239 LPWSTR sczLogPath = NULL;
240
241 // Make sure that no package log files are created when logging has been disabled via Log element.
242 if (BURN_LOGGING_STATE_DISABLED == pLog->state)
243 {
244 ExitFunction();
245 }
246
247 if (pPackage->sczLogPathVariable && *pPackage->sczLogPathVariable)
248 {
249 // Format a suitable log path variable from the original package.
250 hr = StrAllocFormatted(&sczLogPathVariable, L"%ls_Compatible", pPackage->sczLogPathVariable);
251 ExitOnFailure(hr, "Failed to format log path variable for compatible package.");
252
253 hr = StrAllocFormatted(&sczLogPath, L"%ls_%03u_%ls_%ls.%ls", pLog->sczPrefix, vdwPackageSequence, pPackage->sczId, pPackage->compatiblePackage.compatibleEntry.sczId, pLog->sczExtension);
254 ExitOnFailure(hr, "Failed to allocate path for package log.");
255
256 hr = VariableSetString(pVariables, sczLogPathVariable, sczLogPath, FALSE, FALSE);
257 ExitOnFailure(hr, "Failed to set log path into variable.");
258
259 if (psczLogPath)
260 {
261 hr = StrAllocString(psczLogPath, sczLogPath, 0);
262 ExitOnFailure(hr, "Failed to copy package log path.");
263 }
264 }
265
266LExit:
267 ReleaseStr(sczLogPathVariable);
268 ReleaseStr(sczLogPath);
269
270 return hr;
271}
272
230extern "C" HRESULT LoggingSetPackageVariable( 273extern "C" HRESULT LoggingSetPackageVariable(
231 __in BURN_PACKAGE* pPackage, 274 __in BURN_PACKAGE* pPackage,
232 __in_z_opt LPCWSTR wzSuffix, 275 __in_z_opt LPCWSTR wzSuffix,
diff --git a/src/burn/engine/logging.h b/src/burn/engine/logging.h
index 11f676b3..ef603931 100644
--- a/src/burn/engine/logging.h
+++ b/src/burn/engine/logging.h
@@ -53,6 +53,13 @@ void LoggingOpenFailed();
53 53
54void LoggingIncrementPackageSequence(); 54void LoggingIncrementPackageSequence();
55 55
56HRESULT LoggingSetCompatiblePackageVariable(
57 __in BURN_PACKAGE* pPackage,
58 __in BURN_LOGGING* pLog,
59 __in BURN_VARIABLES* pVariables,
60 __out_opt LPWSTR* psczLogPath
61 );
62
56HRESULT LoggingSetPackageVariable( 63HRESULT LoggingSetPackageVariable(
57 __in BURN_PACKAGE* pPackage, 64 __in BURN_PACKAGE* pPackage,
58 __in_z_opt LPCWSTR wzSuffix, 65 __in_z_opt LPCWSTR wzSuffix,
diff --git a/src/burn/engine/msiengine.cpp b/src/burn/engine/msiengine.cpp
index 87ae77e9..68582d29 100644
--- a/src/burn/engine/msiengine.cpp
+++ b/src/burn/engine/msiengine.cpp
@@ -506,6 +506,9 @@ extern "C" HRESULT MsiEngineDetectPackage(
506 { 506 {
507 BURN_RELATED_MSI* pRelatedMsi = &pPackage->Msi.rgRelatedMsis[i]; 507 BURN_RELATED_MSI* pRelatedMsi = &pPackage->Msi.rgRelatedMsis[i];
508 508
509 ReleaseVerutilVersion(pVersion);
510 pVersion = NULL;
511
509 for (DWORD iProduct = 0; ; ++iProduct) 512 for (DWORD iProduct = 0; ; ++iProduct)
510 { 513 {
511 // get product 514 // get product
@@ -708,6 +711,46 @@ extern "C" HRESULT MsiEngineDetectPackage(
708 hr = DependencyDetectChainPackage(pPackage, pRegistration); 711 hr = DependencyDetectChainPackage(pPackage, pRegistration);
709 ExitOnFailure(hr, "Failed to detect dependencies for MSI package."); 712 ExitOnFailure(hr, "Failed to detect dependencies for MSI package.");
710 713
714 if (BOOTSTRAPPER_PACKAGE_STATE_PRESENT > pPackage->currentState)
715 {
716 hr = MsiEngineDetectCompatiblePackage(pPackage);
717 ExitOnFailure(hr, "Failed to detect compatible package for MSI package.");
718
719 if (BURN_PACKAGE_TYPE_MSI == pPackage->compatiblePackage.type)
720 {
721 LPCWSTR wzCompatibleProductCode = pPackage->compatiblePackage.compatibleEntry.sczId;
722 LPCWSTR wzCompatibleInstalledVersion = pPackage->compatiblePackage.Msi.sczVersion;
723
724 ReleaseVerutilVersion(pVersion);
725 pVersion = NULL;
726
727 hr = VerParseVersion(wzCompatibleInstalledVersion, 0, FALSE, &pVersion);
728 ExitOnFailure(hr, "Failed to parse dependency version: '%ls' for ProductCode: %ls", wzCompatibleInstalledVersion, wzCompatibleProductCode);
729
730 if (pVersion->fInvalid)
731 {
732 LogId(REPORT_WARNING, MSG_DETECTED_MSI_PACKAGE_INVALID_VERSION, wzCompatibleProductCode, wzCompatibleInstalledVersion);
733 }
734
735 pPackage->compatiblePackage.Msi.pVersion = pVersion;
736 pVersion = NULL;
737
738 // compare versions
739 hr = VerCompareParsedVersions(pPackage->Msi.pVersion, pPackage->compatiblePackage.Msi.pVersion, &nCompareResult);
740 ExitOnFailure(hr, "Failed to compare version '%ls' to dependency version: '%ls'", pPackage->Msi.pVersion->sczVersion, wzCompatibleInstalledVersion);
741
742 if (nCompareResult < 0)
743 {
744 pPackage->compatiblePackage.fPlannable = TRUE;
745
746 LogId(REPORT_STANDARD, MSG_DETECTED_COMPATIBLE_PACKAGE_FROM_PROVIDER, pPackage->sczId, pPackage->compatiblePackage.compatibleEntry.sczProviderKey, wzCompatibleProductCode, wzCompatibleInstalledVersion, pPackage->Msi.sczProductCode);
747
748 hr = UserExperienceOnDetectCompatibleMsiPackage(pUserExperience, pPackage->sczId, wzCompatibleProductCode, pPackage->compatiblePackage.Msi.pVersion);
749 ExitOnRootFailure(hr, "BA aborted detect compatible MSI package.");
750 }
751 }
752 }
753
711LExit: 754LExit:
712 ReleaseStr(sczInstalledLanguage); 755 ReleaseStr(sczInstalledLanguage);
713 ReleaseStr(sczInstalledVersion); 756 ReleaseStr(sczInstalledVersion);
@@ -716,8 +759,49 @@ LExit:
716 return hr; 759 return hr;
717} 760}
718 761
762extern "C" HRESULT MsiEngineDetectCompatiblePackage(
763 __in BURN_PACKAGE* pPackage
764 )
765{
766 HRESULT hr = S_OK;
767 LPWSTR sczVersion = NULL;
768 LPWSTR sczCacheId = NULL;
769 LPCWSTR wzCompatibleProductCode = pPackage->compatiblePackage.compatibleEntry.sczId;
770
771 if (!pPackage->compatiblePackage.fDetected)
772 {
773 ExitFunction();
774 }
775
776 hr = WiuGetProductInfoEx(wzCompatibleProductCode, NULL, pPackage->fPerMachine ? MSIINSTALLCONTEXT_MACHINE : MSIINSTALLCONTEXT_USERUNMANAGED, INSTALLPROPERTY_VERSIONSTRING, &sczVersion);
777 if (HRESULT_FROM_WIN32(ERROR_UNKNOWN_PRODUCT) == hr || HRESULT_FROM_WIN32(ERROR_UNKNOWN_PROPERTY) == hr)
778 {
779 ExitFunction1(hr = S_OK);
780 }
781 ExitOnFailure(hr, "Failed to get product information for compatible ProductCode: %ls", wzCompatibleProductCode);
782
783 // Assume the package used the default cache ID generation from the binder.
784 hr = StrAllocFormatted(&sczCacheId, L"%lsv%ls", wzCompatibleProductCode, sczVersion);
785 ExitOnFailure(hr, "Failed to format cache ID for compatible package.");
786
787 pPackage->compatiblePackage.sczCacheId = sczCacheId;
788 sczCacheId = NULL;
789
790 pPackage->compatiblePackage.Msi.sczVersion = sczVersion;
791 sczVersion = NULL;
792
793 pPackage->compatiblePackage.type = BURN_PACKAGE_TYPE_MSI;
794
795LExit:
796 ReleaseStr(sczVersion);
797 ReleaseStr(sczCacheId);
798
799 return hr;
800}
801
719extern "C" HRESULT MsiEnginePlanInitializePackage( 802extern "C" HRESULT MsiEnginePlanInitializePackage(
720 __in BURN_PACKAGE* pPackage, 803 __in BURN_PACKAGE* pPackage,
804 __in BOOTSTRAPPER_ACTION overallAction,
721 __in BURN_VARIABLES* pVariables, 805 __in BURN_VARIABLES* pVariables,
722 __in BURN_USER_EXPERIENCE* pUserExperience 806 __in BURN_USER_EXPERIENCE* pUserExperience
723 ) 807 )
@@ -747,6 +831,18 @@ extern "C" HRESULT MsiEnginePlanInitializePackage(
747 } 831 }
748 } 832 }
749 833
834 if (pPackage->compatiblePackage.fPlannable)
835 {
836 Assert(BURN_PACKAGE_TYPE_MSI == pPackage->compatiblePackage.type);
837
838 pPackage->compatiblePackage.fDefaultRequested = BOOTSTRAPPER_ACTION_UNINSTALL == overallAction;
839 pPackage->compatiblePackage.fRequested = pPackage->compatiblePackage.fDefaultRequested;
840
841 hr = UserExperienceOnPlanCompatibleMsiPackageBegin(pUserExperience, pPackage->sczId, pPackage->compatiblePackage.compatibleEntry.sczId, pPackage->compatiblePackage.Msi.pVersion, &pPackage->compatiblePackage.fRequested);
842 UserExperienceOnPlanCompatibleMsiPackageComplete(pUserExperience, pPackage->sczId, pPackage->compatiblePackage.compatibleEntry.sczId, hr, pPackage->compatiblePackage.fRequested);
843 ExitOnRootFailure(hr, "BA aborted plan compatible MSI package begin.");
844 }
845
750LExit: 846LExit:
751 return hr; 847 return hr;
752} 848}
@@ -989,6 +1085,17 @@ extern "C" HRESULT MsiEnginePlanAddPackage(
989 LoggingSetPackageVariable(pPackage, NULL, FALSE, pLog, pVariables, &pAction->msiPackage.sczLogPath); // ignore errors. 1085 LoggingSetPackageVariable(pPackage, NULL, FALSE, pLog, pVariables, &pAction->msiPackage.sczLogPath); // ignore errors.
990 pAction->msiPackage.dwLoggingAttributes = pLog->dwAttributes; 1086 pAction->msiPackage.dwLoggingAttributes = pLog->dwAttributes;
991 } 1087 }
1088 else if (pPackage->compatiblePackage.fRemove)
1089 {
1090 hr = PlanAppendExecuteAction(pPlan, &pAction);
1091 ExitOnFailure(hr, "Failed to append execute action.");
1092
1093 pAction->type = BURN_EXECUTE_ACTION_TYPE_UNINSTALL_MSI_COMPATIBLE_PACKAGE;
1094 pAction->uninstallMsiCompatiblePackage.pParentPackage = pPackage;
1095 pAction->uninstallMsiCompatiblePackage.dwLoggingAttributes = pLog->dwAttributes;
1096
1097 LoggingSetCompatiblePackageVariable(pPackage, pLog, pVariables, &pAction->uninstallMsiCompatiblePackage.sczLogPath); // ignore errors.
1098 }
992 1099
993LExit: 1100LExit:
994 ReleaseMem(rgFeatureActions); 1101 ReleaseMem(rgFeatureActions);
@@ -1246,6 +1353,80 @@ LExit:
1246 return hr; 1353 return hr;
1247} 1354}
1248 1355
1356extern "C" HRESULT MsiEngineUninstallCompatiblePackage(
1357 __in_opt HWND hwndParent,
1358 __in BURN_EXECUTE_ACTION* pExecuteAction,
1359 __in BURN_CACHE* /*pCache*/,
1360 __in BURN_VARIABLES* /*pVariables*/,
1361 __in BOOL fRollback,
1362 __in PFN_MSIEXECUTEMESSAGEHANDLER pfnMessageHandler,
1363 __in LPVOID pvContext,
1364 __out BOOTSTRAPPER_APPLY_RESTART* pRestart
1365 )
1366{
1367 HRESULT hr = S_OK;
1368 WIU_MSI_EXECUTE_CONTEXT context = { };
1369 WIU_RESTART restart = WIU_RESTART_NONE;
1370 LPWSTR sczProperties = NULL;
1371 BOOTSTRAPPER_ACTION_STATE action = BOOTSTRAPPER_ACTION_STATE_UNINSTALL;
1372 BURN_MSI_PROPERTY burnMsiProperty = BURN_MSI_PROPERTY_NONE;
1373 BOOTSTRAPPER_MSI_FILE_VERSIONING fileVersioning = BOOTSTRAPPER_MSI_FILE_VERSIONING_MISSING_OR_OLDER;
1374 BURN_PACKAGE* pParentPackage = pExecuteAction->uninstallMsiCompatiblePackage.pParentPackage;
1375 BURN_COMPATIBLE_PROVIDER_ENTRY* pCompatibleEntry = &pExecuteAction->uninstallMsiCompatiblePackage.pParentPackage->compatiblePackage.compatibleEntry;
1376
1377 // Default to "verbose" logging and set extra debug mode only if explicitly required.
1378 DWORD dwLogMode = WIU_LOG_DEFAULT | INSTALLLOGMODE_VERBOSE;
1379
1380 if (pExecuteAction->uninstallMsiCompatiblePackage.dwLoggingAttributes & BURN_LOGGING_ATTRIBUTE_EXTRADEBUG)
1381 {
1382 dwLogMode |= INSTALLLOGMODE_EXTRADEBUG;
1383 }
1384
1385 hr = WiuInitializeExternalUI(pfnMessageHandler, INSTALLUILEVEL_NONE, hwndParent, pvContext, fRollback, &context);
1386 ExitOnFailure(hr, "Failed to initialize external UI handler.");
1387
1388 if (pExecuteAction->uninstallMsiCompatiblePackage.sczLogPath && *pExecuteAction->uninstallMsiCompatiblePackage.sczLogPath)
1389 {
1390 hr = WiuEnableLog(dwLogMode, pExecuteAction->uninstallMsiCompatiblePackage.sczLogPath, INSTALLLOGATTRIBUTES_APPEND);
1391 ExitOnFailure(hr, "Failed to enable logging for compatible package: %ls to: %ls", pCompatibleEntry->sczId, pExecuteAction->uninstallMsiCompatiblePackage.sczLogPath);
1392 }
1393
1394 hr = MsiEngineConcatBurnProperties(action, burnMsiProperty, fileVersioning, TRUE, FALSE, &sczProperties);
1395 ExitOnFailure(hr, "Failed to add action property to argument string.");
1396
1397 LogId(REPORT_STANDARD, MSG_APPLYING_ORPHAN_COMPATIBLE_PACKAGE, LoggingRollbackOrExecute(fRollback), pCompatibleEntry->sczId, pParentPackage->sczId, LoggingActionStateToString(action), sczProperties ? sczProperties : L"");
1398
1399 hr = WiuConfigureProductEx(pCompatibleEntry->sczId, INSTALLLEVEL_DEFAULT, INSTALLSTATE_ABSENT, sczProperties, &restart);
1400 if (HRESULT_FROM_WIN32(ERROR_UNKNOWN_PRODUCT) == hr)
1401 {
1402 LogId(REPORT_STANDARD, MSG_ATTEMPTED_UNINSTALL_ABSENT_PACKAGE, pCompatibleEntry->sczId);
1403 hr = S_OK;
1404 }
1405 ExitOnFailure(hr, "Failed to uninstall compatible MSI package.");
1406
1407LExit:
1408 WiuUninitializeExternalUI(&context);
1409
1410 StrSecureZeroFreeString(sczProperties);
1411
1412 switch (restart)
1413 {
1414 case WIU_RESTART_NONE:
1415 *pRestart = BOOTSTRAPPER_APPLY_RESTART_NONE;
1416 break;
1417
1418 case WIU_RESTART_REQUIRED:
1419 *pRestart = BOOTSTRAPPER_APPLY_RESTART_REQUIRED;
1420 break;
1421
1422 case WIU_RESTART_INITIATED:
1423 *pRestart = BOOTSTRAPPER_APPLY_RESTART_INITIATED;
1424 break;
1425 }
1426
1427 return hr;
1428}
1429
1249extern "C" HRESULT MsiEngineConcatBurnProperties( 1430extern "C" HRESULT MsiEngineConcatBurnProperties(
1250 __in BOOTSTRAPPER_ACTION_STATE action, 1431 __in BOOTSTRAPPER_ACTION_STATE action,
1251 __in BURN_MSI_PROPERTY actionMsiProperty, 1432 __in BURN_MSI_PROPERTY actionMsiProperty,
diff --git a/src/burn/engine/msiengine.h b/src/burn/engine/msiengine.h
index fbb251e0..bc356fab 100644
--- a/src/burn/engine/msiengine.h
+++ b/src/burn/engine/msiengine.h
@@ -35,8 +35,12 @@ HRESULT MsiEngineDetectPackage(
35 __in BURN_REGISTRATION* pRegistration, 35 __in BURN_REGISTRATION* pRegistration,
36 __in BURN_USER_EXPERIENCE* pUserExperience 36 __in BURN_USER_EXPERIENCE* pUserExperience
37 ); 37 );
38HRESULT MsiEngineDetectCompatiblePackage(
39 __in BURN_PACKAGE* pPackage
40 );
38HRESULT MsiEnginePlanInitializePackage( 41HRESULT MsiEnginePlanInitializePackage(
39 __in BURN_PACKAGE* pPackage, 42 __in BURN_PACKAGE* pPackage,
43 __in BOOTSTRAPPER_ACTION overallAction,
40 __in BURN_VARIABLES* pVariables, 44 __in BURN_VARIABLES* pVariables,
41 __in BURN_USER_EXPERIENCE* pUserExperience 45 __in BURN_USER_EXPERIENCE* pUserExperience
42 ); 46 );
@@ -71,6 +75,16 @@ HRESULT MsiEngineExecutePackage(
71 __in LPVOID pvContext, 75 __in LPVOID pvContext,
72 __out BOOTSTRAPPER_APPLY_RESTART* pRestart 76 __out BOOTSTRAPPER_APPLY_RESTART* pRestart
73 ); 77 );
78HRESULT MsiEngineUninstallCompatiblePackage(
79 __in_opt HWND hwndParent,
80 __in BURN_EXECUTE_ACTION* pExecuteAction,
81 __in BURN_CACHE* pCache,
82 __in BURN_VARIABLES* pVariables,
83 __in BOOL fRollback,
84 __in PFN_MSIEXECUTEMESSAGEHANDLER pfnMessageHandler,
85 __in LPVOID pvContext,
86 __out BOOTSTRAPPER_APPLY_RESTART* pRestart
87 );
74HRESULT MsiEngineConcatBurnProperties( 88HRESULT MsiEngineConcatBurnProperties(
75 __in BOOTSTRAPPER_ACTION_STATE action, 89 __in BOOTSTRAPPER_ACTION_STATE action,
76 __in BURN_MSI_PROPERTY actionMsiProperty, 90 __in BURN_MSI_PROPERTY actionMsiProperty,
diff --git a/src/burn/engine/package.cpp b/src/burn/engine/package.cpp
index d9087f79..d9f92d3d 100644
--- a/src/burn/engine/package.cpp
+++ b/src/burn/engine/package.cpp
@@ -366,6 +366,31 @@ extern "C" void PackageUninitialize(
366 MsuEnginePackageUninitialize(pPackage); // TODO: Modularization 366 MsuEnginePackageUninitialize(pPackage); // TODO: Modularization
367 break; 367 break;
368 } 368 }
369
370 PackageUninitializeCompatible(&pPackage->compatiblePackage);
371}
372
373extern "C" void PackageUninitializeCompatible(
374 __in BURN_COMPATIBLE_PACKAGE* pCompatiblePackage
375 )
376{
377 ReleaseStr(pCompatiblePackage->compatibleEntry.sczId);
378 ReleaseStr(pCompatiblePackage->compatibleEntry.sczName);
379 ReleaseStr(pCompatiblePackage->compatibleEntry.sczProviderKey);
380 ReleaseStr(pCompatiblePackage->compatibleEntry.sczVersion);
381
382 ReleaseStr(pCompatiblePackage->sczCacheId);
383
384 switch (pCompatiblePackage->type)
385 {
386 case BURN_PACKAGE_TYPE_MSI:
387 ReleaseStr(pCompatiblePackage->Msi.sczVersion);
388 ReleaseVerutilVersion(pCompatiblePackage->Msi.pVersion);
389 break;
390 }
391
392 // clear struct
393 memset(pCompatiblePackage, 0, sizeof(BURN_COMPATIBLE_PACKAGE));
369} 394}
370 395
371extern "C" void PackagesUninitialize( 396extern "C" void PackagesUninitialize(
diff --git a/src/burn/engine/package.h b/src/burn/engine/package.h
index 10b5f33c..934355e1 100644
--- a/src/burn/engine/package.h
+++ b/src/burn/engine/package.h
@@ -147,6 +147,14 @@ typedef struct _BURN_MSIFEATURE
147 BOOTSTRAPPER_FEATURE_ACTION rollback; // only valid during Plan. 147 BOOTSTRAPPER_FEATURE_ACTION rollback; // only valid during Plan.
148} BURN_MSIFEATURE; 148} BURN_MSIFEATURE;
149 149
150typedef struct _BURN_COMPATIBLE_PROVIDER_ENTRY
151{
152 LPWSTR sczProviderKey;
153 LPWSTR sczId;
154 LPWSTR sczName;
155 LPWSTR sczVersion;
156} BURN_COMPATIBLE_PROVIDER_ENTRY;
157
150typedef struct _BURN_RELATED_MSI 158typedef struct _BURN_RELATED_MSI
151{ 159{
152 LPWSTR sczUpgradeCode; 160 LPWSTR sczUpgradeCode;
@@ -206,6 +214,27 @@ typedef struct _BURN_PATCH_TARGETCODE
206 BURN_PATCH_TARGETCODE_TYPE type; 214 BURN_PATCH_TARGETCODE_TYPE type;
207} BURN_PATCH_TARGETCODE; 215} BURN_PATCH_TARGETCODE;
208 216
217typedef struct _BURN_COMPATIBLE_PACKAGE
218{
219 BOOL fDetected;
220 BOOL fPlannable;
221 BOOL fDefaultRequested;
222 BOOL fRequested;
223 BOOL fRemove;
224 LPWSTR sczCacheId;
225 BURN_COMPATIBLE_PROVIDER_ENTRY compatibleEntry;
226
227 BURN_PACKAGE_TYPE type;
228 union
229 {
230 struct
231 {
232 LPWSTR sczVersion;
233 VERUTIL_VERSION* pVersion;
234 } Msi;
235 };
236} BURN_COMPATIBLE_PACKAGE;
237
209typedef struct _BURN_PACKAGE 238typedef struct _BURN_PACKAGE
210{ 239{
211 LPWSTR sczId; 240 LPWSTR sczId;
@@ -259,6 +288,8 @@ typedef struct _BURN_PACKAGE
259 BURN_DEPENDENCY_PROVIDER* rgDependencyProviders; 288 BURN_DEPENDENCY_PROVIDER* rgDependencyProviders;
260 DWORD cDependencyProviders; 289 DWORD cDependencyProviders;
261 290
291 BURN_COMPATIBLE_PACKAGE compatiblePackage;
292
262 BURN_PACKAGE_TYPE type; 293 BURN_PACKAGE_TYPE type;
263 union 294 union
264 { 295 {
@@ -371,6 +402,9 @@ HRESULT PackagesParseFromXml(
371void PackageUninitialize( 402void PackageUninitialize(
372 __in BURN_PACKAGE* pPackage 403 __in BURN_PACKAGE* pPackage
373 ); 404 );
405void PackageUninitializeCompatible(
406 __in BURN_COMPATIBLE_PACKAGE* pCompatiblePackage
407 );
374void PackagesUninitialize( 408void PackagesUninitialize(
375 __in BURN_PACKAGES* pPackages 409 __in BURN_PACKAGES* pPackages
376 ); 410 );
diff --git a/src/burn/engine/plan.cpp b/src/burn/engine/plan.cpp
index e0e9a82b..1dd78773 100644
--- a/src/burn/engine/plan.cpp
+++ b/src/burn/engine/plan.cpp
@@ -96,6 +96,10 @@ static HRESULT AppendRollbackCacheAction(
96 __in BURN_PLAN* pPlan, 96 __in BURN_PLAN* pPlan,
97 __out BURN_CACHE_ACTION** ppCacheAction 97 __out BURN_CACHE_ACTION** ppCacheAction
98 ); 98 );
99static HRESULT AppendCleanAction(
100 __in BURN_PLAN* pPlan,
101 __out BURN_CLEAN_ACTION** ppCleanAction
102 );
99static HRESULT ProcessPayloadGroup( 103static HRESULT ProcessPayloadGroup(
100 __in BURN_PLAN* pPlan, 104 __in BURN_PLAN* pPlan,
101 __in BURN_PAYLOAD_GROUP* pPayloadGroup 105 __in BURN_PAYLOAD_GROUP* pPayloadGroup
@@ -286,6 +290,10 @@ extern "C" void PlanUninitializeExecuteAction(
286 case BURN_EXECUTE_ACTION_TYPE_PACKAGE_DEPENDENCY: 290 case BURN_EXECUTE_ACTION_TYPE_PACKAGE_DEPENDENCY:
287 ReleaseStr(pExecuteAction->packageDependency.sczBundleProviderKey); 291 ReleaseStr(pExecuteAction->packageDependency.sczBundleProviderKey);
288 break; 292 break;
293
294 case BURN_EXECUTE_ACTION_TYPE_UNINSTALL_MSI_COMPATIBLE_PACKAGE:
295 ReleaseStr(pExecuteAction->uninstallMsiCompatiblePackage.sczLogPath);
296 break;
289 } 297 }
290} 298}
291 299
@@ -823,6 +831,11 @@ static HRESULT PlanPackagesHelper(
823 BURN_PACKAGE* pPackage = rgPackages + iPackage; 831 BURN_PACKAGE* pPackage = rgPackages + iPackage;
824 832
825 UserExperienceOnPlannedPackage(pUX, pPackage->sczId, pPackage->execute, pPackage->rollback, pPackage->fPlannedCache, pPackage->fPlannedUncache); 833 UserExperienceOnPlannedPackage(pUX, pPackage->sczId, pPackage->execute, pPackage->rollback, pPackage->fPlannedCache, pPackage->fPlannedUncache);
834
835 if (pPackage->compatiblePackage.fPlannable)
836 {
837 UserExperienceOnPlannedCompatiblePackage(pUX, pPackage->sczId, pPackage->compatiblePackage.compatibleEntry.sczId, pPackage->compatiblePackage.fRemove);
838 }
826 } 839 }
827 840
828LExit: 841LExit:
@@ -878,7 +891,7 @@ static HRESULT InitializePackage(
878 891
879 if (BURN_PACKAGE_TYPE_MSI == pPackage->type) 892 if (BURN_PACKAGE_TYPE_MSI == pPackage->type)
880 { 893 {
881 hr = MsiEnginePlanInitializePackage(pPackage, pVariables, pUX); 894 hr = MsiEnginePlanInitializePackage(pPackage, pPlan->action, pVariables, pUX);
882 ExitOnFailure(hr, "Failed to initialize plan package: %ls", pPackage->sczId); 895 ExitOnFailure(hr, "Failed to initialize plan package: %ls", pPackage->sczId);
883 } 896 }
884 897
@@ -918,7 +931,7 @@ static HRESULT ProcessPackage(
918 } 931 }
919 else 932 else
920 { 933 {
921 if (BOOTSTRAPPER_REQUEST_STATE_NONE != pPackage->requested) 934 if (BOOTSTRAPPER_REQUEST_STATE_NONE != pPackage->requested || pPackage->compatiblePackage.fRequested)
922 { 935 {
923 // If the package is in a requested state, plan it. 936 // If the package is in a requested state, plan it.
924 hr = PlanExecutePackage(fBundlePerMachine, pUX, pPlan, pPackage, pLog, pVariables); 937 hr = PlanExecutePackage(fBundlePerMachine, pUX, pPlan, pPackage, pLog, pVariables);
@@ -1151,7 +1164,7 @@ extern "C" HRESULT PlanExecutePackage(
1151 ExitOnFailure(hr, "Failed to complete plan dependency actions for package: %ls", pPackage->sczId); 1164 ExitOnFailure(hr, "Failed to complete plan dependency actions for package: %ls", pPackage->sczId);
1152 1165
1153 // If we are going to take any action on this package, add progress for it. 1166 // If we are going to take any action on this package, add progress for it.
1154 if (BOOTSTRAPPER_ACTION_STATE_NONE != pPackage->execute || BOOTSTRAPPER_ACTION_STATE_NONE != pPackage->rollback) 1167 if (BOOTSTRAPPER_ACTION_STATE_NONE != pPackage->execute || BOOTSTRAPPER_ACTION_STATE_NONE != pPackage->rollback || pPackage->compatiblePackage.fRemove)
1155 { 1168 {
1156 LoggingIncrementPackageSequence(); 1169 LoggingIncrementPackageSequence();
1157 1170
@@ -1560,12 +1573,10 @@ extern "C" HRESULT PlanCleanPackage(
1560 1573
1561 if (fPlanCleanPackage) 1574 if (fPlanCleanPackage)
1562 { 1575 {
1563 hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pPlan->rgCleanActions), pPlan->cCleanActions + 1, sizeof(BURN_CLEAN_ACTION), 5); 1576 hr = AppendCleanAction(pPlan, &pCleanAction);
1564 ExitOnFailure(hr, "Failed to grow plan's array of clean actions."); 1577 ExitOnFailure(hr, "Failed to append clean action to plan.");
1565
1566 pCleanAction = pPlan->rgCleanActions + pPlan->cCleanActions;
1567 ++pPlan->cCleanActions;
1568 1578
1579 pCleanAction->type = BURN_CLEAN_ACTION_TYPE_PACKAGE;
1569 pCleanAction->pPackage = pPackage; 1580 pCleanAction->pPackage = pPackage;
1570 1581
1571 pPackage->fPlannedUncache = TRUE; 1582 pPackage->fPlannedUncache = TRUE;
@@ -1576,6 +1587,15 @@ extern "C" HRESULT PlanCleanPackage(
1576 } 1587 }
1577 } 1588 }
1578 1589
1590 if (pPackage->compatiblePackage.fRemove)
1591 {
1592 hr = AppendCleanAction(pPlan, &pCleanAction);
1593 ExitOnFailure(hr, "Failed to append clean action to plan.");
1594
1595 pCleanAction->type = BURN_CLEAN_ACTION_TYPE_COMPATIBLE_PACKAGE;
1596 pCleanAction->pPackage = pPackage;
1597 }
1598
1579LExit: 1599LExit:
1580 return hr; 1600 return hr;
1581} 1601}
@@ -2229,6 +2249,24 @@ LExit:
2229 return hr; 2249 return hr;
2230} 2250}
2231 2251
2252static HRESULT AppendCleanAction(
2253 __in BURN_PLAN* pPlan,
2254 __out BURN_CLEAN_ACTION** ppCleanAction
2255 )
2256{
2257 HRESULT hr = S_OK;
2258
2259 hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(&pPlan->rgCleanActions), pPlan->cCleanActions, 1, sizeof(BURN_CLEAN_ACTION), 5);
2260 ExitOnFailure(hr, "Failed to grow plan's array of clean actions.");
2261
2262
2263 *ppCleanAction = pPlan->rgCleanActions + pPlan->cCleanActions;
2264 ++pPlan->cCleanActions;
2265
2266LExit:
2267 return hr;
2268}
2269
2232static HRESULT ProcessPayloadGroup( 2270static HRESULT ProcessPayloadGroup(
2233 __in BURN_PLAN* pPlan, 2271 __in BURN_PLAN* pPlan,
2234 __in BURN_PAYLOAD_GROUP* pPayloadGroup 2272 __in BURN_PAYLOAD_GROUP* pPayloadGroup
@@ -2505,6 +2543,8 @@ static HRESULT CalculateExecuteActions(
2505 ExitOnFailure(hr, "Invalid package type."); 2543 ExitOnFailure(hr, "Invalid package type.");
2506 } 2544 }
2507 2545
2546 pPackage->compatiblePackage.fRemove = pPackage->compatiblePackage.fPlannable && pPackage->compatiblePackage.fRequested;
2547
2508LExit: 2548LExit:
2509 return hr; 2549 return hr;
2510} 2550}
@@ -2622,6 +2662,10 @@ static void ExecuteActionLog(
2622 } 2662 }
2623 break; 2663 break;
2624 2664
2665 case BURN_EXECUTE_ACTION_TYPE_UNINSTALL_MSI_COMPATIBLE_PACKAGE:
2666 LogStringLine(PlanDumpLevel, "%ls action[%u]: UNINSTALL_MSI_COMPATIBLE_PACKAGE package id: %ls, compatible package id: %ls, cache id: %ls, log path: %ls, logging attrib: %u", wzBase, iAction, pAction->uninstallMsiCompatiblePackage.pParentPackage->sczId, pAction->uninstallMsiCompatiblePackage.pParentPackage->compatiblePackage.compatibleEntry.sczId, pAction->uninstallMsiCompatiblePackage.pParentPackage->compatiblePackage.sczCacheId, pAction->uninstallMsiCompatiblePackage.sczLogPath, pAction->uninstallMsiCompatiblePackage.dwLoggingAttributes);
2667 break;
2668
2625 case BURN_EXECUTE_ACTION_TYPE_MSP_TARGET: 2669 case BURN_EXECUTE_ACTION_TYPE_MSP_TARGET:
2626 LogStringLine(PlanDumpLevel, "%ls action[%u]: MSP_TARGET package id: %ls, action: %hs, target product code: %ls, target per-machine: %hs, action msi property: %ls, ui level: %u, disable externaluihandler: %hs, file versioning: %hs, log path: %ls", wzBase, iAction, pAction->mspTarget.pPackage->sczId, LoggingActionStateToString(pAction->mspTarget.action), pAction->mspTarget.sczTargetProductCode, LoggingBoolToString(pAction->mspTarget.fPerMachineTarget), LoggingBurnMsiPropertyToString(pAction->mspTarget.actionMsiProperty), pAction->mspTarget.uiLevel, LoggingBoolToString(pAction->mspTarget.fDisableExternalUiHandler), LoggingMsiFileVersioningToString(pAction->mspTarget.fileVersioning), pAction->mspTarget.sczLogPath); 2670 LogStringLine(PlanDumpLevel, "%ls action[%u]: MSP_TARGET package id: %ls, action: %hs, target product code: %ls, target per-machine: %hs, action msi property: %ls, ui level: %u, disable externaluihandler: %hs, file versioning: %hs, log path: %ls", wzBase, iAction, pAction->mspTarget.pPackage->sczId, LoggingActionStateToString(pAction->mspTarget.action), pAction->mspTarget.sczTargetProductCode, LoggingBoolToString(pAction->mspTarget.fPerMachineTarget), LoggingBurnMsiPropertyToString(pAction->mspTarget.actionMsiProperty), pAction->mspTarget.uiLevel, LoggingBoolToString(pAction->mspTarget.fDisableExternalUiHandler), LoggingMsiFileVersioningToString(pAction->mspTarget.fileVersioning), pAction->mspTarget.sczLogPath);
2627 for (DWORD j = 0; j < pAction->mspTarget.cOrderedPatches; ++j) 2671 for (DWORD j = 0; j < pAction->mspTarget.cOrderedPatches; ++j)
@@ -2669,6 +2713,27 @@ static void ExecuteActionLog(
2669 } 2713 }
2670} 2714}
2671 2715
2716static void CleanActionLog(
2717 __in DWORD iAction,
2718 __in BURN_CLEAN_ACTION* pAction
2719 )
2720{
2721 switch (pAction->type)
2722 {
2723 case BURN_CLEAN_ACTION_TYPE_COMPATIBLE_PACKAGE:
2724 LogStringLine(PlanDumpLevel, " Clean action[%u]: CLEAN_COMPATIBLE_PACKAGE package id: %ls", iAction, pAction->pPackage->sczId);
2725 break;
2726
2727 case BURN_CLEAN_ACTION_TYPE_PACKAGE:
2728 LogStringLine(PlanDumpLevel, " Clean action[%u]: CLEAN_PACKAGE package id: %ls", iAction, pAction->pPackage->sczId);
2729 break;
2730
2731 default:
2732 AssertSz(FALSE, "Unknown clean action type.");
2733 break;
2734 }
2735}
2736
2672extern "C" void PlanDump( 2737extern "C" void PlanDump(
2673 __in BURN_PLAN* pPlan 2738 __in BURN_PLAN* pPlan
2674 ) 2739 )
@@ -2709,7 +2774,7 @@ extern "C" void PlanDump(
2709 2774
2710 for (DWORD i = 0; i < pPlan->cCleanActions; ++i) 2775 for (DWORD i = 0; i < pPlan->cCleanActions; ++i)
2711 { 2776 {
2712 LogStringLine(PlanDumpLevel, " Clean action[%u]: CLEAN_PACKAGE package id: %ls", i, pPlan->rgCleanActions[i].pPackage->sczId); 2777 CleanActionLog(i, pPlan->rgCleanActions + i);
2713 } 2778 }
2714 2779
2715 for (DWORD i = 0; i < pPlan->cPlannedProviders; ++i) 2780 for (DWORD i = 0; i < pPlan->cPlannedProviders; ++i)
diff --git a/src/burn/engine/plan.h b/src/burn/engine/plan.h
index 6be19a10..9bf72828 100644
--- a/src/burn/engine/plan.h
+++ b/src/burn/engine/plan.h
@@ -61,12 +61,13 @@ enum BURN_EXECUTE_ACTION_TYPE
61 BURN_EXECUTE_ACTION_TYPE_ROLLBACK_BOUNDARY_END, 61 BURN_EXECUTE_ACTION_TYPE_ROLLBACK_BOUNDARY_END,
62 BURN_EXECUTE_ACTION_TYPE_BEGIN_MSI_TRANSACTION, 62 BURN_EXECUTE_ACTION_TYPE_BEGIN_MSI_TRANSACTION,
63 BURN_EXECUTE_ACTION_TYPE_COMMIT_MSI_TRANSACTION, 63 BURN_EXECUTE_ACTION_TYPE_COMMIT_MSI_TRANSACTION,
64 BURN_EXECUTE_ACTION_TYPE_UNINSTALL_MSI_COMPATIBLE_PACKAGE,
64}; 65};
65 66
66enum BURN_CLEAN_ACTION_TYPE 67enum BURN_CLEAN_ACTION_TYPE
67{ 68{
68 BURN_CLEAN_ACTION_TYPE_NONE, 69 BURN_CLEAN_ACTION_TYPE_NONE,
69 BURN_CLEAN_ACTION_TYPE_BUNDLE, 70 BURN_CLEAN_ACTION_TYPE_COMPATIBLE_PACKAGE,
70 BURN_CLEAN_ACTION_TYPE_PACKAGE, 71 BURN_CLEAN_ACTION_TYPE_PACKAGE,
71}; 72};
72 73
@@ -227,11 +228,18 @@ typedef struct _BURN_EXECUTE_ACTION
227 { 228 {
228 BURN_ROLLBACK_BOUNDARY* pRollbackBoundary; 229 BURN_ROLLBACK_BOUNDARY* pRollbackBoundary;
229 } msiTransaction; 230 } msiTransaction;
231 struct
232 {
233 BURN_PACKAGE* pParentPackage;
234 LPWSTR sczLogPath;
235 DWORD dwLoggingAttributes;
236 } uninstallMsiCompatiblePackage;
230 }; 237 };
231} BURN_EXECUTE_ACTION; 238} BURN_EXECUTE_ACTION;
232 239
233typedef struct _BURN_CLEAN_ACTION 240typedef struct _BURN_CLEAN_ACTION
234{ 241{
242 BURN_CLEAN_ACTION_TYPE type;
235 BURN_PACKAGE* pPackage; 243 BURN_PACKAGE* pPackage;
236} BURN_CLEAN_ACTION; 244} BURN_CLEAN_ACTION;
237 245
diff --git a/src/burn/engine/registration.cpp b/src/burn/engine/registration.cpp
index a5b061eb..c76dde53 100644
--- a/src/burn/engine/registration.cpp
+++ b/src/burn/engine/registration.cpp
@@ -423,6 +423,10 @@ extern "C" void RegistrationUninitialize(
423 ReleaseStr(pRegistration->sczBundlePackageAncestors); 423 ReleaseStr(pRegistration->sczBundlePackageAncestors);
424 RelatedBundlesUninitialize(&pRegistration->relatedBundles); 424 RelatedBundlesUninitialize(&pRegistration->relatedBundles);
425 425
426 if (pRegistration->rgDependents)
427 {
428 ReleaseDependencyArray(pRegistration->rgDependents, pRegistration->cDependents);
429 }
426 // clear struct 430 // clear struct
427 memset(pRegistration, 0, sizeof(BURN_REGISTRATION)); 431 memset(pRegistration, 0, sizeof(BURN_REGISTRATION));
428} 432}
diff --git a/src/burn/engine/userexperience.cpp b/src/burn/engine/userexperience.cpp
index 6ea16905..1439f5f2 100644
--- a/src/burn/engine/userexperience.cpp
+++ b/src/burn/engine/userexperience.cpp
@@ -104,7 +104,7 @@ extern "C" HRESULT UserExperienceLoad(
104 args.pCommand = pCommand; 104 args.pCommand = pCommand;
105 args.pfnBootstrapperEngineProc = EngineForApplicationProc; 105 args.pfnBootstrapperEngineProc = EngineForApplicationProc;
106 args.pvBootstrapperEngineProcContext = pEngineContext; 106 args.pvBootstrapperEngineProcContext = pEngineContext;
107 args.qwEngineAPIVersion = MAKEQWORDVERSION(2021, 12, 30, 0); 107 args.qwEngineAPIVersion = MAKEQWORDVERSION(2022, 1, 10, 0);
108 108
109 results.cbSize = sizeof(BOOTSTRAPPER_CREATE_RESULTS); 109 results.cbSize = sizeof(BOOTSTRAPPER_CREATE_RESULTS);
110 110
@@ -1015,6 +1015,36 @@ LExit:
1015 return hr; 1015 return hr;
1016} 1016}
1017 1017
1018EXTERN_C BAAPI UserExperienceOnDetectCompatibleMsiPackage(
1019 __in BURN_USER_EXPERIENCE* pUserExperience,
1020 __in_z LPCWSTR wzPackageId,
1021 __in_z LPCWSTR wzCompatiblePackageId,
1022 __in VERUTIL_VERSION* pCompatiblePackageVersion
1023 )
1024{
1025 HRESULT hr = S_OK;
1026 BA_ONDETECTCOMPATIBLEMSIPACKAGE_ARGS args = { };
1027 BA_ONDETECTCOMPATIBLEMSIPACKAGE_RESULTS results = { };
1028
1029 args.cbSize = sizeof(args);
1030 args.wzPackageId = wzPackageId;
1031 args.wzCompatiblePackageId = wzCompatiblePackageId;
1032 args.wzCompatiblePackageVersion = pCompatiblePackageVersion->sczVersion;
1033
1034 results.cbSize = sizeof(results);
1035
1036 hr = SendBAMessage(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTCOMPATIBLEMSIPACKAGE, &args, &results);
1037 ExitOnFailure(hr, "BA OnDetectCompatibleMsiPackage failed.");
1038
1039 if (results.fCancel)
1040 {
1041 hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT);
1042 }
1043
1044LExit:
1045 return hr;
1046}
1047
1018EXTERN_C BAAPI UserExperienceOnDetectComplete( 1048EXTERN_C BAAPI UserExperienceOnDetectComplete(
1019 __in BURN_USER_EXPERIENCE* pUserExperience, 1049 __in BURN_USER_EXPERIENCE* pUserExperience,
1020 __in HRESULT hrStatus, 1050 __in HRESULT hrStatus,
@@ -1798,6 +1828,67 @@ LExit:
1798 return hr; 1828 return hr;
1799} 1829}
1800 1830
1831EXTERN_C BAAPI UserExperienceOnPlanCompatibleMsiPackageBegin(
1832 __in BURN_USER_EXPERIENCE* pUserExperience,
1833 __in_z LPCWSTR wzPackageId,
1834 __in_z LPCWSTR wzCompatiblePackageId,
1835 __in VERUTIL_VERSION* pCompatiblePackageVersion,
1836 __inout BOOL* pfRequested
1837 )
1838{
1839 HRESULT hr = S_OK;
1840 BA_ONPLANCOMPATIBLEMSIPACKAGEBEGIN_ARGS args = { };
1841 BA_ONPLANCOMPATIBLEMSIPACKAGEBEGIN_RESULTS results = { };
1842
1843 args.cbSize = sizeof(args);
1844 args.wzPackageId = wzPackageId;
1845 args.wzCompatiblePackageId = wzCompatiblePackageId;
1846 args.wzCompatiblePackageVersion = pCompatiblePackageVersion->sczVersion;
1847 args.fRecommendedRemove = *pfRequested;
1848
1849 results.cbSize = sizeof(results);
1850 results.fRequestRemove = *pfRequested;
1851
1852 hr = SendBAMessage(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANCOMPATIBLEMSIPACKAGEBEGIN, &args, &results);
1853 ExitOnFailure(hr, "BA OnPlanCompatibleMsiPackageBegin failed.");
1854
1855 if (results.fCancel)
1856 {
1857 hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT);
1858 }
1859 *pfRequested = results.fRequestRemove;
1860
1861LExit:
1862 return hr;
1863}
1864
1865EXTERN_C BAAPI UserExperienceOnPlanCompatibleMsiPackageComplete(
1866 __in BURN_USER_EXPERIENCE* pUserExperience,
1867 __in_z LPCWSTR wzPackageId,
1868 __in_z LPCWSTR wzCompatiblePackageId,
1869 __in HRESULT hrStatus,
1870 __in BOOL fRequested
1871 )
1872{
1873 HRESULT hr = S_OK;
1874 BA_ONPLANCOMPATIBLEMSIPACKAGECOMPLETE_ARGS args = { };
1875 BA_ONPLANCOMPATIBLEMSIPACKAGECOMPLETE_RESULTS results = { };
1876
1877 args.cbSize = sizeof(args);
1878 args.wzPackageId = wzPackageId;
1879 args.wzCompatiblePackageId = wzCompatiblePackageId;
1880 args.hrStatus = hrStatus;
1881 args.fRequestedRemove = fRequested;
1882
1883 results.cbSize = sizeof(results);
1884
1885 hr = SendBAMessage(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANCOMPATIBLEMSIPACKAGECOMPLETE, &args, &results);
1886 ExitOnFailure(hr, "BA OnPlanCompatibleMsiPackageComplete failed.");
1887
1888LExit:
1889 return hr;
1890}
1891
1801EXTERN_C BAAPI UserExperienceOnPlanMsiFeature( 1892EXTERN_C BAAPI UserExperienceOnPlanMsiFeature(
1802 __in BURN_USER_EXPERIENCE* pUserExperience, 1893 __in BURN_USER_EXPERIENCE* pUserExperience,
1803 __in_z LPCWSTR wzPackageId, 1894 __in_z LPCWSTR wzPackageId,
@@ -1932,6 +2023,31 @@ LExit:
1932 return hr; 2023 return hr;
1933} 2024}
1934 2025
2026EXTERN_C BAAPI UserExperienceOnPlannedCompatiblePackage(
2027 __in BURN_USER_EXPERIENCE* pUserExperience,
2028 __in_z LPCWSTR wzPackageId,
2029 __in_z LPCWSTR wzCompatiblePackageId,
2030 __in BOOL fRemove
2031 )
2032{
2033 HRESULT hr = S_OK;
2034 BA_ONPLANNEDCOMPATIBLEPACKAGE_ARGS args = { };
2035 BA_ONPLANNEDCOMPATIBLEPACKAGE_RESULTS results = { };
2036
2037 args.cbSize = sizeof(args);
2038 args.wzPackageId = wzPackageId;
2039 args.wzCompatiblePackageId = wzCompatiblePackageId;
2040 args.fRemove = fRemove;
2041
2042 results.cbSize = sizeof(results);
2043
2044 hr = SendBAMessage(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANNEDCOMPATIBLEPACKAGE, &args, &results);
2045 ExitOnFailure(hr, "BA OnPlannedCompatiblePackage failed.");
2046
2047LExit:
2048 return hr;
2049}
2050
1935EXTERN_C BAAPI UserExperienceOnPlannedPackage( 2051EXTERN_C BAAPI UserExperienceOnPlannedPackage(
1936 __in BURN_USER_EXPERIENCE* pUserExperience, 2052 __in BURN_USER_EXPERIENCE* pUserExperience,
1937 __in_z LPCWSTR wzPackageId, 2053 __in_z LPCWSTR wzPackageId,
diff --git a/src/burn/engine/userexperience.h b/src/burn/engine/userexperience.h
index e4c5d3ee..e8341120 100644
--- a/src/burn/engine/userexperience.h
+++ b/src/burn/engine/userexperience.h
@@ -248,6 +248,12 @@ BAAPI UserExperienceOnDetectBegin(
248 __in BOOL fInstalled, 248 __in BOOL fInstalled,
249 __in DWORD cPackages 249 __in DWORD cPackages
250 ); 250 );
251BAAPI UserExperienceOnDetectCompatibleMsiPackage(
252 __in BURN_USER_EXPERIENCE* pUserExperience,
253 __in_z LPCWSTR wzPackageId,
254 __in_z LPCWSTR wzCompatiblePackageId,
255 __in VERUTIL_VERSION* pCompatiblePackageVersion
256 );
251BAAPI UserExperienceOnDetectComplete( 257BAAPI UserExperienceOnDetectComplete(
252 __in BURN_USER_EXPERIENCE* pUserExperience, 258 __in BURN_USER_EXPERIENCE* pUserExperience,
253 __in HRESULT hrStatus, 259 __in HRESULT hrStatus,
@@ -414,6 +420,20 @@ BAAPI UserExperienceOnPlanBegin(
414 __in BURN_USER_EXPERIENCE* pUserExperience, 420 __in BURN_USER_EXPERIENCE* pUserExperience,
415 __in DWORD cPackages 421 __in DWORD cPackages
416 ); 422 );
423BAAPI UserExperienceOnPlanCompatibleMsiPackageBegin(
424 __in BURN_USER_EXPERIENCE* pUserExperience,
425 __in_z LPCWSTR wzPackageId,
426 __in_z LPCWSTR wzCompatiblePackageId,
427 __in VERUTIL_VERSION* pCompatiblePackageVersion,
428 __inout BOOL* pfRequested
429 );
430BAAPI UserExperienceOnPlanCompatibleMsiPackageComplete(
431 __in BURN_USER_EXPERIENCE* pUserExperience,
432 __in_z LPCWSTR wzPackageId,
433 __in_z LPCWSTR wzCompatiblePackageId,
434 __in HRESULT hrStatus,
435 __in BOOL fRequested
436 );
417BAAPI UserExperienceOnPlanComplete( 437BAAPI UserExperienceOnPlanComplete(
418 __in BURN_USER_EXPERIENCE* pUserExperience, 438 __in BURN_USER_EXPERIENCE* pUserExperience,
419 __in HRESULT hrStatus 439 __in HRESULT hrStatus
@@ -443,6 +463,12 @@ BAAPI UserExperienceOnPlanMsiPackage(
443 __inout BOOL* pfDisableExternalUiHandler, 463 __inout BOOL* pfDisableExternalUiHandler,
444 __inout BOOTSTRAPPER_MSI_FILE_VERSIONING* pFileVersioning 464 __inout BOOTSTRAPPER_MSI_FILE_VERSIONING* pFileVersioning
445 ); 465 );
466BAAPI UserExperienceOnPlannedCompatiblePackage(
467 __in BURN_USER_EXPERIENCE* pUserExperience,
468 __in_z LPCWSTR wzPackageId,
469 __in_z LPCWSTR wzCompatiblePackageId,
470 __in BOOL fRemove
471 );
446BAAPI UserExperienceOnPlannedPackage( 472BAAPI UserExperienceOnPlannedPackage(
447 __in BURN_USER_EXPERIENCE* pUserExperience, 473 __in BURN_USER_EXPERIENCE* pUserExperience,
448 __in_z LPCWSTR wzPackageId, 474 __in_z LPCWSTR wzPackageId,
diff --git a/src/burn/test/BurnUnitTest/PlanTest.cpp b/src/burn/test/BurnUnitTest/PlanTest.cpp
index 7e704c23..fc2b8472 100644
--- a/src/burn/test/BurnUnitTest/PlanTest.cpp
+++ b/src/burn/test/BurnUnitTest/PlanTest.cpp
@@ -288,6 +288,74 @@ namespace Bootstrapper
288 } 288 }
289 289
290 [Fact] 290 [Fact]
291 void OrphanCompatiblePackageTest()
292 {
293 HRESULT hr = S_OK;
294 BURN_ENGINE_STATE engineState = { };
295 BURN_ENGINE_STATE* pEngineState = &engineState;
296 BURN_PLAN* pPlan = &engineState.plan;
297
298 InitializeEngineStateForCorePlan(wzSingleMsiManifestFileName, pEngineState);
299 DetectPackagesAsAbsent(pEngineState);
300 DetectCompatibleMsiPackage(pEngineState->packages.rgPackages, L"{C24F3903-38E7-4D44-8037-D9856B3C5046}", L"2.0.0.0");
301
302 hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL);
303 NativeAssert::Succeeded(hr, "CorePlan failed");
304
305 Assert::Equal<DWORD>(BOOTSTRAPPER_ACTION_UNINSTALL, pPlan->action);
306 Assert::Equal<BOOL>(TRUE, pPlan->fPerMachine);
307 Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
308
309 BOOL fRollback = FALSE;
310 DWORD dwIndex = 0;
311 Assert::Equal(dwIndex, pPlan->cCacheActions);
312
313 fRollback = TRUE;
314 dwIndex = 0;
315 Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
316
317 Assert::Equal(0ull, pPlan->qwEstimatedSize);
318 Assert::Equal(0ull, pPlan->qwCacheSizeTotal);
319
320 fRollback = FALSE;
321 dwIndex = 0;
322 DWORD dwExecuteCheckpointId = 1;
323 ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
324 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", BURN_DEPENDENCY_ACTION_UNREGISTER);
325 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_UNREGISTER);
326 ValidateUninstallMsiCompatiblePackage(pPlan, fRollback, dwIndex++, L"PackageA", 0);
327 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
328 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
329 ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++);
330 Assert::Equal(dwIndex, pPlan->cExecuteActions);
331
332 fRollback = TRUE;
333 dwIndex = 0;
334 dwExecuteCheckpointId = 1;
335 ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
336 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
337 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
338 ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++);
339 Assert::Equal(dwIndex, pPlan->cRollbackActions);
340
341 Assert::Equal(1ul, pPlan->cExecutePackagesTotal);
342 Assert::Equal(1ul, pPlan->cOverallProgressTicksTotal);
343
344 dwIndex = 0;
345 ValidateCleanAction(pPlan, dwIndex++, L"PackageA");
346 ValidateCleanCompatibleAction(pPlan, dwIndex++, L"PackageA");
347 Assert::Equal(dwIndex, pPlan->cCleanActions);
348
349 UINT uIndex = 0;
350 ValidatePlannedProvider(pPlan, uIndex++, L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", NULL);
351 ValidatePlannedProvider(pPlan, uIndex++, L"{64633047-D172-4BBB-B202-64337D15C952}", NULL);
352 Assert::Equal(uIndex, pPlan->cPlannedProviders);
353
354 Assert::Equal(1ul, pEngineState->packages.cPackages);
355 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_ABSENT, BURN_PACKAGE_REGISTRATION_STATE_ABSENT);
356 }
357
358 [Fact]
291 void RelatedBundleMissingFromCacheTest() 359 void RelatedBundleMissingFromCacheTest()
292 { 360 {
293 HRESULT hr = S_OK; 361 HRESULT hr = S_OK;
@@ -1026,6 +1094,36 @@ namespace Bootstrapper
1026 } 1094 }
1027 } 1095 }
1028 1096
1097 void DetectCompatibleMsiPackage(BURN_PACKAGE* pPackage, LPCWSTR wzProductCode, LPCWSTR wzVersion)
1098 {
1099 HRESULT hr = S_OK;
1100 Assert(BOOTSTRAPPER_PACKAGE_STATE_PRESENT > pPackage->currentState);
1101 Assert(0 < pPackage->cDependencyProviders);
1102 BURN_DEPENDENCY_PROVIDER* pProvider = pPackage->rgDependencyProviders;
1103 BURN_COMPATIBLE_PACKAGE* pCompatiblePackage = &pPackage->compatiblePackage;
1104 pCompatiblePackage->fDetected = TRUE;
1105 pCompatiblePackage->fPlannable = TRUE;
1106 pCompatiblePackage->type = BURN_PACKAGE_TYPE_MSI;
1107
1108 hr = StrAllocFormatted(&pCompatiblePackage->sczCacheId, L"%lsv%ls", wzProductCode, wzVersion);
1109 NativeAssert::Succeeded(hr, "Failed to format cache id");
1110
1111 hr = StrAllocString(&pCompatiblePackage->Msi.sczVersion, wzVersion, 0);
1112 NativeAssert::Succeeded(hr, "Failed to copy MSI version");
1113
1114 hr = VerParseVersion(wzVersion, 0, FALSE, &pCompatiblePackage->Msi.pVersion);
1115 NativeAssert::Succeeded(hr, "Failed to parse MSI version");
1116
1117 hr = StrAllocString(&pCompatiblePackage->compatibleEntry.sczId, wzProductCode, 0);
1118 NativeAssert::Succeeded(hr, "Failed to copy product code");
1119
1120 hr = StrAllocString(&pCompatiblePackage->compatibleEntry.sczVersion, wzVersion, 0);
1121 NativeAssert::Succeeded(hr, "Failed to copy version");
1122
1123 hr = StrAllocString(&pCompatiblePackage->compatibleEntry.sczProviderKey, pProvider->sczKey, 0);
1124 NativeAssert::Succeeded(hr, "Failed to copy provider key");
1125 }
1126
1029 void DetectPackageAsAbsent(BURN_PACKAGE* pPackage) 1127 void DetectPackageAsAbsent(BURN_PACKAGE* pPackage)
1030 { 1128 {
1031 pPackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT; 1129 pPackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT;
@@ -1262,9 +1360,26 @@ namespace Bootstrapper
1262 __in LPCWSTR wzPackageId 1360 __in LPCWSTR wzPackageId
1263 ) 1361 )
1264 { 1362 {
1363 BURN_CLEAN_ACTION* pCleanAction = ValidateCleanActionExists(pPlan, dwIndex);
1364 Assert::Equal<DWORD>(BURN_CLEAN_ACTION_TYPE_PACKAGE, pCleanAction->type);
1365 Assert::NotEqual((DWORD_PTR)0, (DWORD_PTR)pCleanAction->pPackage);
1366 NativeAssert::StringEqual(wzPackageId, pCleanAction->pPackage->sczId);
1367 }
1368
1369 BURN_CLEAN_ACTION* ValidateCleanActionExists(BURN_PLAN* pPlan, DWORD dwIndex)
1370 {
1265 Assert::InRange(dwIndex + 1ul, 1ul, pPlan->cCleanActions); 1371 Assert::InRange(dwIndex + 1ul, 1ul, pPlan->cCleanActions);
1372 return pPlan->rgCleanActions + dwIndex;
1373 }
1266 1374
1267 BURN_CLEAN_ACTION* pCleanAction = pPlan->rgCleanActions + dwIndex; 1375 void ValidateCleanCompatibleAction(
1376 __in BURN_PLAN* pPlan,
1377 __in DWORD dwIndex,
1378 __in LPCWSTR wzPackageId
1379 )
1380 {
1381 BURN_CLEAN_ACTION* pCleanAction = ValidateCleanActionExists(pPlan, dwIndex);
1382 Assert::Equal<DWORD>(BURN_CLEAN_ACTION_TYPE_COMPATIBLE_PACKAGE, pCleanAction->type);
1268 Assert::NotEqual((DWORD_PTR)0, (DWORD_PTR)pCleanAction->pPackage); 1383 Assert::NotEqual((DWORD_PTR)0, (DWORD_PTR)pCleanAction->pPackage);
1269 NativeAssert::StringEqual(wzPackageId, pCleanAction->pPackage->sczId); 1384 NativeAssert::StringEqual(wzPackageId, pCleanAction->pPackage->sczId);
1270 } 1385 }
@@ -1537,6 +1652,22 @@ namespace Bootstrapper
1537 NativeAssert::StringEqual(wzKey, pProvider->sczKey); 1652 NativeAssert::StringEqual(wzKey, pProvider->sczKey);
1538 NativeAssert::StringEqual(wzName, pProvider->sczName); 1653 NativeAssert::StringEqual(wzName, pProvider->sczName);
1539 } 1654 }
1655
1656 void ValidateUninstallMsiCompatiblePackage(
1657 __in BURN_PLAN* pPlan,
1658 __in BOOL fRollback,
1659 __in DWORD dwIndex,
1660 __in_z LPCWSTR wzPackageId,
1661 __in DWORD dwLoggingAttributes
1662 )
1663 {
1664 BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex);
1665 Assert::Equal<DWORD>(BURN_EXECUTE_ACTION_TYPE_UNINSTALL_MSI_COMPATIBLE_PACKAGE, pAction->type);
1666 NativeAssert::StringEqual(wzPackageId, pAction->uninstallMsiCompatiblePackage.pParentPackage->sczId);
1667 NativeAssert::NotNull(pAction->msiPackage.sczLogPath);
1668 Assert::Equal<DWORD>(dwLoggingAttributes, pAction->uninstallMsiCompatiblePackage.dwLoggingAttributes);
1669 Assert::Equal<BOOL>(FALSE, pAction->fDeleted);
1670 }
1540 }; 1671 };
1541} 1672}
1542} 1673}