Add checkpoint so Exe and Msu packages rollback after being cancelled.
Fixes 5950
Sean Hall committed
Mar 18, 2022 at 20:16 UTC
fbc1a73743368211d5d8c7fc0625adf6eb9ca50c
10 files changed
+171
-57
src/burn/engine/apply.cpp
+71
-22
@@ -63,6 +63,7 @@ typedef struct _BURN_EXECUTE_CONTEXT
63
LPCWSTR wzExecutingPackageId;
64
DWORD cExecutedPackages;
65
DWORD cExecutePackagesTotal;
66
+ BOOL fAbandonedProcess;
67
} BURN_EXECUTE_CONTEXT;
68
69
@@ -322,6 +323,7 @@ static HRESULT ExecutePackageComplete(
323
__in BURN_VARIABLES* pVariables,
324
__in LPCWSTR wzPackageId,
325
__in BOOL fPackageVital,
326
+ __in BOOL fAbandonedProcess,
327
__in HRESULT hrOverall,
328
__in HRESULT hrExecute,
329
__in BOOL fRollback,
@@ -369,6 +371,7 @@ extern "C" void ApplyReset(
371
BURN_PACKAGE* pPackage = pPackages->rgPackages + i;
372
pPackage->hrCacheResult = S_OK;
373
pPackage->fReachedExecution = FALSE;
374
+ pPackage->fAbandonedProcess = FALSE;
375
pPackage->transactionRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN;
376
}
377
}
@@ -715,6 +718,9 @@ extern "C" HRESULT ApplyExecute(
718
continue;
719
}
720
721
+ context.wzExecutingPackageId = NULL;
722
+ context.fAbandonedProcess = FALSE;
723
+
724
// If we are seeking the end of the rollback boundary, skip if this action wasn't it.
725
if (fSeekRollbackBoundaryEnd)
726
{
@@ -2437,6 +2443,9 @@ static HRESULT DoRollbackActions(
2443
continue;
2444
}
2445
2446
+ pContext->wzExecutingPackageId = NULL;
2447
+ pContext->fAbandonedProcess = FALSE;
2448
+
2449
if (BURN_EXECUTE_ACTION_TYPE_CHECKPOINT == pRollbackAction->type)
2450
{
2451
if (pRollbackAction->checkpoint.dwId == dwCheckpoint)
@@ -2533,6 +2542,28 @@ LExit:
2542
return hr;
2543
}
2544
2545
+static BOOL ShouldSkipPackage(
2546
+ __in BURN_PACKAGE* pPackage,
2547
+ __in BOOL fRollback
2548
+ )
2549
+{
2550
+ BOOL fSkip = FALSE;
2551
+
2552
+ if (FAILED(pPackage->hrCacheResult))
2553
+ {
2554
+ LogId(REPORT_STANDARD, MSG_APPLY_SKIPPED_FAILED_CACHED_PACKAGE, pPackage->sczId, pPackage->hrCacheResult);
2555
+ ExitFunction1(fSkip = TRUE);
2556
+ }
2557
+ else if (fRollback && pPackage->fAbandonedProcess)
2558
+ {
2559
+ LogId(REPORT_STANDARD, MSG_APPLY_SKIPPED_PACKAGE_WITH_ABANDONED_PROCESS, pPackage->sczId);
2560
+ ExitFunction1(fSkip = TRUE);
2561
+ }
2562
+
2563
+LExit:
2564
+ return fSkip;
2565
+}
2566
+
2567
static HRESULT ExecuteRelatedBundle(
2568
__in BURN_ENGINE_STATE* pEngineState,
2569
__in BURN_EXECUTE_ACTION* pExecuteAction,
@@ -2551,13 +2582,13 @@ static HRESULT ExecuteRelatedBundle(
2582
BURN_RELATED_BUNDLE* pRelatedBundle = pExecuteAction->relatedBundle.pRelatedBundle;
2583
BURN_PACKAGE* pPackage = &pRelatedBundle->package;
2584
2554
- if (FAILED(pPackage->hrCacheResult))
2585
+ Assert(pContext->fRollback == fRollback);
2586
+
2587
+ if (ShouldSkipPackage(pPackage, fRollback))
2588
{
2556
- LogId(REPORT_STANDARD, MSG_APPLY_SKIPPED_FAILED_CACHED_PACKAGE, pPackage->sczId, pPackage->hrCacheResult);
2589
ExitFunction1(hr = S_OK);
2590
}
2591
2560
- Assert(pContext->fRollback == fRollback);
2592
pContext->wzExecutingPackageId = pPackage->sczId;
2593
fBeginCalled = TRUE;
2594
@@ -2599,7 +2630,8 @@ static HRESULT ExecuteRelatedBundle(
2630
LExit:
2631
if (fBeginCalled)
2632
{
2602
- hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage->sczId, pPackage->fVital, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
2633
+ pPackage->fAbandonedProcess = pContext->fAbandonedProcess;
2634
+ hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage->sczId, pPackage->fVital, pPackage->fAbandonedProcess, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
2635
}
2636
2637
return hr;
@@ -2624,6 +2656,9 @@ static HRESULT DoRestoreRelatedBundleActions(
2656
continue;
2657
}
2658
2659
+ pContext->wzExecutingPackageId = NULL;
2660
+ pContext->fAbandonedProcess = FALSE;
2661
+
2662
BOOTSTRAPPER_APPLY_RESTART restart = BOOTSTRAPPER_APPLY_RESTART_NONE;
2663
switch (pRestoreRelatedBundleAction->type)
2664
{
@@ -2665,13 +2700,13 @@ static HRESULT ExecuteExePackage(
2700
BOOL fExecuted = FALSE;
2701
BURN_PACKAGE* pPackage = pExecuteAction->exePackage.pPackage;
2702
2668
- if (FAILED(pPackage->hrCacheResult))
2703
+ Assert(pContext->fRollback == fRollback);
2704
+
2705
+ if (ShouldSkipPackage(pPackage, fRollback))
2706
{
2670
- LogId(REPORT_STANDARD, MSG_APPLY_SKIPPED_FAILED_CACHED_PACKAGE, pPackage->sczId, pPackage->hrCacheResult);
2707
ExitFunction1(hr = S_OK);
2708
}
2709
2674
- Assert(pContext->fRollback == fRollback);
2710
pContext->wzExecutingPackageId = pPackage->sczId;
2711
fBeginCalled = TRUE;
2712
@@ -2720,7 +2755,8 @@ LExit:
2755
2756
if (fBeginCalled)
2757
{
2723
- hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage->sczId, pPackage->fVital, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
2758
+ pPackage->fAbandonedProcess = pContext->fAbandonedProcess;
2759
+ hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage->sczId, pPackage->fVital, pPackage->fAbandonedProcess, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
2760
}
2761
2762
return hr;
@@ -2743,13 +2779,13 @@ static HRESULT ExecuteMsiPackage(
2779
BOOL fExecuted = FALSE;
2780
BURN_PACKAGE* pPackage = pExecuteAction->msiPackage.pPackage;
2781
2746
- if (FAILED(pPackage->hrCacheResult))
2782
+ Assert(pContext->fRollback == fRollback);
2783
+
2784
+ if (ShouldSkipPackage(pPackage, fRollback))
2785
{
2748
- LogId(REPORT_STANDARD, MSG_APPLY_SKIPPED_FAILED_CACHED_PACKAGE, pPackage->sczId, pPackage->hrCacheResult);
2786
ExitFunction1(hr = S_OK);
2787
}
2788
2752
- Assert(pContext->fRollback == fRollback);
2789
pContext->wzExecutingPackageId = pPackage->sczId;
2790
fBeginCalled = TRUE;
2791
@@ -2784,7 +2820,8 @@ LExit:
2820
2821
if (fBeginCalled)
2822
{
2787
- hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage->sczId, pPackage->fVital, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
2823
+ Assert(!pContext->fAbandonedProcess);
2824
+ hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage->sczId, pPackage->fVital, FALSE, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
2825
}
2826
2827
return hr;
@@ -2807,13 +2844,13 @@ static HRESULT ExecuteMspPackage(
2844
BOOL fExecuted = FALSE;
2845
BURN_PACKAGE* pPackage = pExecuteAction->mspTarget.pPackage;
2846
2810
- if (FAILED(pPackage->hrCacheResult))
2847
+ Assert(pContext->fRollback == fRollback);
2848
+
2849
+ if (ShouldSkipPackage(pPackage, fRollback))
2850
{
2812
- LogId(REPORT_STANDARD, MSG_APPLY_SKIPPED_FAILED_CACHED_PACKAGE, pPackage->sczId, pPackage->hrCacheResult);
2851
ExitFunction1(hr = S_OK);
2852
}
2853
2816
- Assert(pContext->fRollback == fRollback);
2854
pContext->wzExecutingPackageId = pPackage->sczId;
2855
fBeginCalled = TRUE;
2856
@@ -2857,7 +2894,8 @@ LExit:
2894
2895
if (fBeginCalled)
2896
{
2860
- hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage->sczId, pPackage->fVital, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
2897
+ Assert(!pContext->fAbandonedProcess);
2898
+ hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage->sczId, pPackage->fVital, FALSE, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
2899
}
2900
2901
return hr;
@@ -2882,13 +2920,13 @@ static HRESULT ExecuteMsuPackage(
2920
BOOL fExecuted = FALSE;
2921
BURN_PACKAGE* pPackage = pExecuteAction->msuPackage.pPackage;
2922
2885
- if (FAILED(pPackage->hrCacheResult))
2923
+ Assert(pContext->fRollback == fRollback);
2924
+
2925
+ if (ShouldSkipPackage(pPackage, fRollback))
2926
{
2887
- LogId(REPORT_STANDARD, MSG_APPLY_SKIPPED_FAILED_CACHED_PACKAGE, pPackage->sczId, pPackage->hrCacheResult);
2927
ExitFunction1(hr = S_OK);
2928
}
2929
2891
- Assert(pContext->fRollback == fRollback);
2930
pContext->wzExecutingPackageId = pPackage->sczId;
2931
fBeginCalled = TRUE;
2932
@@ -2937,7 +2975,8 @@ LExit:
2975
2976
if (fBeginCalled)
2977
{
2940
- hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage->sczId, pPackage->fVital, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
2978
+ pPackage->fAbandonedProcess = pContext->fAbandonedProcess;
2979
+ hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage->sczId, pPackage->fVital, pPackage->fAbandonedProcess, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
2980
}
2981
2982
return hr;
@@ -3256,7 +3295,8 @@ LExit:
3295
3296
if (fBeginCalled)
3297
{
3259
- hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pContext->wzExecutingPackageId, FALSE, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
3298
+ Assert(!pContext->fAbandonedProcess);
3299
+ hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pContext->wzExecutingPackageId, FALSE, FALSE, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
3300
}
3301
3302
return hr;
@@ -3334,6 +3374,14 @@ static int GenericExecuteMessageHandler(
3374
}
3375
break;
3376
3377
+ case GENERIC_EXECUTE_MESSAGE_PROCESS_STARTED:
3378
+ pContext->fAbandonedProcess = TRUE;
3379
+ break;
3380
+
3381
+ case GENERIC_EXECUTE_MESSAGE_PROCESS_COMPLETED:
3382
+ pContext->fAbandonedProcess = FALSE;
3383
+ break;
3384
+
3385
case GENERIC_EXECUTE_MESSAGE_ERROR:
3386
UserExperienceOnError(pContext->pUX, BOOTSTRAPPER_ERROR_TYPE_EXE_PACKAGE, pContext->wzExecutingPackageId, pMessage->error.dwErrorCode, pMessage->error.wzMessage, pMessage->dwUIHint, 0, NULL, &nResult); // ignore return value.
3387
break;
@@ -3428,6 +3476,7 @@ static HRESULT ExecutePackageComplete(
3476
__in BURN_VARIABLES* pVariables,
3477
__in LPCWSTR wzPackageId,
3478
__in BOOL fPackageVital,
3479
+ __in BOOL fAbandonedProcess,
3480
__in HRESULT hrOverall,
3481
__in HRESULT hrExecute,
3482
__in BOOL fRollback,
@@ -3445,7 +3494,7 @@ static HRESULT ExecutePackageComplete(
3494
{
3495
*pRestart = BOOTSTRAPPER_APPLY_RESTART_INITIATED;
3496
}
3448
- *pfRetry = (FAILED(hrExecute) && BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION_RETRY == executePackageCompleteAction); // allow retry only on failures.
3497
+ *pfRetry = (FAILED(hrExecute) && BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION_RETRY == executePackageCompleteAction && !fAbandonedProcess); // allow retry only on failures.
3498
*pfSuspend = (BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION_SUSPEND == executePackageCompleteAction);
3499
3500
// Remember this package as the package that initiated the forced restart.
src/burn/engine/apply.h
+2
@@ -14,6 +14,8 @@ enum GENERIC_EXECUTE_MESSAGE_TYPE
14
GENERIC_EXECUTE_MESSAGE_PROGRESS,
15
GENERIC_EXECUTE_MESSAGE_NETFX_FILES_IN_USE,
16
GENERIC_EXECUTE_MESSAGE_PROCESS_CANCEL,
17
+ GENERIC_EXECUTE_MESSAGE_PROCESS_STARTED,
18
+ GENERIC_EXECUTE_MESSAGE_PROCESS_COMPLETED,
19
};
20
21
typedef struct _APPLY_AUTHENTICATION_REQUIRED_DATA
src/burn/engine/elevation.cpp
+18
@@ -44,6 +44,8 @@ typedef enum _BURN_ELEVATION_MESSAGE_TYPE
44
BURN_ELEVATION_MESSAGE_TYPE_BURN_CACHE_SUCCESS,
45
BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PROGRESS,
46
BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PROCESS_CANCEL,
47
+ BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PROCESS_STARTED,
48
+ BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PROCESS_COMPLETED,
49
BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_ERROR,
50
BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_MSI_MESSAGE,
51
BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_MSI_FILES_IN_USE,
@@ -1823,6 +1825,14 @@ static HRESULT ProcessGenericExecuteMessages(
1825
ExitOnFailure(hr, "Failed to read processId.");
1826
break;
1827
1828
+ case BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PROCESS_STARTED:
1829
+ message.type = GENERIC_EXECUTE_MESSAGE_PROCESS_STARTED;
1830
+ break;
1831
+
1832
+ case BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PROCESS_COMPLETED:
1833
+ message.type = GENERIC_EXECUTE_MESSAGE_PROCESS_COMPLETED;
1834
+ break;
1835
+
1836
case BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_ERROR:
1837
message.type = GENERIC_EXECUTE_MESSAGE_ERROR;
1838
@@ -3465,6 +3475,14 @@ static int GenericExecuteMessageHandler(
3475
dwMessage = BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PROCESS_CANCEL;
3476
break;
3477
3478
+ case GENERIC_EXECUTE_MESSAGE_PROCESS_STARTED:
3479
+ dwMessage = BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PROCESS_STARTED;
3480
+ break;
3481
+
3482
+ case GENERIC_EXECUTE_MESSAGE_PROCESS_COMPLETED:
3483
+ dwMessage = BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PROCESS_COMPLETED;
3484
+ break;
3485
+
3486
case GENERIC_EXECUTE_MESSAGE_ERROR:
3487
// serialize message data
3488
hr = BuffWriteNumber(&pbData, &cbData, pMessage->error.dwErrorCode);
src/burn/engine/engine.mc
+7
@@ -940,6 +940,13 @@ Language=English
940
Bootstrapper application requested delayed cancel during package process progress, id: %1!ls!. Waiting...
941
.
942
943
+MessageId=365
944
+Severity=Success
945
+SymbolicName=MSG_APPLY_SKIPPED_PACKAGE_WITH_ABANDONED_PROCESS
946
+Language=English
947
+Skipping rollback of package: %1!ls! due to abandoning its process. Continuing...
948
+.
949
+
950
MessageId=370
951
Severity=Success
952
SymbolicName=MSG_SESSION_BEGIN
src/burn/engine/exeengine.cpp
+25
-12
@@ -276,30 +276,33 @@ extern "C" HRESULT ExeEnginePlanAddPackage(
276
hr = DependencyPlanPackage(NULL, pPackage, pPlan);
277
ExitOnFailure(hr, "Failed to plan package dependency actions.");
278
279
- // add execute action
280
- if (BOOTSTRAPPER_ACTION_STATE_NONE != pPackage->execute)
279
+ // add rollback action
280
+ if (BOOTSTRAPPER_ACTION_STATE_NONE != pPackage->rollback)
281
{
282
- hr = PlanAppendExecuteAction(pPlan, &pAction);
283
- ExitOnFailure(hr, "Failed to append execute action.");
282
+ hr = PlanAppendRollbackAction(pPlan, &pAction);
283
+ ExitOnFailure(hr, "Failed to append rollback action.");
284
285
pAction->type = BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE;
286
pAction->exePackage.pPackage = pPackage;
287
- pAction->exePackage.action = pPackage->execute;
287
+ pAction->exePackage.action = pPackage->rollback;
288
289
- LoggingSetPackageVariable(pPackage, NULL, FALSE, pLog, pVariables, NULL); // ignore errors.
289
+ LoggingSetPackageVariable(pPackage, NULL, TRUE, pLog, pVariables, NULL); // ignore errors.
290
+
291
+ hr = PlanExecuteCheckpoint(pPlan);
292
+ ExitOnFailure(hr, "Failed to append execute checkpoint.");
293
}
294
292
- // add rollback action
293
- if (BOOTSTRAPPER_ACTION_STATE_NONE != pPackage->rollback)
295
+ // add execute action
296
+ if (BOOTSTRAPPER_ACTION_STATE_NONE != pPackage->execute)
297
{
295
- hr = PlanAppendRollbackAction(pPlan, &pAction);
296
- ExitOnFailure(hr, "Failed to append rollback action.");
298
+ hr = PlanAppendExecuteAction(pPlan, &pAction);
299
+ ExitOnFailure(hr, "Failed to append execute action.");
300
301
pAction->type = BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE;
302
pAction->exePackage.pPackage = pPackage;
300
- pAction->exePackage.action = pPackage->rollback;
303
+ pAction->exePackage.action = pPackage->execute;
304
302
- LoggingSetPackageVariable(pPackage, NULL, TRUE, pLog, pVariables, NULL); // ignore errors.
305
+ LoggingSetPackageVariable(pPackage, NULL, FALSE, pLog, pVariables, NULL); // ignore errors.
306
}
307
308
LExit:
@@ -493,6 +496,10 @@ extern "C" HRESULT ExeEngineRunProcess(
496
ExitWithLastError(hr, "Failed to CreateProcess on path: %ls", wzExecutablePath);
497
}
498
499
+ message.type = GENERIC_EXECUTE_MESSAGE_PROCESS_STARTED;
500
+ message.dwUIHint = MB_OK;
501
+ pfnGenericMessageHandler(&message, pvContext);
502
+
503
if (fFireAndForget)
504
{
505
::WaitForInputIdle(pi.hProcess, 5000);
@@ -504,6 +511,7 @@ extern "C" HRESULT ExeEngineRunProcess(
511
// Wait for the executable process while sending fake progress to allow cancel.
512
do
513
{
514
+ memset(&message, 0, sizeof(message));
515
message.type = GENERIC_EXECUTE_MESSAGE_PROGRESS;
516
message.dwUIHint = MB_OKCANCEL;
517
message.progress.dwPercentage = 50;
@@ -546,6 +554,11 @@ extern "C" HRESULT ExeEngineRunProcess(
554
}
555
} while (HRESULT_FROM_WIN32(WAIT_TIMEOUT) == hr);
556
557
+ memset(&message, 0, sizeof(message));
558
+ message.type = GENERIC_EXECUTE_MESSAGE_PROCESS_COMPLETED;
559
+ message.dwUIHint = MB_OK;
560
+ pfnGenericMessageHandler(&message, pvContext);
561
+
562
if (fDelayedCancel)
563
{
564
ExitWithRootFailure(hr, HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT), "Bootstrapper application cancelled during package process progress, exit code: 0x%x", *pdwExitCode);
src/burn/engine/msuengine.cpp
+15
-12
@@ -222,30 +222,33 @@ extern "C" HRESULT MsuEnginePlanAddPackage(
222
hr = DependencyPlanPackage(NULL, pPackage, pPlan);
223
ExitOnFailure(hr, "Failed to plan package dependency actions.");
224
225
- // add execute action
226
- if (BOOTSTRAPPER_ACTION_STATE_NONE != pPackage->execute)
225
+ // add rollback action
226
+ if (BOOTSTRAPPER_ACTION_STATE_NONE != pPackage->rollback)
227
{
228
- hr = PlanAppendExecuteAction(pPlan, &pAction);
229
- ExitOnFailure(hr, "Failed to append execute action.");
228
+ hr = PlanAppendRollbackAction(pPlan, &pAction);
229
+ ExitOnFailure(hr, "Failed to append rollback action.");
230
231
pAction->type = BURN_EXECUTE_ACTION_TYPE_MSU_PACKAGE;
232
pAction->msuPackage.pPackage = pPackage;
233
- pAction->msuPackage.action = pPackage->execute;
233
+ pAction->msuPackage.action = pPackage->rollback;
234
235
- LoggingSetPackageVariable(pPackage, NULL, FALSE, pLog, pVariables, &pAction->msuPackage.sczLogPath); // ignore errors.
235
+ LoggingSetPackageVariable(pPackage, NULL, TRUE, pLog, pVariables, &pAction->msuPackage.sczLogPath); // ignore errors.
236
+
237
+ hr = PlanExecuteCheckpoint(pPlan);
238
+ ExitOnFailure(hr, "Failed to append execute checkpoint.");
239
}
240
238
- // add rollback action
239
- if (BOOTSTRAPPER_ACTION_STATE_NONE != pPackage->rollback)
241
+ // add execute action
242
+ if (BOOTSTRAPPER_ACTION_STATE_NONE != pPackage->execute)
243
{
241
- hr = PlanAppendRollbackAction(pPlan, &pAction);
242
- ExitOnFailure(hr, "Failed to append rollback action.");
244
+ hr = PlanAppendExecuteAction(pPlan, &pAction);
245
+ ExitOnFailure(hr, "Failed to append execute action.");
246
247
pAction->type = BURN_EXECUTE_ACTION_TYPE_MSU_PACKAGE;
248
pAction->msuPackage.pPackage = pPackage;
246
- pAction->msuPackage.action = pPackage->rollback;
249
+ pAction->msuPackage.action = pPackage->execute;
250
248
- LoggingSetPackageVariable(pPackage, NULL, TRUE, pLog, pVariables, &pAction->msuPackage.sczLogPath); // ignore errors.
251
+ LoggingSetPackageVariable(pPackage, NULL, FALSE, pLog, pVariables, &pAction->msuPackage.sczLogPath); // ignore errors.
252
}
253
254
LExit:
src/burn/engine/package.h
+1
@@ -282,6 +282,7 @@ typedef struct _BURN_PACKAGE
282
LPWSTR sczCacheFolder; // only valid during Apply.
283
HRESULT hrCacheResult; // only valid during Apply.
284
BOOL fReachedExecution; // only valid during Apply.
285
+ BOOL fAbandonedProcess; // only valid during Apply.
286
287
BURN_PACKAGE_REGISTRATION_STATE cacheRegistrationState; // initialized during Detect, updated during Apply.
288
BURN_PACKAGE_REGISTRATION_STATE installRegistrationState; // initialized during Detect, updated during Apply.
src/burn/test/BurnUnitTest/PlanTest.cpp
+4
@@ -715,6 +715,7 @@ namespace Bootstrapper
715
ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
716
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
717
ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"ExeA");
718
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
719
ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"ExeA", BOOTSTRAPPER_ACTION_STATE_INSTALL);
720
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
721
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
@@ -729,6 +730,7 @@ namespace Bootstrapper
730
ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"ExeA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL);
731
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
732
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
733
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
734
ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++);
735
Assert::Equal(dwIndex, pPlan->cRollbackActions);
736
@@ -1682,6 +1684,7 @@ namespace Bootstrapper
1684
ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
1685
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
1686
ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"test.msu");
1687
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
1688
ValidateExecuteMsuPackage(pPlan, fRollback, dwIndex++, L"test.msu", BOOTSTRAPPER_ACTION_STATE_INSTALL);
1689
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
1690
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
@@ -1697,6 +1700,7 @@ namespace Bootstrapper
1700
ValidateExecuteMsuPackage(pPlan, fRollback, dwIndex++, L"test.msu", BOOTSTRAPPER_ACTION_STATE_UNINSTALL);
1701
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
1702
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
1703
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
1704
ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++);
1705
Assert::Equal(dwIndex, pPlan->cRollbackActions);
1706
src/test/burn/TestBA/TestBA.cs
+22
-3
@@ -4,6 +4,7 @@ namespace WixToolset.Test.BA
4
{
5
using System;
6
using System.Collections.Generic;
7
+ using System.Diagnostics;
8
using System.IO;
9
using System.Linq;
10
using System.Threading;
@@ -37,6 +38,7 @@ namespace WixToolset.Test.BA
38
private string cancelExecuteActionName;
39
private int cancelOnProgressAtProgress;
40
private int retryExecuteFilesInUse;
41
+ private bool rollingBack;
42
43
private IBootstrapperCommand Command { get; }
44
@@ -350,6 +352,8 @@ namespace WixToolset.Test.BA
352
{
353
this.Log("OnExecutePackageBegin() - package: {0}, rollback: {1}", args.PackageId, !args.ShouldExecute);
354
355
+ this.rollingBack = !args.ShouldExecute;
356
+
357
string slowProgress = this.ReadPackageAction(args.PackageId, "SlowExecute");
358
if (String.IsNullOrEmpty(slowProgress) || !Int32.TryParse(slowProgress, out this.sleepDuringExecute))
359
{
@@ -404,7 +408,7 @@ namespace WixToolset.Test.BA
408
if (!String.IsNullOrEmpty(recordTestRegistryValue) && Boolean.TryParse(recordTestRegistryValue, out logTestRegistryValue) && logTestRegistryValue)
409
{
410
var value = this.ReadTestRegistryValue(args.PackageId);
407
- this.Log("TestRegistryValue: {0}, Version, '{1}'", args.PackageId, value);
411
+ this.Log("TestRegistryValue: {0}, {1}, Version, '{2}'", this.rollingBack ? "Rollback" : "Execute", args.PackageId, value);
412
}
413
}
414
@@ -419,8 +423,22 @@ namespace WixToolset.Test.BA
423
424
if (args.Action == BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION.Abandon)
425
{
422
- // Give time to the process to start before its files are deleted.
423
- Thread.Sleep(2000);
426
+ // Kill process to make sure it doesn't affect other tests.
427
+ try
428
+ {
429
+ using (Process process = Process.GetProcessById(args.ProcessId))
430
+ {
431
+ if (process != null)
432
+ {
433
+ process.Kill();
434
+ }
435
+ }
436
+ }
437
+ catch (Exception e)
438
+ {
439
+ this.Log("Failed to kill process {0}: {1}", args.ProcessId, e);
440
+ Thread.Sleep(5000);
441
+ }
442
}
443
444
this.Log("OnExecuteProcessCancel({0})", args.Action);
@@ -494,6 +512,7 @@ namespace WixToolset.Test.BA
512
this.cancelOnProgressAtProgress = -1;
513
this.cancelExecuteAtProgress = -1;
514
this.cancelCacheAtProgress = -1;
515
+ this.rollingBack = false;
516
}
517
518
protected override void OnApplyComplete(ApplyCompleteEventArgs args)
src/test/burn/WixToolsetTest.BurnE2E/FailureTests.cs
+6
-8
@@ -25,12 +25,8 @@ namespace WixToolsetTest.BurnE2E
25
var logPath = bundleD.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_USEREXIT);
26
bundleD.VerifyUnregisteredAndRemovedFromPackageCache();
27
28
- Assert.True(LogVerifier.MessageInLogFile(logPath, "TestRegistryValue: ExeA, Version, ''"));
29
-
30
- // Make sure ExeA finishes running.
31
- Thread.Sleep(3000);
32
-
33
- bundleD.VerifyExeTestRegistryValue("ExeA", "1.0.0.0");
28
+ Assert.True(LogVerifier.MessageInLogFile(logPath, "TestRegistryValue: Execute, ExeA, Version, ''"));
29
+ Assert.False(LogVerifier.MessageInLogFile(logPath, "TestRegistryValue: Rollback, ExeA, Version"));
30
}
31
32
[Fact]
@@ -47,9 +43,11 @@ namespace WixToolsetTest.BurnE2E
43
var logPath = bundleD.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_USEREXIT);
44
bundleD.VerifyUnregisteredAndRemovedFromPackageCache();
45
50
- Assert.True(LogVerifier.MessageInLogFile(logPath, "TestRegistryValue: ExeA, Version, '1.0.0.0'"));
46
+ Assert.True(LogVerifier.MessageInLogFile(logPath, "TestRegistryValue: Execute, ExeA, Version, '1.0.0.0'"));
47
+ Assert.True(LogVerifier.MessageInLogFile(logPath, "TestRegistryValue: Rollback, ExeA, Version, ''"));
48
52
- bundleD.VerifyExeTestRegistryValue("ExeA", "1.0.0.0");
49
+ // The package should have rolled back.
50
+ bundleD.VerifyExeTestRegistryRootDeleted("ExeA");
51
}
52
53
[Fact]