Make engine skip planning if there are any downgrade related bundles.
Fixes 6677, 6722 Reverts 6537
Sean Hall committed
Mar 13, 2022 at 23:51 UTC
9453eaa9a38f78e248526ddd996485140a5d4d9a
20 files changed
+373
-41
src/api/burn/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h
+13
@@ -223,6 +223,7 @@ enum BOOTSTRAPPER_APPLICATION_MESSAGE
223
BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANNEDCOMPATIBLEPACKAGE,
224
BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANRESTORERELATEDBUNDLE,
225
BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANRELATEDBUNDLETYPE,
226
+ BOOTSTRAPPER_APPLICATION_MESSAGE_ONAPPLYDOWNGRADE,
227
};
228
229
enum BOOTSTRAPPER_APPLYCOMPLETE_ACTION
@@ -354,6 +355,18 @@ struct BA_ONAPPLYCOMPLETE_RESULTS
355
BOOTSTRAPPER_APPLYCOMPLETE_ACTION action;
356
};
357
358
+struct BA_ONAPPLYDOWNGRADE_ARGS
359
+{
360
+ DWORD cbSize;
361
+ HRESULT hrRecommended;
362
+};
363
+
364
+struct BA_ONAPPLYDOWNGRADE_RESULTS
365
+{
366
+ DWORD cbSize;
367
+ HRESULT hrStatus;
368
+};
369
+
370
struct BA_ONBEGINMSITRANSACTIONBEGIN_ARGS
371
{
372
DWORD cbSize;
src/api/burn/WixToolset.Mba.Core/BootstrapperApplication.cs
+25
@@ -208,6 +208,9 @@ namespace WixToolset.Mba.Core
208
/// <inheritdoc/>
209
public event EventHandler<ApplyCompleteEventArgs> ApplyComplete;
210
211
+ /// <inheritdoc/>
212
+ public event EventHandler<ApplyDowngradeEventArgs> ApplyDowngrade;
213
+
214
/// <inheritdoc/>
215
public event EventHandler<ExecuteProgressEventArgs> ExecuteProgress;
216
@@ -1055,6 +1058,19 @@ namespace WixToolset.Mba.Core
1058
}
1059
}
1060
1061
+ /// <summary>
1062
+ /// Called by the engine, raises the <see cref="ApplyDowngrade"/> event.
1063
+ /// </summary>
1064
+ /// <param name="args">Additional arguments for this event.</param>
1065
+ protected virtual void OnApplyDowngrade(ApplyDowngradeEventArgs args)
1066
+ {
1067
+ EventHandler<ApplyDowngradeEventArgs> handler = this.ApplyDowngrade;
1068
+ if (null != handler)
1069
+ {
1070
+ handler(this, args);
1071
+ }
1072
+ }
1073
+
1074
/// <summary>
1075
/// Called by the engine, raises the <see cref="ExecuteProgress"/> event.
1076
/// </summary>
@@ -1907,6 +1923,15 @@ namespace WixToolset.Mba.Core
1923
return args.HResult;
1924
}
1925
1926
+ int IBootstrapperApplication.OnApplyDowngrade(int hrRecommendation, ref int hrStatus)
1927
+ {
1928
+ ApplyDowngradeEventArgs args = new ApplyDowngradeEventArgs(hrRecommendation, hrStatus);
1929
+ this.OnApplyDowngrade(args);
1930
+
1931
+ hrStatus = args.Status;
1932
+ return args.HResult;
1933
+ }
1934
+
1935
int IBootstrapperApplication.OnLaunchApprovedExeBegin(ref bool fCancel)
1936
{
1937
LaunchApprovedExeBeginEventArgs args = new LaunchApprovedExeBeginEventArgs(fCancel);
src/api/burn/WixToolset.Mba.Core/EventArgs.cs
+24
@@ -1858,6 +1858,30 @@ namespace WixToolset.Mba.Core
1858
public ApplyRestart Restart { get; private set; }
1859
}
1860
1861
+ /// <summary>
1862
+ /// Event arguments for <see cref="IDefaultBootstrapperApplication.ApplyDowngrade"/>
1863
+ /// </summary>
1864
+ [Serializable]
1865
+ public class ApplyDowngradeEventArgs : HResultEventArgs
1866
+ {
1867
+ /// <summary />
1868
+ public ApplyDowngradeEventArgs(int hrRecommendation, int hrStatus)
1869
+ {
1870
+ this.Recommendation = hrRecommendation;
1871
+ this.Status = hrStatus;
1872
+ }
1873
+
1874
+ /// <summary>
1875
+ /// Gets the recommended HRESULT.
1876
+ /// </summary>
1877
+ public int Recommendation { get; private set; }
1878
+
1879
+ /// <summary>
1880
+ /// Gets or sets the HRESULT for Apply.
1881
+ /// </summary>
1882
+ public int Status { get; set; }
1883
+ }
1884
+
1885
/// <summary>
1886
/// EventArgs for <see cref="IDefaultBootstrapperApplication.CacheAcquireResolving"/>.
1887
/// </summary>
src/api/burn/WixToolset.Mba.Core/IBootstrapperApplication.cs
+10
@@ -1160,6 +1160,16 @@ namespace WixToolset.Mba.Core
1160
[MarshalAs(UnmanagedType.U4)] ref RelatedBundlePlanType pRequestedType,
1161
[MarshalAs(UnmanagedType.Bool)] ref bool fCancel
1162
);
1163
+
1164
+ /// <summary>
1165
+ /// See <see cref="IDefaultBootstrapperApplication.ApplyDowngrade"/>.
1166
+ /// </summary>
1167
+ [PreserveSig]
1168
+ [return: MarshalAs(UnmanagedType.I4)]
1169
+ int OnApplyDowngrade(
1170
+ [MarshalAs(UnmanagedType.I4)] int hrRecommended,
1171
+ [MarshalAs(UnmanagedType.I4)] ref int hrStatus
1172
+ );
1173
}
1174
1175
/// <summary>
src/api/burn/WixToolset.Mba.Core/IDefaultBootstrapperApplication.cs
+5
@@ -19,6 +19,11 @@ namespace WixToolset.Mba.Core
19
/// </summary>
20
event EventHandler<ApplyCompleteEventArgs> ApplyComplete;
21
22
+ /// <summary>
23
+ /// Fired when the plan determined that nothing should happen to prevent downgrading.
24
+ /// </summary>
25
+ event EventHandler<ApplyDowngradeEventArgs> ApplyDowngrade;
26
+
27
/// <summary>
28
/// Fired when the engine is about to begin an MSI transaction.
29
/// </summary>
src/api/burn/balutil/inc/BAFunctions.h
+1
@@ -90,6 +90,7 @@ enum BA_FUNCTIONS_MESSAGE
90
BA_FUNCTIONS_MESSAGE_ONPLANNEDCOMPATIBLEPACKAGE = BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANNEDCOMPATIBLEPACKAGE,
91
BA_FUNCTIONS_MESSAGE_ONPLANRESTORERELATEDBUNDLE = BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANRESTORERELATEDBUNDLE,
92
BA_FUNCTIONS_MESSAGE_ONPLANRELATEDBUNDLETYPE = BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANRELATEDBUNDLETYPE,
93
+ BA_FUNCTIONS_MESSAGE_ONAPPLYDOWNGRADE = BOOTSTRAPPER_APPLICATION_MESSAGE_ONAPPLYDOWNGRADE,
94
95
BA_FUNCTIONS_MESSAGE_ONTHEMELOADED = 1024,
96
BA_FUNCTIONS_MESSAGE_WNDPROC,
src/api/burn/balutil/inc/BalBaseBAFunctions.h
+8
@@ -869,6 +869,14 @@ public: // IBootstrapperApplication
869
return S_OK;
870
}
871
872
+ virtual STDMETHODIMP OnApplyDowngrade(
873
+ __in HRESULT /*hrRecommended*/,
874
+ __in HRESULT* /*phrStatus*/
875
+ )
876
+ {
877
+ return S_OK;
878
+ }
879
+
880
public: // IBAFunctions
881
virtual STDMETHODIMP OnPlan(
882
)
src/api/burn/balutil/inc/BalBaseBAFunctionsProc.h
+1
@@ -161,6 +161,7 @@ static HRESULT WINAPI BalBaseBAFunctionsProc(
161
case BA_FUNCTIONS_MESSAGE_ONPLANNEDCOMPATIBLEPACKAGE:
162
case BA_FUNCTIONS_MESSAGE_ONPLANRESTORERELATEDBUNDLE:
163
case BA_FUNCTIONS_MESSAGE_ONPLANRELATEDBUNDLETYPE:
164
+ case BA_FUNCTIONS_MESSAGE_ONAPPLYDOWNGRADE:
165
hr = BalBaseBootstrapperApplicationProc((BOOTSTRAPPER_APPLICATION_MESSAGE)message, pvArgs, pvResults, pvContext);
166
break;
167
case BA_FUNCTIONS_MESSAGE_ONTHEMELOADED:
src/api/burn/balutil/inc/BalBaseBootstrapperApplication.h
+8
@@ -1069,6 +1069,14 @@ public: // IBootstrapperApplication
1069
return S_OK;
1070
}
1071
1072
+ virtual STDMETHODIMP OnApplyDowngrade(
1073
+ __in HRESULT /*hrRecommended*/,
1074
+ __in HRESULT* /*phrStatus*/
1075
+ )
1076
+ {
1077
+ return S_OK;
1078
+ }
1079
+
1080
public: //CBalBaseBootstrapperApplication
1081
virtual STDMETHODIMP Initialize(
1082
__in const BOOTSTRAPPER_CREATE_ARGS* pCreateArgs
src/api/burn/balutil/inc/BalBaseBootstrapperApplicationProc.h
+12
@@ -738,6 +738,15 @@ static HRESULT BalBaseBAProcOnPlanRelatedBundleType(
738
return pBA->OnPlanRelatedBundleType(pArgs->wzBundleId, pArgs->recommendedType, &pResults->requestedType, &pResults->fCancel);
739
}
740
741
+static HRESULT BalBaseBAProcOnApplyDowngrade(
742
+ __in IBootstrapperApplication* pBA,
743
+ __in BA_ONAPPLYDOWNGRADE_ARGS* pArgs,
744
+ __inout BA_ONAPPLYDOWNGRADE_RESULTS* pResults
745
+ )
746
+{
747
+ return pBA->OnApplyDowngrade(pArgs->hrRecommended, &pResults->hrStatus);
748
+}
749
+
750
/*******************************************************************
751
BalBaseBootstrapperApplicationProc - requires pvContext to be of type IBootstrapperApplication.
752
Provides a default mapping between the new message based BA interface and
@@ -1000,6 +1009,9 @@ static HRESULT WINAPI BalBaseBootstrapperApplicationProc(
1009
case BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANRELATEDBUNDLETYPE:
1010
hr = BalBaseBAProcOnPlanRelatedBundleType(pBA, reinterpret_cast<BA_ONPLANRELATEDBUNDLETYPE_ARGS*>(pvArgs), reinterpret_cast<BA_ONPLANRELATEDBUNDLETYPE_RESULTS*>(pvResults));
1011
break;
1012
+ case BOOTSTRAPPER_APPLICATION_MESSAGE_ONAPPLYDOWNGRADE:
1013
+ hr = BalBaseBAProcOnApplyDowngrade(pBA, reinterpret_cast<BA_ONAPPLYDOWNGRADE_ARGS*>(pvArgs), reinterpret_cast<BA_ONAPPLYDOWNGRADE_RESULTS*>(pvResults));
1014
+ break;
1015
}
1016
}
1017
src/api/burn/balutil/inc/IBootstrapperApplication.h
+7
@@ -707,4 +707,11 @@ DECLARE_INTERFACE_IID_(IBootstrapperApplication, IUnknown, "53C31D56-49C0-426B-A
707
__inout BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE* pRequestedType,
708
__inout BOOL* pfCancel
709
) = 0;
710
+
711
+ // OnApplyDowngrade - called when the plan determined that nothing should happen to prevent downgrading.
712
+ //
713
+ STDMETHOD(OnApplyDowngrade)(
714
+ __in HRESULT hrRecommended,
715
+ __inout HRESULT* phrStatus
716
+ ) = 0;
717
};
src/burn/engine/core.cpp
+30
-9
@@ -527,8 +527,15 @@ extern "C" HRESULT CorePlan(
527
hr = PlanRelatedBundlesInitialize(&pEngineState->userExperience, &pEngineState->registration, pEngineState->command.relationType, &pEngineState->plan);
528
ExitOnFailure(hr, "Failed to initialize related bundles for plan.");
529
530
- hr = PlanRegistration(&pEngineState->plan, &pEngineState->registration, &pEngineState->dependencies, pEngineState->command.resumeType, pEngineState->command.relationType, &fContinuePlanning);
531
- ExitOnFailure(hr, "Failed to plan registration.");
530
+ if (pEngineState->plan.fDowngrade)
531
+ {
532
+ fContinuePlanning = FALSE;
533
+ }
534
+ else
535
+ {
536
+ hr = PlanRegistration(&pEngineState->plan, &pEngineState->registration, &pEngineState->dependencies, pEngineState->command.resumeType, pEngineState->command.relationType, &fContinuePlanning);
537
+ ExitOnFailure(hr, "Failed to plan registration.");
538
+ }
539
540
if (fContinuePlanning)
541
{
@@ -615,6 +622,7 @@ extern "C" HRESULT CoreApply(
622
{
623
HRESULT hr = S_OK;
624
HANDLE hLock = NULL;
625
+ BOOL fApplyBegan = FALSE;
626
BOOL fApplyInitialize = FALSE;
627
BOOL fElevated = FALSE;
628
BOOL fRegistered = FALSE;
@@ -627,8 +635,6 @@ extern "C" HRESULT CoreApply(
635
DWORD dwPhaseCount = 0;
636
BOOTSTRAPPER_APPLYCOMPLETE_ACTION applyCompleteAction = BOOTSTRAPPER_APPLYCOMPLETE_ACTION_NONE;
637
630
- LogId(REPORT_STANDARD, MSG_APPLY_BEGIN);
631
-
638
if (!pEngineState->fPlanned)
639
{
640
ExitOnFailure(hr = E_INVALIDSTATE, "Apply cannot be done without a successful Plan.");
@@ -638,6 +644,10 @@ extern "C" HRESULT CoreApply(
644
ExitOnFailure(hr = E_INVALIDSTATE, "Plans cannot be applied multiple times.");
645
}
646
647
+ fApplyBegan = TRUE;
648
+
649
+ LogId(REPORT_STANDARD, MSG_APPLY_BEGIN);
650
+
651
// Ensure any previous attempts to execute are reset.
652
ApplyReset(&pEngineState->userExperience, &pEngineState->packages);
653
@@ -653,6 +663,14 @@ extern "C" HRESULT CoreApply(
663
hr = UserExperienceOnApplyBegin(&pEngineState->userExperience, dwPhaseCount);
664
ExitOnRootFailure(hr, "BA aborted apply begin.");
665
666
+ if (pEngineState->plan.fDowngrade)
667
+ {
668
+ hr = HRESULT_FROM_WIN32(ERROR_PRODUCT_VERSION);
669
+ UserExperienceOnApplyDowngrade(&pEngineState->userExperience, &hr);
670
+
671
+ ExitFunction();
672
+ }
673
+
674
pEngineState->plan.fAffectedMachineState = pEngineState->plan.fCanAffectMachineState;
675
676
hr = ApplyLock(FALSE, &hLock);
@@ -804,13 +822,16 @@ LExit:
822
DeleteCriticalSection(&applyContext.csApply);
823
}
824
807
- UserExperienceOnApplyComplete(&pEngineState->userExperience, hr, restart, &applyCompleteAction);
808
- if (BOOTSTRAPPER_APPLYCOMPLETE_ACTION_RESTART == applyCompleteAction)
825
+ if (fApplyBegan)
826
{
810
- pEngineState->fRestart = TRUE;
811
- }
827
+ UserExperienceOnApplyComplete(&pEngineState->userExperience, hr, restart, &applyCompleteAction);
828
+ if (BOOTSTRAPPER_APPLYCOMPLETE_ACTION_RESTART == applyCompleteAction)
829
+ {
830
+ pEngineState->fRestart = TRUE;
831
+ }
832
813
- LogId(REPORT_STANDARD, MSG_APPLY_COMPLETE, hr, LoggingRestartToString(restart), LoggingBoolToString(pEngineState->fRestart));
833
+ LogId(REPORT_STANDARD, MSG_APPLY_COMPLETE, hr, LoggingRestartToString(restart), LoggingBoolToString(pEngineState->fRestart));
834
+ }
835
836
return hr;
837
}
src/burn/engine/engine.mc
+14
@@ -499,6 +499,20 @@ Language=English
499
Ignoring bundle dependents due to action UnsafeUninstall...
500
.
501
502
+MessageId=224
503
+Severity=Warning
504
+SymbolicName=MSG_PLAN_SKIPPED_DUE_TO_DOWNGRADE
505
+Language=English
506
+Plan skipped due to related bundle of plan type Downgrade:
507
+.
508
+
509
+MessageId=225
510
+Severity=Warning
511
+SymbolicName=MSG_UPGRADE_BUNDLE_DOWNGRADE
512
+Language=English
513
+ id: %1!ls!, version: %2!ls!
514
+.
515
+
516
MessageId=299
517
Severity=Success
518
SymbolicName=MSG_PLAN_COMPLETE
src/burn/engine/plan.cpp
+17
-2
@@ -1328,11 +1328,12 @@ LExit:
1328
extern "C" HRESULT PlanRelatedBundlesInitialize(
1329
__in BURN_USER_EXPERIENCE* pUserExperience,
1330
__in BURN_REGISTRATION* pRegistration,
1331
- __in BOOTSTRAPPER_RELATION_TYPE /*relationType*/,
1332
- __in BURN_PLAN* /*pPlan*/
1331
+ __in BOOTSTRAPPER_RELATION_TYPE relationType,
1332
+ __in BURN_PLAN* pPlan
1333
)
1334
{
1335
HRESULT hr = S_OK;
1336
+ BOOL fUninstalling = BOOTSTRAPPER_ACTION_UNINSTALL == pPlan->action || BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == pPlan->action;
1337
1338
for (DWORD i = 0; i < pRegistration->relatedBundles.cRelatedBundles; ++i)
1339
{
@@ -1356,6 +1357,19 @@ extern "C" HRESULT PlanRelatedBundlesInitialize(
1357
1358
hr = UserExperienceOnPlanRelatedBundleType(pUserExperience, pRelatedBundle->package.sczId, &pRelatedBundle->planRelationType);
1359
ExitOnRootFailure(hr, "BA aborted plan related bundle type.");
1360
+
1361
+ if (BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE_DOWNGRADE == pRelatedBundle->planRelationType &&
1362
+ pRelatedBundle->fPlannable && !fUninstalling && BOOTSTRAPPER_RELATION_UPGRADE != relationType)
1363
+ {
1364
+ if (!pPlan->fDowngrade)
1365
+ {
1366
+ pPlan->fDowngrade = TRUE;
1367
+
1368
+ LogId(REPORT_STANDARD, MSG_PLAN_SKIPPED_DUE_TO_DOWNGRADE);
1369
+ }
1370
+
1371
+ LogId(REPORT_VERBOSE, MSG_UPGRADE_BUNDLE_DOWNGRADE, pRelatedBundle->package.sczId, pRelatedBundle->pVersion->sczVersion);
1372
+ }
1373
}
1374
1375
RelatedBundlesSortPlan(&pRegistration->relatedBundles);
@@ -3011,6 +3025,7 @@ extern "C" void PlanDump(
3025
LogStringLine(PlanDumpLevel, " can affect machine state: %hs", LoggingTrueFalseToString(pPlan->fCanAffectMachineState));
3026
LogStringLine(PlanDumpLevel, " disable-rollback: %hs", LoggingTrueFalseToString(pPlan->fDisableRollback));
3027
LogStringLine(PlanDumpLevel, " disallow-removal: %hs", LoggingTrueFalseToString(pPlan->fDisallowRemoval));
3028
+ LogStringLine(PlanDumpLevel, " downgrade: %hs", LoggingTrueFalseToString(pPlan->fDowngrade));
3029
LogStringLine(PlanDumpLevel, " registration options: %hs", LoggingRegistrationOptionsToString(pPlan->dwRegistrationOperations));
3030
LogStringLine(PlanDumpLevel, " estimated size: %llu", pPlan->qwEstimatedSize);
3031
if (pPlan->sczLayoutDirectory)
src/burn/engine/plan.h
+1
@@ -250,6 +250,7 @@ typedef struct _BURN_PLAN
250
BOOL fAffectedMachineState;
251
LPWSTR sczLayoutDirectory;
252
BOOL fPlanPackageCacheRollback;
253
+ BOOL fDowngrade;
254
255
DWORD64 qwCacheSizeTotal;
256
src/burn/engine/userexperience.cpp
+24
@@ -335,6 +335,30 @@ LExit:
335
return hr;
336
}
337
338
+EXTERN_C BAAPI UserExperienceOnApplyDowngrade(
339
+ __in BURN_USER_EXPERIENCE* pUserExperience,
340
+ __inout HRESULT* phrStatus
341
+ )
342
+{
343
+ HRESULT hr = S_OK;
344
+ BA_ONAPPLYDOWNGRADE_ARGS args = { };
345
+ BA_ONAPPLYDOWNGRADE_RESULTS results = { };
346
+
347
+ args.cbSize = sizeof(args);
348
+ args.hrRecommended = *phrStatus;
349
+
350
+ results.cbSize = sizeof(results);
351
+ results.hrStatus = *phrStatus;
352
+
353
+ hr = SendBAMessage(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONAPPLYDOWNGRADE, &args, &results);
354
+ ExitOnFailure(hr, "BA OnApplyDowngrade failed.");
355
+
356
+ *phrStatus = results.hrStatus;
357
+
358
+LExit:
359
+ return hr;
360
+}
361
+
362
EXTERN_C BAAPI UserExperienceOnBeginMsiTransactionBegin(
363
__in BURN_USER_EXPERIENCE* pUserExperience,
364
__in LPCWSTR wzTransactionId
src/burn/engine/userexperience.h
+4
@@ -110,6 +110,10 @@ BAAPI UserExperienceOnApplyComplete(
110
__in BOOTSTRAPPER_APPLY_RESTART restart,
111
__inout BOOTSTRAPPER_APPLYCOMPLETE_ACTION* pAction
112
);
113
+BAAPI UserExperienceOnApplyDowngrade(
114
+ __in BURN_USER_EXPERIENCE* pUserExperience,
115
+ __inout HRESULT* phrStatus
116
+ );
117
BAAPI UserExperienceOnBeginMsiTransactionBegin(
118
__in BURN_USER_EXPERIENCE* pUserExperience,
119
__in LPCWSTR wzTransactionId
src/burn/test/BurnUnitTest/PlanTest.cpp
+88
@@ -67,6 +67,7 @@ namespace Bootstrapper
67
Assert::Equal<BOOL>(TRUE, pPlan->fCanAffectMachineState);
68
Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
69
Assert::Equal<BOOL>(FALSE, pPlan->fDisallowRemoval);
70
+ Assert::Equal<BOOL>(FALSE, pPlan->fDowngrade);
71
72
BOOL fRollback = FALSE;
73
DWORD dwIndex = 0;
@@ -226,6 +227,7 @@ namespace Bootstrapper
227
Assert::Equal<BOOL>(TRUE, pPlan->fCanAffectMachineState);
228
Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
229
Assert::Equal<BOOL>(FALSE, pPlan->fDisallowRemoval);
230
+ Assert::Equal<BOOL>(FALSE, pPlan->fDowngrade);
231
232
BOOL fRollback = FALSE;
233
DWORD dwIndex = 0;
@@ -358,6 +360,7 @@ namespace Bootstrapper
360
Assert::Equal<BOOL>(TRUE, pPlan->fCanAffectMachineState);
361
Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
362
Assert::Equal<BOOL>(FALSE, pPlan->fDisallowRemoval);
363
+ Assert::Equal<BOOL>(FALSE, pPlan->fDowngrade);
364
365
BOOL fRollback = FALSE;
366
DWORD dwIndex = 0;
@@ -457,6 +460,7 @@ namespace Bootstrapper
460
Assert::Equal<BOOL>(TRUE, pPlan->fCanAffectMachineState);
461
Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
462
Assert::Equal<BOOL>(FALSE, pPlan->fDisallowRemoval);
463
+ Assert::Equal<BOOL>(FALSE, pPlan->fDowngrade);
464
465
BOOL fRollback = FALSE;
466
DWORD dwIndex = 0;
@@ -575,6 +579,7 @@ namespace Bootstrapper
579
Assert::Equal<BOOL>(TRUE, pPlan->fCanAffectMachineState);
580
Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
581
Assert::Equal<BOOL>(FALSE, pPlan->fDisallowRemoval);
582
+ Assert::Equal<BOOL>(FALSE, pPlan->fDowngrade);
583
584
BOOL fRollback = FALSE;
585
DWORD dwIndex = 0;
@@ -677,6 +682,7 @@ namespace Bootstrapper
682
Assert::Equal<BOOL>(TRUE, pPlan->fCanAffectMachineState);
683
Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
684
Assert::Equal<BOOL>(FALSE, pPlan->fDisallowRemoval);
685
+ Assert::Equal<BOOL>(FALSE, pPlan->fDowngrade);
686
687
BOOL fRollback = FALSE;
688
DWORD dwIndex = 0;
@@ -741,6 +747,76 @@ namespace Bootstrapper
747
ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_ABSENT);
748
}
749
750
+ [Fact]
751
+ void SingleMsiDowngradeTest()
752
+ {
753
+ HRESULT hr = S_OK;
754
+ BURN_ENGINE_STATE engineState = { };
755
+ BURN_ENGINE_STATE* pEngineState = &engineState;
756
+ BURN_PLAN* pPlan = &engineState.plan;
757
+
758
+ InitializeEngineStateForCorePlan(wzSingleMsiManifestFileName, pEngineState);
759
+ DetectAttachedContainerAsAttached(pEngineState);
760
+ DetectPackagesAsAbsent(pEngineState);
761
+ DetectRelatedBundle(pEngineState, L"{AF8355C9-CCDD-4D61-BF5F-EA5F948D8F01}", L"1.1.0.0", BOOTSTRAPPER_RELATION_UPGRADE);
762
+
763
+ hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL);
764
+ NativeAssert::Succeeded(hr, "CorePlan failed");
765
+
766
+ Assert::Equal<DWORD>(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action);
767
+ NativeAssert::StringEqual(L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", pPlan->wzBundleId);
768
+ NativeAssert::StringEqual(L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", pPlan->wzBundleProviderKey);
769
+ Assert::Equal<BOOL>(FALSE, pPlan->fEnabledForwardCompatibleBundle);
770
+ Assert::Equal<BOOL>(TRUE, pPlan->fPerMachine);
771
+ Assert::Equal<BOOL>(FALSE, pPlan->fCanAffectMachineState);
772
+ Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
773
+ Assert::Equal<BOOL>(FALSE, pPlan->fDisallowRemoval);
774
+ Assert::Equal<BOOL>(TRUE, pPlan->fDowngrade);
775
+
776
+ BOOL fRollback = FALSE;
777
+ DWORD dwIndex = 0;
778
+ Assert::Equal(dwIndex, pPlan->cRegistrationActions);
779
+
780
+ fRollback = TRUE;
781
+ dwIndex = 0;
782
+ Assert::Equal(dwIndex, pPlan->cRollbackRegistrationActions);
783
+
784
+ fRollback = FALSE;
785
+ dwIndex = 0;
786
+ Assert::Equal(dwIndex, pPlan->cCacheActions);
787
+
788
+ fRollback = TRUE;
789
+ dwIndex = 0;
790
+ Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
791
+
792
+ Assert::Equal(0ull, pPlan->qwEstimatedSize);
793
+ Assert::Equal(0ull, pPlan->qwCacheSizeTotal);
794
+
795
+ fRollback = FALSE;
796
+ dwIndex = 0;
797
+ Assert::Equal(dwIndex, pPlan->cExecuteActions);
798
+
799
+ fRollback = TRUE;
800
+ dwIndex = 0;
801
+ Assert::Equal(dwIndex, pPlan->cRollbackActions);
802
+
803
+ Assert::Equal(0ul, pPlan->cExecutePackagesTotal);
804
+ Assert::Equal(0ul, pPlan->cOverallProgressTicksTotal);
805
+
806
+ dwIndex = 0;
807
+ Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions);
808
+
809
+ dwIndex = 0;
810
+ Assert::Equal(dwIndex, pPlan->cCleanActions);
811
+
812
+ UINT uIndex = 0;
813
+ ValidatePlannedProvider(pPlan, uIndex++, L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", NULL);
814
+ Assert::Equal(uIndex, pPlan->cPlannedProviders);
815
+
816
+ Assert::Equal(1ul, pEngineState->packages.cPackages);
817
+ ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN, BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN);
818
+ }
819
+
820
[Fact]
821
void SingleMsiForceAbsentTest()
822
{
@@ -770,6 +846,7 @@ namespace Bootstrapper
846
Assert::Equal<BOOL>(TRUE, pPlan->fCanAffectMachineState);
847
Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
848
Assert::Equal<BOOL>(FALSE, pPlan->fDisallowRemoval);
849
+ Assert::Equal<BOOL>(FALSE, pPlan->fDowngrade);
850
851
BOOL fRollback = FALSE;
852
DWORD dwIndex = 0;
@@ -858,6 +935,7 @@ namespace Bootstrapper
935
Assert::Equal<BOOL>(TRUE, pPlan->fCanAffectMachineState);
936
Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
937
Assert::Equal<BOOL>(FALSE, pPlan->fDisallowRemoval);
938
+ Assert::Equal<BOOL>(FALSE, pPlan->fDowngrade);
939
940
BOOL fRollback = FALSE;
941
DWORD dwIndex = 0;
@@ -948,6 +1026,7 @@ namespace Bootstrapper
1026
Assert::Equal<BOOL>(TRUE, pPlan->fCanAffectMachineState);
1027
Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
1028
Assert::Equal<BOOL>(FALSE, pPlan->fDisallowRemoval);
1029
+ Assert::Equal<BOOL>(FALSE, pPlan->fDowngrade);
1030
1031
BOOL fRollback = FALSE;
1032
DWORD dwIndex = 0;
@@ -1053,6 +1132,7 @@ namespace Bootstrapper
1132
Assert::Equal<BOOL>(TRUE, pPlan->fCanAffectMachineState);
1133
Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
1134
Assert::Equal<BOOL>(FALSE, pPlan->fDisallowRemoval);
1135
+ Assert::Equal<BOOL>(FALSE, pPlan->fDowngrade);
1136
1137
BOOL fRollback = FALSE;
1138
DWORD dwIndex = 0;
@@ -1131,6 +1211,7 @@ namespace Bootstrapper
1211
Assert::Equal<BOOL>(TRUE, pPlan->fCanAffectMachineState);
1212
Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
1213
Assert::Equal<BOOL>(FALSE, pPlan->fDisallowRemoval);
1214
+ Assert::Equal<BOOL>(FALSE, pPlan->fDowngrade);
1215
1216
BOOL fRollback = FALSE;
1217
DWORD dwIndex = 0;
@@ -1225,6 +1306,7 @@ namespace Bootstrapper
1306
Assert::Equal<BOOL>(TRUE, pPlan->fCanAffectMachineState);
1307
Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
1308
Assert::Equal<BOOL>(TRUE, pPlan->fDisallowRemoval);
1309
+ Assert::Equal<BOOL>(FALSE, pPlan->fDowngrade);
1310
1311
BOOL fRollback = FALSE;
1312
DWORD dwIndex = 0;
@@ -1294,6 +1376,7 @@ namespace Bootstrapper
1376
Assert::Equal<BOOL>(TRUE, pPlan->fCanAffectMachineState);
1377
Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
1378
Assert::Equal<BOOL>(FALSE, pPlan->fDisallowRemoval);
1379
+ Assert::Equal<BOOL>(FALSE, pPlan->fDowngrade);
1380
1381
BOOL fRollback = FALSE;
1382
DWORD dwIndex = 0;
@@ -1377,6 +1460,7 @@ namespace Bootstrapper
1460
Assert::Equal<BOOL>(TRUE, pPlan->fCanAffectMachineState);
1461
Assert::Equal<BOOL>(TRUE, pPlan->fDisableRollback);
1462
Assert::Equal<BOOL>(FALSE, pPlan->fDisallowRemoval);
1463
+ Assert::Equal<BOOL>(FALSE, pPlan->fDowngrade);
1464
1465
BOOL fRollback = FALSE;
1466
DWORD dwIndex = 0;
@@ -1471,6 +1555,7 @@ namespace Bootstrapper
1555
Assert::Equal<BOOL>(TRUE, pPlan->fCanAffectMachineState);
1556
Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
1557
Assert::Equal<BOOL>(FALSE, pPlan->fDisallowRemoval);
1558
+ Assert::Equal<BOOL>(FALSE, pPlan->fDowngrade);
1559
1560
BOOL fRollback = FALSE;
1561
DWORD dwIndex = 0;
@@ -1601,6 +1686,7 @@ namespace Bootstrapper
1686
Assert::Equal<BOOL>(TRUE, pPlan->fCanAffectMachineState);
1687
Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
1688
Assert::Equal<BOOL>(FALSE, pPlan->fDisallowRemoval);
1689
+ Assert::Equal<BOOL>(FALSE, pPlan->fDowngrade);
1690
1691
BOOL fRollback = FALSE;
1692
DWORD dwIndex = 0;
@@ -1716,6 +1802,7 @@ namespace Bootstrapper
1802
Assert::Equal<BOOL>(TRUE, pPlan->fCanAffectMachineState);
1803
Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
1804
Assert::Equal<BOOL>(FALSE, pPlan->fDisallowRemoval);
1805
+ Assert::Equal<BOOL>(FALSE, pPlan->fDowngrade);
1806
1807
BOOL fRollback = FALSE;
1808
DWORD dwIndex = 0;
@@ -1810,6 +1897,7 @@ namespace Bootstrapper
1897
Assert::Equal<BOOL>(TRUE, pPlan->fCanAffectMachineState);
1898
Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
1899
Assert::Equal<BOOL>(FALSE, pPlan->fDisallowRemoval);
1900
+ Assert::Equal<BOOL>(FALSE, pPlan->fDowngrade);
1901
1902
BOOL fRollback = FALSE;
1903
DWORD dwIndex = 0;
src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp
+26
-30
@@ -254,7 +254,6 @@ public: // IBootstrapperApplication
254
)
255
{
256
BAL_INFO_PACKAGE* pPackage = NULL;
257
- int nCompare = 0;
257
258
if (!fMissingFromCache)
259
{
@@ -262,14 +261,6 @@ public: // IBootstrapperApplication
261
{
262
InitializePackageInfoForPackage(pPackage);
263
}
265
-
266
- // If we're not doing a prerequisite install, remember when our bundle would cause a downgrade.
267
- if (!m_fPrereq && BOOTSTRAPPER_RELATION_UPGRADE == relationType &&
268
- SUCCEEDED(m_pEngine->CompareVersions(m_sczBundleVersion, wzVersion, &nCompare)) && 0 > nCompare)
269
- {
270
- BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "A newer version (v%ls) of this product is installed.", wzVersion);
271
- m_fDowngrading = TRUE;
272
- }
264
}
265
266
return CBalBaseBootstrapperApplication::OnDetectRelatedBundle(wzBundleId, relationType, wzBundleTag, fPerMachine, wzVersion, fMissingFromCache, pfCancel);
@@ -345,23 +336,6 @@ public: // IBootstrapperApplication
336
}
337
}
338
}
348
- else if (m_fDowngrading && BOOTSTRAPPER_ACTION_UNINSTALL < m_command.action)
349
- {
350
- if (m_fSuppressDowngradeFailure)
351
- {
352
- BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Downgrade failure has been suppressed; exiting bundle.");
353
-
354
- hr = S_OK;
355
- SetState(WIXSTDBA_STATE_APPLIED, hr);
356
- ExitFunction();
357
- }
358
- else
359
- {
360
- // If we are going to apply a downgrade, bail.
361
- hr = HRESULT_FROM_WIN32(ERROR_PRODUCT_VERSION);
362
- BalExitOnFailure(hr, "Cannot install a product when a newer version is installed.");
363
- }
364
- }
339
}
340
341
SetState(WIXSTDBA_STATE_DETECTED, hrStatus);
@@ -371,7 +345,6 @@ public: // IBootstrapperApplication
345
::PostMessageW(m_hWnd, WM_WIXSTDBA_PLAN_PACKAGES, 0, m_command.action);
346
}
347
374
- LExit:
348
return hr;
349
}
350
@@ -1092,6 +1065,20 @@ public: // IBootstrapperApplication
1065
return hr;
1066
}
1067
1068
+ virtual STDMETHODIMP OnApplyDowngrade(
1069
+ __in HRESULT /*hrRecommendation*/,
1070
+ __in HRESULT* phrStatus
1071
+ )
1072
+ {
1073
+ HRESULT hr = S_OK;
1074
+
1075
+ if (m_fSuppressDowngradeFailure)
1076
+ {
1077
+ *phrStatus = S_OK;
1078
+ }
1079
+
1080
+ return hr;
1081
+ }
1082
1083
virtual STDMETHODIMP OnApplyComplete(
1084
__in HRESULT hrStatus,
@@ -1445,6 +1432,9 @@ public: // IBootstrapperApplication
1432
case BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANRELATEDBUNDLETYPE:
1433
OnPlanRelatedBundleTypeFallback(reinterpret_cast<BA_ONPLANRELATEDBUNDLETYPE_ARGS*>(pvArgs), reinterpret_cast<BA_ONPLANRELATEDBUNDLETYPE_RESULTS*>(pvResults));
1434
break;
1435
+ case BOOTSTRAPPER_APPLICATION_MESSAGE_ONAPPLYDOWNGRADE:
1436
+ OnApplyDowngradeFallback(reinterpret_cast<BA_ONAPPLYDOWNGRADE_ARGS*>(pvArgs), reinterpret_cast<BA_ONAPPLYDOWNGRADE_RESULTS*>(pvResults));
1437
+ break;
1438
default:
1439
#ifdef DEBUG
1440
BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "WIXSTDBA: Forwarding unknown BA message: %d", message);
@@ -2118,6 +2108,14 @@ private: // privates
2108
BalLogId(BOOTSTRAPPER_LOG_LEVEL_STANDARD, MSG_WIXSTDBA_PLANNED_RESTORE_RELATED_BUNDLE, m_hModule, pArgs->wzBundleId, LoggingRequestStateToString(requestedState), LoggingRequestStateToString(pResults->requestedState));
2109
}
2110
2111
+ void OnApplyDowngradeFallback(
2112
+ __in BA_ONAPPLYDOWNGRADE_ARGS* pArgs,
2113
+ __inout BA_ONAPPLYDOWNGRADE_RESULTS* pResults
2114
+ )
2115
+ {
2116
+ m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONAPPLYDOWNGRADE, pArgs, pResults, m_pvBAFunctionsProcContext);
2117
+ }
2118
+
2119
2120
public: //CBalBaseBootstrapperApplication
2121
virtual STDMETHODIMP Initialize(
@@ -4195,7 +4193,7 @@ public:
4193
__in BOOL fPrereq,
4194
__in HRESULT hrHostInitialization,
4195
__in IBootstrapperEngine* pEngine
4198
- ) : CBalBaseBootstrapperApplication(pEngine, 3, 3000)
4196
+ ) : CBalBaseBootstrapperApplication(pEngine, 3, 3000)
4197
{
4198
THEME_ASSIGN_CONTROL_ID* pAssignControl = NULL;
4199
@@ -4224,7 +4222,6 @@ public:
4222
m_state = WIXSTDBA_STATE_INITIALIZING;
4223
m_hrFinal = hrHostInitialization;
4224
4227
- m_fDowngrading = FALSE;
4225
m_restartResult = BOOTSTRAPPER_APPLY_RESTART_NONE;
4226
m_fRestartRequired = FALSE;
4227
m_fShouldRestart = FALSE;
@@ -4529,7 +4526,6 @@ private:
4526
DWORD m_dwCalculatedCacheProgress;
4527
DWORD m_dwCalculatedExecuteProgress;
4528
4532
- BOOL m_fDowngrading;
4529
BOOTSTRAPPER_APPLY_RESTART m_restartResult;
4530
BOOL m_fRestartRequired;
4531
BOOL m_fShouldRestart;
src/test/burn/WixToolsetTest.BurnE2E/WixStdBaTests.cs
new
+55
@@ -0,0 +1,55 @@
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
+namespace WixToolsetTest.BurnE2E
4
+{
5
+ using WixTestTools;
6
+ using Xunit;
7
+ using Xunit.Abstractions;
8
+
9
+ public class WixStdBaTests : BurnE2ETests
10
+ {
11
+ public WixStdBaTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { }
12
+
13
+ [Fact]
14
+ public void ExitsWithErrorWhenDowngradingWithoutSuppression()
15
+ {
16
+ var packageA = this.CreatePackageInstaller("PackageA");
17
+ var bundle1v10 = this.CreateBundleInstaller("WixStdBaTest1_v10");
18
+ var bundle1v11 = this.CreateBundleInstaller("WixStdBaTest1_v11");
19
+
20
+ packageA.VerifyInstalled(false);
21
+
22
+ bundle1v11.Install();
23
+ bundle1v11.VerifyRegisteredAndInPackageCache();
24
+
25
+ packageA.VerifyInstalled(true);
26
+
27
+ bundle1v10.Install((int)MSIExec.MSIExecReturnCode.ERROR_PRODUCT_VERSION);
28
+ bundle1v10.VerifyUnregisteredAndRemovedFromPackageCache();
29
+ bundle1v11.VerifyRegisteredAndInPackageCache();
30
+
31
+ packageA.VerifyInstalled(true);
32
+ }
33
+
34
+ [Fact]
35
+ public void ExitsWithoutErrorWhenDowngradingWithSuppression()
36
+ {
37
+ var packageA = this.CreatePackageInstaller("PackageA");
38
+ var bundle1v11 = this.CreateBundleInstaller("WixStdBaTest1_v11");
39
+ var bundle1v12 = this.CreateBundleInstaller("WixStdBaTest1_v12");
40
+
41
+ packageA.VerifyInstalled(false);
42
+
43
+ bundle1v12.Install();
44
+ bundle1v12.VerifyRegisteredAndInPackageCache();
45
+
46
+ packageA.VerifyInstalled(true);
47
+
48
+ bundle1v11.Install();
49
+ bundle1v11.VerifyUnregisteredAndRemovedFromPackageCache();
50
+ bundle1v12.VerifyRegisteredAndInPackageCache();
51
+
52
+ packageA.VerifyInstalled(true);
53
+ }
54
+ }
55
+}