@joebigelow / wix / commits / e71de85e

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,