Use plan to decide when to begin, commit, or rollback MSI transactions
Sean Hall committed
Nov 15, 2020 at 21:38 UTC
e71de85e4ec2899ecd01ac236603cf1dddc4a6c7
9 files changed
+226
-149
src/engine/apply.cpp
+95
-99
@@ -3,6 +3,12 @@
3
#include "precomp.h"
4
5
6
+#ifdef DEBUG
7
+ #define IgnoreRollbackError(x, f, ...) if (FAILED(x)) { TraceError(x, f, __VA_ARGS__); }
8
+#else
9
+ #define IgnoreRollbackError(x, f, ...)
10
+#endif
11
+
12
const DWORD BURN_CACHE_MAX_RECOMMENDED_VERIFY_TRYAGAIN_ATTEMPTS = 2;
13
14
// structs
@@ -134,7 +140,7 @@ static HRESULT DoExecuteAction(
140
__in_opt HANDLE hCacheThread,
141
__in BURN_EXECUTE_CONTEXT* pContext,
142
__inout BURN_ROLLBACK_BOUNDARY** ppRollbackBoundary,
137
- __out DWORD* pdwCheckpoint,
143
+ __inout BURN_EXECUTE_ACTION_CHECKPOINT** ppCheckpoint,
144
__out BOOL* pfKeepRegistration,
145
__out BOOL* pfSuspend,
146
__out BOOTSTRAPPER_APPLY_RESTART* pRestart
@@ -143,7 +149,6 @@ static HRESULT DoRollbackActions(
149
__in BURN_ENGINE_STATE* pEngineState,
150
__in BURN_EXECUTE_CONTEXT* pContext,
151
__in DWORD dwCheckpoint,
146
- __in BOOL fInTransaction,
152
__out BOOL* pfKeepRegistration,
153
__out BOOTSTRAPPER_APPLY_RESTART* pRestart
154
);
@@ -200,15 +205,17 @@ static HRESULT ExecuteCompatiblePackageAction(
205
);
206
static HRESULT ExecuteMsiBeginTransaction(
207
__in BURN_ENGINE_STATE* pEngineState,
203
- __in LPCWSTR wzName,
208
+ __in BURN_ROLLBACK_BOUNDARY* pRollbackBoundary,
209
__in BURN_EXECUTE_CONTEXT* pContext
210
);
211
static HRESULT ExecuteMsiCommitTransaction(
212
__in BURN_ENGINE_STATE* pEngineState,
213
+ __in BURN_ROLLBACK_BOUNDARY* pRollbackBoundary,
214
__in BURN_EXECUTE_CONTEXT* pContext
215
);
216
static HRESULT ExecuteMsiRollbackTransaction(
217
__in BURN_ENGINE_STATE* pEngineState,
218
+ __in BURN_ROLLBACK_BOUNDARY* pRollbackBoundary,
219
__in BURN_EXECUTE_CONTEXT* pContext
220
);
221
static HRESULT CleanPackage(
@@ -732,11 +739,11 @@ extern "C" HRESULT ApplyExecute(
739
)
740
{
741
HRESULT hr = S_OK;
735
- DWORD dwCheckpoint = 0;
742
+ HRESULT hrRollback = S_OK;
743
+ BURN_EXECUTE_ACTION_CHECKPOINT* pCheckpoint = NULL;
744
BURN_EXECUTE_CONTEXT context = { };
745
BURN_ROLLBACK_BOUNDARY* pRollbackBoundary = NULL;
746
BOOL fSeekNextRollbackBoundary = FALSE;
739
- BOOL fInTransaction = FALSE;
747
748
context.pUX = &pEngineState->userExperience;
749
context.cExecutePackagesTotal = pEngineState->plan.cExecutePackagesTotal;
@@ -755,36 +762,6 @@ extern "C" HRESULT ApplyExecute(
762
continue;
763
}
764
758
- // Transaction end/start
759
- if (BURN_EXECUTE_ACTION_TYPE_ROLLBACK_BOUNDARY == pExecuteAction->type)
760
- {
761
- // End previous transaction
762
- if (fInTransaction)
763
- {
764
- LogString(REPORT_STANDARD, "Committing MSI transaction\n");
765
- hr = ExecuteMsiCommitTransaction(pEngineState, &context);
766
- ExitOnFailure(hr, "Failed committing an MSI transaction");
767
- fInTransaction = FALSE;
768
- }
769
-
770
- // Start New transaction
771
- if (!fInTransaction && pExecuteAction->rollbackBoundary.pRollbackBoundary && pExecuteAction->rollbackBoundary.pRollbackBoundary->fTransaction)
772
- {
773
- // Transactions don't go together with DisableRollback.
774
- if (pEngineState->fDisableRollback)
775
- {
776
- LogString(REPORT_STANDARD, "Ignoring Transaction flag due to DisableRollback flag\n");
777
- }
778
- else
779
- {
780
- LogString(REPORT_STANDARD, "Starting a new MSI transaction\n");
781
- hr = ExecuteMsiBeginTransaction(pEngineState, pExecuteAction->rollbackBoundary.pRollbackBoundary->sczId, &context);
782
- ExitOnFailure(hr, "Failed beginning an MSI transaction");
783
- fInTransaction = TRUE;
784
- }
785
- }
786
- }
787
-
765
// If we are seeking the next rollback boundary, skip if this action wasn't it.
766
if (fSeekNextRollbackBoundary)
767
{
@@ -799,11 +776,11 @@ extern "C" HRESULT ApplyExecute(
776
}
777
778
// Execute the action.
802
- hr = DoExecuteAction(pEngineState, pExecuteAction, hCacheThread, &context, &pRollbackBoundary, &dwCheckpoint, pfKeepRegistration, pfSuspend, pRestart);
779
+ hr = DoExecuteAction(pEngineState, pExecuteAction, hCacheThread, &context, &pRollbackBoundary, &pCheckpoint, pfKeepRegistration, pfSuspend, pRestart);
780
781
if (*pfSuspend || BOOTSTRAPPER_APPLY_RESTART_INITIATED == *pRestart)
782
{
806
- if (fInTransaction)
783
+ if (pCheckpoint && pCheckpoint->pActiveRollbackBoundary && pCheckpoint->pActiveRollbackBoundary->fActiveTransaction)
784
{
785
hr = E_INVALIDSTATE;
786
LogString(REPORT_ERROR, "Ilegal state: Reboot requested within an MSI transaction. Transaction will rollback.");
@@ -816,37 +793,43 @@ extern "C" HRESULT ApplyExecute(
793
794
if (FAILED(hr))
795
{
819
- // If we failed, but rollback is disabled just bail with our error code.
820
- if (pEngineState->fDisableRollback)
796
+ // If rollback is disabled, keep what we have and always end execution here.
797
+ if (pEngineState->plan.fDisableRollback)
798
{
799
+ if (pCheckpoint && pCheckpoint->pActiveRollbackBoundary && pCheckpoint->pActiveRollbackBoundary->fActiveTransaction)
800
+ {
801
+ hrRollback = ExecuteMsiCommitTransaction(pEngineState, pCheckpoint->pActiveRollbackBoundary, &context);
802
+ IgnoreRollbackError(hrRollback, "Failed commit transaction from disable rollback");
803
+ }
804
+
805
*pfRollback = TRUE;
806
break;
807
}
825
- else // the action failed, roll back to previous rollback boundary.
808
+
809
+ // If inside a MSI transaction, roll it back.
810
+ if (pCheckpoint && pCheckpoint->pActiveRollbackBoundary && pCheckpoint->pActiveRollbackBoundary->fActiveTransaction)
811
{
827
- HRESULT hrRollback = DoRollbackActions(pEngineState, &context, dwCheckpoint, fInTransaction, pfKeepRegistration, pRestart);
828
- UNREFERENCED_PARAMETER(hrRollback);
829
- fInTransaction = FALSE;
812
+ hrRollback = ExecuteMsiRollbackTransaction(pEngineState, pCheckpoint->pActiveRollbackBoundary, &context);
813
+ IgnoreRollbackError(hrRollback, "Failed rolling back transaction");
814
+ }
815
831
- // If the rollback boundary is vital, end execution here.
832
- if (pRollbackBoundary && pRollbackBoundary->fVital)
833
- {
834
- *pfRollback = TRUE;
835
- break;
836
- }
816
+ // The action failed, roll back to previous rollback boundary.
817
+ if (pCheckpoint)
818
+ {
819
+ hrRollback = DoRollbackActions(pEngineState, &context, pCheckpoint->dwId, pfKeepRegistration, pRestart);
820
+ IgnoreRollbackError(hrRollback, "Failed rollback actions");
821
+ }
822
838
- // Move forward to next rollback boundary.
839
- fSeekNextRollbackBoundary = TRUE;
823
+ // If the rollback boundary is vital, end execution here.
824
+ if (pRollbackBoundary && pRollbackBoundary->fVital)
825
+ {
826
+ *pfRollback = TRUE;
827
+ break;
828
}
841
- }
842
- }
829
844
- if (fInTransaction)
845
- {
846
- LogString(REPORT_STANDARD, "Committing an MSI transaction\n");
847
- hr = ExecuteMsiCommitTransaction(pEngineState, &context);
848
- ExitOnFailure(hr, "Failed committing an MSI transaction");
849
- fInTransaction = FALSE;
830
+ // Move forward to next rollback boundary.
831
+ fSeekNextRollbackBoundary = TRUE;
832
+ }
833
}
834
835
LExit:
@@ -1653,7 +1636,7 @@ static HRESULT DoExecuteAction(
1636
__in_opt HANDLE hCacheThread,
1637
__in BURN_EXECUTE_CONTEXT* pContext,
1638
__inout BURN_ROLLBACK_BOUNDARY** ppRollbackBoundary,
1656
- __out DWORD* pdwCheckpoint,
1639
+ __inout BURN_EXECUTE_ACTION_CHECKPOINT** ppCheckpoint,
1640
__out BOOL* pfKeepRegistration,
1641
__out BOOL* pfSuspend,
1642
__out BOOTSTRAPPER_APPLY_RESTART* pRestart
@@ -1674,7 +1657,7 @@ static HRESULT DoExecuteAction(
1657
switch (pExecuteAction->type)
1658
{
1659
case BURN_EXECUTE_ACTION_TYPE_CHECKPOINT:
1677
- *pdwCheckpoint = pExecuteAction->checkpoint.dwId;
1660
+ *ppCheckpoint = &pExecuteAction->checkpoint;
1661
break;
1662
1663
case BURN_EXECUTE_ACTION_TYPE_WAIT_SYNCPOINT:
@@ -1748,6 +1731,18 @@ static HRESULT DoExecuteAction(
1731
*ppRollbackBoundary = pExecuteAction->rollbackBoundary.pRollbackBoundary;
1732
break;
1733
1734
+ case BURN_EXECUTE_ACTION_TYPE_BEGIN_MSI_TRANSACTION:
1735
+ LogString(REPORT_STANDARD, "Starting a new MSI transaction\n");
1736
+ hr = ExecuteMsiBeginTransaction(pEngineState, pExecuteAction->msiTransaction.pRollbackBoundary, pContext);
1737
+ ExitOnFailure(hr, "Failed to execute begin MSI transaction action.");
1738
+ break;
1739
+
1740
+ case BURN_EXECUTE_ACTION_TYPE_COMMIT_MSI_TRANSACTION:
1741
+ LogString(REPORT_STANDARD, "Committing MSI transaction\n");
1742
+ hr = ExecuteMsiCommitTransaction(pEngineState, pExecuteAction->msiTransaction.pRollbackBoundary, pContext);
1743
+ ExitOnFailure(hr, "Failed to execute commit MSI transaction action.");
1744
+ break;
1745
+
1746
case BURN_EXECUTE_ACTION_TYPE_SERVICE_STOP: __fallthrough;
1747
case BURN_EXECUTE_ACTION_TYPE_SERVICE_START: __fallthrough;
1748
default:
@@ -1769,7 +1764,6 @@ static HRESULT DoRollbackActions(
1764
__in BURN_ENGINE_STATE* pEngineState,
1765
__in BURN_EXECUTE_CONTEXT* pContext,
1766
__in DWORD dwCheckpoint,
1772
- __in BOOL fInTransaction,
1767
__out BOOL* pfKeepRegistration,
1768
__out BOOTSTRAPPER_APPLY_RESTART* pRestart
1769
)
@@ -1781,13 +1775,6 @@ static HRESULT DoRollbackActions(
1775
1776
pContext->fRollback = TRUE;
1777
1784
- // Rollback MSI transaction
1785
- if (fInTransaction)
1786
- {
1787
- hr = ExecuteMsiRollbackTransaction(pEngineState, pContext);
1788
- ExitOnFailure(hr, "Failed rolling back transaction");
1789
- }
1790
-
1778
// scan to last checkpoint
1779
for (DWORD i = 0; i < pEngineState->plan.cRollbackActions; ++i)
1780
{
@@ -1827,53 +1814,32 @@ static HRESULT DoRollbackActions(
1814
1815
case BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE:
1816
hr = ExecuteExePackage(pEngineState, pRollbackAction, pContext, TRUE, &fRetryIgnored, &fSuspendIgnored, &restart);
1830
- TraceError(hr, "Failed to rollback EXE package.");
1831
- hr = S_OK;
1817
+ IgnoreRollbackError(hr, "Failed to rollback EXE package.");
1818
break;
1819
1820
case BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE:
1835
- if (fInTransaction)
1836
- {
1837
- LogString(REPORT_STANDARD, "Skipping rolling back an MSI package- already done in transaction rollback\n");
1838
- break;
1839
- }
1821
hr = ExecuteMsiPackage(pEngineState, pRollbackAction, pContext, TRUE, &fRetryIgnored, &fSuspendIgnored, &restart);
1841
- TraceError(hr, "Failed to rollback MSI package.");
1842
- hr = S_OK;
1822
+ IgnoreRollbackError(hr, "Failed to rollback MSI package.");
1823
break;
1824
1825
case BURN_EXECUTE_ACTION_TYPE_MSP_TARGET:
1846
- if (fInTransaction)
1847
- {
1848
- LogString(REPORT_STANDARD, "Skipping rolling back an MSP package- already done in transaction rollback\n");
1849
- break;
1850
- }
1826
hr = ExecuteMspPackage(pEngineState, pRollbackAction, pContext, TRUE, &fRetryIgnored, &fSuspendIgnored, &restart);
1852
- TraceError(hr, "Failed to rollback MSP package.");
1853
- hr = S_OK;
1827
+ IgnoreRollbackError(hr, "Failed to rollback MSP package.");
1828
break;
1829
1830
case BURN_EXECUTE_ACTION_TYPE_MSU_PACKAGE:
1857
- if (fInTransaction)
1858
- {
1859
- LogString(REPORT_STANDARD, "Skipping rolling back an MSU package- already done in transaction rollback\n");
1860
- break;
1861
- }
1831
hr = ExecuteMsuPackage(pEngineState, pRollbackAction, pContext, TRUE, FALSE, &fRetryIgnored, &fSuspendIgnored, &restart);
1863
- TraceError(hr, "Failed to rollback MSU package.");
1864
- hr = S_OK;
1832
+ IgnoreRollbackError(hr, "Failed to rollback MSU package.");
1833
break;
1834
1835
case BURN_EXECUTE_ACTION_TYPE_PACKAGE_PROVIDER:
1836
hr = ExecutePackageProviderAction(pEngineState, pRollbackAction, pContext);
1869
- TraceError(hr, "Failed to rollback package provider action.");
1870
- hr = S_OK;
1837
+ IgnoreRollbackError(hr, "Failed to rollback package provider action.");
1838
break;
1839
1840
case BURN_EXECUTE_ACTION_TYPE_PACKAGE_DEPENDENCY:
1841
hr = ExecuteDependencyAction(pEngineState, pRollbackAction, pContext);
1875
- TraceError(hr, "Failed to rollback dependency action.");
1876
- hr = S_OK;
1842
+ IgnoreRollbackError(hr, "Failed to rollback dependency action.");
1843
break;
1844
1845
case BURN_EXECUTE_ACTION_TYPE_REGISTRATION:
@@ -1885,6 +1851,7 @@ static HRESULT DoRollbackActions(
1851
1852
case BURN_EXECUTE_ACTION_TYPE_UNCACHE_PACKAGE:
1853
hr = CleanPackage(pEngineState->companionConnection.hPipe, pRollbackAction->uncachePackage.pPackage);
1854
+ IgnoreRollbackError(hr, "Failed to uncache package for rollback.");
1855
break;
1856
1857
case BURN_EXECUTE_ACTION_TYPE_SERVICE_STOP: __fallthrough;
@@ -2234,20 +2201,30 @@ LExit:
2201
2202
static HRESULT ExecuteMsiBeginTransaction(
2203
__in BURN_ENGINE_STATE* pEngineState,
2237
- __in LPCWSTR wzName,
2204
+ __in BURN_ROLLBACK_BOUNDARY* pRollbackBoundary,
2205
__in BURN_EXECUTE_CONTEXT* /*pContext*/
2206
)
2207
{
2208
HRESULT hr = S_OK;
2209
2210
+ if (pRollbackBoundary->fActiveTransaction)
2211
+ {
2212
+ ExitFunction1(hr = E_INVALIDSTATE);
2213
+ }
2214
+
2215
if (pEngineState->plan.fPerMachine)
2216
{
2245
- hr = ElevationMsiBeginTransaction(pEngineState->companionConnection.hPipe, wzName);
2217
+ hr = ElevationMsiBeginTransaction(pEngineState->companionConnection.hPipe, pRollbackBoundary->sczId);
2218
ExitOnFailure(hr, "Failed to begin an elevated MSI transaction.");
2219
}
2220
else
2221
{
2250
- hr = MsiEngineBeginTransaction(wzName);
2222
+ hr = MsiEngineBeginTransaction(pRollbackBoundary->sczId);
2223
+ }
2224
+
2225
+ if (SUCCEEDED(hr))
2226
+ {
2227
+ pRollbackBoundary->fActiveTransaction = TRUE;
2228
}
2229
2230
LExit:
@@ -2256,11 +2233,17 @@ LExit:
2233
2234
static HRESULT ExecuteMsiCommitTransaction(
2235
__in BURN_ENGINE_STATE* pEngineState,
2236
+ __in BURN_ROLLBACK_BOUNDARY* pRollbackBoundary,
2237
__in BURN_EXECUTE_CONTEXT* /*pContext*/
2238
)
2239
{
2240
HRESULT hr = S_OK;
2241
2242
+ if (!pRollbackBoundary->fActiveTransaction)
2243
+ {
2244
+ ExitFunction1(hr = E_INVALIDSTATE);
2245
+ }
2246
+
2247
if (pEngineState->plan.fPerMachine)
2248
{
2249
hr = ElevationMsiCommitTransaction(pEngineState->companionConnection.hPipe);
@@ -2271,17 +2254,28 @@ static HRESULT ExecuteMsiCommitTransaction(
2254
hr = MsiEngineCommitTransaction();
2255
}
2256
2257
+ if (SUCCEEDED(hr))
2258
+ {
2259
+ pRollbackBoundary->fActiveTransaction = FALSE;
2260
+ }
2261
+
2262
LExit:
2263
return hr;
2264
}
2265
2266
static HRESULT ExecuteMsiRollbackTransaction(
2267
__in BURN_ENGINE_STATE* pEngineState,
2268
+ __in BURN_ROLLBACK_BOUNDARY* pRollbackBoundary,
2269
__in BURN_EXECUTE_CONTEXT* /*pContext*/
2270
)
2271
{
2272
HRESULT hr = S_OK;
2273
2274
+ if (!pRollbackBoundary->fActiveTransaction)
2275
+ {
2276
+ ExitFunction();
2277
+ }
2278
+
2279
if (pEngineState->plan.fPerMachine)
2280
{
2281
hr = ElevationMsiRollbackTransaction(pEngineState->companionConnection.hPipe);
@@ -2293,6 +2287,8 @@ static HRESULT ExecuteMsiRollbackTransaction(
2287
}
2288
2289
LExit:
2290
+ pRollbackBoundary->fActiveTransaction = FALSE;
2291
+
2292
return hr;
2293
}
2294
src/engine/msiengine.cpp
+3
-2
@@ -717,7 +717,8 @@ extern "C" HRESULT MsiEnginePlanCalculatePackage(
717
__in BURN_PACKAGE* pPackage,
718
__in BURN_VARIABLES* pVariables,
719
__in BURN_USER_EXPERIENCE* pUserExperience,
720
- __out BOOL* pfBARequestedCache
720
+ __in BOOL fInsideMsiTransaction,
721
+ __out_opt BOOL* pfBARequestedCache
722
)
723
{
724
Trace(REPORT_STANDARD, "Planning MSI package 0x%p", pPackage);
@@ -853,7 +854,7 @@ extern "C" HRESULT MsiEnginePlanCalculatePackage(
854
}
855
856
// Calculate the rollback action if there is an execute action.
856
- if (BOOTSTRAPPER_ACTION_STATE_NONE != execute)
857
+ if (BOOTSTRAPPER_ACTION_STATE_NONE != execute && !fInsideMsiTransaction)
858
{
859
switch (BOOTSTRAPPER_PACKAGE_STATE_UNKNOWN != pPackage->expected ? pPackage->expected : pPackage->currentState)
860
{
src/engine/msiengine.h
+1
@@ -35,6 +35,7 @@ HRESULT MsiEnginePlanCalculatePackage(
35
__in BURN_PACKAGE* pPackage,
36
__in BURN_VARIABLES* pVariables,
37
__in BURN_USER_EXPERIENCE* pUserExperience,
38
+ __in BOOL fInsideMsiTransaction,
39
__out_opt BOOL* pfBARequestedCache
40
);
41
HRESULT MsiEnginePlanAddPackage(
src/engine/mspengine.cpp
+3
-2
@@ -266,6 +266,7 @@ LExit:
266
extern "C" HRESULT MspEnginePlanCalculatePackage(
267
__in BURN_PACKAGE* pPackage,
268
__in BURN_USER_EXPERIENCE* pUserExperience,
269
+ __in BOOL fInsideMsiTransaction,
270
__out BOOL* pfBARequestedCache
271
)
272
{
@@ -329,7 +330,7 @@ extern "C" HRESULT MspEnginePlanCalculatePackage(
330
}
331
332
// Calculate the rollback action if there is an execute action.
332
- if (BOOTSTRAPPER_ACTION_STATE_NONE != execute)
333
+ if (BOOTSTRAPPER_ACTION_STATE_NONE != execute && !fInsideMsiTransaction)
334
{
335
switch (BOOTSTRAPPER_PACKAGE_STATE_UNKNOWN != pPackage->expected ? pPackage->expected : pPackage->currentState)
336
{
@@ -442,7 +443,7 @@ extern "C" HRESULT MspEnginePlanAddPackage(
443
if (BOOTSTRAPPER_ACTION_STATE_NONE != pTargetProduct->rollback)
444
{
445
hr = PlanTargetProduct(display, pUserExperience, TRUE, pPlan, pLog, pVariables, pTargetProduct->rollback, pPackage, pTargetProduct, hCacheEvent);
445
- ExitOnFailure(hr, "Failed to plan rollack target product.");
446
+ ExitOnFailure(hr, "Failed to plan rollback target product.");
447
}
448
}
449
src/engine/mspengine.h
+1
@@ -35,6 +35,7 @@ HRESULT MspEngineDetectPackage(
35
HRESULT MspEnginePlanCalculatePackage(
36
__in BURN_PACKAGE* pPackage,
37
__in BURN_USER_EXPERIENCE* pUserExperience,
38
+ __in BOOL fInsideMsiTransaction,
39
__out_opt BOOL* pfBARequestedCache
40
);
41
HRESULT MspEnginePlanAddPackage(
src/engine/package.h
+1
@@ -155,6 +155,7 @@ typedef struct _BURN_ROLLBACK_BOUNDARY
155
LPWSTR sczId;
156
BOOL fVital;
157
BOOL fTransaction;
158
+ BOOL fActiveTransaction; // only valid during Apply.
159
} BURN_ROLLBACK_BOUNDARY;
160
161
typedef struct _BURN_PATCH_TARGETCODE
src/engine/plan.cpp
+68
-18
@@ -23,9 +23,12 @@ static void UninitializeCacheAction(
23
static void ResetPlannedPackageState(
24
__in BURN_PACKAGE* pPackage
25
);
26
+static void ResetPlannedRollbackBoundaryState(
27
+ __in BURN_ROLLBACK_BOUNDARY* pRollbackBoundary
28
+ );
29
static HRESULT ProcessPackage(
30
__in BOOL fBundlePerMachine,
28
- __in BURN_PACKAGE* pCompatiblePackageParent,
31
+ __in_opt BURN_PACKAGE* pCompatiblePackageParent,
32
__in BURN_USER_EXPERIENCE* pUX,
33
__in BURN_PLAN* pPlan,
34
__in BURN_PACKAGE* pPackage,
@@ -153,6 +156,7 @@ static HRESULT CalculateExecuteActions(
156
__in BURN_USER_EXPERIENCE* pUserExperience,
157
__in BURN_PACKAGE* pPackage,
158
__in BURN_VARIABLES* pVariables,
159
+ __in_opt BURN_ROLLBACK_BOUNDARY* pActiveRollbackBoundary,
160
__out_opt BOOL* pfBARequestedCache
161
);
162
static BOOL NeedsCache(
@@ -263,6 +267,15 @@ extern "C" void PlanReset(
267
ResetPlannedPackageState(&pPackages->rgPackages[i]);
268
}
269
}
270
+
271
+ // Reset the planned state for each rollback boundary.
272
+ if (pPackages->rgRollbackBoundaries)
273
+ {
274
+ for (DWORD i = 0; i < pPackages->cRollbackBoundaries; ++i)
275
+ {
276
+ ResetPlannedRollbackBoundaryState(&pPackages->rgRollbackBoundaries[i]);
277
+ }
278
+ }
279
}
280
281
extern "C" void PlanUninitializeExecuteAction(
@@ -853,7 +866,7 @@ LExit:
866
867
static HRESULT ProcessPackage(
868
__in BOOL fBundlePerMachine,
856
- __in BURN_PACKAGE* pCompatiblePackageParent,
869
+ __in_opt BURN_PACKAGE* pCompatiblePackageParent,
870
__in BURN_USER_EXPERIENCE* pUX,
871
__in BURN_PLAN* pPlan,
872
__in BURN_PACKAGE* pPackage,
@@ -1069,7 +1082,7 @@ extern "C" HRESULT PlanCachePackage(
1082
BOOL fBARequestedCache = FALSE;
1083
1084
// Calculate the execute actions because we need them to decide whether the package should be cached.
1072
- hr = CalculateExecuteActions(pUserExperience, pPackage, pVariables, &fBARequestedCache);
1085
+ hr = CalculateExecuteActions(pUserExperience, pPackage, pVariables, pPlan->pActiveRollbackBoundary, &fBARequestedCache);
1086
ExitOnFailure(hr, "Failed to calculate execute actions for package: %ls", pPackage->sczId);
1087
1088
if (fBARequestedCache || NeedsCache(pPlan, pPackage))
@@ -1105,7 +1118,7 @@ extern "C" HRESULT PlanExecutePackage(
1118
HRESULT hr = S_OK;
1119
BOOL fBARequestedCache = FALSE;
1120
1108
- hr = CalculateExecuteActions(pUserExperience, pPackage, pVariables, &fBARequestedCache);
1121
+ hr = CalculateExecuteActions(pUserExperience, pPackage, pVariables, pPlan->pActiveRollbackBoundary, &fBARequestedCache);
1122
ExitOnFailure(hr, "Failed to calculate plan actions for package: %ls", pPackage->sczId);
1123
1124
// Calculate package states based on reference count and plan certain dependency actions prior to planning the package execute action.
@@ -1631,6 +1644,7 @@ extern "C" HRESULT PlanExecuteCheckpoint(
1644
1645
pAction->type = BURN_EXECUTE_ACTION_TYPE_CHECKPOINT;
1646
pAction->checkpoint.dwId = dwCheckpointId;
1647
+ pAction->checkpoint.pActiveRollbackBoundary = pPlan->pActiveRollbackBoundary;
1648
1649
// rollback checkpoint
1650
hr = PlanAppendRollbackAction(pPlan, &pAction);
@@ -1638,6 +1652,7 @@ extern "C" HRESULT PlanExecuteCheckpoint(
1652
1653
pAction->type = BURN_EXECUTE_ACTION_TYPE_CHECKPOINT;
1654
pAction->checkpoint.dwId = dwCheckpointId;
1655
+ pAction->checkpoint.pActiveRollbackBoundary = pPlan->pActiveRollbackBoundary;
1656
1657
LExit:
1658
return hr;
@@ -1783,6 +1798,9 @@ extern "C" HRESULT PlanRollbackBoundaryBegin(
1798
HRESULT hr = S_OK;
1799
BURN_EXECUTE_ACTION* pExecuteAction = NULL;
1800
1801
+ AssertSz(!pPlan->pActiveRollbackBoundary, "PlanRollbackBoundaryBegin called without completing previous RollbackBoundary");
1802
+ pPlan->pActiveRollbackBoundary = pRollbackBoundary;
1803
+
1804
// Add begin rollback boundary to execute plan.
1805
hr = PlanAppendExecuteAction(pPlan, &pExecuteAction);
1806
ExitOnFailure(hr, "Failed to append rollback boundary begin action.");
@@ -1797,6 +1815,19 @@ extern "C" HRESULT PlanRollbackBoundaryBegin(
1815
pExecuteAction->type = BURN_EXECUTE_ACTION_TYPE_ROLLBACK_BOUNDARY;
1816
pExecuteAction->rollbackBoundary.pRollbackBoundary = pRollbackBoundary;
1817
1818
+ // Add begin MSI transaction to execute plan.
1819
+ if (pRollbackBoundary->fTransaction)
1820
+ {
1821
+ hr = PlanExecuteCheckpoint(pPlan);
1822
+ ExitOnFailure(hr, "Failed to append checkpoint before MSI transaction begin action.");
1823
+
1824
+ hr = PlanAppendExecuteAction(pPlan, &pExecuteAction);
1825
+ ExitOnFailure(hr, "Failed to append MSI transaction begin action.");
1826
+
1827
+ pExecuteAction->type = BURN_EXECUTE_ACTION_TYPE_BEGIN_MSI_TRANSACTION;
1828
+ pExecuteAction->msiTransaction.pRollbackBoundary = pRollbackBoundary;
1829
+ }
1830
+
1831
LExit:
1832
return hr;
1833
}
@@ -1807,22 +1838,24 @@ extern "C" HRESULT PlanRollbackBoundaryComplete(
1838
{
1839
HRESULT hr = S_OK;
1840
BURN_EXECUTE_ACTION* pExecuteAction = NULL;
1810
- DWORD dwCheckpointId = 0;
1841
+ BURN_ROLLBACK_BOUNDARY* pRollbackBoundary = pPlan->pActiveRollbackBoundary;
1842
1812
- // Add checkpoints.
1813
- dwCheckpointId = GetNextCheckpointId(pPlan);
1843
+ AssertSz(pRollbackBoundary, "PlanRollbackBoundaryComplete called without an active RollbackBoundary");
1844
1815
- hr = PlanAppendExecuteAction(pPlan, &pExecuteAction);
1816
- ExitOnFailure(hr, "Failed to append execute action.");
1845
+ if (pRollbackBoundary && pRollbackBoundary->fTransaction)
1846
+ {
1847
+ // Add commit MSI transaction to execute plan.
1848
+ hr = PlanAppendExecuteAction(pPlan, &pExecuteAction);
1849
+ ExitOnFailure(hr, "Failed to append MSI transaction commit action.");
1850
1818
- pExecuteAction->type = BURN_EXECUTE_ACTION_TYPE_CHECKPOINT;
1819
- pExecuteAction->checkpoint.dwId = dwCheckpointId;
1851
+ pExecuteAction->type = BURN_EXECUTE_ACTION_TYPE_COMMIT_MSI_TRANSACTION;
1852
+ pExecuteAction->msiTransaction.pRollbackBoundary = pRollbackBoundary;
1853
+ }
1854
1821
- hr = PlanAppendRollbackAction(pPlan, &pExecuteAction);
1822
- ExitOnFailure(hr, "Failed to append rollback action.");
1855
+ pPlan->pActiveRollbackBoundary = NULL;
1856
1824
- pExecuteAction->type = BURN_EXECUTE_ACTION_TYPE_CHECKPOINT;
1825
- pExecuteAction->checkpoint.dwId = dwCheckpointId;
1857
+ // Add checkpoints.
1858
+ hr = PlanExecuteCheckpoint(pPlan);
1859
1860
LExit:
1861
return hr;
@@ -1936,6 +1969,13 @@ static void ResetPlannedPackageState(
1969
}
1970
}
1971
1972
+static void ResetPlannedRollbackBoundaryState(
1973
+ __in BURN_ROLLBACK_BOUNDARY* pRollbackBoundary
1974
+ )
1975
+{
1976
+ pRollbackBoundary->fActiveTransaction = FALSE;
1977
+}
1978
+
1979
static HRESULT GetActionDefaultRequestState(
1980
__in BOOTSTRAPPER_ACTION action,
1981
__in BOOL fPermanent,
@@ -2848,10 +2888,12 @@ static HRESULT CalculateExecuteActions(
2888
__in BURN_USER_EXPERIENCE* pUserExperience,
2889
__in BURN_PACKAGE* pPackage,
2890
__in BURN_VARIABLES* pVariables,
2891
+ __in_opt BURN_ROLLBACK_BOUNDARY* pActiveRollbackBoundary,
2892
__out_opt BOOL* pfBARequestedCache
2893
)
2894
{
2895
HRESULT hr = S_OK;
2896
+ BOOL fInsideMsiTransaction = pActiveRollbackBoundary && pActiveRollbackBoundary->fTransaction;
2897
2898
// Calculate execute actions.
2899
switch (pPackage->type)
@@ -2861,11 +2903,11 @@ static HRESULT CalculateExecuteActions(
2903
break;
2904
2905
case BURN_PACKAGE_TYPE_MSI:
2864
- hr = MsiEnginePlanCalculatePackage(pPackage, pVariables, pUserExperience, pfBARequestedCache);
2906
+ hr = MsiEnginePlanCalculatePackage(pPackage, pVariables, pUserExperience, fInsideMsiTransaction, pfBARequestedCache);
2907
break;
2908
2909
case BURN_PACKAGE_TYPE_MSP:
2868
- hr = MspEnginePlanCalculatePackage(pPackage, pUserExperience, pfBARequestedCache);
2910
+ hr = MspEnginePlanCalculatePackage(pPackage, pUserExperience, fInsideMsiTransaction, pfBARequestedCache);
2911
break;
2912
2913
case BURN_PACKAGE_TYPE_MSU:
@@ -3065,7 +3107,7 @@ static void ExecuteActionLog(
3107
switch (pAction->type)
3108
{
3109
case BURN_EXECUTE_ACTION_TYPE_CHECKPOINT:
3068
- LogStringLine(REPORT_STANDARD, "%ls action[%u]: CHECKPOINT id: %u", wzBase, iAction, pAction->checkpoint.dwId);
3110
+ LogStringLine(REPORT_STANDARD, "%ls action[%u]: CHECKPOINT id: %u, msi transaction id: %ls", wzBase, iAction, pAction->checkpoint.dwId, pAction->checkpoint.pActiveRollbackBoundary && pAction->checkpoint.pActiveRollbackBoundary->fTransaction ? pAction->checkpoint.pActiveRollbackBoundary->sczId : L"(none)");
3111
break;
3112
3113
case BURN_EXECUTE_ACTION_TYPE_PACKAGE_PROVIDER:
@@ -3120,6 +3162,14 @@ static void ExecuteActionLog(
3162
LogStringLine(REPORT_STANDARD, "%ls action[%u]: COMPATIBLE_PACKAGE reference id: %ls, installed ProductCode: %ls", wzBase, iAction, pAction->compatiblePackage.pReferencePackage->sczId, pAction->compatiblePackage.sczInstalledProductCode);
3163
break;
3164
3165
+ case BURN_EXECUTE_ACTION_TYPE_BEGIN_MSI_TRANSACTION:
3166
+ LogStringLine(REPORT_STANDARD, "%ls action[%u]: BEGIN_MSI_TRANSACTION id: %ls", wzBase, iAction, pAction->msiTransaction.pRollbackBoundary->sczId);
3167
+ break;
3168
+
3169
+ case BURN_EXECUTE_ACTION_TYPE_COMMIT_MSI_TRANSACTION:
3170
+ LogStringLine(REPORT_STANDARD, "%ls action[%u]: COMMIT_MSI_TRANSACTION id: %ls", wzBase, iAction, pAction->msiTransaction.pRollbackBoundary->sczId);
3171
+ break;
3172
+
3173
default:
3174
AssertSz(FALSE, "Unknown execute action type.");
3175
break;
src/engine/plan.h
+15
-5
@@ -68,6 +68,8 @@ enum BURN_EXECUTE_ACTION_TYPE
68
BURN_EXECUTE_ACTION_TYPE_ROLLBACK_BOUNDARY,
69
BURN_EXECUTE_ACTION_TYPE_REGISTRATION,
70
BURN_EXECUTE_ACTION_TYPE_COMPATIBLE_PACKAGE,
71
+ BURN_EXECUTE_ACTION_TYPE_BEGIN_MSI_TRANSACTION,
72
+ BURN_EXECUTE_ACTION_TYPE_COMMIT_MSI_TRANSACTION,
73
};
74
75
enum BURN_CLEAN_ACTION_TYPE
@@ -214,16 +216,19 @@ typedef struct _BURN_ORDERED_PATCHES
216
BURN_PACKAGE* pPackage;
217
} BURN_ORDERED_PATCHES;
218
219
+typedef struct _BURN_EXECUTE_ACTION_CHECKPOINT
220
+{
221
+ DWORD dwId;
222
+ BURN_ROLLBACK_BOUNDARY* pActiveRollbackBoundary;
223
+} BURN_EXECUTE_ACTION_CHECKPOINT;
224
+
225
typedef struct _BURN_EXECUTE_ACTION
226
{
227
BURN_EXECUTE_ACTION_TYPE type;
228
BOOL fDeleted; // used to skip an action after it was planned since deleting actions out of the plan is too hard.
229
union
230
{
223
- struct
224
- {
225
- DWORD dwId;
226
- } checkpoint;
231
+ BURN_EXECUTE_ACTION_CHECKPOINT checkpoint;
232
struct
233
{
234
HANDLE hEvent;
@@ -307,6 +312,10 @@ typedef struct _BURN_EXECUTE_ACTION
312
LPWSTR sczInstalledProductCode;
313
VERUTIL_VERSION* pInstalledVersion;
314
} compatiblePackage;
315
+ struct
316
+ {
317
+ BURN_ROLLBACK_BOUNDARY* pRollbackBoundary;
318
+ } msiTransaction;
319
};
320
} BURN_EXECUTE_ACTION;
321
@@ -368,7 +377,8 @@ typedef struct _BURN_PLAN
377
DWORD cPayloadProgress;
378
STRINGDICT_HANDLE shPayloadProgress;
379
371
- DWORD dwNextCheckpointId;
380
+ DWORD dwNextCheckpointId; // for plan internal use
381
+ BURN_ROLLBACK_BOUNDARY* pActiveRollbackBoundary; // for plan internal use
382
} BURN_PLAN;
383
384
src/test/BurnUnitTest/PlanTest.cpp
+39
-23
@@ -173,7 +173,7 @@ namespace Bootstrapper
173
ValidateCacheCachePayload(pPlan, fRollback, dwIndex++, L"PackageA", L"cab1QmlL013Hqv_44W64R0cvnHn_2c", TRUE, FALSE, dwPackageStart);
174
ValidateCachePackageStop(pPlan, fRollback, dwIndex++, L"PackageA", FALSE);
175
ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, FALSE);
176
- ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 8);
176
+ ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 9);
177
dwPackageStart = ValidateCachePackageStart(pPlan, fRollback, dwIndex++, L"PackageB", 14, 2, 33753, FALSE);
178
ValidateCacheAcquireContainer(pPlan, fRollback, dwIndex++, L"WixAttachedContainer", TRUE);
179
ValidateCacheExtractContainer(pPlan, fRollback, dwIndex++, L"WixAttachedContainer", FALSE, dwPackageStart, 2);
@@ -195,10 +195,6 @@ namespace Bootstrapper
195
dwIndex = 0;
196
ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
197
ValidateCacheRollbackPackage(pPlan, fRollback, dwIndex++, L"PackageA", FALSE);
198
- ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 8);
199
- ValidateCacheRollbackPackage(pPlan, fRollback, dwIndex++, L"PackageB", FALSE);
200
- ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 14);
201
- ValidateCacheRollbackPackage(pPlan, fRollback, dwIndex++, L"PackageC", FALSE);
198
Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
199
200
Assert::Equal(106166ull, pPlan->qwEstimatedSize);
@@ -220,30 +216,31 @@ namespace Bootstrapper
216
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
217
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
218
ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ", TRUE, TRUE);
219
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
220
+ ValidateExecuteBeginMsiTransaction(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ");
221
ValidateExecuteWaitSyncpoint(pPlan, fRollback, dwIndex++, pPlan->rgCacheActions[15].syncpoint.hEvent);
224
- dwExecuteCheckpointId = 9;
222
+ dwExecuteCheckpointId += 1; // cache checkpoints
223
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
224
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
225
ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageB", BURN_DEPENDENCY_ACTION_REGISTER);
228
- ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
226
ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageB", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
227
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
228
ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageB", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_REGISTER);
229
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
230
ValidateExecuteWaitSyncpoint(pPlan, fRollback, dwIndex++, pPlan->rgCacheActions[23].syncpoint.hEvent);
234
- dwExecuteCheckpointId = 15;
231
+ dwExecuteCheckpointId += 1; // cache checkpoints
232
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
233
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
234
ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageC", BURN_DEPENDENCY_ACTION_REGISTER);
238
- ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
235
ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageC", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
236
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
237
ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageC", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_REGISTER);
238
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
239
+ ValidateExecuteCommitMsiTransaction(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ");
240
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
241
ValidateExecuteWaitSyncpoint(pPlan, fRollback, dwIndex++, pPlan->rgCacheActions[23].syncpoint.hEvent);
242
ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, NULL);
246
- Assert::Equal(34ul, pPlan->cExecuteActions);
243
+ Assert::Equal(dwIndex, pPlan->cExecuteActions);
244
245
fRollback = TRUE;
246
dwIndex = 0;
@@ -261,29 +258,26 @@ namespace Bootstrapper
258
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
259
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
260
ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ", TRUE, TRUE);
261
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
262
ValidateExecuteUncachePackage(pPlan, fRollback, dwIndex++, L"PackageB");
265
- dwExecuteCheckpointId = 9;
263
+ dwExecuteCheckpointId += 1; // cache checkpoints
264
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
265
ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageB", BURN_DEPENDENCY_ACTION_UNREGISTER);
266
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
269
- ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageB", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
270
- ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
267
ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageB", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_UNREGISTER);
268
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
269
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
270
ValidateExecuteUncachePackage(pPlan, fRollback, dwIndex++, L"PackageC");
275
- dwExecuteCheckpointId = 15;
271
+ dwExecuteCheckpointId += 1; // cache checkpoints
272
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
273
ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageC", BURN_DEPENDENCY_ACTION_UNREGISTER);
274
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
279
- ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageC", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
280
- ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
275
ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageC", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_UNREGISTER);
276
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
277
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
278
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
279
ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", BOOTSTRAPPER_ACTION_STATE_INSTALL, NULL);
286
- Assert::Equal(33ul, pPlan->cRollbackActions);
280
+ Assert::Equal(dwIndex, pPlan->cRollbackActions);
281
282
Assert::Equal(4ul, pPlan->cExecutePackagesTotal);
283
Assert::Equal(7ul, pPlan->cOverallProgressTicksTotal);
@@ -331,19 +325,20 @@ namespace Bootstrapper
325
DWORD dwExecuteCheckpointId = 1;
326
ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ", TRUE, TRUE);
327
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
328
+ ValidateExecuteBeginMsiTransaction(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ");
329
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
330
ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageC", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_UNREGISTER);
331
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
332
ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageC", BURN_DEPENDENCY_ACTION_UNREGISTER);
337
- ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
333
ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageC", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
334
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
335
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
336
ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageB", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_UNREGISTER);
337
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
338
ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageB", BURN_DEPENDENCY_ACTION_UNREGISTER);
344
- ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
339
ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageB", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
340
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
341
+ ValidateExecuteCommitMsiTransaction(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ");
342
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
343
ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
344
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
@@ -361,19 +356,16 @@ namespace Bootstrapper
356
dwIndex = 0;
357
dwExecuteCheckpointId = 1;
358
ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"rbaOCA08D8ky7uBOK71_6FWz1K3TuQ", TRUE, TRUE);
359
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
360
ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageC", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_REGISTER);
361
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
362
ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageC", BURN_DEPENDENCY_ACTION_REGISTER);
363
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
368
- ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageC", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
369
- ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
364
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
365
ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageB", L"{c096190a-8bf3-4342-a1d2-94ea9cb853d6}", BURN_DEPENDENCY_ACTION_REGISTER);
366
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
367
ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageB", BURN_DEPENDENCY_ACTION_REGISTER);
368
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
375
- ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageB", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
376
- ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
369
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
370
ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
371
ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
@@ -818,6 +810,18 @@ namespace Bootstrapper
810
return (fRollback ? pPlan->rgRollbackActions : pPlan->rgExecuteActions) + dwIndex;
811
}
812
813
+ void ValidateExecuteBeginMsiTransaction(
814
+ __in BURN_PLAN* pPlan,
815
+ __in BOOL fRollback,
816
+ __in DWORD dwIndex,
817
+ __in LPCWSTR wzRollbackBoundaryId
818
+ )
819
+ {
820
+ BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex);
821
+ Assert::Equal<DWORD>(BURN_EXECUTE_ACTION_TYPE_BEGIN_MSI_TRANSACTION, pAction->type);
822
+ NativeAssert::StringEqual(wzRollbackBoundaryId, pAction->msiTransaction.pRollbackBoundary->sczId);
823
+ }
824
+
825
void ValidateExecuteCheckpoint(
826
__in BURN_PLAN* pPlan,
827
__in BOOL fRollback,
@@ -830,6 +834,18 @@ namespace Bootstrapper
834
Assert::Equal(dwId, pAction->checkpoint.dwId);
835
}
836
837
+ void ValidateExecuteCommitMsiTransaction(
838
+ __in BURN_PLAN* pPlan,
839
+ __in BOOL fRollback,
840
+ __in DWORD dwIndex,
841
+ __in LPCWSTR wzRollbackBoundaryId
842
+ )
843
+ {
844
+ BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex);
845
+ Assert::Equal<DWORD>(BURN_EXECUTE_ACTION_TYPE_COMMIT_MSI_TRANSACTION, pAction->type);
846
+ NativeAssert::StringEqual(wzRollbackBoundaryId, pAction->msiTransaction.pRollbackBoundary->sczId);
847
+ }
848
+
849
void ValidateExecuteExePackage(
850
__in BURN_PLAN* pPlan,
851
__in BOOL fRollback,