@joebigelow / wix-1 / commits / dea65729

Add ability for non-vital cache package action.

Sean Hall committed Jun 14, 2022 at 15:09 UTC dea657295df261bb0e3e4d620eeae321531e3a11
31 files changed +723 -155
src/api/burn/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h
+25
@@ -226,6 +226,7 @@ enum BOOTSTRAPPER_APPLICATION_MESSAGE
226 BOOTSTRAPPER_APPLICATION_MESSAGE_ONAPPLYDOWNGRADE,
227 BOOTSTRAPPER_APPLICATION_MESSAGE_ONEXECUTEPROCESSCANCEL,
228 BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTRELATEDBUNDLEPACKAGE,
229 + BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEPACKAGENONVITALVALIDATIONFAILURE,
230 };
231
232 enum BOOTSTRAPPER_APPLYCOMPLETE_ACTION
@@ -257,6 +258,14 @@ enum BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION
258 BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION_RETRY,
259 };
260
261 +enum BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION
262 +{
263 + BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION_NONE,
264 + // Instructs the engine to try to acquire the package so execution can use it.
265 + // Most of the time this is used for installing the package during rollback.
266 + BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION_ACQUIRE,
267 +};
268 +
269 enum BOOTSTRAPPER_CACHEVERIFYCOMPLETE_ACTION
270 {
271 BOOTSTRAPPER_CACHEVERIFYCOMPLETE_ACTION_NONE,
@@ -546,6 +555,8 @@ struct BA_ONCACHEPACKAGEBEGIN_ARGS
555 LPCWSTR wzPackageId;
556 DWORD cCachePayloads;
557 DWORD64 dw64PackageCacheSize;
558 + // If caching a package is not vital, then acquisition will be skipped unless the BA opts in through OnCachePackageNonVitalValidationFailure.
559 + BOOL fVital;
560 };
561
562 struct BA_ONCACHEPACKAGEBEGIN_RESULTS
@@ -568,6 +579,20 @@ struct BA_ONCACHEPACKAGECOMPLETE_RESULTS
579 BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION action;
580 };
581
582 +struct BA_ONCACHEPACKAGENONVITALVALIDATIONFAILURE_ARGS
583 +{
584 + DWORD cbSize;
585 + LPCWSTR wzPackageId;
586 + HRESULT hrStatus;
587 + BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION recommendation;
588 +};
589 +
590 +struct BA_ONCACHEPACKAGENONVITALVALIDATIONFAILURE_RESULTS
591 +{
592 + DWORD cbSize;
593 + BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION action;
594 +};
595 +
596 struct BA_ONCACHEPAYLOADEXTRACTBEGIN_ARGS
597 {
598 DWORD cbSize;
src/api/burn/WixToolset.Mba.Core/BootstrapperApplication.cs
+27 -2
@@ -280,6 +280,9 @@ namespace WixToolset.Mba.Core
280 /// <inheritdoc/>
281 public event EventHandler<DetectRelatedBundlePackageEventArgs> DetectRelatedBundlePackage;
282
283 + /// <inheritdoc/>
284 + public event EventHandler<CachePackageNonVitalValidationFailureEventArgs> CachePackageNonVitalValidationFailure;
285 +
286 /// <summary>
287 /// Entry point that is called when the bootstrapper application is ready to run.
288 /// </summary>
@@ -1376,6 +1379,18 @@ namespace WixToolset.Mba.Core
1379 }
1380 }
1381
1382 + /// <summary>
1383 + /// Called by the engine, raises the <see cref="CachePackageNonVitalValidationFailure"/> event.
1384 + /// </summary>
1385 + protected virtual void OnCachePackageNonVitalValidationFailure(CachePackageNonVitalValidationFailureEventArgs args)
1386 + {
1387 + EventHandler<CachePackageNonVitalValidationFailureEventArgs> handler = this.CachePackageNonVitalValidationFailure;
1388 + if (null != handler)
1389 + {
1390 + handler(this, args);
1391 + }
1392 + }
1393 +
1394 #region IBootstrapperApplication Members
1395
1396 int IBootstrapperApplication.BAProc(int message, IntPtr pvArgs, IntPtr pvResults, IntPtr pvContext)
@@ -1570,6 +1585,7 @@ namespace WixToolset.Mba.Core
1585 this.OnPlanPackageBegin(args);
1586
1587 pRequestedState = args.State;
1588 + pRequestedCacheType = args.CacheType;
1589 fCancel = args.Cancel;
1590 return args.HResult;
1591 }
@@ -1728,9 +1744,9 @@ namespace WixToolset.Mba.Core
1744 return args.HResult;
1745 }
1746
1731 - int IBootstrapperApplication.OnCachePackageBegin(string wzPackageId, int cCachePayloads, long dw64PackageCacheSize, ref bool fCancel)
1747 + int IBootstrapperApplication.OnCachePackageBegin(string wzPackageId, int cCachePayloads, long dw64PackageCacheSize, bool fVital, ref bool fCancel)
1748 {
1733 - CachePackageBeginEventArgs args = new CachePackageBeginEventArgs(wzPackageId, cCachePayloads, dw64PackageCacheSize, fCancel);
1749 + CachePackageBeginEventArgs args = new CachePackageBeginEventArgs(wzPackageId, cCachePayloads, dw64PackageCacheSize, fVital, fCancel);
1750 this.OnCachePackageBegin(args);
1751
1752 fCancel = args.Cancel;
@@ -2131,6 +2147,15 @@ namespace WixToolset.Mba.Core
2147 return args.HResult;
2148 }
2149
2150 + int IBootstrapperApplication.OnCachePackageNonVitalValidationFailure(string wzPackageId, int hrStatus, BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION recommendation, ref BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION action)
2151 + {
2152 + CachePackageNonVitalValidationFailureEventArgs args = new CachePackageNonVitalValidationFailureEventArgs(wzPackageId, hrStatus, recommendation, action);
2153 + this.OnCachePackageNonVitalValidationFailure(args);
2154 +
2155 + action = args.Action;
2156 + return args.HResult;
2157 + }
2158 +
2159 #endregion
2160 }
2161 }
src/api/burn/WixToolset.Mba.Core/EventArgs.cs
+26 -1
@@ -1930,12 +1930,13 @@ namespace WixToolset.Mba.Core
1930 public class CachePackageBeginEventArgs : CancellableHResultEventArgs
1931 {
1932 /// <summary />
1933 - public CachePackageBeginEventArgs(string packageId, int cachePayloads, long packageCacheSize, bool cancelRecommendation)
1933 + public CachePackageBeginEventArgs(string packageId, int cachePayloads, long packageCacheSize, bool vital, bool cancelRecommendation)
1934 : base(cancelRecommendation)
1935 {
1936 this.PackageId = packageId;
1937 this.CachePayloads = cachePayloads;
1938 this.PackageCacheSize = packageCacheSize;
1939 + this.Vital = vital;
1940 }
1941
1942 /// <summary>
@@ -1952,6 +1953,11 @@ namespace WixToolset.Mba.Core
1953 /// Gets the size on disk required by the specific package.
1954 /// </summary>
1955 public long PackageCacheSize { get; private set; }
1956 +
1957 + /// <summary>
1958 + /// If caching a package is not vital, then acquisition will be skipped unless the BA opts in through <see cref="IDefaultBootstrapperApplication.CachePackageNonVitalValidationFailure"/>.
1959 + /// </summary>
1960 + public bool Vital { get; private set; }
1961 }
1962
1963 /// <summary>
@@ -2482,4 +2488,23 @@ namespace WixToolset.Mba.Core
2488 /// </summary>
2489 public string Version { get; private set; }
2490 }
2491 +
2492 + /// <summary>
2493 + /// Event arguments for <see cref="IDefaultBootstrapperApplication.CachePackageNonVitalValidationFailure"/>
2494 + /// </summary>
2495 + [Serializable]
2496 + public class CachePackageNonVitalValidationFailureEventArgs : ActionEventArgs<BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION>
2497 + {
2498 + /// <summary />
2499 + public CachePackageNonVitalValidationFailureEventArgs(string packageId, int hrStatus, BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION recommendation, BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION action)
2500 + : base(hrStatus, recommendation, action)
2501 + {
2502 + this.PackageId = packageId;
2503 + }
2504 +
2505 + /// <summary>
2506 + /// Gets the identity of the package that was being validated.
2507 + /// </summary>
2508 + public string PackageId { get; private set; }
2509 + }
2510 }
src/api/burn/WixToolset.Mba.Core/IBootstrapperApplication.cs
+30 -10
@@ -553,17 +553,13 @@ namespace WixToolset.Mba.Core
553 /// <summary>
554 /// See <see cref="IDefaultBootstrapperApplication.CachePackageBegin"/>.
555 /// </summary>
556 - /// <param name="wzPackageId"></param>
557 - /// <param name="cCachePayloads"></param>
558 - /// <param name="dw64PackageCacheSize"></param>
559 - /// <param name="fCancel"></param>
560 - /// <returns></returns>
556 [PreserveSig]
557 [return: MarshalAs(UnmanagedType.I4)]
558 int OnCachePackageBegin(
559 [MarshalAs(UnmanagedType.LPWStr)] string wzPackageId,
560 [MarshalAs(UnmanagedType.U4)] int cCachePayloads,
561 [MarshalAs(UnmanagedType.U8)] long dw64PackageCacheSize,
562 + [MarshalAs(UnmanagedType.Bool)] bool fVital,
563 [MarshalAs(UnmanagedType.Bool)] ref bool fCancel
564 );
565
@@ -672,11 +668,6 @@ namespace WixToolset.Mba.Core
668 /// <summary>
669 /// See <see cref="IDefaultBootstrapperApplication.CachePackageComplete"/>.
670 /// </summary>
675 - /// <param name="wzPackageId"></param>
676 - /// <param name="hrStatus"></param>
677 - /// <param name="recommendation"></param>
678 - /// <param name="action"></param>
679 - /// <returns></returns>
671 [PreserveSig]
672 [return: MarshalAs(UnmanagedType.I4)]
673 int OnCachePackageComplete(
@@ -1184,6 +1175,18 @@ namespace WixToolset.Mba.Core
1175 [MarshalAs(UnmanagedType.LPWStr)] string wzVersion,
1176 [MarshalAs(UnmanagedType.Bool)] ref bool fCancel
1177 );
1178 +
1179 + /// <summary>
1180 + /// See <see cref="IDefaultBootstrapperApplication.CachePackageNonVitalValidationFailure"/>.
1181 + /// </summary>
1182 + [PreserveSig]
1183 + [return: MarshalAs(UnmanagedType.I4)]
1184 + int OnCachePackageNonVitalValidationFailure(
1185 + [MarshalAs(UnmanagedType.LPWStr)] string wzPackageId,
1186 + int hrStatus,
1187 + BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION recommendation,
1188 + ref BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION action
1189 + );
1190 }
1191
1192 /// <summary>
@@ -1870,6 +1873,23 @@ namespace WixToolset.Mba.Core
1873 Retry,
1874 }
1875
1876 + /// <summary>
1877 + /// The available actions for <see cref="IDefaultBootstrapperApplication.CachePackageNonVitalValidationFailure"/>
1878 + /// </summary>
1879 + public enum BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION
1880 + {
1881 + /// <summary>
1882 + ///
1883 + /// </summary>
1884 + None,
1885 +
1886 + /// <summary>
1887 + /// Instructs the engine to try to acquire the package so execution can use it.
1888 + /// Most of the time this is used for installing the package during rollback.
1889 + /// </summary>
1890 + Acquire,
1891 + }
1892 +
1893 /// <summary>
1894 /// The available actions for <see cref="IDefaultBootstrapperApplication.CacheVerifyComplete"/>.
1895 /// </summary>
src/api/burn/WixToolset.Mba.Core/IDefaultBootstrapperApplication.cs
+5
@@ -93,6 +93,11 @@ namespace WixToolset.Mba.Core
93 /// </summary>
94 event EventHandler<CachePackageCompleteEventArgs> CachePackageComplete;
95
96 + /// <summary>
97 + /// Fired when the engine failed validating a package in the package cache that is non-vital to execution.
98 + /// </summary>
99 + event EventHandler<CachePackageNonVitalValidationFailureEventArgs> CachePackageNonVitalValidationFailure;
100 +
101 /// <summary>
102 /// Fired when the engine begins the extraction of the payload from the container.
103 /// </summary>
src/api/burn/balutil/inc/BAFunctions.h
+1
@@ -92,6 +92,7 @@ enum BA_FUNCTIONS_MESSAGE
92 BA_FUNCTIONS_MESSAGE_ONAPPLYDOWNGRADE = BOOTSTRAPPER_APPLICATION_MESSAGE_ONAPPLYDOWNGRADE,
93 BA_FUNCTIONS_MESSAGE_ONEXECUTEPROCESSCANCEL = BOOTSTRAPPER_APPLICATION_MESSAGE_ONEXECUTEPROCESSCANCEL,
94 BA_FUNCTIONS_MESSAGE_ONDETECTRELATEDBUNDLEPACKAGE = BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTRELATEDBUNDLEPACKAGE,
95 + BA_FUNCTIONS_MESSAGE_ONCACHEPACKAGENONVITALVALIDATIONFAILURE = BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEPACKAGENONVITALVALIDATIONFAILURE,
96
97 BA_FUNCTIONS_MESSAGE_ONTHEMELOADED = 1024,
98 BA_FUNCTIONS_MESSAGE_WNDPROC,
src/api/burn/balutil/inc/BalBaseBAFunctions.h
+11
@@ -447,6 +447,7 @@ public: // IBootstrapperApplication
447 __in_z LPCWSTR /*wzPackageId*/,
448 __in DWORD /*cCachePayloads*/,
449 __in DWORD64 /*dw64PackageCacheSize*/,
450 + __in BOOL /*fVital*/,
451 __inout BOOL* /*pfCancel*/
452 )
453 {
@@ -892,6 +893,16 @@ public: // IBootstrapperApplication
893 return S_OK;
894 }
895
896 + virtual STDMETHODIMP OnCachePackageNonVitalValidationFailure(
897 + __in_z LPCWSTR /*wzPackageId*/,
898 + __in HRESULT /*hrStatus*/,
899 + __in BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION /*recommendation*/,
900 + __inout BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION* /*pAction*/
901 + )
902 + {
903 + return S_OK;
904 + }
905 +
906 public: // IBAFunctions
907 virtual STDMETHODIMP OnPlan(
908 )
src/api/burn/balutil/inc/BalBaseBAFunctionsProc.h
+1
@@ -163,6 +163,7 @@ static HRESULT WINAPI BalBaseBAFunctionsProc(
163 case BA_FUNCTIONS_MESSAGE_ONAPPLYDOWNGRADE:
164 case BA_FUNCTIONS_MESSAGE_ONEXECUTEPROCESSCANCEL:
165 case BA_FUNCTIONS_MESSAGE_ONDETECTRELATEDBUNDLEPACKAGE:
166 + case BA_FUNCTIONS_MESSAGE_ONCACHEPACKAGENONVITALVALIDATIONFAILURE:
167 hr = BalBaseBootstrapperApplicationProc((BOOTSTRAPPER_APPLICATION_MESSAGE)message, pvArgs, pvResults, pvContext);
168 break;
169 case BA_FUNCTIONS_MESSAGE_ONTHEMELOADED:
src/api/burn/balutil/inc/BalBaseBootstrapperApplication.h
+11
@@ -505,6 +505,7 @@ public: // IBootstrapperApplication
505 __in_z LPCWSTR /*wzPackageId*/,
506 __in DWORD /*cCachePayloads*/,
507 __in DWORD64 /*dw64PackageCacheSize*/,
508 + __in BOOL /*fVital*/,
509 __inout BOOL* pfCancel
510 )
511 {
@@ -1084,6 +1085,16 @@ public: // IBootstrapperApplication
1085 return S_OK;
1086 }
1087
1088 + virtual STDMETHODIMP OnCachePackageNonVitalValidationFailure(
1089 + __in_z LPCWSTR /*wzPackageId*/,
1090 + __in HRESULT /*hrStatus*/,
1091 + __in BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION /*recommendation*/,
1092 + __inout BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION* /*pAction*/
1093 + )
1094 + {
1095 + return S_OK;
1096 + }
1097 +
1098 public: //CBalBaseBootstrapperApplication
1099 virtual STDMETHODIMP Initialize(
1100 __in const BOOTSTRAPPER_CREATE_ARGS* pCreateArgs
src/api/burn/balutil/inc/BalBaseBootstrapperApplicationProc.h
+13 -1
@@ -330,7 +330,7 @@ static HRESULT BalBaseBAProcOnCachePackageBegin(
330 __inout BA_ONCACHEPACKAGEBEGIN_RESULTS* pResults
331 )
332 {
333 - return pBA->OnCachePackageBegin(pArgs->wzPackageId, pArgs->cCachePayloads, pArgs->dw64PackageCacheSize, &pResults->fCancel);
333 + return pBA->OnCachePackageBegin(pArgs->wzPackageId, pArgs->cCachePayloads, pArgs->dw64PackageCacheSize, pArgs->fVital, &pResults->fCancel);
334 }
335
336 static HRESULT BalBaseBAProcOnCacheAcquireBegin(
@@ -756,6 +756,15 @@ static HRESULT BalBaseBAProcOnDetectRelatedBundlePackage(
756 return pBA->OnDetectRelatedBundlePackage(pArgs->wzPackageId, pArgs->wzBundleId, pArgs->relationType, pArgs->fPerMachine, pArgs->wzVersion, &pResults->fCancel);
757 }
758
759 +static HRESULT BalBaseBAProcOnCachePackageNonVitalValidationFailure(
760 + __in IBootstrapperApplication* pBA,
761 + __in BA_ONCACHEPACKAGENONVITALVALIDATIONFAILURE_ARGS* pArgs,
762 + __inout BA_ONCACHEPACKAGENONVITALVALIDATIONFAILURE_RESULTS* pResults
763 + )
764 +{
765 + return pBA->OnCachePackageNonVitalValidationFailure(pArgs->wzPackageId, pArgs->hrStatus, pArgs->recommendation, &pResults->action);
766 +}
767 +
768 /*******************************************************************
769 BalBaseBootstrapperApplicationProc - requires pvContext to be of type IBootstrapperApplication.
770 Provides a default mapping between the new message based BA interface and
@@ -1024,6 +1033,9 @@ static HRESULT WINAPI BalBaseBootstrapperApplicationProc(
1033 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTRELATEDBUNDLEPACKAGE:
1034 hr = BalBaseBAProcOnDetectRelatedBundlePackage(pBA, reinterpret_cast<BA_ONDETECTRELATEDBUNDLEPACKAGE_ARGS*>(pvArgs), reinterpret_cast<BA_ONDETECTRELATEDBUNDLEPACKAGE_RESULTS*>(pvResults));
1035 break;
1036 + case BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEPACKAGENONVITALVALIDATIONFAILURE:
1037 + hr = BalBaseBAProcOnCachePackageNonVitalValidationFailure(pBA, reinterpret_cast<BA_ONCACHEPACKAGENONVITALVALIDATIONFAILURE_ARGS*>(pvArgs), reinterpret_cast<BA_ONCACHEPACKAGENONVITALVALIDATIONFAILURE_RESULTS*>(pvResults));
1038 + break;
1039 }
1040 }
1041
src/api/burn/balutil/inc/IBootstrapperApplication.h
+9
@@ -343,6 +343,7 @@ DECLARE_INTERFACE_IID_(IBootstrapperApplication, IUnknown, "53C31D56-49C0-426B-A
343 __in_z LPCWSTR wzPackageId,
344 __in DWORD cCachePayloads,
345 __in DWORD64 dw64PackageCacheSize,
346 + __in BOOL fVital,
347 __inout BOOL* pfCancel
348 ) = 0;
349
@@ -728,4 +729,12 @@ DECLARE_INTERFACE_IID_(IBootstrapperApplication, IUnknown, "53C31D56-49C0-426B-A
729 __in_z LPCWSTR wzVersion,
730 __inout BOOL* pfCancel
731 ) = 0;
732 +
733 + // OnCachePackageNonVitalValidationFailure - called when the engine failed validating a package in the package cache that is non-vital to execution.
734 + STDMETHOD(OnCachePackageNonVitalValidationFailure)(
735 + __in_z LPCWSTR wzPackageId,
736 + __in HRESULT hrStatus,
737 + __in BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION recommendation,
738 + __inout BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION* pAction
739 + ) = 0;
740 };
src/burn/engine/apply.cpp
+41 -10
@@ -110,7 +110,8 @@ static HRESULT ApplyLayoutContainer(
110 static HRESULT ApplyProcessPayload(
111 __in BURN_CACHE_CONTEXT* pContext,
112 __in_opt BURN_PACKAGE* pPackage,
113 - __in BURN_PAYLOAD_GROUP_ITEM* pPayloadGroupItem
113 + __in BURN_PAYLOAD_GROUP_ITEM* pPayloadGroupItem,
114 + __in BOOL fVital
115 );
116 static HRESULT ApplyCacheVerifyContainerOrPayload(
117 __in BURN_CACHE_CONTEXT* pContext,
@@ -203,6 +204,10 @@ static HRESULT DoRollbackActions(
204 __in DWORD dwCheckpoint,
205 __out BOOTSTRAPPER_APPLY_RESTART* pRestart
206 );
207 +static BOOL ShouldSkipPackage(
208 + __in BURN_PACKAGE* pPackage,
209 + __in BOOL fRollback
210 + );
211 static HRESULT ExecuteRelatedBundle(
212 __in BURN_ENGINE_STATE* pEngineState,
213 __in BURN_EXECUTE_ACTION* pExecuteAction,
@@ -379,6 +384,7 @@ extern "C" void ApplyReset(
384 {
385 BURN_PACKAGE* pPackage = pPackages->rgPackages + i;
386 pPackage->hrCacheResult = S_OK;
387 + pPackage->fAcquireOptionalSource = FALSE;
388 pPackage->fReachedExecution = FALSE;
389 pPackage->fAbandonedProcess = FALSE;
390 pPackage->transactionRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN;
@@ -633,7 +639,7 @@ extern "C" HRESULT ApplyCache(
639 break;
640
641 case BURN_CACHE_ACTION_TYPE_SIGNAL_SYNCPOINT:
636 - if (!::SetEvent(pCacheAction->syncpoint.hEvent))
642 + if (!::SetEvent(pCacheAction->syncpoint.pPackage->hCacheEvent))
643 {
644 ExitWithLastError(hr, "Failed to set syncpoint event.");
645 }
@@ -959,12 +965,13 @@ static HRESULT ApplyCachePackage(
965 HRESULT hr = S_OK;
966 BOOL fCanceledBegin = FALSE;
967 BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION cachePackageCompleteAction = BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION_NONE;
968 + BOOL fVital = pPackage->fCacheVital;
969
970 for (;;)
971 {
972 fCanceledBegin = FALSE;
973
967 - hr = UserExperienceOnCachePackageBegin(pContext->pUX, pPackage->sczId, pPackage->payloads.cItems, pPackage->payloads.qwTotalSize);
974 + hr = UserExperienceOnCachePackageBegin(pContext->pUX, pPackage->sczId, pPackage->payloads.cItems, pPackage->payloads.qwTotalSize, fVital);
975 if (FAILED(hr))
976 {
977 fCanceledBegin = TRUE;
@@ -975,7 +982,7 @@ static HRESULT ApplyCachePackage(
982 {
983 BURN_PAYLOAD_GROUP_ITEM* pPayloadGroupItem = pPackage->payloads.rgItems + i;
984
978 - hr = ApplyProcessPayload(pContext, pPackage, pPayloadGroupItem);
985 + hr = ApplyProcessPayload(pContext, pPackage, pPayloadGroupItem, fVital);
986 if (FAILED(hr))
987 {
988 break;
@@ -984,7 +991,7 @@ static HRESULT ApplyCachePackage(
991 }
992
993 pPackage->hrCacheResult = hr;
987 - cachePackageCompleteAction = SUCCEEDED(hr) || pPackage->fVital || fCanceledBegin ? BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION_NONE : BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION_IGNORE;
994 + cachePackageCompleteAction = SUCCEEDED(hr) || (pPackage->fVital && fVital) || fCanceledBegin ? BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION_NONE : BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION_IGNORE;
995 UserExperienceOnCachePackageComplete(pContext->pUX, pPackage->sczId, hr, &cachePackageCompleteAction);
996
997 if (SUCCEEDED(hr))
@@ -1014,7 +1021,7 @@ static HRESULT ApplyCachePackage(
1021
1022 continue;
1023 }
1017 - else if (BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION_IGNORE == cachePackageCompleteAction && !pPackage->fVital) // ignore non-vital download failures.
1024 + else if (BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION_IGNORE == cachePackageCompleteAction && (!pPackage->fVital || !fVital)) // ignore non-vital download failures.
1025 {
1026 LogId(REPORT_STANDARD, MSG_CACHE_CONTINUING_NONVITAL_PACKAGE, pPackage->sczId, hr);
1027 hr = S_OK;
@@ -1101,7 +1108,7 @@ static HRESULT ApplyLayoutBundle(
1108 {
1109 BURN_PAYLOAD_GROUP_ITEM* pPayloadGroupItem = pPayloads->rgItems + i;
1110
1104 - hr = ApplyProcessPayload(pContext, NULL, pPayloadGroupItem);
1111 + hr = ApplyProcessPayload(pContext, NULL, pPayloadGroupItem, TRUE);
1112 ExitOnFailure(hr, "Failed to layout bundle payload: %ls", pPayloadGroupItem->pPayload->sczKey);
1113 }
1114
@@ -1164,12 +1171,14 @@ LExit:
1171 static HRESULT ApplyProcessPayload(
1172 __in BURN_CACHE_CONTEXT* pContext,
1173 __in_opt BURN_PACKAGE* pPackage,
1167 - __in BURN_PAYLOAD_GROUP_ITEM* pPayloadGroupItem
1174 + __in BURN_PAYLOAD_GROUP_ITEM* pPayloadGroupItem,
1175 + __in BOOL fVital
1176 )
1177 {
1178 HRESULT hr = S_OK;
1179 DWORD cTryAgainAttempts = 0;
1180 BOOL fRetry = FALSE;
1181 + BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION action = BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION_NONE;
1182 BURN_PAYLOAD* pPayload = pPayloadGroupItem->pPayload;
1183
1184 Assert(pContext->pPayloads && pPackage || pContext->wzLayoutDirectory);
@@ -1184,6 +1193,18 @@ static HRESULT ApplyProcessPayload(
1193 {
1194 ExitFunction();
1195 }
1196 + else if (pPackage && !pPackage->fAcquireOptionalSource && !fVital)
1197 + {
1198 + HRESULT hrResponse = UserExperienceOnCachePackageNonVitalValidationFailure(pContext->pUX, pPackage->sczId, hr, &action);
1199 + ExitOnRootFailure(hrResponse, "BA aborted cache package non-vital failure.");
1200 +
1201 + if (BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION_ACQUIRE != action)
1202 + {
1203 + ExitFunction();
1204 + }
1205 +
1206 + pPackage->fAcquireOptionalSource = TRUE;
1207 + }
1208
1209 for (;;)
1210 {
@@ -2567,10 +2588,20 @@ static BOOL ShouldSkipPackage(
2588 )
2589 {
2590 BOOL fSkip = FALSE;
2591 + BURN_CACHE_PACKAGE_TYPE cachePackageType = fRollback ? pPackage->rollbackCacheType : pPackage->executeCacheType;
2592 + BOOL fCacheVital = BURN_CACHE_PACKAGE_TYPE_REQUIRED == cachePackageType;
2593
2571 - if (FAILED(pPackage->hrCacheResult))
2594 + if (fCacheVital && FAILED(pPackage->hrCacheResult))
2595 {
2573 - LogId(REPORT_STANDARD, MSG_APPLY_SKIPPED_FAILED_CACHED_PACKAGE, pPackage->sczId, pPackage->hrCacheResult);
2596 + if (fRollback)
2597 + {
2598 + LogId(REPORT_STANDARD, MSG_APPLY_SKIPPED_ROLLBACK_NO_CACHE, pPackage->sczId, pPackage->hrCacheResult, LoggingActionStateToString(pPackage->rollback));
2599 + }
2600 + else
2601 + {
2602 + LogId(REPORT_STANDARD, MSG_APPLY_SKIPPED_FAILED_CACHED_PACKAGE, pPackage->sczId, pPackage->hrCacheResult);
2603 + }
2604 +
2605 ExitFunction1(fSkip = TRUE);
2606 }
2607 else if (fRollback && pPackage->fAbandonedProcess)
src/burn/engine/core.cpp
+1 -1
@@ -2329,7 +2329,7 @@ static void LogPackages(
2329 LogRollbackBoundary(pPackage->pRollbackBoundaryBackward);
2330 }
2331
2332 - LogId(REPORT_STANDARD, MSG_PLANNED_PACKAGE, pPackage->sczId, LoggingPackageStateToString(pPackage->currentState), LoggingRequestStateToString(pPackage->defaultRequested), LoggingRequestStateToString(pPackage->requested), LoggingActionStateToString(pPackage->execute), LoggingActionStateToString(pPackage->rollback), LoggingCacheTypeToString(pPackage->authoredCacheType), LoggingCacheTypeToString(pPackage->cacheType), LoggingBoolToString(pPackage->fPlannedCache), LoggingBoolToString(pPackage->fPlannedUncache), LoggingDependencyActionToString(pPackage->dependencyExecute), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->expectedInstallRegistrationState), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->expectedCacheRegistrationState));
2332 + LogId(REPORT_STANDARD, MSG_PLANNED_PACKAGE, pPackage->sczId, LoggingPackageStateToString(pPackage->currentState), LoggingRequestStateToString(pPackage->defaultRequested), LoggingRequestStateToString(pPackage->requested), LoggingActionStateToString(pPackage->execute), LoggingActionStateToString(pPackage->rollback), LoggingCacheTypeToString(pPackage->authoredCacheType), LoggingCacheTypeToString(pPackage->cacheType), LoggingPlannedCacheToString(pPackage), LoggingBoolToString(pPackage->fPlannedUncache), LoggingDependencyActionToString(pPackage->dependencyExecute), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->expectedInstallRegistrationState), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->expectedCacheRegistrationState));
2333
2334 if (BURN_PACKAGE_TYPE_MSI == pPackage->type)
2335 {
src/burn/engine/engine.mc
+2 -2
@@ -417,9 +417,9 @@ Planned related bundle: %1!ls!, detect type: %2!hs!, default plan type: %3!hs!,
417
418 MessageId=208
419 Severity=Warning
420 -SymbolicName=MSG_PLAN_DISABLING_ROLLBACK_NO_CACHE
420 +SymbolicName=MSG_APPLY_SKIPPED_ROLLBACK_NO_CACHE
421 Language=English
422 -Plan disabled rollback due to incomplete cache for package: %1!ls!, original rollback action: %2!hs!
422 +Skipping apply rollback of package: %1!ls! due to cache error: 0x%2!x!, original rollback action: %3!hs!. Continuing...
423 .
424
425 MessageId=209
src/burn/engine/logging.cpp
+29
@@ -445,6 +445,23 @@ extern "C" LPCSTR LoggingCacheTypeToString(
445 }
446 }
447
448 +extern "C" LPCSTR LoggingCachePackageTypeToString(
449 + BURN_CACHE_PACKAGE_TYPE cachePackageType
450 + )
451 +{
452 + switch (cachePackageType)
453 + {
454 + case BURN_CACHE_PACKAGE_TYPE_NONE:
455 + return "None";
456 + case BURN_CACHE_PACKAGE_TYPE_OPTIONAL:
457 + return "Optional";
458 + case BURN_CACHE_PACKAGE_TYPE_REQUIRED:
459 + return "Required";
460 + default:
461 + return "Invalid";
462 + }
463 +}
464 +
465 extern "C" LPCSTR LoggingDependencyActionToString(
466 BURN_DEPENDENCY_ACTION action
467 )
@@ -669,6 +686,18 @@ extern "C" LPCSTR LoggingPerMachineToString(
686 return "PerUser";
687 }
688
689 +extern "C" LPCSTR LoggingPlannedCacheToString(
690 + __in const BURN_PACKAGE* pPackage
691 + )
692 +{
693 + if (!pPackage->hCacheEvent)
694 + {
695 + return "No";
696 + }
697 +
698 + return pPackage->fCacheVital ? "Vital" : "NonVital";
699 +}
700 +
701 extern "C" LPCSTR LoggingRegistrationTypeToString(
702 __in BOOTSTRAPPER_REGISTRATION_TYPE registrationType
703 )
src/burn/engine/logging.h
+8
@@ -92,6 +92,10 @@ LPCSTR LoggingCacheTypeToString(
92 BOOTSTRAPPER_CACHE_TYPE cacheType
93 );
94
95 +LPCSTR LoggingCachePackageTypeToString(
96 + BURN_CACHE_PACKAGE_TYPE cachePackageType
97 + );
98 +
99 LPCSTR LoggingDependencyActionToString(
100 BURN_DEPENDENCY_ACTION action
101 );
@@ -142,6 +146,10 @@ LPCSTR LoggingPerMachineToString(
146 __in BOOL fPerMachine
147 );
148
149 +LPCSTR LoggingPlannedCacheToString(
150 + __in const BURN_PACKAGE* pPackage
151 + );
152 +
153 LPCSTR LoggingRegistrationTypeToString(
154 __in BOOTSTRAPPER_REGISTRATION_TYPE registrationType
155 );
src/burn/engine/package.h
+11 -1
@@ -16,6 +16,13 @@ typedef _BURN_PACKAGE BURN_PACKAGE;
16
17 const DWORD BURN_PACKAGE_INVALID_PATCH_INDEX = 0x80000000;
18
19 +enum BURN_CACHE_PACKAGE_TYPE
20 +{
21 + BURN_CACHE_PACKAGE_TYPE_NONE,
22 + BURN_CACHE_PACKAGE_TYPE_OPTIONAL,
23 + BURN_CACHE_PACKAGE_TYPE_REQUIRED,
24 +};
25 +
26 enum BURN_EXE_DETECTION_TYPE
27 {
28 BURN_EXE_DETECTION_TYPE_NONE,
@@ -277,7 +284,7 @@ typedef struct _BURN_PACKAGE
284 BOOTSTRAPPER_CACHE_TYPE cacheType; // only valid during Plan.
285 BOOTSTRAPPER_REQUEST_STATE defaultRequested;// only valid during Plan.
286 BOOTSTRAPPER_REQUEST_STATE requested; // only valid during Plan.
280 - BOOL fPlannedCache; // only valid during Plan.
287 + BOOL fCacheVital; // only valid during Plan.
288 BOOL fPlannedUncache; // only valid during Plan.
289 BOOTSTRAPPER_ACTION_STATE execute; // only valid during Plan.
290 BOOTSTRAPPER_ACTION_STATE rollback; // only valid during Plan.
@@ -286,9 +293,12 @@ typedef struct _BURN_PACKAGE
293 BURN_DEPENDENCY_ACTION dependencyExecute; // only valid during Plan.
294 BURN_DEPENDENCY_ACTION dependencyRollback; // only valid during Plan.
295 BOOL fDependencyManagerWasHere; // only valid during Plan.
296 + BURN_CACHE_PACKAGE_TYPE executeCacheType; // only valid during Plan.
297 + BURN_CACHE_PACKAGE_TYPE rollbackCacheType; // only valid during Plan.
298 HANDLE hCacheEvent; // only valid during Plan.
299 LPWSTR sczCacheFolder; // only valid during Apply.
300 HRESULT hrCacheResult; // only valid during Apply.
301 + BOOL fAcquireOptionalSource; // only valid during Apply.
302 BOOL fReachedExecution; // only valid during Apply.
303 BOOL fAbandonedProcess; // only valid during Apply.
304
src/burn/engine/plan.cpp
+66 -45
@@ -78,11 +78,13 @@ static HRESULT AddRegistrationAction(
78 );
79 static HRESULT AddCachePackage(
80 __in BURN_PLAN* pPlan,
81 - __in BURN_PACKAGE* pPackage
81 + __in BURN_PACKAGE* pPackage,
82 + __in BOOL fVital
83 );
84 static HRESULT AddCachePackageHelper(
85 __in BURN_PLAN* pPlan,
85 - __in BURN_PACKAGE* pPackage
86 + __in BURN_PACKAGE* pPackage,
87 + __in BOOL fVital
88 );
89 static HRESULT AddCacheSlipstreamMsps(
90 __in BURN_PLAN* pPlan,
@@ -134,7 +136,7 @@ static HRESULT CalculateExecuteActions(
136 __in BURN_PACKAGE* pPackage,
137 __in_opt BURN_ROLLBACK_BOUNDARY* pActiveRollbackBoundary
138 );
137 -static BOOL NeedsCache(
139 +static BURN_CACHE_PACKAGE_TYPE GetCachePackageType(
140 __in BURN_PACKAGE* pPackage,
141 __in BOOL fExecute
142 );
@@ -894,7 +896,7 @@ static HRESULT PlanPackagesHelper(
896 DWORD iPackage = fReverseOrder ? cPackages - 1 - i : i;
897 BURN_PACKAGE* pPackage = rgPackages + iPackage;
898
897 - UserExperienceOnPlannedPackage(pUX, pPackage->sczId, pPackage->execute, pPackage->rollback, pPackage->fPlannedCache, pPackage->fPlannedUncache);
899 + UserExperienceOnPlannedPackage(pUX, pPackage->sczId, pPackage->execute, pPackage->rollback, NULL != pPackage->hCacheEvent, pPackage->fPlannedUncache);
900
901 if (pPackage->compatiblePackage.fPlannable)
902 {
@@ -999,7 +1001,7 @@ static HRESULT ProcessPackage(
1001 {
1002 if (BOOTSTRAPPER_REQUEST_STATE_NONE != pPackage->requested)
1003 {
1002 - hr = PlanLayoutPackage(pPlan, pPackage);
1004 + hr = PlanLayoutPackage(pPlan, pPackage, TRUE);
1005 ExitOnFailure(hr, "Failed to plan layout package.");
1006 }
1007 }
@@ -1015,7 +1017,7 @@ static HRESULT ProcessPackage(
1017 {
1018 if (ForceCache(pPlan, pPackage))
1019 {
1018 - hr = AddCachePackage(pPlan, pPackage);
1020 + hr = AddCachePackage(pPlan, pPackage, TRUE);
1021 ExitOnFailure(hr, "Failed to plan cache package.");
1022
1023 if (pPackage->fPerMachine)
@@ -1127,7 +1129,8 @@ LExit:
1129
1130 extern "C" HRESULT PlanLayoutPackage(
1131 __in BURN_PLAN* pPlan,
1130 - __in BURN_PACKAGE* pPackage
1132 + __in BURN_PACKAGE* pPackage,
1133 + __in BOOL fVital
1134 )
1135 {
1136 HRESULT hr = S_OK;
@@ -1143,6 +1146,7 @@ extern "C" HRESULT PlanLayoutPackage(
1146
1147 pCacheAction->type = BURN_CACHE_ACTION_TYPE_PACKAGE;
1148 pCacheAction->package.pPackage = pPackage;
1149 + pPackage->fCacheVital = fVital;
1150
1151 ++pPlan->cOverallProgressTicksTotal;
1152
@@ -1170,18 +1174,14 @@ extern "C" HRESULT PlanExecutePackage(
1174 hr = DependencyPlanPackageBegin(fPerMachine, pPackage, pPlan);
1175 ExitOnFailure(hr, "Failed to begin plan dependency actions for package: %ls", pPackage->sczId);
1176
1173 - if (fRequestedCache || NeedsCache(pPackage, TRUE))
1177 + pPackage->executeCacheType = fRequestedCache ? BURN_CACHE_PACKAGE_TYPE_REQUIRED : GetCachePackageType(pPackage, TRUE);
1178 + pPackage->rollbackCacheType = GetCachePackageType(pPackage, FALSE);
1179 +
1180 + if (BURN_CACHE_PACKAGE_TYPE_NONE != pPackage->executeCacheType || BURN_CACHE_PACKAGE_TYPE_NONE != pPackage->rollbackCacheType)
1181 {
1175 - hr = AddCachePackage(pPlan, pPackage);
1182 + hr = AddCachePackage(pPlan, pPackage, BURN_CACHE_PACKAGE_TYPE_REQUIRED == pPackage->executeCacheType);
1183 ExitOnFailure(hr, "Failed to plan cache package.");
1184 }
1178 - else if (!pPackage->fCached && NeedsCache(pPackage, FALSE))
1179 - {
1180 - // TODO: this decision should be made during apply instead of plan based on whether the package is actually cached.
1181 - // If the package is not in the cache, disable any rollback that would require the package from the cache.
1182 - LogId(REPORT_STANDARD, MSG_PLAN_DISABLING_ROLLBACK_NO_CACHE, pPackage->sczId, LoggingActionStateToString(pPackage->rollback));
1183 - pPackage->rollback = BOOTSTRAPPER_ACTION_STATE_NONE;
1184 - }
1185
1186 // Add execute actions.
1187 switch (pPackage->type)
@@ -1364,6 +1364,8 @@ extern "C" HRESULT PlanRelatedBundlesInitialize(
1364 pRelatedBundle->package.requested = BOOTSTRAPPER_REQUEST_STATE_NONE;
1365 pRelatedBundle->defaultPlanRelationType = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_NONE;
1366 pRelatedBundle->planRelationType = BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_NONE;
1367 + pRelatedBundle->package.executeCacheType = BURN_CACHE_PACKAGE_TYPE_NONE;
1368 + pRelatedBundle->package.rollbackCacheType = BURN_CACHE_PACKAGE_TYPE_NONE;
1369
1370 // Determine the plan relation type even if later it is ignored due to the planned action, the command relation type, or the related bundle not being plannable.
1371 // This gives more information to the BA in case it wants to override default behavior.
@@ -2088,10 +2090,6 @@ static void UninitializeCacheAction(
2090 {
2091 switch (pCacheAction->type)
2092 {
2091 - case BURN_CACHE_ACTION_TYPE_SIGNAL_SYNCPOINT:
2092 - ReleaseHandle(pCacheAction->syncpoint.hEvent);
2093 - break;
2094 -
2093 case BURN_CACHE_ACTION_TYPE_LAYOUT_BUNDLE:
2094 ReleaseStr(pCacheAction->bundleLayout.sczExecutableName);
2095 ReleaseStr(pCacheAction->bundleLayout.sczUnverifiedPath);
@@ -2145,7 +2143,7 @@ static void ResetPlannedPackageState(
2143 pPackage->cacheType = pPackage->authoredCacheType;
2144 pPackage->defaultRequested = BOOTSTRAPPER_REQUEST_STATE_NONE;
2145 pPackage->requested = BOOTSTRAPPER_REQUEST_STATE_NONE;
2148 - pPackage->fPlannedCache = FALSE;
2146 + pPackage->fCacheVital = FALSE;
2147 pPackage->fPlannedUncache = FALSE;
2148 pPackage->execute = BOOTSTRAPPER_ACTION_STATE_NONE;
2149 pPackage->rollback = BOOTSTRAPPER_ACTION_STATE_NONE;
@@ -2156,7 +2154,9 @@ static void ResetPlannedPackageState(
2154 pPackage->fDependencyManagerWasHere = FALSE;
2155 pPackage->expectedCacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN;
2156 pPackage->expectedInstallRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN;
2159 - pPackage->hCacheEvent = NULL;
2157 + pPackage->executeCacheType = BURN_CACHE_PACKAGE_TYPE_NONE;
2158 + pPackage->rollbackCacheType = BURN_CACHE_PACKAGE_TYPE_NONE;
2159 + ReleaseHandle(pPackage->hCacheEvent);
2160
2161 ReleaseNullStr(pPackage->sczCacheFolder);
2162
@@ -2314,19 +2314,21 @@ LExit:
2314
2315 static HRESULT AddCachePackage(
2316 __in BURN_PLAN* pPlan,
2317 - __in BURN_PACKAGE* pPackage
2317 + __in BURN_PACKAGE* pPackage,
2318 + __in BOOL fVital
2319 )
2320 {
2321 HRESULT hr = S_OK;
2322
2323 // If this is an MSI package with slipstream MSPs, ensure the MSPs are cached first.
2323 - if (BURN_PACKAGE_TYPE_MSI == pPackage->type && 0 < pPackage->Msi.cSlipstreamMspPackages)
2324 + // TODO: Slipstream packages are not accounted for when caching the MSI package is optional.
2325 + if (BURN_PACKAGE_TYPE_MSI == pPackage->type && 0 < pPackage->Msi.cSlipstreamMspPackages && fVital)
2326 {
2327 hr = AddCacheSlipstreamMsps(pPlan, pPackage);
2328 ExitOnFailure(hr, "Failed to plan slipstream patches for package.");
2329 }
2330
2329 - hr = AddCachePackageHelper(pPlan, pPackage);
2331 + hr = AddCachePackageHelper(pPlan, pPackage, fVital);
2332 ExitOnFailure(hr, "Failed to plan cache package.");
2333
2334 LExit:
@@ -2335,7 +2337,8 @@ LExit:
2337
2338 static HRESULT AddCachePackageHelper(
2339 __in BURN_PLAN* pPlan,
2338 - __in BURN_PACKAGE* pPackage
2340 + __in BURN_PACKAGE* pPackage,
2341 + __in BOOL fVital
2342 )
2343 {
2344 AssertSz(pPackage->sczCacheId && *pPackage->sczCacheId, "AddCachePackageHelper() expects the package to have a cache id.");
@@ -2354,6 +2357,9 @@ static HRESULT AddCachePackageHelper(
2357 ExitFunction();
2358 }
2359
2360 + pPackage->hCacheEvent = ::CreateEventW(NULL, TRUE, FALSE, NULL);
2361 + ExitOnNullWithLastError(pPackage->hCacheEvent, hr, "Failed to create syncpoint event.");
2362 +
2363 // Cache checkpoints happen before the package is cached because downloading packages'
2364 // payloads will not roll themselves back the way installation packages rollback on
2365 // failure automatically.
@@ -2381,7 +2387,7 @@ static HRESULT AddCachePackageHelper(
2387 pCacheAction->checkpoint.dwId = dwCheckpoint;
2388 }
2389
2384 - hr = PlanLayoutPackage(pPlan, pPackage);
2390 + hr = PlanLayoutPackage(pPlan, pPackage, fVital);
2391 ExitOnFailure(hr, "Failed to plan cache for package.");
2392
2393 // Create syncpoint action.
@@ -2389,15 +2395,11 @@ static HRESULT AddCachePackageHelper(
2395 ExitOnFailure(hr, "Failed to append cache action.");
2396
2397 pCacheAction->type = BURN_CACHE_ACTION_TYPE_SIGNAL_SYNCPOINT;
2392 - pCacheAction->syncpoint.hEvent = ::CreateEventW(NULL, TRUE, FALSE, NULL);
2393 - ExitOnNullWithLastError(pCacheAction->syncpoint.hEvent, hr, "Failed to create syncpoint event.");
2394 -
2395 - pPackage->hCacheEvent = pCacheAction->syncpoint.hEvent;
2398 + pCacheAction->syncpoint.pPackage = pPackage;
2399
2400 hr = PlanExecuteCacheSyncAndRollback(pPlan, pPackage);
2401 ExitOnFailure(hr, "Failed to plan package cache syncpoint");
2402
2400 - pPackage->fPlannedCache = TRUE;
2403 if (pPackage->fCanAffectRegistration)
2404 {
2405 pPackage->expectedCacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT;
@@ -2421,7 +2423,7 @@ static HRESULT AddCacheSlipstreamMsps(
2423 BURN_PACKAGE* pMspPackage = pPackage->Msi.rgSlipstreamMsps[i].pMspPackage;
2424 AssertSz(BURN_PACKAGE_TYPE_MSP == pMspPackage->type, "Only MSP packages can be slipstream patches.");
2425
2424 - hr = AddCachePackageHelper(pPlan, pMspPackage);
2426 + hr = AddCachePackageHelper(pPlan, pMspPackage, TRUE);
2427 ExitOnFailure(hr, "Failed to plan slipstream MSP: %ls", pMspPackage->sczId);
2428 }
2429
@@ -2791,22 +2793,41 @@ LExit:
2793 return hr;
2794 }
2795
2794 -static BOOL NeedsCache(
2796 +static BURN_CACHE_PACKAGE_TYPE GetCachePackageType(
2797 __in BURN_PACKAGE* pPackage,
2798 __in BOOL fExecute
2799 )
2800 {
2799 - BOOTSTRAPPER_ACTION_STATE action = fExecute ? pPackage->execute : pPackage->rollback;
2800 - // TODO: bundles could theoretically use package cache
2801 - if (BURN_PACKAGE_TYPE_BUNDLE == pPackage->type || // Bundle and Exe packages require the package for all operations (even uninstall).
2802 - BURN_PACKAGE_TYPE_EXE == pPackage->type && BURN_EXE_DETECTION_TYPE_ARP != pPackage->Exe.detectionType)
2803 - {
2804 - return BOOTSTRAPPER_ACTION_STATE_NONE != action;
2805 - }
2806 - else // The other package types can uninstall without the original package.
2801 + BURN_CACHE_PACKAGE_TYPE cachePackageType = BURN_CACHE_PACKAGE_TYPE_NONE;
2802 +
2803 + switch (fExecute ? pPackage->execute : pPackage->rollback)
2804 {
2808 - return BOOTSTRAPPER_ACTION_STATE_UNINSTALL < action;
2805 + case BOOTSTRAPPER_ACTION_STATE_NONE:
2806 + break;
2807 + case BOOTSTRAPPER_ACTION_STATE_UNINSTALL:
2808 + if (BURN_PACKAGE_TYPE_BUNDLE == pPackage->type ||
2809 + BURN_PACKAGE_TYPE_EXE == pPackage->type && BURN_EXE_DETECTION_TYPE_ARP != pPackage->Exe.detectionType)
2810 + {
2811 + // Bundle and non-ArpEntry Exe packages require the package for all operations (even uninstall).
2812 + // TODO: bundles could theoretically use package cache.
2813 + cachePackageType = BURN_CACHE_PACKAGE_TYPE_REQUIRED;
2814 + }
2815 + else
2816 + {
2817 + // The other package types can uninstall without the original package.
2818 + cachePackageType = BURN_CACHE_PACKAGE_TYPE_NONE;
2819 + }
2820 + break;
2821 + case BOOTSTRAPPER_ACTION_STATE_INSTALL: __fallthrough;
2822 + case BOOTSTRAPPER_ACTION_STATE_MODIFY: __fallthrough;
2823 + case BOOTSTRAPPER_ACTION_STATE_REPAIR: __fallthrough;
2824 + case BOOTSTRAPPER_ACTION_STATE_MINOR_UPGRADE: __fallthrough;
2825 + default:
2826 + cachePackageType = BURN_CACHE_PACKAGE_TYPE_REQUIRED;
2827 + break;
2828 }
2829 +
2830 + return cachePackageType;
2831 }
2832
2833 static BOOL ForceCache(
@@ -2881,7 +2902,7 @@ static void CacheActionLog(
2902 break;
2903
2904 case BURN_CACHE_ACTION_TYPE_PACKAGE:
2884 - LogStringLine(PlanDumpLevel, "%ls action[%u]: PACKAGE id: %ls", wzBase, iAction, pAction->package.pPackage->sczId);
2905 + LogStringLine(PlanDumpLevel, "%ls action[%u]: PACKAGE id: %ls, vital: %hs, execute cache type: %hs, rollback cache type: %hs", wzBase, iAction, pAction->package.pPackage->sczId, LoggingBoolToString(pAction->package.pPackage->fCacheVital), LoggingCachePackageTypeToString(pAction->package.pPackage->executeCacheType), LoggingCachePackageTypeToString(pAction->package.pPackage->rollbackCacheType));
2906 break;
2907
2908 case BURN_CACHE_ACTION_TYPE_ROLLBACK_PACKAGE:
@@ -2889,7 +2910,7 @@ static void CacheActionLog(
2910 break;
2911
2912 case BURN_CACHE_ACTION_TYPE_SIGNAL_SYNCPOINT:
2892 - LogStringLine(PlanDumpLevel, "%ls action[%u]: SIGNAL_SYNCPOINT event handle: 0x%p", wzBase, iAction, pAction->syncpoint.hEvent);
2913 + LogStringLine(PlanDumpLevel, "%ls action[%u]: SIGNAL_SYNCPOINT package id: %ls, event handle: 0x%p", wzBase, iAction, pAction->syncpoint.pPackage->sczId, pAction->syncpoint.pPackage->hCacheEvent);
2914 break;
2915
2916 default:
src/burn/engine/plan.h
+3 -2
@@ -117,7 +117,7 @@ typedef struct _BURN_CACHE_ACTION
117 } rollbackPackage;
118 struct
119 {
120 - HANDLE hEvent;
120 + BURN_PACKAGE* pPackage;
121 } syncpoint;
122 struct
123 {
@@ -392,7 +392,8 @@ HRESULT PlanLayoutContainer(
392 );
393 HRESULT PlanLayoutPackage(
394 __in BURN_PLAN* pPlan,
395 - __in BURN_PACKAGE* pPackage
395 + __in BURN_PACKAGE* pPackage,
396 + __in BOOL fVital
397 );
398 HRESULT PlanExecutePackage(
399 __in BOOL fPerMachine,
src/burn/engine/userexperience.cpp
+38 -2
@@ -104,7 +104,7 @@ extern "C" HRESULT UserExperienceLoad(
104 args.pCommand = pCommand;
105 args.pfnBootstrapperEngineProc = EngineForApplicationProc;
106 args.pvBootstrapperEngineProcContext = pEngineContext;
107 - args.qwEngineAPIVersion = MAKEQWORDVERSION(2022, 3, 31, 0);
107 + args.qwEngineAPIVersion = MAKEQWORDVERSION(2022, 6, 10, 0);
108
109 results.cbSize = sizeof(BOOTSTRAPPER_CREATE_RESULTS);
110
@@ -726,7 +726,8 @@ EXTERN_C BAAPI UserExperienceOnCachePackageBegin(
726 __in BURN_USER_EXPERIENCE* pUserExperience,
727 __in_z LPCWSTR wzPackageId,
728 __in DWORD cCachePayloads,
729 - __in DWORD64 dw64PackageCacheSize
729 + __in DWORD64 dw64PackageCacheSize,
730 + __in BOOL fVital
731 )
732 {
733 HRESULT hr = S_OK;
@@ -737,6 +738,7 @@ EXTERN_C BAAPI UserExperienceOnCachePackageBegin(
738 args.wzPackageId = wzPackageId;
739 args.cCachePayloads = cCachePayloads;
740 args.dw64PackageCacheSize = dw64PackageCacheSize;
741 + args.fVital = fVital;
742
743 results.cbSize = sizeof(results);
744
@@ -783,6 +785,40 @@ LExit:
785 return hr;
786 }
787
788 +EXTERN_C BAAPI UserExperienceOnCachePackageNonVitalValidationFailure(
789 + __in BURN_USER_EXPERIENCE* pUserExperience,
790 + __in_z LPCWSTR wzPackageId,
791 + __in HRESULT hrStatus,
792 + __inout BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION* pAction
793 + )
794 +{
795 + HRESULT hr = S_OK;
796 + BA_ONCACHEPACKAGENONVITALVALIDATIONFAILURE_ARGS args = { };
797 + BA_ONCACHEPACKAGENONVITALVALIDATIONFAILURE_RESULTS results = { };
798 +
799 + args.cbSize = sizeof(args);
800 + args.wzPackageId = wzPackageId;
801 + args.hrStatus = hrStatus;
802 + args.recommendation = *pAction;
803 +
804 + results.cbSize = sizeof(results);
805 + results.action = *pAction;
806 +
807 + hr = SendBAMessage(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEPACKAGENONVITALVALIDATIONFAILURE, &args, &results);
808 + ExitOnFailure(hr, "BA OnCachePackageNonVitalValidationFailure failed.");
809 +
810 + switch (results.action)
811 + {
812 + case BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION_NONE: __fallthrough;
813 + case BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION_ACQUIRE:
814 + *pAction = results.action;
815 + break;
816 + }
817 +
818 +LExit:
819 + return hr;
820 +}
821 +
822 EXTERN_C BAAPI UserExperienceOnCachePayloadExtractBegin(
823 __in BURN_USER_EXPERIENCE* pUserExperience,
824 __in_z_opt LPCWSTR wzContainerId,
src/burn/engine/userexperience.h
+8 -1
@@ -189,7 +189,14 @@ BAAPI UserExperienceOnCachePackageBegin(
189 __in BURN_USER_EXPERIENCE* pUserExperience,
190 __in_z LPCWSTR wzPackageId,
191 __in DWORD cCachePayloads,
192 - __in DWORD64 dw64PackageCacheSize
192 + __in DWORD64 dw64PackageCacheSize,
193 + __in BOOL fVital
194 + );
195 +BAAPI UserExperienceOnCachePackageNonVitalValidationFailure(
196 + __in BURN_USER_EXPERIENCE* pUserExperience,
197 + __in_z LPCWSTR wzPackageId,
198 + __in HRESULT hrStatus,
199 + __inout BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION* pAction
200 );
201 BAAPI UserExperienceOnCachePackageComplete(
202 __in BURN_USER_EXPERIENCE* pUserExperience,
src/burn/test/BurnUnitTest/PlanTest.cpp
+116 -63
@@ -87,8 +87,8 @@ namespace Bootstrapper
87 fRollback = FALSE;
88 dwIndex = 0;
89 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
90 - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"TestExe");
91 - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
90 + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"TestExe", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE);
91 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"TestExe");
92 Assert::Equal(dwIndex, pPlan->cCacheActions);
93
94 fRollback = TRUE;
@@ -259,19 +259,24 @@ namespace Bootstrapper
259
260 fRollback = FALSE;
261 dwIndex = 0;
262 + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
263 + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"TestExe", FALSE, BURN_CACHE_PACKAGE_TYPE_NONE, BURN_CACHE_PACKAGE_TYPE_REQUIRED);
264 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"TestExe");
265 Assert::Equal(dwIndex, pPlan->cCacheActions);
266
267 fRollback = TRUE;
268 dwIndex = 0;
269 Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
270
268 - Assert::Equal(0ull, pPlan->qwCacheSizeTotal);
271 + Assert::Equal(143724ull, pPlan->qwCacheSizeTotal);
272
273 fRollback = FALSE;
274 dwIndex = 0;
272 - DWORD dwExecuteCheckpointId = 1;
275 + DWORD dwExecuteCheckpointId = 2;
276 ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
277 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
278 + ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"TestExe");
279 + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
280 ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"TestExe", BOOTSTRAPPER_ACTION_STATE_UNINSTALL);
281 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
282 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
@@ -280,8 +285,9 @@ namespace Bootstrapper
285
286 fRollback = TRUE;
287 dwIndex = 0;
283 - dwExecuteCheckpointId = 1;
288 + dwExecuteCheckpointId = 2;
289 ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
290 + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
291 ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"TestExe", BOOTSTRAPPER_ACTION_STATE_INSTALL);
292 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
293 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
@@ -290,7 +296,7 @@ namespace Bootstrapper
296 Assert::Equal(dwIndex, pPlan->cRollbackActions);
297
298 Assert::Equal(1ul, pPlan->cExecutePackagesTotal);
293 - Assert::Equal(1ul, pPlan->cOverallProgressTicksTotal);
299 + Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal);
300
301 dwIndex = 0;
302 Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions);
@@ -347,14 +353,14 @@ namespace Bootstrapper
353 fRollback = FALSE;
354 dwIndex = 0;
355 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
350 - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
351 - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
356 + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE);
357 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA");
358 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 9);
353 - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageB");
354 - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
359 + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageB", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE);
360 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageB");
361 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 14);
356 - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageC");
357 - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
362 + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageC", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE);
363 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageC");
364 Assert::Equal(dwIndex, pPlan->cCacheActions);
365
366 fRollback = TRUE;
@@ -506,13 +512,16 @@ namespace Bootstrapper
512
513 fRollback = FALSE;
514 dwIndex = 0;
515 + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 9);
516 + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", FALSE, BURN_CACHE_PACKAGE_TYPE_NONE, BURN_CACHE_PACKAGE_TYPE_REQUIRED);
517 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA");
518 Assert::Equal(dwIndex, pPlan->cCacheActions);
519
520 fRollback = TRUE;
521 dwIndex = 0;
522 Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
523
515 - Assert::Equal(0ull, pPlan->qwCacheSizeTotal);
524 + Assert::Equal(185118ull, pPlan->qwCacheSizeTotal);
525
526 fRollback = FALSE;
527 dwIndex = 0;
@@ -536,6 +545,9 @@ namespace Bootstrapper
545 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
546 ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++);
547 ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
548 + dwExecuteCheckpointId += 1; // cache checkpoints
549 + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
550 + ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
551 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
552 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", unregisterActions1, 1);
553 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
@@ -565,6 +577,8 @@ namespace Bootstrapper
577 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
578 ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++);
579 ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
580 + dwExecuteCheckpointId += 1; // cache checkpoints
581 + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
582 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{E6469F05-BDC8-4EB8-B218-67412543EFAA}", registerActions1, 1);
583 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
584 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", registerActions1, 1);
@@ -577,7 +591,7 @@ namespace Bootstrapper
591 Assert::Equal(dwIndex, pPlan->cRollbackActions);
592
593 Assert::Equal(3ul, pPlan->cExecutePackagesTotal);
580 - Assert::Equal(3ul, pPlan->cOverallProgressTicksTotal);
594 + Assert::Equal(4ul, pPlan->cOverallProgressTicksTotal);
595
596 dwIndex = 0;
597 Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions);
@@ -640,11 +654,11 @@ namespace Bootstrapper
654 fRollback = FALSE;
655 dwIndex = 0;
656 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
643 - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
644 - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
657 + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_REQUIRED);
658 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA");
659 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 6);
646 - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageB");
647 - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
660 + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageB", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_REQUIRED);
661 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageB");
662 Assert::Equal(dwIndex, pPlan->cCacheActions);
663
664 fRollback = TRUE;
@@ -753,8 +767,8 @@ namespace Bootstrapper
767 fRollback = FALSE;
768 dwIndex = 0;
769 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 2);
756 - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageB");
757 - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
770 + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageB", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE);
771 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageB");
772 Assert::Equal(dwIndex, pPlan->cCacheActions);
773
774 fRollback = TRUE;
@@ -949,8 +963,8 @@ namespace Bootstrapper
963 fRollback = FALSE;
964 dwIndex = 0;
965 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
952 - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
953 - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
966 + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE);
967 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA");
968 Assert::Equal(dwIndex, pPlan->cCacheActions);
969
970 fRollback = TRUE;
@@ -1068,8 +1082,8 @@ namespace Bootstrapper
1082 fRollback = FALSE;
1083 dwIndex = 0;
1084 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
1071 - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
1072 - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
1085 + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE);
1086 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA");
1087 Assert::Equal(dwIndex, pPlan->cCacheActions);
1088
1089 fRollback = TRUE;
@@ -1170,8 +1184,8 @@ namespace Bootstrapper
1184 fRollback = FALSE;
1185 dwIndex = 0;
1186 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
1173 - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"ExeA");
1174 - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
1187 + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"ExeA", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_REQUIRED);
1188 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"ExeA");
1189 Assert::Equal(dwIndex, pPlan->cCacheActions);
1190
1191 fRollback = TRUE;
@@ -1264,8 +1278,8 @@ namespace Bootstrapper
1278 fRollback = FALSE;
1279 dwIndex = 0;
1280 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
1267 - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
1268 - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
1281 + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE);
1282 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA");
1283 Assert::Equal(dwIndex, pPlan->cCacheActions);
1284
1285 fRollback = TRUE;
@@ -1515,8 +1529,8 @@ namespace Bootstrapper
1529 fRollback = FALSE;
1530 dwIndex = 0;
1531 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
1518 - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
1519 - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
1532 + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE);
1533 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA");
1534 Assert::Equal(dwIndex, pPlan->cCacheActions);
1535
1536 fRollback = TRUE;
@@ -1610,8 +1624,8 @@ namespace Bootstrapper
1624 fRollback = FALSE;
1625 dwIndex = 0;
1626 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
1613 - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
1614 - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
1627 + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE);
1628 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA");
1629 Assert::Equal(dwIndex, pPlan->cCacheActions);
1630
1631 fRollback = TRUE;
@@ -1794,19 +1808,24 @@ namespace Bootstrapper
1808
1809 fRollback = FALSE;
1810 dwIndex = 0;
1811 + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
1812 + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", FALSE, BURN_CACHE_PACKAGE_TYPE_NONE, BURN_CACHE_PACKAGE_TYPE_REQUIRED);
1813 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA");
1814 Assert::Equal(dwIndex, pPlan->cCacheActions);
1815
1816 fRollback = TRUE;
1817 dwIndex = 0;
1818 Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
1819
1803 - Assert::Equal(0ull, pPlan->qwCacheSizeTotal);
1820 + Assert::Equal(175674ull, pPlan->qwCacheSizeTotal);
1821
1822 fRollback = FALSE;
1823 dwIndex = 0;
1807 - DWORD dwExecuteCheckpointId = 1;
1824 + DWORD dwExecuteCheckpointId = 2;
1825 ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
1826 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
1827 + ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
1828 + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
1829 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", unregisterActions1, 1);
1830 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
1831 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", unregisterActions1, 1);
@@ -1819,8 +1838,9 @@ namespace Bootstrapper
1838
1839 fRollback = TRUE;
1840 dwIndex = 0;
1822 - dwExecuteCheckpointId = 1;
1841 + dwExecuteCheckpointId = 2;
1842 ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
1843 + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
1844 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", registerActions1, 1);
1845 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
1846 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", registerActions1, 1);
@@ -1833,7 +1853,7 @@ namespace Bootstrapper
1853 Assert::Equal(dwIndex, pPlan->cRollbackActions);
1854
1855 Assert::Equal(1ul, pPlan->cExecutePackagesTotal);
1836 - Assert::Equal(1ul, pPlan->cOverallProgressTicksTotal);
1856 + Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal);
1857
1858 dwIndex = 0;
1859 Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions);
@@ -2043,19 +2063,24 @@ namespace Bootstrapper
2063
2064 fRollback = FALSE;
2065 dwIndex = 0;
2066 + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
2067 + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", FALSE, BURN_CACHE_PACKAGE_TYPE_NONE, BURN_CACHE_PACKAGE_TYPE_REQUIRED);
2068 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA");
2069 Assert::Equal(dwIndex, pPlan->cCacheActions);
2070
2071 fRollback = TRUE;
2072 dwIndex = 0;
2073 Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
2074
2052 - Assert::Equal(0ull, pPlan->qwCacheSizeTotal);
2075 + Assert::Equal(175674ull, pPlan->qwCacheSizeTotal);
2076
2077 fRollback = FALSE;
2078 dwIndex = 0;
2056 - DWORD dwExecuteCheckpointId = 1;
2079 + DWORD dwExecuteCheckpointId = 2;
2080 ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
2081 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
2082 + ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
2083 + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
2084 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", unregisterActions1, 1);
2085 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
2086 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", unregisterActions1, 1);
@@ -2068,8 +2093,9 @@ namespace Bootstrapper
2093
2094 fRollback = TRUE;
2095 dwIndex = 0;
2071 - dwExecuteCheckpointId = 1;
2096 + dwExecuteCheckpointId = 2;
2097 ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
2098 + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
2099 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", registerActions1, 1);
2100 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
2101 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", registerActions1, 1);
@@ -2082,7 +2108,7 @@ namespace Bootstrapper
2108 Assert::Equal(dwIndex, pPlan->cRollbackActions);
2109
2110 Assert::Equal(1ul, pPlan->cExecutePackagesTotal);
2085 - Assert::Equal(1ul, pPlan->cOverallProgressTicksTotal);
2111 + Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal);
2112
2113 dwIndex = 0;
2114 Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions);
@@ -2139,8 +2165,8 @@ namespace Bootstrapper
2165 fRollback = FALSE;
2166 dwIndex = 0;
2167 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
2142 - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"test.msu");
2143 - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
2168 + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"test.msu", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE);
2169 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"test.msu");
2170 Assert::Equal(dwIndex, pPlan->cCacheActions);
2171
2172 fRollback = TRUE;
@@ -2233,14 +2259,14 @@ namespace Bootstrapper
2259 fRollback = FALSE;
2260 dwIndex = 0;
2261 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
2236 - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"NetFx48Web");
2237 - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
2262 + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"NetFx48Web", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE);
2263 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"NetFx48Web");
2264 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 3);
2239 - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PatchA");
2240 - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
2265 + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PatchA", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE);
2266 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PatchA");
2267 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 5);
2242 - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
2243 - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
2268 + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE);
2269 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA");
2270 Assert::Equal(dwIndex, pPlan->cCacheActions);
2271
2272 fRollback = TRUE;
@@ -2363,26 +2389,37 @@ namespace Bootstrapper
2389
2390 fRollback = FALSE;
2391 dwIndex = 0;
2392 + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
2393 + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PatchA", FALSE, BURN_CACHE_PACKAGE_TYPE_NONE, BURN_CACHE_PACKAGE_TYPE_REQUIRED);
2394 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PatchA");
2395 + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 6);
2396 + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", FALSE, BURN_CACHE_PACKAGE_TYPE_NONE, BURN_CACHE_PACKAGE_TYPE_REQUIRED);
2397 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA");
2398 Assert::Equal(dwIndex, pPlan->cCacheActions);
2399
2400 fRollback = TRUE;
2401 dwIndex = 0;
2402 Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
2403
2372 - Assert::Equal(0ull, pPlan->qwCacheSizeTotal);
2404 + Assert::Equal(212992ull, pPlan->qwCacheSizeTotal);
2405
2406 fRollback = FALSE;
2407 dwIndex = 0;
2376 - DWORD dwExecuteCheckpointId = 1;
2408 + DWORD dwExecuteCheckpointId = 2;
2409 BURN_EXECUTE_ACTION* pExecuteAction = NULL;
2410 ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
2411 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
2412 + ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"PatchA");
2413 + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
2414 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PatchA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", unregisterActions1, 1);
2415 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
2416 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PatchA", unregisterActions1, 1);
2417 pExecuteAction = ValidateDeletedExecuteMspTarget(pPlan, fRollback, dwIndex++, L"PatchA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, L"{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}", TRUE, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, BOOTSTRAPPER_MSI_FILE_VERSIONING_MISSING_OR_OLDER, TRUE);
2418 ValidateExecuteMspTargetPatch(pExecuteAction, 0, L"PatchA");
2419 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
2420 + dwExecuteCheckpointId += 1; // cache checkpoints
2421 + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
2422 + ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
2423 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
2424 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", unregisterActions1, 1);
2425 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
@@ -2396,8 +2433,9 @@ namespace Bootstrapper
2433
2434 fRollback = TRUE;
2435 dwIndex = 0;
2399 - dwExecuteCheckpointId = 1;
2436 + dwExecuteCheckpointId = 2;
2437 ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
2438 + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
2439 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PatchA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", registerActions1, 1);
2440 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
2441 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PatchA", registerActions1, 1);
@@ -2405,6 +2443,8 @@ namespace Bootstrapper
2443 pExecuteAction = ValidateDeletedExecuteMspTarget(pPlan, fRollback, dwIndex++, L"PatchA", BOOTSTRAPPER_ACTION_STATE_INSTALL, L"{5FF7F534-3FFC-41E0-80CD-E6361E5E7B7B}", TRUE, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, BOOTSTRAPPER_MSI_FILE_VERSIONING_MISSING_OR_OLDER, TRUE);
2444 ValidateExecuteMspTargetPatch(pExecuteAction, 0, L"PatchA");
2445 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
2446 + dwExecuteCheckpointId += 1; // cache checkpoints
2447 + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
2448 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", registerActions1, 1);
2449 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
2450 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", registerActions1, 1);
@@ -2417,7 +2457,7 @@ namespace Bootstrapper
2457 Assert::Equal(dwIndex, pPlan->cRollbackActions);
2458
2459 Assert::Equal(2ul, pPlan->cExecutePackagesTotal);
2420 - Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal);
2460 + Assert::Equal(4ul, pPlan->cOverallProgressTicksTotal);
2461
2462 dwIndex = 0;
2463 Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions);
@@ -2479,19 +2519,24 @@ namespace Bootstrapper
2519
2520 fRollback = FALSE;
2521 dwIndex = 0;
2522 + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
2523 + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", FALSE, BURN_CACHE_PACKAGE_TYPE_NONE, BURN_CACHE_PACKAGE_TYPE_REQUIRED);
2524 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA");
2525 Assert::Equal(dwIndex, pPlan->cCacheActions);
2526
2527 fRollback = TRUE;
2528 dwIndex = 0;
2529 Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
2530
2488 - Assert::Equal(0ull, pPlan->qwCacheSizeTotal);
2531 + Assert::Equal(131072ull, pPlan->qwCacheSizeTotal);
2532
2533 fRollback = FALSE;
2534 dwIndex = 0;
2492 - DWORD dwExecuteCheckpointId = 1;
2535 + DWORD dwExecuteCheckpointId = 2;
2536 ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
2537 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
2538 + ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
2539 + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
2540 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", unregisterActions1, 1);
2541 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
2542 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", unregisterActions1, 1);
@@ -2504,8 +2549,9 @@ namespace Bootstrapper
2549
2550 fRollback = TRUE;
2551 dwIndex = 0;
2507 - dwExecuteCheckpointId = 1;
2552 + dwExecuteCheckpointId = 2;
2553 ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
2554 + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
2555 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{22D1DDBA-284D-40A7-BD14-95EA07906F21}", registerActions1, 1);
2556 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
2557 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", registerActions1, 1);
@@ -2518,7 +2564,7 @@ namespace Bootstrapper
2564 Assert::Equal(dwIndex, pPlan->cRollbackActions);
2565
2566 Assert::Equal(1ul, pPlan->cExecutePackagesTotal);
2521 - Assert::Equal(1ul, pPlan->cOverallProgressTicksTotal);
2567 + Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal);
2568
2569 dwIndex = 0;
2570 Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions);
@@ -2575,11 +2621,11 @@ namespace Bootstrapper
2621 fRollback = FALSE;
2622 dwIndex = 0;
2623 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
2578 - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"NetFx48Web");
2579 - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
2624 + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"NetFx48Web", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE);
2625 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"NetFx48Web");
2626 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 4);
2581 - ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
2582 - ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++);
2627 + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA", TRUE, BURN_CACHE_PACKAGE_TYPE_REQUIRED, BURN_CACHE_PACKAGE_TYPE_NONE);
2628 + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, L"PackageA");
2629 Assert::Equal(dwIndex, pPlan->cCacheActions);
2630
2631 fRollback = TRUE;
@@ -3008,12 +3054,18 @@ namespace Bootstrapper
3054 __in BURN_PLAN* pPlan,
3055 __in BOOL fRollback,
3056 __in DWORD dwIndex,
3011 - __in LPCWSTR wzPackageId
3057 + __in LPCWSTR wzPackageId,
3058 + __in BOOL fVital,
3059 + __in BURN_CACHE_PACKAGE_TYPE executeCacheType,
3060 + __in BURN_CACHE_PACKAGE_TYPE rollbackCacheType
3061 )
3062 {
3063 BURN_CACHE_ACTION* pAction = ValidateCacheActionExists(pPlan, fRollback, dwIndex);
3064 Assert::Equal<DWORD>(BURN_CACHE_ACTION_TYPE_PACKAGE, pAction->type);
3065 NativeAssert::StringEqual(wzPackageId, pAction->package.pPackage->sczId);
3066 + Assert::Equal<BOOL>(fVital, pAction->package.pPackage->fCacheVital);
3067 + Assert::Equal<DWORD>(executeCacheType, pAction->package.pPackage->executeCacheType);
3068 + Assert::Equal<DWORD>(rollbackCacheType, pAction->package.pPackage->rollbackCacheType);
3069 return dwIndex + 1;
3070 }
3071
@@ -3032,12 +3084,13 @@ namespace Bootstrapper
3084 void ValidateCacheSignalSyncpoint(
3085 __in BURN_PLAN* pPlan,
3086 __in BOOL fRollback,
3035 - __in DWORD dwIndex
3087 + __in DWORD dwIndex,
3088 + __in LPCWSTR wzPackageId
3089 )
3090 {
3091 BURN_CACHE_ACTION* pAction = ValidateCacheActionExists(pPlan, fRollback, dwIndex);
3092 Assert::Equal<DWORD>(BURN_CACHE_ACTION_TYPE_SIGNAL_SYNCPOINT, pAction->type);
3040 - Assert::NotEqual((DWORD_PTR)NULL, (DWORD_PTR)pAction->syncpoint.hEvent);
3093 + NativeAssert::StringEqual(wzPackageId, pAction->syncpoint.pPackage->sczId);
3094 }
3095
3096 void ValidateCleanAction(
src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp
+13 -1
@@ -655,6 +655,7 @@ public: // IBootstrapperApplication
655 __in_z LPCWSTR wzPackageId,
656 __in DWORD cCachePayloads,
657 __in DWORD64 dw64PackageCacheSize,
658 + __in BOOL fVital,
659 __inout BOOL* pfCancel
660 )
661 {
@@ -673,7 +674,7 @@ public: // IBootstrapperApplication
674 }
675 }
676
676 - return __super::OnCachePackageBegin(wzPackageId, cCachePayloads, dw64PackageCacheSize, pfCancel);
677 + return __super::OnCachePackageBegin(wzPackageId, cCachePayloads, dw64PackageCacheSize, fVital, pfCancel);
678 }
679
680
@@ -1488,6 +1489,9 @@ public: // IBootstrapperApplication
1489 case BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTRELATEDBUNDLEPACKAGE:
1490 OnDetectRelatedBundlePackageFallback(reinterpret_cast<BA_ONDETECTRELATEDBUNDLEPACKAGE_ARGS*>(pvArgs), reinterpret_cast<BA_ONDETECTRELATEDBUNDLEPACKAGE_RESULTS*>(pvResults));
1491 break;
1492 + case BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEPACKAGENONVITALVALIDATIONFAILURE:
1493 + OnCachePackageNonVitalValidationFailureFallback(reinterpret_cast<BA_ONCACHEPACKAGENONVITALVALIDATIONFAILURE_ARGS*>(pvArgs), reinterpret_cast<BA_ONCACHEPACKAGENONVITALVALIDATIONFAILURE_RESULTS*>(pvResults));
1494 + break;
1495 default:
1496 #ifdef DEBUG
1497 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "WIXSTDBA: Forwarding unknown BA message: %d", message);
@@ -2177,6 +2181,14 @@ private: // privates
2181 m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONDETECTRELATEDBUNDLEPACKAGE, pArgs, pResults, m_pvBAFunctionsProcContext);
2182 }
2183
2184 + void OnCachePackageNonVitalValidationFailureFallback(
2185 + __in BA_ONCACHEPACKAGENONVITALVALIDATIONFAILURE_ARGS* pArgs,
2186 + __inout BA_ONCACHEPACKAGENONVITALVALIDATIONFAILURE_RESULTS* pResults
2187 + )
2188 + {
2189 + m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONCACHEPACKAGENONVITALVALIDATIONFAILURE, pArgs, pResults, m_pvBAFunctionsProcContext);
2190 + }
2191 +
2192
2193 public: //CBalBaseBootstrapperApplication
2194 virtual STDMETHODIMP Initialize(
src/test/burn/TestBA/TestBA.cs
+31 -1
@@ -27,6 +27,7 @@ namespace WixToolset.Test.BA
27
28 private string updateBundlePath;
29
30 + private bool allowAcquireAfterValidationFailure;
31 private bool forceKeepRegistration;
32 private bool immediatelyQuit;
33 private bool quitAfterDetect;
@@ -85,7 +86,11 @@ namespace WixToolset.Test.BA
86
87 List<string> verifyArguments = this.ReadVerifyArguments();
88
88 - foreach (string arg in BootstrapperCommand.ParseCommandLineToArgs(this.Command.CommandLine))
89 + IBootstrapperApplicationData baManifest = new BootstrapperApplicationData();
90 + IMbaCommand mbaCommand = this.Command.ParseCommandLine();
91 + mbaCommand.SetOverridableVariables(baManifest.Bundle.OverridableVariables, this.engine);
92 +
93 + foreach (string arg in mbaCommand.UnknownCommandLineArgs)
94 {
95 // If we're not in the update already, process the updatebundle.
96 if (this.Command.Relation != RelationType.Update && arg.StartsWith("-updatebundle:", StringComparison.OrdinalIgnoreCase))
@@ -126,6 +131,12 @@ namespace WixToolset.Test.BA
131 redetectCount = 0;
132 }
133
134 + string allowAcquireAfterValidationFailure = this.ReadPackageAction(null, "AllowAcquireAfterValidationFailure");
135 + if (String.IsNullOrEmpty(allowAcquireAfterValidationFailure) || !Boolean.TryParse(allowAcquireAfterValidationFailure, out this.allowAcquireAfterValidationFailure))
136 + {
137 + this.allowAcquireAfterValidationFailure = false;
138 + }
139 +
140 string explicitlyElevateAndPlanFromOnElevateBegin = this.ReadPackageAction(null, "ExplicitlyElevateAndPlanFromOnElevateBegin");
141 if (String.IsNullOrEmpty(explicitlyElevateAndPlanFromOnElevateBegin) || !Boolean.TryParse(explicitlyElevateAndPlanFromOnElevateBegin, out this.explicitlyElevateAndPlanFromOnElevateBegin))
142 {
@@ -277,6 +288,15 @@ namespace WixToolset.Test.BA
288 {
289 args.State = state;
290 }
291 +
292 + BOOTSTRAPPER_CACHE_TYPE cacheType;
293 + string cacheAction = this.ReadPackageAction(args.PackageId, "CacheRequested");
294 + if (TryParseEnum<BOOTSTRAPPER_CACHE_TYPE>(cacheAction, out cacheType))
295 + {
296 + args.CacheType = cacheType;
297 + }
298 +
299 + this.Log("OnPlanPackageBegin() - id: {0}, defaultState: {1}, requestedState: {2}, defaultCache: {3}, requestedCache: {4}", args.PackageId, args.RecommendedState, args.State, args.RecommendedCacheType, args.CacheType);
300 }
301
302 protected override void OnPlanPatchTarget(PlanPatchTargetEventArgs args)
@@ -337,6 +357,16 @@ namespace WixToolset.Test.BA
357 }
358 }
359
360 + protected override void OnCachePackageNonVitalValidationFailure(CachePackageNonVitalValidationFailureEventArgs args)
361 + {
362 + if (this.allowAcquireAfterValidationFailure)
363 + {
364 + args.Action = BOOTSTRAPPER_CACHEPACKAGENONVITALVALIDATIONFAILURE_ACTION.Acquire;
365 + }
366 +
367 + this.Log("OnCachePackageNonVitalValidationFailure() - id: {0}, default: {1}, requested: {2}", args.PackageId, args.Recommendation, args.Action);
368 + }
369 +
370 protected override void OnCacheAcquireProgress(CacheAcquireProgressEventArgs args)
371 {
372 this.Log("OnCacheAcquireProgress() - container/package: {0}, payload: {1}, progress: {2}, total: {3}, overall progress: {4}%", args.PackageOrContainerId, args.PayloadId, args.Progress, args.Total, args.OverallPercentage);
src/test/burn/TestData/ExePackageTests/PackageTestExe/PackageTestExe.wixproj new
+16
@@ -0,0 +1,16 @@
1 +<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
2 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <ProductComponentsRef>true</ProductComponentsRef>
5 + <UpgradeCode>{9281948B-9C8D-4914-A00E-3EF0F98D17EB}</UpgradeCode>
6 + </PropertyGroup>
7 + <ItemGroup>
8 + <Compile Include="..\..\Templates\Package.wxs" Link="Package.wxs" />
9 + </ItemGroup>
10 + <ItemGroup>
11 + <ProjectReference Include="..\..\TestBA\TestBAWixlib\testbawixlib.wixproj" />
12 + </ItemGroup>
13 + <ItemGroup>
14 + <PackageReference Include="WixToolset.Util.wixext" />
15 + </ItemGroup>
16 +</Project>
\ No newline at end of file
src/test/burn/TestData/ExePackageTests/PackageTestExe/ProductComponents.wxs new
+12
@@ -0,0 +1,12 @@
1 +<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
2 +
3 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
4 + <Fragment>
5 + <ComponentGroup Id="ProductComponents">
6 + <ComponentRef Id="TestExeComponent" />
7 + </ComponentGroup>
8 +
9 + <util:FailWhenDeferred />
10 + <Property Id="WIXFAILWHENDEFERRED" Secure="yes" />
11 + </Fragment>
12 +</Wix>
src/test/burn/TestData/ExePackageTests/PerMachineArpEntryExePackageUninstallFailure/PerMachineArpEntryExePackageUninstallFailure.wixproj new
+18
@@ -0,0 +1,18 @@
1 +<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
2 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <OutputType>Bundle</OutputType>
5 + <UpgradeCode>{799DF604-49CB-4B2C-9FD9-A1C4F93A2FDE}</UpgradeCode>
6 + </PropertyGroup>
7 + <ItemGroup>
8 + <Compile Include="..\..\Templates\Bundle.wxs" Link="Bundle.wxs" />
9 + </ItemGroup>
10 + <ItemGroup>
11 + <ProjectReference Include="..\..\TestBA\TestBAWixlib\testbawixlib.wixproj" />
12 + <ProjectReference Include="..\PackageTestExe\PackageTestExe.wixproj" />
13 + </ItemGroup>
14 + <ItemGroup>
15 + <PackageReference Include="WixToolset.Bal.wixext" />
16 + <PackageReference Include="WixToolset.NetFx.wixext" />
17 + </ItemGroup>
18 +</Project>
\ No newline at end of file
src/test/burn/TestData/ExePackageTests/PerMachineArpEntryExePackageUninstallFailure/PerMachineArpEntryExePackageUninstallFailure.wxs new
+24
@@ -0,0 +1,24 @@
1 +<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
2 +
3 +<?define ArpId = {2BE9DAA8-E202-4E42-B25E-B39AA987A59C}?>
4 +<?define ArpKeyPath = HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(var.ArpId)?>
5 +<?define ArpVersion = 1.0.0.0?>
6 +<?define TestExePath = [ProgramFilesFolder]~Test WiX\$(var.TestGroupName)\PackageTestExe\testexe.exe?>
7 +
8 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
9 + <Fragment>
10 + <Variable Name="FAILWHENDEFERRED" bal:Overridable="yes" />
11 +
12 + <PackageGroup Id="BundlePackages">
13 + <MsiPackage Id="PackageTestExe" SourceFile="$(var.PackageTestExe.TargetPath)">
14 + <MsiProperty Name="WIXFAILWHENDEFERRED" Value="[FAILWHENDEFERRED]" />
15 + </MsiPackage>
16 + <ExePackage Id="TestExe" PerMachine="yes"
17 + InstallArguments="/regw &quot;$(var.ArpKeyPath),DisplayVersion,String,$(var.ArpVersion)&quot; /regw &quot;$(var.ArpKeyPath),QuietUninstallString,String,\&quot;$(var.TestExePath)\&quot; /regd \&quot;$(var.ArpKeyPath)\&quot;&quot;">
18 + <ArpEntry Id="$(var.ArpId)" Version="$(var.ArpVersion)" Win64="no" />
19 +
20 + <PayloadGroupRef Id="TestExePayloads" />
21 + </ExePackage>
22 + </PackageGroup>
23 + </Fragment>
24 +</Wix>
src/test/burn/TestData/TestBA/TestBAWixlib/TestExe.wxs
+7
@@ -6,4 +6,11 @@
6 <Payload SourceFile="!(bindpath.net2x86)\TestExe.exe.config" />
7 </PayloadGroup>
8 </Fragment>
9 +
10 + <Fragment>
11 + <Component Id="TestExeComponent" Directory="INSTALLFOLDER">
12 + <File Source="!(bindpath.net2x86)\TestExe.exe" KeyPath="yes" />
13 + <File Source="!(bindpath.net2x86)\TestExe.exe.config" />
14 + </Component>
15 + </Fragment>
16 </Wix>
src/test/burn/WixToolsetTest.BurnE2E/ExePackageTests.cs
+105 -12
@@ -3,6 +3,7 @@
3 namespace WixToolsetTest.BurnE2E
4 {
5 using WixTestTools;
6 + using WixToolset.Mba.Core;
7 using Xunit;
8 using Xunit.Abstractions;
9
@@ -13,9 +14,9 @@ namespace WixToolsetTest.BurnE2E
14 [RuntimeFact]
15 public void CanInstallAndUninstallPerMachineArpEntryExePackage()
16 {
16 - const string arpId = "{4D9EC36A-1E63-4244-875C-3ECB0A2CAE30}";
17 var perMachineArpEntryExePackageBundle = this.CreateBundleInstaller(@"PerMachineArpEntryExePackage");
18 var arpEntryExePackage = this.CreateArpEntryInstaller(perMachineArpEntryExePackageBundle, "TestExe");
19 + var arpId = arpEntryExePackage.ArpId;
20
21 arpEntryExePackage.VerifyRegistered(false);
22
@@ -23,21 +24,113 @@ namespace WixToolsetTest.BurnE2E
24 perMachineArpEntryExePackageBundle.VerifyRegisteredAndInPackageCache();
25 arpEntryExePackage.VerifyRegistered(true);
26
26 - LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\"");
27 + Assert.True(LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\""));
28
29 var uninstallLogPath = perMachineArpEntryExePackageBundle.Uninstall();
30 perMachineArpEntryExePackageBundle.VerifyUnregisteredAndRemovedFromPackageCache();
31 arpEntryExePackage.VerifyRegistered(false);
32
32 - LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}");
33 + Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}"));
34 }
35
36 [RuntimeFact]
36 - public void CanUninstallPerMachineArpEntryExePackageOnRollback()
37 + public void CanRecacheAndReinstallPerMachineArpEntryExePackageOnUninstallRollback()
38 + {
39 + var packageTestExe = this.CreatePackageInstaller("PackageTestExe");
40 + var perMachineArpEntryExePackageUninstallFailureBundle = this.CreateBundleInstaller(@"PerMachineArpEntryExePackageUninstallFailure");
41 + var arpEntryExePackage = this.CreateArpEntryInstaller(perMachineArpEntryExePackageUninstallFailureBundle, "TestExe");
42 + var arpId = arpEntryExePackage.ArpId;
43 + var testBAController = this.CreateTestBAController();
44 +
45 + arpEntryExePackage.VerifyRegistered(false);
46 + packageTestExe.VerifyInstalled(false);
47 +
48 + testBAController.SetPackageRequestedCacheType("TestExe", BOOTSTRAPPER_CACHE_TYPE.Remove);
49 +
50 + var installLogPath = perMachineArpEntryExePackageUninstallFailureBundle.Install();
51 + perMachineArpEntryExePackageUninstallFailureBundle.VerifyRegisteredAndInPackageCache();
52 + arpEntryExePackage.VerifyRegistered(true);
53 + packageTestExe.VerifyInstalled(true);
54 +
55 + Assert.True(LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\""));
56 +
57 + testBAController.ResetPackageStates("TestExe");
58 + testBAController.SetAllowAcquireAfterValidationFailure();
59 +
60 + var uninstallLogPath = perMachineArpEntryExePackageUninstallFailureBundle.Uninstall((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_FAILURE, "FAILWHENDEFERRED=1");
61 + perMachineArpEntryExePackageUninstallFailureBundle.VerifyRegisteredAndInPackageCache();
62 + arpEntryExePackage.VerifyRegistered(true);
63 + packageTestExe.VerifyInstalled(true);
64 +
65 + Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, "TESTBA: OnCachePackageNonVitalValidationFailure() - id: TestExe, default: None, requested: Acquire"));
66 + Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}"));
67 + Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"TestExe.exe\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\""));
68 + }
69 +
70 + [RuntimeFact]
71 + public void CanReinstallPerMachineArpEntryExePackageOnUninstallRollback()
72 + {
73 + var packageTestExe = this.CreatePackageInstaller("PackageTestExe");
74 + var perMachineArpEntryExePackageUninstallFailureBundle = this.CreateBundleInstaller(@"PerMachineArpEntryExePackageUninstallFailure");
75 + var arpEntryExePackage = this.CreateArpEntryInstaller(perMachineArpEntryExePackageUninstallFailureBundle, "TestExe");
76 + var arpId = arpEntryExePackage.ArpId;
77 +
78 + arpEntryExePackage.VerifyRegistered(false);
79 + packageTestExe.VerifyInstalled(false);
80 +
81 + var installLogPath = perMachineArpEntryExePackageUninstallFailureBundle.Install();
82 + perMachineArpEntryExePackageUninstallFailureBundle.VerifyRegisteredAndInPackageCache();
83 + arpEntryExePackage.VerifyRegistered(true);
84 + packageTestExe.VerifyInstalled(true);
85 +
86 + Assert.True(LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\""));
87 +
88 + var uninstallLogPath = perMachineArpEntryExePackageUninstallFailureBundle.Uninstall((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_FAILURE, "FAILWHENDEFERRED=1");
89 + perMachineArpEntryExePackageUninstallFailureBundle.VerifyRegisteredAndInPackageCache();
90 + arpEntryExePackage.VerifyRegistered(true);
91 + packageTestExe.VerifyInstalled(true);
92 +
93 + Assert.False(LogVerifier.MessageInLogFile(uninstallLogPath, "TESTBA: OnCachePackageNonVitalValidationFailure() - id: TestExe"));
94 + Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}"));
95 + Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"TestExe.exe\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\""));
96 + }
97 +
98 + [RuntimeFact]
99 + public void CanSkipReinstallPerMachineArpEntryExePackageOnUninstallRollback()
100 + {
101 + var packageTestExe = this.CreatePackageInstaller("PackageTestExe");
102 + var perMachineArpEntryExePackageUninstallFailureBundle = this.CreateBundleInstaller(@"PerMachineArpEntryExePackageUninstallFailure");
103 + var arpEntryExePackage = this.CreateArpEntryInstaller(perMachineArpEntryExePackageUninstallFailureBundle, "TestExe");
104 + var arpId = arpEntryExePackage.ArpId;
105 + var testBAController = this.CreateTestBAController();
106 +
107 + arpEntryExePackage.VerifyRegistered(false);
108 + packageTestExe.VerifyInstalled(false);
109 +
110 + testBAController.SetPackageRequestedCacheType("TestExe", BOOTSTRAPPER_CACHE_TYPE.Remove);
111 +
112 + var installLogPath = perMachineArpEntryExePackageUninstallFailureBundle.Install();
113 + perMachineArpEntryExePackageUninstallFailureBundle.VerifyRegisteredAndInPackageCache();
114 + arpEntryExePackage.VerifyRegistered(true);
115 + packageTestExe.VerifyInstalled(true);
116 +
117 + Assert.True(LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\""));
118 +
119 + var uninstallLogPath = perMachineArpEntryExePackageUninstallFailureBundle.Uninstall((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_FAILURE, "FAILWHENDEFERRED=1");
120 + perMachineArpEntryExePackageUninstallFailureBundle.VerifyRegisteredAndInPackageCache();
121 + arpEntryExePackage.VerifyRegistered(false);
122 + packageTestExe.VerifyInstalled(true);
123 +
124 + Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, "TESTBA: OnCachePackageNonVitalValidationFailure() - id: TestExe, default: None, requested: None"));
125 + Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}"));
126 + }
127 +
128 + [RuntimeFact]
129 + public void CanUninstallPerMachineArpEntryExePackageOnInstallRollback()
130 {
38 - const string arpId = "{80E90929-EEA5-48A7-A680-A0237A1CAD84}";
131 var perMachineArpEntryExePackageFailureBundle = this.CreateBundleInstaller(@"PerMachineArpEntryExePackageFailure");
132 var arpEntryExePackage = this.CreateArpEntryInstaller(perMachineArpEntryExePackageFailureBundle, "TestExe");
133 + var arpId = arpEntryExePackage.ArpId;
134
135 arpEntryExePackage.VerifyRegistered(false);
136
@@ -45,16 +138,16 @@ namespace WixToolsetTest.BurnE2E
138 perMachineArpEntryExePackageFailureBundle.VerifyUnregisteredAndRemovedFromPackageCache();
139 arpEntryExePackage.VerifyRegistered(false);
140
48 - LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\"");
49 - LogVerifier.MessageInLogFile(installLogPath, $"testexe.exe\" /regd HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}");
141 + Assert.True(LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\""));
142 + Assert.True(LogVerifier.MessageInLogFile(installLogPath, $"testexe.exe\" /regd HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}"));
143 }
144
145 [RuntimeFact]
146 public void CanInstallAndUninstallPerUserArpEntryExePackage()
147 {
55 - const string arpId = "{9B5300C7-9B34-4670-9614-185B02AB87EF}";
148 var perUserArpEntryExePackageBundle = this.CreateBundleInstaller(@"PerUserArpEntryExePackage");
149 var arpEntryExePackage = this.CreateArpEntryInstaller(perUserArpEntryExePackageBundle, "TestExe");
150 + var arpId = arpEntryExePackage.ArpId;
151
152 arpEntryExePackage.VerifyRegistered(false);
153
@@ -62,21 +155,21 @@ namespace WixToolsetTest.BurnE2E
155 perUserArpEntryExePackageBundle.VerifyRegisteredAndInPackageCache();
156 arpEntryExePackage.VerifyRegistered(true);
157
65 - LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\"");
158 + Assert.True(LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\" /regw \"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},QuietUninstallString,String,\\\""));
159
160 var uninstallLogPath = perUserArpEntryExePackageBundle.Uninstall();
161 perUserArpEntryExePackageBundle.VerifyUnregisteredAndRemovedFromPackageCache();
162 arpEntryExePackage.VerifyRegistered(false);
163
71 - LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}");
164 + Assert.True(LogVerifier.MessageInLogFile(uninstallLogPath, $"testexe.exe\" /regd HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId}"));
165 }
166
167 [RuntimeFact]
168 public void FailsUninstallWhenPerUserArpEntryExePackageMissingQuietUninstallString()
169 {
77 - const string arpId = "{DE9F8594-5856-4454-AB10-3C01ED246D7D}";
170 var brokenPerUserArpEntryExePackageBundle = this.CreateBundleInstaller(@"BrokenPerUserArpEntryExePackage");
171 var arpEntryExePackage = this.CreateArpEntryInstaller(brokenPerUserArpEntryExePackageBundle, "TestExe");
172 + var arpId = arpEntryExePackage.ArpId;
173
174 arpEntryExePackage.VerifyRegistered(false);
175 brokenPerUserArpEntryExePackageBundle.VerifyUnregisteredAndRemovedFromPackageCache();
@@ -85,7 +178,7 @@ namespace WixToolsetTest.BurnE2E
178 brokenPerUserArpEntryExePackageBundle.VerifyRegisteredAndInPackageCache();
179 arpEntryExePackage.VerifyRegistered(true);
180
88 - LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\"");
181 + Assert.True(LogVerifier.MessageInLogFile(installLogPath, $"TestExe.exe\" /regw \"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{arpId},DisplayVersion,String,1.0.0.0\""));
182
183 brokenPerUserArpEntryExePackageBundle.Uninstall((int)MSIExec.MSIExecReturnCode.ERROR_INVALID_PARAMETER);
184 brokenPerUserArpEntryExePackageBundle.VerifyRegisteredAndInPackageCache();
src/test/burn/WixToolsetTest.BurnE2E/Utilities/TestBAController.cs
+15
@@ -42,6 +42,11 @@ namespace WixToolsetTest.BurnE2E
42 }
43 }
44
45 + public void SetAllowAcquireAfterValidationFailure(string value = "true")
46 + {
47 + this.SetBurnTestValue("AllowAcquireAfterValidationFailure", value);
48 + }
49 +
50 public void SetExplicitlyElevateAndPlanFromOnElevateBegin(string value = "true")
51 {
52 this.SetBurnTestValue("ExplicitlyElevateAndPlanFromOnElevateBegin", value);
@@ -132,6 +137,16 @@ namespace WixToolsetTest.BurnE2E
137 this.SetPackageState(packageId, "RetryExecuteFilesInUse", retryCount.HasValue ? retryCount.ToString() : null);
138 }
139
140 + /// <summary>
141 + /// Sets the requested cache type for a package that the TestBA will return to the engine during plan.
142 + /// </summary>
143 + /// <param name="packageId">Package identity.</param>
144 + /// <param name="type">Cache type to request.</param>
145 + public void SetPackageRequestedCacheType(string packageId, BOOTSTRAPPER_CACHE_TYPE type)
146 + {
147 + this.SetPackageState(packageId, "CacheRequested", type.ToString());
148 + }
149 +
150 /// <summary>
151 /// Sets the requested state for a package that the TestBA will return to the engine during plan.
152 /// </summary>