Remove orphan compatible MSI packages.
Reimplements #3190
Sean Hall committed
Jan 14, 2022 at 21:37 UTC
da1d1376953ef1c9afb32d5eee02b785e52e372e
43 files changed
+1964
-84
src/api/burn/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h
+61
@@ -205,6 +205,10 @@ enum BOOTSTRAPPER_APPLICATION_MESSAGE
205
BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANROLLBACKBOUNDARY,
206
BOOTSTRAPPER_APPLICATION_MESSAGE_ONSETUPDATEBEGIN,
207
BOOTSTRAPPER_APPLICATION_MESSAGE_ONSETUPDATECOMPLETE,
208
+ BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTCOMPATIBLEMSIPACKAGE,
209
+ BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANCOMPATIBLEMSIPACKAGEBEGIN,
210
+ BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANCOMPATIBLEMSIPACKAGECOMPLETE,
211
+ BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANNEDCOMPATIBLEPACKAGE,
212
};
213
214
enum BOOTSTRAPPER_APPLYCOMPLETE_ACTION
@@ -648,6 +652,20 @@ struct BA_ONDETECTBEGIN_RESULTS
652
BOOL fCancel;
653
};
654
655
+struct BA_ONDETECTCOMPATIBLEMSIPACKAGE_ARGS
656
+{
657
+ DWORD cbSize;
658
+ LPCWSTR wzPackageId;
659
+ LPCWSTR wzCompatiblePackageId;
660
+ LPCWSTR wzCompatiblePackageVersion;
661
+};
662
+
663
+struct BA_ONDETECTCOMPATIBLEMSIPACKAGE_RESULTS
664
+{
665
+ DWORD cbSize;
666
+ BOOL fCancel;
667
+};
668
+
669
struct BA_ONDETECTCOMPLETE_ARGS
670
{
671
DWORD cbSize;
@@ -1023,6 +1041,36 @@ struct BA_ONPLANBEGIN_RESULTS
1041
BOOL fCancel;
1042
};
1043
1044
+struct BA_ONPLANCOMPATIBLEMSIPACKAGEBEGIN_ARGS
1045
+{
1046
+ DWORD cbSize;
1047
+ LPCWSTR wzPackageId;
1048
+ LPCWSTR wzCompatiblePackageId;
1049
+ LPCWSTR wzCompatiblePackageVersion;
1050
+ BOOL fRecommendedRemove;
1051
+};
1052
+
1053
+struct BA_ONPLANCOMPATIBLEMSIPACKAGEBEGIN_RESULTS
1054
+{
1055
+ DWORD cbSize;
1056
+ BOOL fCancel;
1057
+ BOOL fRequestRemove;
1058
+};
1059
+
1060
+struct BA_ONPLANCOMPATIBLEMSIPACKAGECOMPLETE_ARGS
1061
+{
1062
+ DWORD cbSize;
1063
+ LPCWSTR wzPackageId;
1064
+ LPCWSTR wzCompatiblePackageId;
1065
+ HRESULT hrStatus;
1066
+ BOOL fRequestedRemove;
1067
+};
1068
+
1069
+struct BA_ONPLANCOMPATIBLEMSIPACKAGECOMPLETE_RESULTS
1070
+{
1071
+ DWORD cbSize;
1072
+};
1073
+
1074
struct BA_ONPLANCOMPLETE_ARGS
1075
{
1076
DWORD cbSize;
@@ -1086,6 +1134,19 @@ struct BA_ONPLANMSIPACKAGE_RESULTS
1134
BOOTSTRAPPER_MSI_FILE_VERSIONING fileVersioning;
1135
};
1136
1137
+struct BA_ONPLANNEDCOMPATIBLEPACKAGE_ARGS
1138
+{
1139
+ DWORD cbSize;
1140
+ LPCWSTR wzPackageId;
1141
+ LPCWSTR wzCompatiblePackageId;
1142
+ BOOL fRemove;
1143
+};
1144
+
1145
+struct BA_ONPLANNEDCOMPATIBLEPACKAGE_RESULTS
1146
+{
1147
+ DWORD cbSize;
1148
+};
1149
+
1150
struct BA_ONPLANNEDPACKAGE_ARGS
1151
{
1152
DWORD cbSize;
src/api/burn/WixToolset.Mba.Core/BootstrapperApplication.cs
+99
@@ -63,6 +63,9 @@ namespace WixToolset.Mba.Core
63
64
/// <inheritdoc/>
65
public event EventHandler<DetectPackageBeginEventArgs> DetectPackageBegin;
66
+
67
+ /// <inheritdoc/>
68
+ public event EventHandler<DetectCompatibleMsiPackageEventArgs> DetectCompatibleMsiPackage;
69
70
/// <inheritdoc/>
71
public event EventHandler<DetectRelatedMsiPackageEventArgs> DetectRelatedMsiPackage;
@@ -91,6 +94,12 @@ namespace WixToolset.Mba.Core
94
/// <inheritdoc/>
95
public event EventHandler<PlanPackageBeginEventArgs> PlanPackageBegin;
96
97
+ /// <inheritdoc/>
98
+ public event EventHandler<PlanCompatibleMsiPackageBeginEventArgs> PlanCompatibleMsiPackageBegin;
99
+
100
+ /// <inheritdoc/>
101
+ public event EventHandler<PlanCompatibleMsiPackageCompleteEventArgs> PlanCompatibleMsiPackageComplete;
102
+
103
/// <inheritdoc/>
104
public event EventHandler<PlanPatchTargetEventArgs> PlanPatchTarget;
105
@@ -103,6 +112,9 @@ namespace WixToolset.Mba.Core
112
/// <inheritdoc/>
113
public event EventHandler<PlanPackageCompleteEventArgs> PlanPackageComplete;
114
115
+ /// <inheritdoc/>
116
+ public event EventHandler<PlannedCompatiblePackageEventArgs> PlannedCompatiblePackage;
117
+
118
/// <inheritdoc/>
119
public event EventHandler<PlannedPackageEventArgs> PlannedPackage;
120
@@ -414,6 +426,19 @@ namespace WixToolset.Mba.Core
426
}
427
}
428
429
+ /// <summary>
430
+ /// Called by the engine, raises the <see cref="DetectCompatibleMsiPackage"/> event.
431
+ /// </summary>
432
+ /// <param name="args">Additional arguments for this event.</param>
433
+ protected virtual void OnDetectCompatibleMsiPackage(DetectCompatibleMsiPackageEventArgs args)
434
+ {
435
+ EventHandler<DetectCompatibleMsiPackageEventArgs> handler = this.DetectCompatibleMsiPackage;
436
+ if (null != handler)
437
+ {
438
+ handler(this, args);
439
+ }
440
+ }
441
+
442
/// <summary>
443
/// Called by the engine, raises the <see cref="DetectRelatedMsiPackage"/> event.
444
/// </summary>
@@ -530,6 +555,32 @@ namespace WixToolset.Mba.Core
555
}
556
}
557
558
+ /// <summary>
559
+ /// Called by the engine, raises the <see cref="PlanCompatibleMsiPackageBegin"/> event.
560
+ /// </summary>
561
+ /// <param name="args">Additional arguments for this event.</param>
562
+ protected virtual void OnPlanCompatibleMsiPackageBegin(PlanCompatibleMsiPackageBeginEventArgs args)
563
+ {
564
+ EventHandler<PlanCompatibleMsiPackageBeginEventArgs> handler = this.PlanCompatibleMsiPackageBegin;
565
+ if (null != handler)
566
+ {
567
+ handler(this, args);
568
+ }
569
+ }
570
+
571
+ /// <summary>
572
+ /// Called by the engine, raises the <see cref="PlanCompatibleMsiPackageComplete"/> event.
573
+ /// </summary>
574
+ /// <param name="args">Additional arguments for this event.</param>
575
+ protected virtual void OnPlanCompatibleMsiPackageComplete(PlanCompatibleMsiPackageCompleteEventArgs args)
576
+ {
577
+ EventHandler<PlanCompatibleMsiPackageCompleteEventArgs> handler = this.PlanCompatibleMsiPackageComplete;
578
+ if (null != handler)
579
+ {
580
+ handler(this, args);
581
+ }
582
+ }
583
+
584
/// <summary>
585
/// Called by the engine, raises the <see cref="PlanPatchTarget"/> event.
586
/// </summary>
@@ -582,6 +633,19 @@ namespace WixToolset.Mba.Core
633
}
634
}
635
636
+ /// <summary>
637
+ /// Called by the engine, raises the <see cref="PlannedCompatiblePackage"/> event.
638
+ /// </summary>
639
+ /// <param name="args">Additional arguments for this event.</param>
640
+ protected virtual void OnPlannedCompatiblePackage(PlannedCompatiblePackageEventArgs args)
641
+ {
642
+ EventHandler<PlannedCompatiblePackageEventArgs> handler = this.PlannedCompatiblePackage;
643
+ if (null != handler)
644
+ {
645
+ handler(this, args);
646
+ }
647
+ }
648
+
649
/// <summary>
650
/// Called by the engine, raises the <see cref="PlannedPackage"/> event.
651
/// </summary>
@@ -1363,6 +1427,15 @@ namespace WixToolset.Mba.Core
1427
return args.HResult;
1428
}
1429
1430
+ int IBootstrapperApplication.OnDetectCompatibleMsiPackage(string wzPackageId, string wzCompatiblePackageId, string wzCompatiblePackageVersion, ref bool fCancel)
1431
+ {
1432
+ DetectCompatibleMsiPackageEventArgs args = new DetectCompatibleMsiPackageEventArgs(wzPackageId, wzCompatiblePackageId, wzCompatiblePackageVersion, fCancel);
1433
+ this.OnDetectCompatibleMsiPackage(args);
1434
+
1435
+ fCancel = args.Cancel;
1436
+ return args.HResult;
1437
+ }
1438
+
1439
int IBootstrapperApplication.OnDetectRelatedMsiPackage(string wzPackageId, string wzUpgradeCode, string wzProductCode, bool fPerMachine, string wzVersion, RelatedOperation operation, ref bool fCancel)
1440
{
1441
DetectRelatedMsiPackageEventArgs args = new DetectRelatedMsiPackageEventArgs(wzPackageId, wzUpgradeCode, wzProductCode, fPerMachine, wzVersion, operation, fCancel);
@@ -1445,6 +1518,24 @@ namespace WixToolset.Mba.Core
1518
return args.HResult;
1519
}
1520
1521
+ int IBootstrapperApplication.OnPlanCompatibleMsiPackageBegin(string wzPackageId, string wzCompatiblePackageId, string wzCompatiblePackageVersion, bool recommendedRemove, ref bool pRequestedRemove, ref bool fCancel)
1522
+ {
1523
+ PlanCompatibleMsiPackageBeginEventArgs args = new PlanCompatibleMsiPackageBeginEventArgs(wzPackageId, wzCompatiblePackageId, wzCompatiblePackageVersion, recommendedRemove, pRequestedRemove, fCancel);
1524
+ this.OnPlanCompatibleMsiPackageBegin(args);
1525
+
1526
+ pRequestedRemove = args.RequestRemove;
1527
+ fCancel = args.Cancel;
1528
+ return args.HResult;
1529
+ }
1530
+
1531
+ int IBootstrapperApplication.OnPlanCompatibleMsiPackageComplete(string wzPackageId, string wzCompatiblePackageId, int hrStatus, bool requestedRemove)
1532
+ {
1533
+ PlanCompatibleMsiPackageCompleteEventArgs args = new PlanCompatibleMsiPackageCompleteEventArgs(wzPackageId, wzCompatiblePackageId, hrStatus, requestedRemove);
1534
+ this.OnPlanCompatibleMsiPackageComplete(args);
1535
+
1536
+ return args.HResult;
1537
+ }
1538
+
1539
int IBootstrapperApplication.OnPlanPatchTarget(string wzPackageId, string wzProductCode, RequestState recommendedState, ref RequestState pRequestedState, ref bool fCancel)
1540
{
1541
PlanPatchTargetEventArgs args = new PlanPatchTargetEventArgs(wzPackageId, wzProductCode, recommendedState, pRequestedState, fCancel);
@@ -1486,6 +1577,14 @@ namespace WixToolset.Mba.Core
1577
return args.HResult;
1578
}
1579
1580
+ int IBootstrapperApplication.OnPlannedCompatiblePackage(string wzPackageId, string wzCompatiblePackageId, bool remove)
1581
+ {
1582
+ var args = new PlannedCompatiblePackageEventArgs(wzPackageId, wzCompatiblePackageId, remove);
1583
+ this.OnPlannedCompatiblePackage(args);
1584
+
1585
+ return args.HResult;
1586
+ }
1587
+
1588
int IBootstrapperApplication.OnPlannedPackage(string wzPackageId, ActionState execute, ActionState rollback, bool fPlannedCache, bool fPlannedUncache)
1589
{
1590
var args = new PlannedPackageEventArgs(wzPackageId, execute, rollback, fPlannedCache, fPlannedUncache);
src/api/burn/WixToolset.Mba.Core/EventArgs.cs
+135
@@ -495,6 +495,37 @@ namespace WixToolset.Mba.Core
495
public string PackageId { get; private set; }
496
}
497
498
+ /// <summary>
499
+ /// Event arguments for <see cref="IDefaultBootstrapperApplication.DetectCompatibleMsiPackage"/>
500
+ /// </summary>
501
+ [Serializable]
502
+ public class DetectCompatibleMsiPackageEventArgs : CancellableHResultEventArgs
503
+ {
504
+ /// <summary />
505
+ public DetectCompatibleMsiPackageEventArgs(string packageId, string compatiblePackageId, string compatiblePackageVersion, bool cancelRecommendation)
506
+ : base(cancelRecommendation)
507
+ {
508
+ this.PackageId = packageId;
509
+ this.CompatiblePackageId = compatiblePackageId;
510
+ this.CompatiblePackageVersion = compatiblePackageVersion;
511
+ }
512
+
513
+ /// <summary>
514
+ /// Gets the identity of the package that was not detected.
515
+ /// </summary>
516
+ public string PackageId { get; private set; }
517
+
518
+ /// <summary>
519
+ /// Gets the identity of the compatible package that was detected.
520
+ /// </summary>
521
+ public string CompatiblePackageId { get; private set; }
522
+
523
+ /// <summary>
524
+ /// Gets the version of the compatible package that was detected.
525
+ /// </summary>
526
+ public string CompatiblePackageVersion { get; private set; }
527
+ }
528
+
529
/// <summary>
530
/// Event arguments for <see cref="IDefaultBootstrapperApplication.DetectRelatedMsiPackage"/>
531
/// </summary>
@@ -775,6 +806,80 @@ namespace WixToolset.Mba.Core
806
public BOOTSTRAPPER_CACHE_TYPE CacheType { get; set; }
807
}
808
809
+ /// <summary>
810
+ /// Event arguments for <see cref="IDefaultBootstrapperApplication.PlanCompatibleMsiPackageBegin"/>
811
+ /// </summary>
812
+ [Serializable]
813
+ public class PlanCompatibleMsiPackageBeginEventArgs : CancellableHResultEventArgs
814
+ {
815
+ /// <summary />
816
+ public PlanCompatibleMsiPackageBeginEventArgs(string packageId, string compatiblePackageId, string compatiblePackageVersion, bool recommendedRemove, bool requestRemove, bool cancelRecommendation)
817
+ : base(cancelRecommendation)
818
+ {
819
+ this.PackageId = packageId;
820
+ this.CompatiblePackageId = compatiblePackageId;
821
+ this.CompatiblePackageVersion = compatiblePackageVersion;
822
+ this.RecommendedRemove = recommendedRemove;
823
+ this.RequestRemove = requestRemove;
824
+ }
825
+
826
+ /// <summary>
827
+ /// Gets the identity of the package that was not detected.
828
+ /// </summary>
829
+ public string PackageId { get; private set; }
830
+
831
+ /// <summary>
832
+ /// Gets the identity of the compatible package detected.
833
+ /// </summary>
834
+ public string CompatiblePackageId { get; private set; }
835
+
836
+ /// <summary>
837
+ /// Gets the version of the compatible package detected.
838
+ /// </summary>
839
+ public string CompatiblePackageVersion { get; private set; }
840
+
841
+ /// <summary>
842
+ /// Gets the recommended state to use for the compatible package for planning.
843
+ /// </summary>
844
+ public bool RecommendedRemove { get; private set; }
845
+
846
+ /// <summary>
847
+ /// Gets or sets whether to uninstall the compatible package.
848
+ /// </summary>
849
+ public bool RequestRemove { get; set; }
850
+ }
851
+
852
+ /// <summary>
853
+ /// Event arguments for <see cref="IDefaultBootstrapperApplication.PlanCompatibleMsiPackageComplete"/>
854
+ /// </summary>
855
+ [Serializable]
856
+ public class PlanCompatibleMsiPackageCompleteEventArgs : StatusEventArgs
857
+ {
858
+ /// <summary />
859
+ public PlanCompatibleMsiPackageCompleteEventArgs(string packageId, string compatiblePackageId, int hrStatus, bool requestedRemove)
860
+ : base(hrStatus)
861
+ {
862
+ this.PackageId = packageId;
863
+ this.CompatiblePackageId = compatiblePackageId;
864
+ this.RequestedRemove = requestedRemove;
865
+ }
866
+
867
+ /// <summary>
868
+ /// Gets the identity of the package planned for.
869
+ /// </summary>
870
+ public string PackageId { get; private set; }
871
+
872
+ /// <summary>
873
+ /// Gets the identity of the compatible package detected.
874
+ /// </summary>
875
+ public string CompatiblePackageId { get; private set; }
876
+
877
+ /// <summary>
878
+ /// Gets the requested state of the package.
879
+ /// </summary>
880
+ public bool RequestedRemove { get; private set; }
881
+ }
882
+
883
/// <summary>
884
/// Event arguments for <see cref="IDefaultBootstrapperApplication.PlanRollbackBoundary"/>
885
/// </summary>
@@ -980,6 +1085,36 @@ namespace WixToolset.Mba.Core
1085
public RequestState Requested { get; private set; }
1086
}
1087
1088
+ /// <summary>
1089
+ /// Event arguments for <see cref="IDefaultBootstrapperApplication.PlannedCompatiblePackage"/>
1090
+ /// </summary>
1091
+ [Serializable]
1092
+ public class PlannedCompatiblePackageEventArgs : HResultEventArgs
1093
+ {
1094
+ /// <summary />
1095
+ public PlannedCompatiblePackageEventArgs(string packageId, string compatiblePackageId, bool remove)
1096
+ {
1097
+ this.PackageId = packageId;
1098
+ this.CompatiblePackageId = compatiblePackageId;
1099
+ this.Remove = remove;
1100
+ }
1101
+
1102
+ /// <summary>
1103
+ /// Gets the identity of the package planned for.
1104
+ /// </summary>
1105
+ public string PackageId { get; private set; }
1106
+
1107
+ /// <summary>
1108
+ /// Gets the identity of the compatible package detected.
1109
+ /// </summary>
1110
+ public string CompatiblePackageId { get; private set; }
1111
+
1112
+ /// <summary>
1113
+ /// Gets the planned state of the package.
1114
+ /// </summary>
1115
+ public bool Remove { get; private set; }
1116
+ }
1117
+
1118
/// <summary>
1119
/// Event arguments for <see cref="IDefaultBootstrapperApplication.PlannedPackage"/>
1120
/// </summary>
src/api/burn/WixToolset.Mba.Core/IBootstrapperApplication.cs
+49
-8
@@ -181,17 +181,21 @@ namespace WixToolset.Mba.Core
181
[MarshalAs(UnmanagedType.Bool)] ref bool fCancel
182
);
183
184
+ /// <summary>
185
+ /// See <see cref="IDefaultBootstrapperApplication.DetectCompatibleMsiPackage"/>.
186
+ /// </summary>
187
+ [PreserveSig]
188
+ [return: MarshalAs(UnmanagedType.I4)]
189
+ int OnDetectCompatibleMsiPackage(
190
+ [MarshalAs(UnmanagedType.LPWStr)] string wzPackageId,
191
+ [MarshalAs(UnmanagedType.LPWStr)] string wzCompatiblePackageId,
192
+ [MarshalAs(UnmanagedType.LPWStr)] string wzCompatiblePackageVersion,
193
+ [MarshalAs(UnmanagedType.Bool)] ref bool fCancel
194
+ );
195
+
196
/// <summary>
197
/// See <see cref="IDefaultBootstrapperApplication.DetectRelatedMsiPackage"/>.
198
/// </summary>
187
- /// <param name="wzPackageId"></param>
188
- /// <param name="wzUpgradeCode"></param>
189
- /// <param name="wzProductCode"></param>
190
- /// <param name="fPerMachine"></param>
191
- /// <param name="wzVersion"></param>
192
- /// <param name="operation"></param>
193
- /// <param name="fCancel"></param>
194
- /// <returns></returns>
199
[PreserveSig]
200
[return: MarshalAs(UnmanagedType.I4)]
201
int OnDetectRelatedMsiPackage(
@@ -317,6 +321,32 @@ namespace WixToolset.Mba.Core
321
[MarshalAs(UnmanagedType.Bool)] ref bool fCancel
322
);
323
324
+ /// <summary>
325
+ /// See <see cref="IDefaultBootstrapperApplication.PlanCompatibleMsiPackageBegin"/>.
326
+ /// </summary>
327
+ [PreserveSig]
328
+ [return: MarshalAs(UnmanagedType.I4)]
329
+ int OnPlanCompatibleMsiPackageBegin(
330
+ [MarshalAs(UnmanagedType.LPWStr)] string wzPackageId,
331
+ [MarshalAs(UnmanagedType.LPWStr)] string wzCompatiblePackageId,
332
+ [MarshalAs(UnmanagedType.LPWStr)] string wzCompatiblePackageVersion,
333
+ [MarshalAs(UnmanagedType.Bool)] bool fRecommendedRemove,
334
+ [MarshalAs(UnmanagedType.Bool)] ref bool fRequestRemove,
335
+ [MarshalAs(UnmanagedType.Bool)] ref bool fCancel
336
+ );
337
+
338
+ /// <summary>
339
+ /// See <see cref="IDefaultBootstrapperApplication.PlanCompatibleMsiPackageComplete"/>.
340
+ /// </summary>
341
+ [PreserveSig]
342
+ [return: MarshalAs(UnmanagedType.I4)]
343
+ int OnPlanCompatibleMsiPackageComplete(
344
+ [MarshalAs(UnmanagedType.LPWStr)] string wzPackageId,
345
+ [MarshalAs(UnmanagedType.LPWStr)] string wzCompatiblePackageId,
346
+ int hrStatus,
347
+ [MarshalAs(UnmanagedType.Bool)] bool fRequestedRemove
348
+ );
349
+
350
/// <summary>
351
/// See <see cref="IDefaultBootstrapperApplication.PlanPatchTarget"/>.
352
/// </summary>
@@ -387,6 +417,17 @@ namespace WixToolset.Mba.Core
417
[MarshalAs(UnmanagedType.U4)] RequestState requested
418
);
419
420
+ /// <summary>
421
+ /// See <see cref="IDefaultBootstrapperApplication.PlannedCompatiblePackage"/>.
422
+ /// </summary>
423
+ [PreserveSig]
424
+ [return: MarshalAs(UnmanagedType.I4)]
425
+ int OnPlannedCompatiblePackage(
426
+ [MarshalAs(UnmanagedType.LPWStr)] string wzPackageId,
427
+ [MarshalAs(UnmanagedType.LPWStr)] string wzCompatiblePackageId,
428
+ [MarshalAs(UnmanagedType.Bool)] bool fRemove
429
+ );
430
+
431
/// <summary>
432
/// See <see cref="IDefaultBootstrapperApplication.PlannedPackage"/>.
433
/// </summary>
src/api/burn/WixToolset.Mba.Core/IDefaultBootstrapperApplication.cs
+21
-1
@@ -133,6 +133,11 @@ namespace WixToolset.Mba.Core
133
/// </summary>
134
event EventHandler<DetectBeginEventArgs> DetectBegin;
135
136
+ /// <summary>
137
+ /// Fired when a package was not detected but a package using the same provider key was.
138
+ /// </summary>
139
+ event EventHandler<DetectCompatibleMsiPackageEventArgs> DetectCompatibleMsiPackage;
140
+
141
/// <summary>
142
/// Fired when the detection phase has completed.
143
/// </summary>
@@ -268,6 +273,16 @@ namespace WixToolset.Mba.Core
273
/// </summary>
274
event EventHandler<PlanBeginEventArgs> PlanBegin;
275
276
+ /// <summary>
277
+ /// Fired when the engine plans a new, compatible package using the same provider key.
278
+ /// </summary>
279
+ event EventHandler<PlanCompatibleMsiPackageBeginEventArgs> PlanCompatibleMsiPackageBegin;
280
+
281
+ /// <summary>
282
+ /// Fired when the engine has completed planning the installation of a specific package.
283
+ /// </summary>
284
+ event EventHandler<PlanCompatibleMsiPackageCompleteEventArgs> PlanCompatibleMsiPackageComplete;
285
+
286
/// <summary>
287
/// Fired when the engine has completed planning the installation.
288
/// </summary>
@@ -278,6 +293,11 @@ namespace WixToolset.Mba.Core
293
/// </summary>
294
event EventHandler<PlanForwardCompatibleBundleEventArgs> PlanForwardCompatibleBundle;
295
296
+ /// <summary>
297
+ /// Fired when the engine has completed planning a compatible package.
298
+ /// </summary>
299
+ event EventHandler<PlannedCompatiblePackageEventArgs> PlannedCompatiblePackage;
300
+
301
/// <summary>
302
/// Fired when the engine has completed planning a package.
303
/// </summary>
@@ -399,4 +419,4 @@ namespace WixToolset.Mba.Core
419
/// </summary>
420
event EventHandler<UnregisterCompleteEventArgs> UnregisterComplete;
421
}
402
-}
\ No newline at end of file
422
+}
src/api/burn/balutil/inc/BAFunctions.h
+4
@@ -84,6 +84,10 @@ enum BA_FUNCTIONS_MESSAGE
84
BA_FUNCTIONS_MESSAGE_ONPLANROLLBACKBOUNDARY = BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANROLLBACKBOUNDARY,
85
BA_FUNCTIONS_MESSAGE_ONSETUPDATEBEGIN = BOOTSTRAPPER_APPLICATION_MESSAGE_ONSETUPDATEBEGIN,
86
BA_FUNCTIONS_MESSAGE_ONSETUPDATECOMPLETE = BOOTSTRAPPER_APPLICATION_MESSAGE_ONSETUPDATECOMPLETE,
87
+ BA_FUNCTIONS_MESSAGE_ONDETECTCOMPATIBLEMSIPACKAGE = BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTCOMPATIBLEMSIPACKAGE,
88
+ BA_FUNCTIONS_MESSAGE_ONPLANCOMPATIBLEMSIPACKAGEBEGIN = BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANCOMPATIBLEMSIPACKAGEBEGIN,
89
+ BA_FUNCTIONS_MESSAGE_ONPLANCOMPATIBLEMSIPACKAGECOMPLETE = BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANCOMPATIBLEMSIPACKAGECOMPLETE,
90
+ BA_FUNCTIONS_MESSAGE_ONPLANNEDCOMPATIBLEPACKAGE = BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANNEDCOMPATIBLEPACKAGE,
91
92
BA_FUNCTIONS_MESSAGE_ONTHEMELOADED = 1024,
93
BA_FUNCTIONS_MESSAGE_WNDPROC,
src/api/burn/balutil/inc/BalBaseBAFunctions.h
+41
@@ -182,6 +182,16 @@ public: // IBootstrapperApplication
182
return S_OK;
183
}
184
185
+ virtual STDMETHODIMP OnDetectCompatibleMsiPackage(
186
+ __in_z LPCWSTR /*wzPackageId*/,
187
+ __in_z LPCWSTR /*wzCompatiblePackageId*/,
188
+ __in LPCWSTR /*wzCompatiblePackageVersion*/,
189
+ __inout BOOL* /*pfCancel*/
190
+ )
191
+ {
192
+ return S_OK;
193
+ }
194
+
195
virtual STDMETHODIMP OnDetectRelatedMsiPackage(
196
__in_z LPCWSTR /*wzPackageId*/,
197
__in_z LPCWSTR /*wzUpgradeCode*/,
@@ -276,6 +286,28 @@ public: // IBootstrapperApplication
286
return S_OK;
287
}
288
289
+ virtual STDMETHODIMP OnPlanCompatibleMsiPackageBegin(
290
+ __in_z LPCWSTR /*wzPackageId*/,
291
+ __in_z LPCWSTR /*wzCompatiblePackageId*/,
292
+ __in LPCWSTR /*wzCompatiblePackageVersion*/,
293
+ __in BOOL /*fRecommendedRemove*/,
294
+ __inout BOOL* /*pfRequestRemove*/,
295
+ __inout BOOL* /*pfCancel*/
296
+ )
297
+ {
298
+ return S_OK;
299
+ }
300
+
301
+ virtual STDMETHODIMP OnPlanCompatibleMsiPackageComplete(
302
+ __in_z LPCWSTR /*wzPackageId*/,
303
+ __in_z LPCWSTR /*wzCompatiblePackageId*/,
304
+ __in HRESULT /*hrStatus*/,
305
+ __in BOOL /*fRequestedRemove*/
306
+ )
307
+ {
308
+ return S_OK;
309
+ }
310
+
311
virtual STDMETHODIMP OnPlanPatchTarget(
312
__in_z LPCWSTR /*wzPackageId*/,
313
__in_z LPCWSTR /*wzProductCode*/,
@@ -322,6 +354,15 @@ public: // IBootstrapperApplication
354
return S_OK;
355
}
356
357
+ virtual STDMETHODIMP OnPlannedCompatiblePackage(
358
+ __in_z LPCWSTR /*wzPackageId*/,
359
+ __in_z LPCWSTR /*wzCompatiblePackageId*/,
360
+ __in BOOL /*fRemove*/
361
+ )
362
+ {
363
+ return S_OK;
364
+ }
365
+
366
virtual STDMETHODIMP OnPlannedPackage(
367
__in_z LPCWSTR /*wzPackageId*/,
368
__in BOOTSTRAPPER_ACTION_STATE /*execute*/,
src/api/burn/balutil/inc/BalBaseBAFunctionsProc.h
+4
@@ -155,6 +155,10 @@ static HRESULT WINAPI BalBaseBAFunctionsProc(
155
case BA_FUNCTIONS_MESSAGE_ONPLANROLLBACKBOUNDARY:
156
case BA_FUNCTIONS_MESSAGE_ONSETUPDATEBEGIN:
157
case BA_FUNCTIONS_MESSAGE_ONSETUPDATECOMPLETE:
158
+ case BA_FUNCTIONS_MESSAGE_ONDETECTCOMPATIBLEMSIPACKAGE:
159
+ case BA_FUNCTIONS_MESSAGE_ONPLANCOMPATIBLEMSIPACKAGEBEGIN:
160
+ case BA_FUNCTIONS_MESSAGE_ONPLANCOMPATIBLEMSIPACKAGECOMPLETE:
161
+ case BA_FUNCTIONS_MESSAGE_ONPLANNEDCOMPATIBLEPACKAGE:
162
hr = BalBaseBootstrapperApplicationProc((BOOTSTRAPPER_APPLICATION_MESSAGE)message, pvArgs, pvResults, pvContext);
163
break;
164
case BA_FUNCTIONS_MESSAGE_ONTHEMELOADED:
src/api/burn/balutil/inc/BalBaseBootstrapperApplication.h
+43
@@ -189,6 +189,17 @@ public: // IBootstrapperApplication
189
return S_OK;
190
}
191
192
+ virtual STDMETHODIMP OnDetectCompatibleMsiPackage(
193
+ __in_z LPCWSTR /*wzPackageId*/,
194
+ __in_z LPCWSTR /*wzCompatiblePackageId*/,
195
+ __in LPCWSTR /*wzCompatiblePackageVersion*/,
196
+ __inout BOOL* pfCancel
197
+ )
198
+ {
199
+ *pfCancel |= CheckCanceled();
200
+ return S_OK;
201
+ }
202
+
203
virtual STDMETHODIMP OnDetectRelatedMsiPackage(
204
__in_z LPCWSTR /*wzPackageId*/,
205
__in_z LPCWSTR /*wzUpgradeCode*/,
@@ -290,6 +301,29 @@ public: // IBootstrapperApplication
301
return S_OK;
302
}
303
304
+ virtual STDMETHODIMP OnPlanCompatibleMsiPackageBegin(
305
+ __in_z LPCWSTR /*wzPackageId*/,
306
+ __in_z LPCWSTR /*wzCompatiblePackageId*/,
307
+ __in LPCWSTR /*wzCompatiblePackageVersion*/,
308
+ __in BOOL /*fRecommendedRemove*/,
309
+ __inout BOOL* /*pfRequestRemove*/,
310
+ __inout BOOL* pfCancel
311
+ )
312
+ {
313
+ *pfCancel |= CheckCanceled();
314
+ return S_OK;
315
+ }
316
+
317
+ virtual STDMETHODIMP OnPlanCompatibleMsiPackageComplete(
318
+ __in_z LPCWSTR /*wzPackageId*/,
319
+ __in_z LPCWSTR /*wzCompatiblePackageId*/,
320
+ __in HRESULT /*hrStatus*/,
321
+ __in BOOL /*fRequestedRemove*/
322
+ )
323
+ {
324
+ return S_OK;
325
+ }
326
+
327
virtual STDMETHODIMP OnPlanPatchTarget(
328
__in_z LPCWSTR /*wzPackageId*/,
329
__in_z LPCWSTR /*wzProductCode*/,
@@ -339,6 +373,15 @@ public: // IBootstrapperApplication
373
return S_OK;
374
}
375
376
+ virtual STDMETHODIMP OnPlannedCompatiblePackage(
377
+ __in_z LPCWSTR /*wzPackageId*/,
378
+ __in_z LPCWSTR /*wzCompatiblePackageId*/,
379
+ __in BOOL /*fRemove*/
380
+ )
381
+ {
382
+ return S_OK;
383
+ }
384
+
385
virtual STDMETHODIMP OnPlannedPackage(
386
__in_z LPCWSTR /*wzPackageId*/,
387
__in BOOTSTRAPPER_ACTION_STATE /*execute*/,
src/api/burn/balutil/inc/BalBaseBootstrapperApplicationProc.h
+48
@@ -126,6 +126,15 @@ static HRESULT BalBaseBAProcOnDetectPackageBegin(
126
return pBA->OnDetectPackageBegin(pArgs->wzPackageId, &pResults->fCancel);
127
}
128
129
+static HRESULT BalBaseBAProcOnDetectCompatiblePackage(
130
+ __in IBootstrapperApplication* pBA,
131
+ __in BA_ONDETECTCOMPATIBLEMSIPACKAGE_ARGS* pArgs,
132
+ __inout BA_ONDETECTCOMPATIBLEMSIPACKAGE_RESULTS* pResults
133
+ )
134
+{
135
+ return pBA->OnDetectCompatibleMsiPackage(pArgs->wzPackageId, pArgs->wzCompatiblePackageId, pArgs->wzCompatiblePackageVersion, &pResults->fCancel);
136
+}
137
+
138
static HRESULT BalBaseBAProcOnDetectRelatedMsiPackage(
139
__in IBootstrapperApplication* pBA,
140
__in BA_ONDETECTRELATEDMSIPACKAGE_ARGS* pArgs,
@@ -189,6 +198,24 @@ static HRESULT BalBaseBAProcOnPlanPackageBegin(
198
return pBA->OnPlanPackageBegin(pArgs->wzPackageId, pArgs->state, pArgs->fCached, pArgs->installCondition, pArgs->recommendedState, pArgs->recommendedCacheType, &pResults->requestedState, &pResults->requestedCacheType, &pResults->fCancel);
199
}
200
201
+static HRESULT BalBaseBAProcOnPlanCompatibleMsiPackageBegin(
202
+ __in IBootstrapperApplication* pBA,
203
+ __in BA_ONPLANCOMPATIBLEMSIPACKAGEBEGIN_ARGS* pArgs,
204
+ __inout BA_ONPLANCOMPATIBLEMSIPACKAGEBEGIN_RESULTS* pResults
205
+ )
206
+{
207
+ return pBA->OnPlanCompatibleMsiPackageBegin(pArgs->wzPackageId, pArgs->wzCompatiblePackageId, pArgs->wzCompatiblePackageVersion, pArgs->fRecommendedRemove, &pResults->fRequestRemove, &pResults->fCancel);
208
+}
209
+
210
+static HRESULT BalBaseBAProcOnPlanCompatibleMsiPackageComplete(
211
+ __in IBootstrapperApplication* pBA,
212
+ __in BA_ONPLANCOMPATIBLEMSIPACKAGECOMPLETE_ARGS* pArgs,
213
+ __inout BA_ONPLANCOMPATIBLEMSIPACKAGECOMPLETE_RESULTS* /*pResults*/
214
+ )
215
+{
216
+ return pBA->OnPlanCompatibleMsiPackageComplete(pArgs->wzPackageId, pArgs->wzCompatiblePackageId, pArgs->hrStatus, pArgs->fRequestedRemove);
217
+}
218
+
219
static HRESULT BalBaseBAProcOnPlanPatchTarget(
220
__in IBootstrapperApplication* pBA,
221
__in BA_ONPLANPATCHTARGET_ARGS* pArgs,
@@ -216,6 +243,15 @@ static HRESULT BalBaseBAProcOnPlanPackageComplete(
243
return pBA->OnPlanPackageComplete(pArgs->wzPackageId, pArgs->hrStatus, pArgs->requested);
244
}
245
246
+static HRESULT BalBaseBAProcOnPlannedCompatiblePackage(
247
+ __in IBootstrapperApplication* pBA,
248
+ __in BA_ONPLANNEDCOMPATIBLEPACKAGE_ARGS* pArgs,
249
+ __inout BA_ONPLANNEDCOMPATIBLEPACKAGE_RESULTS* /*pResults*/
250
+ )
251
+{
252
+ return pBA->OnPlannedCompatiblePackage(pArgs->wzPackageId, pArgs->wzCompatiblePackageId, pArgs->fRemove);
253
+}
254
+
255
static HRESULT BalBaseBAProcOnPlannedPackage(
256
__in IBootstrapperApplication* pBA,
257
__in BA_ONPLANNEDPACKAGE_ARGS* pArgs,
@@ -928,6 +964,18 @@ static HRESULT WINAPI BalBaseBootstrapperApplicationProc(
964
case BOOTSTRAPPER_APPLICATION_MESSAGE_ONSETUPDATECOMPLETE:
965
hr = BalBaseBAProcOnSetUpdateComplete(pBA, reinterpret_cast<BA_ONSETUPDATECOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONSETUPDATECOMPLETE_RESULTS*>(pvResults));
966
break;
967
+ case BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTCOMPATIBLEMSIPACKAGE:
968
+ hr = BalBaseBAProcOnDetectCompatiblePackage(pBA, reinterpret_cast<BA_ONDETECTCOMPATIBLEMSIPACKAGE_ARGS*>(pvArgs), reinterpret_cast<BA_ONDETECTCOMPATIBLEMSIPACKAGE_RESULTS*>(pvResults));
969
+ break;
970
+ case BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANCOMPATIBLEMSIPACKAGEBEGIN:
971
+ hr = BalBaseBAProcOnPlanCompatibleMsiPackageBegin(pBA, reinterpret_cast<BA_ONPLANCOMPATIBLEMSIPACKAGEBEGIN_ARGS*>(pvArgs), reinterpret_cast<BA_ONPLANCOMPATIBLEMSIPACKAGEBEGIN_RESULTS*>(pvResults));
972
+ break;
973
+ case BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANCOMPATIBLEMSIPACKAGECOMPLETE:
974
+ hr = BalBaseBAProcOnPlanCompatibleMsiPackageComplete(pBA, reinterpret_cast<BA_ONPLANCOMPATIBLEMSIPACKAGECOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONPLANCOMPATIBLEMSIPACKAGECOMPLETE_RESULTS*>(pvResults));
975
+ break;
976
+ case BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANNEDCOMPATIBLEPACKAGE:
977
+ hr = BalBaseBAProcOnPlannedCompatiblePackage(pBA, reinterpret_cast<BA_ONPLANNEDCOMPATIBLEPACKAGE_ARGS*>(pvArgs), reinterpret_cast<BA_ONPLANNEDCOMPATIBLEPACKAGE_RESULTS*>(pvResults));
978
+ break;
979
}
980
}
981
src/api/burn/balutil/inc/IBootstrapperApplication.h
+34
@@ -101,6 +101,14 @@ DECLARE_INTERFACE_IID_(IBootstrapperApplication, IUnknown, "53C31D56-49C0-426B-A
101
__inout BOOL* pfCancel
102
) = 0;
103
104
+ // OnDetectCompatibleMsiPackage - called when the engine detects that a package is not installed but a newer package using the same provider key is.
105
+ STDMETHOD(OnDetectCompatibleMsiPackage)(
106
+ __in_z LPCWSTR wzPackageId,
107
+ __in_z LPCWSTR wzCompatiblePackageId,
108
+ __in_z LPCWSTR wzCompatiblePackageVersion,
109
+ __inout BOOL* pfCancel
110
+ ) = 0;
111
+
112
// OnDetectRelatedMsiPackage - called when the engine begins detects a related package.
113
STDMETHOD(OnDetectRelatedMsiPackage)(
114
__in_z LPCWSTR wzPackageId,
@@ -181,6 +189,25 @@ DECLARE_INTERFACE_IID_(IBootstrapperApplication, IUnknown, "53C31D56-49C0-426B-A
189
__inout BOOL* pfCancel
190
) = 0;
191
192
+ // OnPlanCompatibleMsiPackageBegin - called when the engine plans a newer, compatible package using the same provider key.
193
+ STDMETHOD(OnPlanCompatibleMsiPackageBegin)(
194
+ __in_z LPCWSTR wzPackageId,
195
+ __in_z LPCWSTR wzCompatiblePackageId,
196
+ __in_z LPCWSTR wzCompatiblePackageVersion,
197
+ __in BOOL fRecommendedRemove,
198
+ __inout BOOL* pfRequestRemove,
199
+ __inout BOOL* pfCancel
200
+ ) = 0;
201
+
202
+ // OnPlanCompatibleMsiPackageComplete - called after the engine plans the package.
203
+ //
204
+ STDMETHOD(OnPlanCompatibleMsiPackageComplete)(
205
+ __in_z LPCWSTR wzPackageId,
206
+ __in_z LPCWSTR wzCompatiblePackageId,
207
+ __in HRESULT hrStatus,
208
+ __in BOOL fRequestedRemove
209
+ ) = 0;
210
+
211
// OnPlanPatchTarget - called when the engine is about to plan a target
212
// of an MSP package.
213
STDMETHOD(OnPlanPatchTarget)(
@@ -223,6 +250,13 @@ DECLARE_INTERFACE_IID_(IBootstrapperApplication, IUnknown, "53C31D56-49C0-426B-A
250
__in BOOTSTRAPPER_REQUEST_STATE requested
251
) = 0;
252
253
+ // OnPlannedCompatiblePackage - called after the engine has completed planning a compatible package.
254
+ STDMETHOD(OnPlannedCompatiblePackage)(
255
+ __in_z LPCWSTR wzPackageId,
256
+ __in_z LPCWSTR wzCompatiblePackageId,
257
+ __in BOOL fRemove
258
+ ) = 0;
259
+
260
// OnPlannedPackage - called after the engine has completed planning a package.
261
STDMETHOD(OnPlannedPackage)(
262
__in_z LPCWSTR wzPackageId,
src/burn/engine/apply.cpp
+134
-28
@@ -60,7 +60,7 @@ typedef struct _BURN_EXECUTE_CONTEXT
60
BURN_USER_EXPERIENCE* pUX;
61
BURN_APPLY_CONTEXT* pApplyContext;
62
BOOL fRollback;
63
- BURN_PACKAGE* pExecutingPackage;
63
+ LPCWSTR wzExecutingPackageId;
64
DWORD cExecutedPackages;
65
DWORD cExecutePackagesTotal;
66
} BURN_EXECUTE_CONTEXT;
@@ -278,6 +278,19 @@ static void ResetTransactionRegistrationState(
278
__in BURN_ENGINE_STATE* pEngineState,
279
__in BOOL fCommit
280
);
281
+static HRESULT ExecuteUninstallMsiCompatiblePackage(
282
+ __in BURN_ENGINE_STATE* pEngineState,
283
+ __in BURN_EXECUTE_ACTION* pExecuteAction,
284
+ __in BURN_EXECUTE_CONTEXT* pContext,
285
+ __out BOOL* pfRetry,
286
+ __out BOOL* pfSuspend,
287
+ __out BOOTSTRAPPER_APPLY_RESTART* pRestart
288
+ );
289
+static HRESULT CleanCompatiblePackage(
290
+ __in BURN_CACHE* pCache,
291
+ __in HANDLE hElevatedPipe,
292
+ __in BURN_PACKAGE* pPackage
293
+ );
294
static HRESULT CleanPackage(
295
__in BURN_CACHE* pCache,
296
__in HANDLE hElevatedPipe,
@@ -300,7 +313,8 @@ static HRESULT ReportOverallProgressTicks(
313
static HRESULT ExecutePackageComplete(
314
__in BURN_USER_EXPERIENCE* pUX,
315
__in BURN_VARIABLES* pVariables,
303
- __in BURN_PACKAGE* pPackage,
316
+ __in LPCWSTR wzPackageId,
317
+ __in BOOL fPackageVital,
318
__in HRESULT hrOverall,
319
__in HRESULT hrExecute,
320
__in BOOL fRollback,
@@ -808,7 +822,20 @@ extern "C" void ApplyClean(
822
BURN_CLEAN_ACTION* pCleanAction = pPlan->rgCleanActions + i;
823
BURN_PACKAGE* pPackage = pCleanAction->pPackage;
824
811
- hr = CleanPackage(pPlan->pCache, hPipe, pPackage);
825
+ switch (pCleanAction->type)
826
+ {
827
+ case BURN_CLEAN_ACTION_TYPE_COMPATIBLE_PACKAGE:
828
+ hr = CleanCompatiblePackage(pPlan->pCache, hPipe, pPackage);
829
+ break;
830
+
831
+ case BURN_CLEAN_ACTION_TYPE_PACKAGE:
832
+ hr = CleanPackage(pPlan->pCache, hPipe, pPackage);
833
+ break;
834
+
835
+ default:
836
+ AssertSz(FALSE, "Unknown clean action.");
837
+ break;
838
+ }
839
}
840
}
841
@@ -2350,6 +2377,11 @@ static HRESULT DoExecuteAction(
2377
ExitOnFailure(hr, "Failed to execute commit MSI transaction action.");
2378
break;
2379
2380
+ case BURN_EXECUTE_ACTION_TYPE_UNINSTALL_MSI_COMPATIBLE_PACKAGE:
2381
+ hr = ExecuteUninstallMsiCompatiblePackage(pEngineState, pExecuteAction, pContext, &fRetry, pfSuspend, &restart);
2382
+ ExitOnFailure(hr, "Failed to execute uninstall MSI compatible package.");
2383
+ break;
2384
+
2385
default:
2386
hr = E_UNEXPECTED;
2387
ExitOnFailure(hr, "Invalid execute action.");
@@ -2509,7 +2541,7 @@ static HRESULT ExecuteRelatedBundle(
2541
}
2542
2543
Assert(pContext->fRollback == fRollback);
2512
- pContext->pExecutingPackage = pPackage;
2544
+ pContext->wzExecutingPackageId = pPackage->sczId;
2545
fBeginCalled = TRUE;
2546
2547
// Send package execute begin to BA.
@@ -2550,7 +2582,7 @@ static HRESULT ExecuteRelatedBundle(
2582
LExit:
2583
if (fBeginCalled)
2584
{
2553
- hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
2585
+ hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage->sczId, pPackage->fVital, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
2586
}
2587
2588
return hr;
@@ -2581,7 +2613,7 @@ static HRESULT ExecuteExePackage(
2613
}
2614
2615
Assert(pContext->fRollback == fRollback);
2584
- pContext->pExecutingPackage = pPackage;
2616
+ pContext->wzExecutingPackageId = pPackage->sczId;
2617
fBeginCalled = TRUE;
2618
2619
// Send package execute begin to BA.
@@ -2629,7 +2661,7 @@ LExit:
2661
2662
if (fBeginCalled)
2663
{
2632
- hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
2664
+ hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage->sczId, pPackage->fVital, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
2665
}
2666
2667
return hr;
@@ -2659,7 +2691,7 @@ static HRESULT ExecuteMsiPackage(
2691
}
2692
2693
Assert(pContext->fRollback == fRollback);
2662
- pContext->pExecutingPackage = pPackage;
2694
+ pContext->wzExecutingPackageId = pPackage->sczId;
2695
fBeginCalled = TRUE;
2696
2697
// Send package execute begin to BA.
@@ -2693,7 +2725,7 @@ LExit:
2725
2726
if (fBeginCalled)
2727
{
2696
- hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
2728
+ hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage->sczId, pPackage->fVital, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
2729
}
2730
2731
return hr;
@@ -2723,7 +2755,7 @@ static HRESULT ExecuteMspPackage(
2755
}
2756
2757
Assert(pContext->fRollback == fRollback);
2726
- pContext->pExecutingPackage = pPackage;
2758
+ pContext->wzExecutingPackageId = pPackage->sczId;
2759
fBeginCalled = TRUE;
2760
2761
// Send package execute begin to BA.
@@ -2766,7 +2798,7 @@ LExit:
2798
2799
if (fBeginCalled)
2800
{
2769
- hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
2801
+ hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage->sczId, pPackage->fVital, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
2802
}
2803
2804
return hr;
@@ -2798,7 +2830,7 @@ static HRESULT ExecuteMsuPackage(
2830
}
2831
2832
Assert(pContext->fRollback == fRollback);
2801
- pContext->pExecutingPackage = pPackage;
2833
+ pContext->wzExecutingPackageId = pPackage->sczId;
2834
fBeginCalled = TRUE;
2835
2836
// Send package execute begin to BA.
@@ -2846,7 +2878,7 @@ LExit:
2878
2879
if (fBeginCalled)
2880
{
2849
- hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
2881
+ hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage->sczId, pPackage->fVital, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
2882
}
2883
2884
return hr;
@@ -3110,6 +3142,79 @@ static void ResetTransactionRegistrationState(
3142
}
3143
}
3144
3145
+static HRESULT ExecuteUninstallMsiCompatiblePackage(
3146
+ __in BURN_ENGINE_STATE* pEngineState,
3147
+ __in BURN_EXECUTE_ACTION* pExecuteAction,
3148
+ __in BURN_EXECUTE_CONTEXT* pContext,
3149
+ __out BOOL* pfRetry,
3150
+ __out BOOL* pfSuspend,
3151
+ __out BOOTSTRAPPER_APPLY_RESTART* pRestart
3152
+ )
3153
+{
3154
+ HRESULT hr = S_OK;
3155
+ HRESULT hrExecute = S_OK;
3156
+ BOOL fRollback = FALSE;
3157
+ BOOTSTRAPPER_ACTION_STATE action = BOOTSTRAPPER_ACTION_STATE_UNINSTALL;
3158
+ INSTALLUILEVEL uiLevel = INSTALLUILEVEL_NONE;
3159
+ BOOL fDisableExternalUiHandler = FALSE;
3160
+ BOOL fBeginCalled = FALSE;
3161
+ BURN_PACKAGE* pParentPackage = pExecuteAction->uninstallMsiCompatiblePackage.pParentPackage;
3162
+
3163
+ Assert(pContext->fRollback == fRollback);
3164
+ pContext->wzExecutingPackageId = pParentPackage->compatiblePackage.compatibleEntry.sczId;
3165
+ fBeginCalled = TRUE;
3166
+
3167
+ // Send package execute begin to BA.
3168
+ hr = UserExperienceOnExecutePackageBegin(&pEngineState->userExperience, pContext->wzExecutingPackageId, !fRollback, action, uiLevel, fDisableExternalUiHandler);
3169
+ ExitOnRootFailure(hr, "BA aborted execute MSI compatible package begin.");
3170
+
3171
+ // execute package
3172
+ if (pParentPackage->fPerMachine)
3173
+ {
3174
+ hrExecute = ElevationUninstallMsiCompatiblePackage(pEngineState->companionConnection.hPipe, pEngineState->userExperience.hwndApply, pExecuteAction, &pEngineState->variables, fRollback, MsiExecuteMessageHandler, pContext, pRestart);
3175
+ ExitOnFailure(hrExecute, "Failed to uninstall per-machine MSI compatible package.");
3176
+ }
3177
+ else
3178
+ {
3179
+ hrExecute = MsiEngineUninstallCompatiblePackage(pEngineState->userExperience.hwndApply, pExecuteAction, pContext->pCache, &pEngineState->variables, fRollback, MsiExecuteMessageHandler, pContext, pRestart);
3180
+ ExitOnFailure(hrExecute, "Failed to uninstall per-user MSI compatible package.");
3181
+ }
3182
+
3183
+ pContext->cExecutedPackages += fRollback ? -1 : 1;
3184
+
3185
+ hr = ReportOverallProgressTicks(&pEngineState->userExperience, fRollback, pEngineState->plan.cOverallProgressTicksTotal, pContext->pApplyContext);
3186
+ ExitOnRootFailure(hr, "BA aborted MSI compatible package execute progress.");
3187
+
3188
+LExit:
3189
+
3190
+ if (fBeginCalled)
3191
+ {
3192
+ hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pContext->wzExecutingPackageId, FALSE, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend);
3193
+ }
3194
+
3195
+ return hr;
3196
+}
3197
+
3198
+static HRESULT CleanCompatiblePackage(
3199
+ __in BURN_CACHE* pCache,
3200
+ __in HANDLE hElevatedPipe,
3201
+ __in BURN_PACKAGE* pPackage
3202
+ )
3203
+{
3204
+ HRESULT hr = S_OK;
3205
+
3206
+ if (pPackage->fPerMachine)
3207
+ {
3208
+ hr = ElevationCleanCompatiblePackage(hElevatedPipe, pPackage);
3209
+ }
3210
+ else
3211
+ {
3212
+ hr = CacheRemovePackage(pCache, FALSE, pPackage->compatiblePackage.compatibleEntry.sczId, pPackage->compatiblePackage.sczCacheId);
3213
+ }
3214
+
3215
+ return hr;
3216
+}
3217
+
3218
static HRESULT CleanPackage(
3219
__in BURN_CACHE* pCache,
3220
__in HANDLE hElevatedPipe,
@@ -3150,16 +3255,16 @@ static int GenericExecuteMessageHandler(
3255
case GENERIC_EXECUTE_MESSAGE_PROGRESS:
3256
{
3257
DWORD dwOverallProgress = pContext->cExecutePackagesTotal ? (pContext->cExecutedPackages * 100 + pMessage->progress.dwPercentage) / (pContext->cExecutePackagesTotal) : 0;
3153
- UserExperienceOnExecuteProgress(pContext->pUX, pContext->pExecutingPackage->sczId, pMessage->progress.dwPercentage, dwOverallProgress, &nResult); // ignore return value.
3258
+ UserExperienceOnExecuteProgress(pContext->pUX, pContext->wzExecutingPackageId, pMessage->progress.dwPercentage, dwOverallProgress, &nResult); // ignore return value.
3259
}
3260
break;
3261
3262
case GENERIC_EXECUTE_MESSAGE_ERROR:
3158
- UserExperienceOnError(pContext->pUX, BOOTSTRAPPER_ERROR_TYPE_EXE_PACKAGE, pContext->pExecutingPackage->sczId, pMessage->error.dwErrorCode, pMessage->error.wzMessage, pMessage->dwUIHint, 0, NULL, &nResult); // ignore return value.
3263
+ UserExperienceOnError(pContext->pUX, BOOTSTRAPPER_ERROR_TYPE_EXE_PACKAGE, pContext->wzExecutingPackageId, pMessage->error.dwErrorCode, pMessage->error.wzMessage, pMessage->dwUIHint, 0, NULL, &nResult); // ignore return value.
3264
break;
3265
3266
case GENERIC_EXECUTE_MESSAGE_NETFX_FILES_IN_USE:
3162
- UserExperienceOnExecuteFilesInUse(pContext->pUX, pContext->pExecutingPackage->sczId, pMessage->filesInUse.cFiles, pMessage->filesInUse.rgwzFiles, BOOTSTRAPPER_FILES_IN_USE_TYPE_NETFX, &nResult); // ignore return value.
3267
+ UserExperienceOnExecuteFilesInUse(pContext->pUX, pContext->wzExecutingPackageId, pMessage->filesInUse.cFiles, pMessage->filesInUse.rgwzFiles, BOOTSTRAPPER_FILES_IN_USE_TYPE_NETFX, &nResult); // ignore return value.
3268
fPassthrough = TRUE;
3269
break;
3270
}
@@ -3188,25 +3293,25 @@ static int MsiExecuteMessageHandler(
3293
case WIU_MSI_EXECUTE_MESSAGE_PROGRESS:
3294
{
3295
DWORD dwOverallProgress = pContext->cExecutePackagesTotal ? (pContext->cExecutedPackages * 100 + pMessage->progress.dwPercentage) / (pContext->cExecutePackagesTotal) : 0;
3191
- UserExperienceOnExecuteProgress(pContext->pUX, pContext->pExecutingPackage->sczId, pMessage->progress.dwPercentage, dwOverallProgress, &nResult); // ignore return value.
3296
+ UserExperienceOnExecuteProgress(pContext->pUX, pContext->wzExecutingPackageId, pMessage->progress.dwPercentage, dwOverallProgress, &nResult); // ignore return value.
3297
}
3298
break;
3299
3300
case WIU_MSI_EXECUTE_MESSAGE_ERROR:
3301
nResult = pMessage->nResultRecommendation;
3197
- UserExperienceOnError(pContext->pUX, BOOTSTRAPPER_ERROR_TYPE_WINDOWS_INSTALLER, pContext->pExecutingPackage->sczId, pMessage->error.dwErrorCode, pMessage->error.wzMessage, pMessage->dwUIHint, pMessage->cData, pMessage->rgwzData, &nResult); // ignore return value.
3302
+ UserExperienceOnError(pContext->pUX, BOOTSTRAPPER_ERROR_TYPE_WINDOWS_INSTALLER, pContext->wzExecutingPackageId, pMessage->error.dwErrorCode, pMessage->error.wzMessage, pMessage->dwUIHint, pMessage->cData, pMessage->rgwzData, &nResult); // ignore return value.
3303
break;
3304
3305
case WIU_MSI_EXECUTE_MESSAGE_MSI_MESSAGE:
3306
nResult = pMessage->nResultRecommendation;
3202
- UserExperienceOnExecuteMsiMessage(pContext->pUX, pContext->pExecutingPackage->sczId, pMessage->msiMessage.mt, pMessage->dwUIHint, pMessage->msiMessage.wzMessage, pMessage->cData, pMessage->rgwzData, &nResult); // ignore return value.
3307
+ UserExperienceOnExecuteMsiMessage(pContext->pUX, pContext->wzExecutingPackageId, pMessage->msiMessage.mt, pMessage->dwUIHint, pMessage->msiMessage.wzMessage, pMessage->cData, pMessage->rgwzData, &nResult); // ignore return value.
3308
break;
3309
3310
case WIU_MSI_EXECUTE_MESSAGE_MSI_RM_FILES_IN_USE:
3311
fRestartManager = TRUE;
3312
__fallthrough;
3313
case WIU_MSI_EXECUTE_MESSAGE_MSI_FILES_IN_USE:
3209
- UserExperienceOnExecuteFilesInUse(pContext->pUX, pContext->pExecutingPackage->sczId, pMessage->msiFilesInUse.cFiles, pMessage->msiFilesInUse.rgwzFiles, fRestartManager ? BOOTSTRAPPER_FILES_IN_USE_TYPE_MSI_RM : BOOTSTRAPPER_FILES_IN_USE_TYPE_MSI, &nResult); // ignore return value.
3314
+ UserExperienceOnExecuteFilesInUse(pContext->pUX, pContext->wzExecutingPackageId, pMessage->msiFilesInUse.cFiles, pMessage->msiFilesInUse.rgwzFiles, fRestartManager ? BOOTSTRAPPER_FILES_IN_USE_TYPE_MSI_RM : BOOTSTRAPPER_FILES_IN_USE_TYPE_MSI, &nResult); // ignore return value.
3315
fPassthrough = TRUE;
3316
break;
3317
}
@@ -3246,7 +3351,8 @@ static HRESULT ReportOverallProgressTicks(
3351
static HRESULT ExecutePackageComplete(
3352
__in BURN_USER_EXPERIENCE* pUX,
3353
__in BURN_VARIABLES* pVariables,
3249
- __in BURN_PACKAGE* pPackage,
3354
+ __in LPCWSTR wzPackageId,
3355
+ __in BOOL fPackageVital,
3356
__in HRESULT hrOverall,
3357
__in HRESULT hrExecute,
3358
__in BOOL fRollback,
@@ -3256,10 +3362,10 @@ static HRESULT ExecutePackageComplete(
3362
)
3363
{
3364
HRESULT hr = FAILED(hrOverall) ? hrOverall : hrExecute; // if the overall function failed use that otherwise use the execution result.
3259
- BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION executePackageCompleteAction = FAILED(hrOverall) || SUCCEEDED(hrExecute) || pPackage->fVital ? BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION_NONE : BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION_IGNORE;
3365
+ BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION executePackageCompleteAction = FAILED(hrOverall) || SUCCEEDED(hrExecute) || fPackageVital ? BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION_NONE : BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION_IGNORE;
3366
3367
// Send package execute complete to BA.
3262
- UserExperienceOnExecutePackageComplete(pUX, pPackage->sczId, hr, *pRestart, &executePackageCompleteAction);
3368
+ UserExperienceOnExecutePackageComplete(pUX, wzPackageId, hr, *pRestart, &executePackageCompleteAction);
3369
if (BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION_RESTART == executePackageCompleteAction)
3370
{
3371
*pRestart = BOOTSTRAPPER_APPLY_RESTART_INITIATED;
@@ -3271,23 +3377,23 @@ static HRESULT ExecutePackageComplete(
3377
if (BOOTSTRAPPER_APPLY_RESTART_INITIATED == *pRestart)
3378
{
3379
// Best effort to set the forced restart package variable.
3274
- VariableSetString(pVariables, BURN_BUNDLE_FORCED_RESTART_PACKAGE, pPackage->sczId, TRUE, FALSE);
3380
+ VariableSetString(pVariables, BURN_BUNDLE_FORCED_RESTART_PACKAGE, wzPackageId, TRUE, FALSE);
3381
}
3382
3383
// If we're retrying, leave a message in the log file and say everything is okay.
3384
if (*pfRetry)
3385
{
3280
- LogId(REPORT_STANDARD, MSG_APPLY_RETRYING_PACKAGE, pPackage->sczId, hrExecute);
3386
+ LogId(REPORT_STANDARD, MSG_APPLY_RETRYING_PACKAGE, wzPackageId, hrExecute);
3387
hr = S_OK;
3388
}
3283
- else if (SUCCEEDED(hrOverall) && FAILED(hrExecute) && BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION_IGNORE == executePackageCompleteAction && !pPackage->fVital) // If we *only* failed to execute and the BA ignored this *not-vital* package, say everything is okay.
3389
+ else if (SUCCEEDED(hrOverall) && FAILED(hrExecute) && BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION_IGNORE == executePackageCompleteAction && !fPackageVital) // If we *only* failed to execute and the BA ignored this *not-vital* package, say everything is okay.
3390
{
3285
- LogId(REPORT_STANDARD, MSG_APPLY_CONTINUING_NONVITAL_PACKAGE, pPackage->sczId, hrExecute);
3391
+ LogId(REPORT_STANDARD, MSG_APPLY_CONTINUING_NONVITAL_PACKAGE, wzPackageId, hrExecute);
3392
hr = S_OK;
3393
}
3394
else
3395
{
3290
- LogId(REPORT_STANDARD, MSG_APPLY_COMPLETED_PACKAGE, LoggingRollbackOrExecute(fRollback), pPackage->sczId, hr, LoggingRestartToString(*pRestart));
3396
+ LogId(REPORT_STANDARD, MSG_APPLY_COMPLETED_PACKAGE, LoggingRollbackOrExecute(fRollback), wzPackageId, hr, LoggingRestartToString(*pRestart));
3397
}
3398
3399
return hr;
src/burn/engine/core.cpp
+7
-1
@@ -389,6 +389,7 @@ extern "C" HRESULT CoreDetect(
389
pPackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_UNKNOWN;
390
pPackage->cacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN;
391
pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_UNKNOWN;
392
+ pPackage->compatiblePackage.fDetected = FALSE;
393
}
394
}
395
@@ -2240,7 +2241,7 @@ static void LogPackages(
2241
}
2242
2243
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));
2243
-
2244
+
2245
if (BURN_PACKAGE_TYPE_MSI == pPackage->type)
2246
{
2247
if (pPackage->Msi.cFeatures)
@@ -2266,6 +2267,11 @@ static void LogPackages(
2267
LogId(REPORT_STANDARD, MSG_PLANNED_SLIPSTREAMED_MSP_TARGET, pSlipstreamMsp->pMspPackage->sczId, LoggingActionStateToString(pSlipstreamMsp->execute), LoggingActionStateToString(pSlipstreamMsp->rollback));
2268
}
2269
}
2270
+
2271
+ if (pPackage->compatiblePackage.fRemove)
2272
+ {
2273
+ LogId(REPORT_STANDARD, MSG_PLANNED_ORPHAN_PACKAGE_FROM_PROVIDER, pPackage->sczId, pPackage->compatiblePackage.compatibleEntry.sczId, pPackage->Msi.sczProductCode);
2274
+ }
2275
}
2276
else if (BURN_PACKAGE_TYPE_MSP == pPackage->type && pPackage->Msp.cTargetProductCodes)
2277
{
src/burn/engine/dependency.cpp
+108
-15
@@ -54,6 +54,10 @@ static HRESULT AddPackageDependencyActions(
54
__in const BURN_DEPENDENCY_ACTION dependencyRollbackAction
55
);
56
57
+static LPCWSTR GetPackageProviderId(
58
+ __in const BURN_PACKAGE* pPackage
59
+ );
60
+
61
static HRESULT RegisterPackageProvider(
62
__in const BURN_PACKAGE* pPackage
63
);
@@ -299,6 +303,9 @@ extern "C" HRESULT DependencyDetectChainPackage(
303
hr = DetectPackageDependents(pPackage, pRegistration);
304
ExitOnFailure(hr, "Failed to detect dependents for package '%ls'", pPackage->sczId);
305
306
+ hr = DependencyDetectCompatibleEntry(pPackage, pRegistration);
307
+ ExitOnFailure(hr, "Failed to detect compatible package for package '%ls'", pPackage->sczId);
308
+
309
LExit:
310
return hr;
311
}
@@ -396,6 +403,8 @@ extern "C" HRESULT DependencyPlanPackageBegin(
403
STRINGDICT_HANDLE sdIgnoredDependents = NULL;
404
BURN_DEPENDENCY_ACTION dependencyExecuteAction = BURN_DEPENDENCY_ACTION_NONE;
405
BURN_DEPENDENCY_ACTION dependencyRollbackAction = BURN_DEPENDENCY_ACTION_NONE;
406
+ BOOL fDependentBlocksUninstall = FALSE;
407
+ BOOL fAttemptingUninstall = BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pPackage->execute || pPackage->compatiblePackage.fRemove;
408
409
pPackage->dependencyExecute = BURN_DEPENDENCY_ACTION_NONE;
410
pPackage->dependencyRollback = BURN_DEPENDENCY_ACTION_NONE;
@@ -415,7 +424,7 @@ extern "C" HRESULT DependencyPlanPackageBegin(
424
}
425
426
// If we're uninstalling the package, check if any dependents are registered.
418
- if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pPackage->execute)
427
+ if (fAttemptingUninstall)
428
{
429
// Build up a list of dependents to ignore, including the current bundle.
430
hr = GetIgnoredDependents(pPackage, pPlan, &sdIgnoredDependents);
@@ -444,9 +453,9 @@ extern "C" HRESULT DependencyPlanPackageBegin(
453
{
454
hr = S_OK;
455
447
- if (!pPackage->fDependencyManagerWasHere)
456
+ if (!fDependentBlocksUninstall)
457
{
449
- pPackage->fDependencyManagerWasHere = TRUE;
458
+ fDependentBlocksUninstall = TRUE;
459
460
LogId(REPORT_STANDARD, MSG_DEPENDENCY_PACKAGE_HASDEPENDENTS, pPackage->sczId);
461
}
@@ -459,14 +468,20 @@ extern "C" HRESULT DependencyPlanPackageBegin(
468
}
469
}
470
471
+ if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pPackage->execute)
472
+ {
473
+ pPackage->fDependencyManagerWasHere = fDependentBlocksUninstall;
474
+ }
475
+
476
// Calculate the dependency actions before the package itself is planned.
477
CalculateDependencyActionStates(pPackage, pPlan->action, &dependencyExecuteAction, &dependencyRollbackAction);
478
479
// If dependents were found, change the action to not uninstall the package.
466
- if (pPackage->fDependencyManagerWasHere)
480
+ if (fDependentBlocksUninstall)
481
{
482
pPackage->execute = BOOTSTRAPPER_ACTION_STATE_NONE;
483
pPackage->rollback = BOOTSTRAPPER_ACTION_STATE_NONE;
484
+ pPackage->compatiblePackage.fRemove = FALSE;
485
}
486
else
487
{
@@ -494,7 +509,7 @@ extern "C" HRESULT DependencyPlanPackageBegin(
509
}
510
511
// If the package will be removed, add its providers to the growing list in the plan.
497
- if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pPackage->execute)
512
+ if (fAttemptingUninstall)
513
{
514
for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
515
{
@@ -739,6 +754,73 @@ extern "C" void DependencyUnregisterBundle(
754
}
755
}
756
757
+extern "C" HRESULT DependencyDetectCompatibleEntry(
758
+ __in BURN_PACKAGE* pPackage,
759
+ __in BURN_REGISTRATION* pRegistration
760
+ )
761
+{
762
+ HRESULT hr = S_OK;
763
+ LPWSTR sczId = NULL;
764
+ LPWSTR sczName = NULL;
765
+ LPWSTR sczVersion = NULL;
766
+ LPCWSTR wzPackageProviderId = GetPackageProviderId(pPackage);
767
+ HKEY hkHive = pRegistration->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
768
+
769
+ switch (pPackage->type)
770
+ {
771
+ case BURN_PACKAGE_TYPE_MSI:
772
+ // Only MSI packages can handle compatible entries.
773
+ break;
774
+ default:
775
+ ExitFunction();
776
+ }
777
+
778
+ for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
779
+ {
780
+ BURN_DEPENDENCY_PROVIDER* pProvider = &pPackage->rgDependencyProviders[i];
781
+
782
+ hr = DepGetProviderInformation(hkHive, pProvider->sczKey, &sczId, &sczName, &sczVersion);
783
+ if (E_NOTFOUND == hr)
784
+ {
785
+ hr = S_OK;
786
+ continue;
787
+ }
788
+ ExitOnFailure(hr, "Failed to get provider information for compatible package: %ls", pProvider->sczKey);
789
+
790
+ // Make sure the compatible package is not the package itself.
791
+ if (!wzPackageProviderId)
792
+ {
793
+ if (!sczId)
794
+ {
795
+ continue;
796
+ }
797
+ }
798
+ else if (sczId && CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, wzPackageProviderId, -1, sczId, -1))
799
+ {
800
+ continue;
801
+ }
802
+
803
+ pPackage->compatiblePackage.fDetected = TRUE;
804
+
805
+ hr = StrAllocString(&pPackage->compatiblePackage.compatibleEntry.sczProviderKey, pProvider->sczKey, 0);
806
+ ExitOnFailure(hr, "Failed to copy provider key for compatible entry.");
807
+
808
+ pPackage->compatiblePackage.compatibleEntry.sczId = sczId;
809
+ sczId = NULL;
810
+
811
+ pPackage->compatiblePackage.compatibleEntry.sczName = sczName;
812
+ sczName = NULL;
813
+
814
+ pPackage->compatiblePackage.compatibleEntry.sczVersion = sczVersion;
815
+ sczVersion = NULL;
816
+
817
+ break;
818
+ }
819
+
820
+LExit:
821
+ return hr;
822
+}
823
+
824
// internal functions
825
826
@@ -1170,24 +1252,35 @@ LExit:
1252
return hr;
1253
}
1254
1255
+static LPCWSTR GetPackageProviderId(
1256
+ __in const BURN_PACKAGE* pPackage
1257
+ )
1258
+{
1259
+ LPCWSTR wzId = NULL;
1260
+
1261
+ switch (pPackage->type)
1262
+ {
1263
+ case BURN_PACKAGE_TYPE_MSI:
1264
+ wzId = pPackage->Msi.sczProductCode;
1265
+ break;
1266
+ case BURN_PACKAGE_TYPE_MSP:
1267
+ wzId = pPackage->Msp.sczPatchCode;
1268
+ break;
1269
+ }
1270
+
1271
+ return wzId;
1272
+}
1273
+
1274
static HRESULT RegisterPackageProvider(
1275
__in const BURN_PACKAGE* pPackage
1276
)
1277
{
1278
HRESULT hr = S_OK;
1178
- LPWSTR wzId = NULL;
1179
- HKEY hkRoot = pPackage->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1279
1280
if (pPackage->rgDependencyProviders)
1281
{
1183
- if (BURN_PACKAGE_TYPE_MSI == pPackage->type)
1184
- {
1185
- wzId = pPackage->Msi.sczProductCode;
1186
- }
1187
- else if (BURN_PACKAGE_TYPE_MSP == pPackage->type)
1188
- {
1189
- wzId = pPackage->Msp.sczPatchCode;
1190
- }
1282
+ HKEY hkRoot = pPackage->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1283
+ LPCWSTR wzId = GetPackageProviderId(pPackage);
1284
1285
for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
1286
{
src/burn/engine/dependency.h
+5
@@ -191,6 +191,11 @@ void DependencyUnregisterBundle(
191
__in const BURN_PACKAGES* pPackages
192
);
193
194
+HRESULT DependencyDetectCompatibleEntry(
195
+ __in BURN_PACKAGE* pPackage,
196
+ __in BURN_REGISTRATION* pRegistration
197
+ );
198
+
199
#if defined(__cplusplus)
200
}
201
#endif
src/burn/engine/detect.cpp
+2
@@ -98,6 +98,8 @@ extern "C" void DetectReset(
98
pProvider->rgDependents = NULL;
99
pProvider->cDependents = 0;
100
}
101
+
102
+ PackageUninitializeCompatible(&pPackage->compatiblePackage);
103
}
104
105
for (DWORD iPatchInfo = 0; iPatchInfo < pPackages->cPatchInfo; ++iPatchInfo)
src/burn/engine/elevation.cpp
+297
-6
@@ -32,6 +32,8 @@ typedef enum _BURN_ELEVATION_MESSAGE_TYPE
32
BURN_ELEVATION_MESSAGE_TYPE_BEGIN_MSI_TRANSACTION,
33
BURN_ELEVATION_MESSAGE_TYPE_COMMIT_MSI_TRANSACTION,
34
BURN_ELEVATION_MESSAGE_TYPE_ROLLBACK_MSI_TRANSACTION,
35
+ BURN_ELEVATION_MESSAGE_TYPE_UNINSTALL_MSI_COMPATIBLE_PACKAGE,
36
+ BURN_ELEVATION_MESSAGE_TYPE_CLEAN_COMPATIBLE_PACKAGE,
37
38
BURN_ELEVATION_MESSAGE_TYPE_APPLY_INITIALIZE_PAUSE_AU_BEGIN,
39
BURN_ELEVATION_MESSAGE_TYPE_APPLY_INITIALIZE_PAUSE_AU_COMPLETE,
@@ -168,11 +170,16 @@ static HRESULT OnApplyInitialize(
170
__in HANDLE hPipe,
171
__in BURN_VARIABLES* pVariables,
172
__in BURN_REGISTRATION* pRegistration,
173
+ __in BURN_PACKAGES* pPackages,
174
__in HANDLE* phLock,
175
__in BOOL* pfDisabledWindowsUpdate,
176
__in BYTE* pbData,
177
__in SIZE_T cbData
178
);
179
+static HRESULT ElevatedProcessDetect(
180
+ __in BURN_REGISTRATION* pRegistration,
181
+ __in BURN_PACKAGES* pPackages
182
+ );
183
static HRESULT OnApplyUninitialize(
184
__in HANDLE* phLock
185
);
@@ -271,6 +278,14 @@ static HRESULT OnExecuteMsuPackage(
278
__in BYTE* pbData,
279
__in SIZE_T cbData
280
);
281
+static HRESULT OnUninstallMsiCompatiblePackage(
282
+ __in HANDLE hPipe,
283
+ __in BURN_CACHE* pCache,
284
+ __in BURN_PACKAGES* pPackages,
285
+ __in BURN_VARIABLES* pVariables,
286
+ __in BYTE* pbData,
287
+ __in SIZE_T cbData
288
+ );
289
static HRESULT OnExecutePackageProviderAction(
290
__in BURN_PACKAGES* pPackages,
291
__in BURN_RELATED_BUNDLES* pRelatedBundles,
@@ -306,6 +321,12 @@ static int MsiExecuteMessageHandler(
321
__in WIU_MSI_EXECUTE_MESSAGE* pMessage,
322
__in_opt LPVOID pvContext
323
);
324
+static HRESULT OnCleanCompatiblePackage(
325
+ __in BURN_CACHE* pCache,
326
+ __in BURN_PACKAGES* pPackages,
327
+ __in BYTE* pbData,
328
+ __in SIZE_T cbData
329
+ );
330
static HRESULT OnCleanPackage(
331
__in BURN_CACHE* pCache,
332
__in BURN_PACKAGES* pPackages,
@@ -1230,6 +1251,58 @@ LExit:
1251
return hr;
1252
}
1253
1254
+extern "C" HRESULT ElevationUninstallMsiCompatiblePackage(
1255
+ __in HANDLE hPipe,
1256
+ __in_opt HWND hwndParent,
1257
+ __in BURN_EXECUTE_ACTION* pExecuteAction,
1258
+ __in BURN_VARIABLES* pVariables,
1259
+ __in BOOL fRollback,
1260
+ __in PFN_MSIEXECUTEMESSAGEHANDLER pfnMessageHandler,
1261
+ __in LPVOID pvContext,
1262
+ __out BOOTSTRAPPER_APPLY_RESTART* pRestart
1263
+ )
1264
+{
1265
+ HRESULT hr = S_OK;
1266
+ BYTE* pbData = NULL;
1267
+ SIZE_T cbData = 0;
1268
+ BURN_ELEVATION_MSI_MESSAGE_CONTEXT context = { };
1269
+ DWORD dwResult = 0;
1270
+
1271
+ // serialize message data
1272
+ hr = BuffWriteNumber(&pbData, &cbData, (DWORD)fRollback);
1273
+ ExitOnFailure(hr, "Failed to write rollback flag to message buffer.");
1274
+
1275
+ hr = BuffWriteString(&pbData, &cbData, pExecuteAction->uninstallMsiCompatiblePackage.pParentPackage->sczId);
1276
+ ExitOnFailure(hr, "Failed to write package id to message buffer.");
1277
+
1278
+ hr = BuffWriteString(&pbData, &cbData, pExecuteAction->uninstallMsiCompatiblePackage.pParentPackage->compatiblePackage.compatibleEntry.sczId);
1279
+ ExitOnFailure(hr, "Failed to write compatible package id to message buffer.");
1280
+
1281
+ hr = BuffWritePointer(&pbData, &cbData, (DWORD_PTR)hwndParent);
1282
+ ExitOnFailure(hr, "Failed to write parent hwnd to message buffer.");
1283
+
1284
+ hr = BuffWriteString(&pbData, &cbData, pExecuteAction->uninstallMsiCompatiblePackage.sczLogPath);
1285
+ ExitOnFailure(hr, "Failed to write package log to message buffer.");
1286
+
1287
+ hr = VariableSerialize(pVariables, FALSE, &pbData, &cbData);
1288
+ ExitOnFailure(hr, "Failed to write variables.");
1289
+
1290
+
1291
+ // send message
1292
+ context.pfnMessageHandler = pfnMessageHandler;
1293
+ context.pvContext = pvContext;
1294
+
1295
+ hr = PipeSendMessage(hPipe, BURN_ELEVATION_MESSAGE_TYPE_UNINSTALL_MSI_COMPATIBLE_PACKAGE, pbData, cbData, ProcessMsiPackageMessages, &context, &dwResult);
1296
+ ExitOnFailure(hr, "Failed to send BURN_ELEVATION_MESSAGE_TYPE_UNINSTALL_MSI_COMPATIBLE_PACKAGE message to per-machine process.");
1297
+
1298
+ hr = ProcessResult(dwResult, pRestart);
1299
+
1300
+LExit:
1301
+ ReleaseBuffer(pbData);
1302
+
1303
+ return hr;
1304
+}
1305
+
1306
extern "C" HRESULT ElevationExecutePackageProviderAction(
1307
__in HANDLE hPipe,
1308
__in BURN_EXECUTE_ACTION* pExecuteAction
@@ -1295,6 +1368,35 @@ LExit:
1368
return hr;
1369
}
1370
1371
+extern "C" HRESULT ElevationCleanCompatiblePackage(
1372
+ __in HANDLE hPipe,
1373
+ __in BURN_PACKAGE* pPackage
1374
+ )
1375
+{
1376
+ HRESULT hr = S_OK;
1377
+ BYTE* pbData = NULL;
1378
+ SIZE_T cbData = 0;
1379
+ DWORD dwResult = 0;
1380
+
1381
+ // serialize message data
1382
+ hr = BuffWriteString(&pbData, &cbData, pPackage->sczId);
1383
+ ExitOnFailure(hr, "Failed to write clean package id to message buffer.");
1384
+
1385
+ hr = BuffWriteString(&pbData, &cbData, pPackage->compatiblePackage.compatibleEntry.sczId);
1386
+ ExitOnFailure(hr, "Failed to write compatible package id to message buffer.");
1387
+
1388
+ // send message
1389
+ hr = PipeSendMessage(hPipe, BURN_ELEVATION_MESSAGE_TYPE_CLEAN_COMPATIBLE_PACKAGE, pbData, cbData, NULL, NULL, &dwResult);
1390
+ ExitOnFailure(hr, "Failed to send BURN_ELEVATION_MESSAGE_TYPE_CLEAN_COMPATIBLE_PACKAGE message to per-machine process.");
1391
+
1392
+ hr = (HRESULT)dwResult;
1393
+
1394
+LExit:
1395
+ ReleaseBuffer(pbData);
1396
+
1397
+ return hr;
1398
+}
1399
+
1400
/*******************************************************************
1401
ElevationCleanPackage -
1402
@@ -1940,7 +2042,7 @@ static HRESULT ProcessElevatedChildMessage(
2042
break;
2043
2044
case BURN_ELEVATION_MESSAGE_TYPE_APPLY_INITIALIZE:
1943
- hrResult = OnApplyInitialize(pContext->hPipe, pContext->pVariables, pContext->pRegistration, pContext->phLock, pContext->pfDisabledAutomaticUpdates, (BYTE*)pMsg->pvData, pMsg->cbData);
2045
+ hrResult = OnApplyInitialize(pContext->hPipe, pContext->pVariables, pContext->pRegistration, pContext->pPackages, pContext->phLock, pContext->pfDisabledAutomaticUpdates, (BYTE*)pMsg->pvData, pMsg->cbData);
2046
break;
2047
2048
case BURN_ELEVATION_MESSAGE_TYPE_APPLY_UNINITIALIZE:
@@ -2003,6 +2105,14 @@ static HRESULT ProcessElevatedChildMessage(
2105
hrResult = OnLaunchApprovedExe(pContext->hPipe, pContext->pApprovedExes, pContext->pCache, pContext->pVariables, (BYTE*)pMsg->pvData, pMsg->cbData);
2106
break;
2107
2108
+ case BURN_ELEVATION_MESSAGE_TYPE_UNINSTALL_MSI_COMPATIBLE_PACKAGE:
2109
+ hrResult = OnUninstallMsiCompatiblePackage(pContext->hPipe, pContext->pCache, pContext->pPackages, pContext->pVariables, (BYTE*)pMsg->pvData, pMsg->cbData);
2110
+ break;
2111
+
2112
+ case BURN_ELEVATION_MESSAGE_TYPE_CLEAN_COMPATIBLE_PACKAGE:
2113
+ hrResult = OnCleanCompatiblePackage(pContext->pCache, pContext->pPackages, (BYTE*)pMsg->pvData, pMsg->cbData);
2114
+ break;
2115
+
2116
default:
2117
hr = E_INVALIDARG;
2118
ExitOnRootFailure(hr, "Unexpected elevated message sent to child process, msg: %u", pMsg->dwMessage);
@@ -2082,6 +2192,7 @@ static HRESULT OnApplyInitialize(
2192
__in HANDLE hPipe,
2193
__in BURN_VARIABLES* pVariables,
2194
__in BURN_REGISTRATION* pRegistration,
2195
+ __in BURN_PACKAGES* pPackages,
2196
__in HANDLE* phLock,
2197
__in BOOL* pfDisabledWindowsUpdate,
2198
__in BYTE* pbData,
@@ -2113,11 +2224,9 @@ static HRESULT OnApplyInitialize(
2224
hr = ApplyLock(TRUE, phLock);
2225
ExitOnFailure(hr, "Failed to acquire lock due to setup in other session.");
2226
2116
- // Reset and reload the related bundles.
2117
- RelatedBundlesUninitialize(&pRegistration->relatedBundles);
2118
-
2119
- hr = RelatedBundlesInitializeForScope(TRUE, pRegistration, &pRegistration->relatedBundles);
2120
- ExitOnFailure(hr, "Failed to initialize per-machine related bundles.");
2227
+ // Detect.
2228
+ hr = ElevatedProcessDetect(pRegistration, pPackages);
2229
+ ExitOnFailure(hr, "Failed to run detection in elevated process.");
2230
2231
// Attempt to pause AU with best effort.
2232
if (BURN_AU_PAUSE_ACTION_IFELEVATED == dwAUAction || BURN_AU_PAUSE_ACTION_IFELEVATED_NORESUME == dwAUAction)
@@ -2187,6 +2296,39 @@ LExit:
2296
return hr;
2297
}
2298
2299
+static HRESULT ElevatedProcessDetect(
2300
+ __in BURN_REGISTRATION* pRegistration,
2301
+ __in BURN_PACKAGES* pPackages
2302
+ )
2303
+{
2304
+ HRESULT hr = S_OK;
2305
+
2306
+ DetectReset(pRegistration, pPackages);
2307
+
2308
+ hr = RelatedBundlesInitializeForScope(TRUE, pRegistration, &pRegistration->relatedBundles);
2309
+ ExitOnFailure(hr, "Failed to initialize per-machine related bundles.");
2310
+
2311
+ for (DWORD i = 0; i < pPackages->cPackages; ++i)
2312
+ {
2313
+ BURN_PACKAGE* pPackage = pPackages->rgPackages + i;
2314
+
2315
+ hr = DependencyDetectCompatibleEntry(pPackage, pRegistration);
2316
+ ExitOnFailure(hr, "Failed to detect per-machine compatible entry for package: %ls", pPackage->sczId);
2317
+
2318
+ switch (pPackage->type)
2319
+ {
2320
+ case BURN_PACKAGE_TYPE_MSI:
2321
+ hr = MsiEngineDetectCompatiblePackage(pPackage);
2322
+ ExitOnFailure(hr, "Failed to detect per-machine compatible package for package: %ls", pPackage->sczId);
2323
+
2324
+ break;
2325
+ }
2326
+ }
2327
+
2328
+LExit:
2329
+ return hr;
2330
+}
2331
+
2332
static HRESULT OnApplyUninitialize(
2333
__in HANDLE* phLock
2334
)
@@ -2659,6 +2801,11 @@ static HRESULT OnExecuteExePackage(
2801
hr = PackageFindById(pPackages, sczPackage, &executeAction.exePackage.pPackage);
2802
ExitOnFailure(hr, "Failed to find package: %ls", sczPackage);
2803
2804
+ if (BURN_PACKAGE_TYPE_EXE != executeAction.exePackage.pPackage->type)
2805
+ {
2806
+ ExitWithRootFailure(hr, E_INVALIDARG, "Package is not an EXE package: %ls", sczPackage);
2807
+ }
2808
+
2809
// Execute EXE package.
2810
hr = ExeEngineExecutePackage(&executeAction, pCache, pVariables, static_cast<BOOL>(dwRollback), GenericExecuteMessageHandler, hPipe, &exeRestart);
2811
ExitOnFailure(hr, "Failed to execute EXE package.");
@@ -2760,6 +2907,11 @@ static HRESULT OnExecuteMsiPackage(
2907
hr = VariableDeserialize(pVariables, FALSE, pbData, cbData, &iData);
2908
ExitOnFailure(hr, "Failed to read variables.");
2909
2910
+ if (BURN_PACKAGE_TYPE_MSI != executeAction.msiPackage.pPackage->type)
2911
+ {
2912
+ ExitWithRootFailure(hr, E_INVALIDARG, "Package is not an MSI package: %ls", sczPackage);
2913
+ }
2914
+
2915
// Execute MSI package.
2916
hr = MsiEngineExecutePackage(hwndParent, &executeAction, pCache, pVariables, fRollback, MsiExecuteMessageHandler, hPipe, &msiRestart);
2917
ExitOnFailure(hr, "Failed to execute MSI package.");
@@ -2859,6 +3011,11 @@ static HRESULT OnExecuteMspPackage(
3011
hr = BuffReadNumber(pbData, cbData, &iData, (DWORD*)&fRollback);
3012
ExitOnFailure(hr, "Failed to read rollback flag.");
3013
3014
+ if (BURN_PACKAGE_TYPE_MSP != executeAction.mspTarget.pPackage->type)
3015
+ {
3016
+ ExitWithRootFailure(hr, E_INVALIDARG, "Package is not an MSP package: %ls", sczPackage);
3017
+ }
3018
+
3019
// Execute MSP package.
3020
hr = MspEngineExecutePackage(hwndParent, &executeAction, pCache, pVariables, fRollback, MsiExecuteMessageHandler, hPipe, &restart);
3021
ExitOnFailure(hr, "Failed to execute MSP package.");
@@ -2920,6 +3077,11 @@ static HRESULT OnExecuteMsuPackage(
3077
hr = PackageFindById(pPackages, sczPackage, &executeAction.msuPackage.pPackage);
3078
ExitOnFailure(hr, "Failed to find package: %ls", sczPackage);
3079
3080
+ if (BURN_PACKAGE_TYPE_MSU != executeAction.msuPackage.pPackage->type)
3081
+ {
3082
+ ExitWithRootFailure(hr, E_INVALIDARG, "Package is not an MSU package: %ls", sczPackage);
3083
+ }
3084
+
3085
// execute MSU package
3086
hr = MsuEngineExecutePackage(&executeAction, pCache, pVariables, static_cast<BOOL>(dwRollback), static_cast<BOOL>(dwStopWusaService), GenericExecuteMessageHandler, hPipe, &restart);
3087
ExitOnFailure(hr, "Failed to execute MSU package.");
@@ -2943,6 +3105,88 @@ LExit:
3105
return hr;
3106
}
3107
3108
+static HRESULT OnUninstallMsiCompatiblePackage(
3109
+ __in HANDLE hPipe,
3110
+ __in BURN_CACHE* pCache,
3111
+ __in BURN_PACKAGES* pPackages,
3112
+ __in BURN_VARIABLES* pVariables,
3113
+ __in BYTE* pbData,
3114
+ __in SIZE_T cbData
3115
+ )
3116
+{
3117
+ HRESULT hr = S_OK;
3118
+ SIZE_T iData = 0;
3119
+ LPWSTR sczPackageId = NULL;
3120
+ LPWSTR sczCompatiblePackageId = NULL;
3121
+ HWND hwndParent = NULL;
3122
+ BOOL fRollback = 0;
3123
+ BURN_EXECUTE_ACTION executeAction = { };
3124
+ BURN_PACKAGE* pPackage = NULL;
3125
+ BURN_COMPATIBLE_PACKAGE* pCompatiblePackage = NULL;
3126
+ BOOTSTRAPPER_APPLY_RESTART msiRestart = BOOTSTRAPPER_APPLY_RESTART_NONE;
3127
+
3128
+ executeAction.type = BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE;
3129
+
3130
+ // Deserialize message data.
3131
+ hr = BuffReadNumber(pbData, cbData, &iData, (DWORD*)&fRollback);
3132
+ ExitOnFailure(hr, "Failed to read rollback flag.");
3133
+
3134
+ hr = BuffReadString(pbData, cbData, &iData, &sczPackageId);
3135
+ ExitOnFailure(hr, "Failed to read MSI package id.");
3136
+
3137
+ hr = BuffReadString(pbData, cbData, &iData, &sczCompatiblePackageId);
3138
+ ExitOnFailure(hr, "Failed to read MSI compatible package id.");
3139
+
3140
+ hr = BuffReadPointer(pbData, cbData, &iData, (DWORD_PTR*)&hwndParent);
3141
+ ExitOnFailure(hr, "Failed to read parent hwnd.");
3142
+
3143
+ hr = BuffReadString(pbData, cbData, &iData, &executeAction.uninstallMsiCompatiblePackage.sczLogPath);
3144
+ ExitOnFailure(hr, "Failed to read package log.");
3145
+
3146
+ hr = VariableDeserialize(pVariables, FALSE, pbData, cbData, &iData);
3147
+ ExitOnFailure(hr, "Failed to read variables.");
3148
+
3149
+ hr = PackageFindById(pPackages, sczPackageId, &pPackage);
3150
+ ExitOnFailure(hr, "Failed to find package: %ls", sczPackageId);
3151
+
3152
+ executeAction.uninstallMsiCompatiblePackage.pParentPackage = pPackage;
3153
+ pCompatiblePackage = &pPackage->compatiblePackage;
3154
+
3155
+ if (!pCompatiblePackage->fDetected || BURN_PACKAGE_TYPE_MSI != pCompatiblePackage->type || !pCompatiblePackage->compatibleEntry.sczId)
3156
+ {
3157
+ ExitWithRootFailure(hr, E_INVALIDARG, "Package '%ls' has no compatible MSI package", sczPackageId);
3158
+ }
3159
+
3160
+ if (!sczCompatiblePackageId || !*sczCompatiblePackageId ||
3161
+ CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pCompatiblePackage->compatibleEntry.sczId, -1, sczCompatiblePackageId, -1))
3162
+ {
3163
+ ExitWithRootFailure(hr, E_INVALIDARG, "Package '%ls' has no compatible package with id: %ls", sczPackageId, sczCompatiblePackageId);
3164
+ }
3165
+
3166
+ // Uninstall MSI compatible package.
3167
+ hr = MsiEngineUninstallCompatiblePackage(hwndParent, &executeAction, pCache, pVariables, fRollback, MsiExecuteMessageHandler, hPipe, &msiRestart);
3168
+ ExitOnFailure(hr, "Failed to execute MSI package.");
3169
+
3170
+LExit:
3171
+ ReleaseStr(sczPackageId);
3172
+ ReleaseStr(sczCompatiblePackageId);
3173
+ PlanUninitializeExecuteAction(&executeAction);
3174
+
3175
+ if (SUCCEEDED(hr))
3176
+ {
3177
+ if (BOOTSTRAPPER_APPLY_RESTART_REQUIRED == msiRestart)
3178
+ {
3179
+ hr = HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED);
3180
+ }
3181
+ else if (BOOTSTRAPPER_APPLY_RESTART_INITIATED == msiRestart)
3182
+ {
3183
+ hr = HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_INITIATED);
3184
+ }
3185
+ }
3186
+
3187
+ return hr;
3188
+}
3189
+
3190
static HRESULT OnExecutePackageProviderAction(
3191
__in BURN_PACKAGES* pPackages,
3192
__in BURN_RELATED_BUNDLES* pRelatedBundles,
@@ -3258,6 +3502,53 @@ LExit:
3502
return nResult;
3503
}
3504
3505
+static HRESULT OnCleanCompatiblePackage(
3506
+ __in BURN_CACHE* pCache,
3507
+ __in BURN_PACKAGES* pPackages,
3508
+ __in BYTE* pbData,
3509
+ __in SIZE_T cbData
3510
+ )
3511
+{
3512
+ HRESULT hr = S_OK;
3513
+ SIZE_T iData = 0;
3514
+ LPWSTR sczPackageId = NULL;
3515
+ LPWSTR sczCompatiblePackageId = NULL;
3516
+ BURN_PACKAGE* pPackage = NULL;
3517
+ BURN_COMPATIBLE_PACKAGE* pCompatiblePackage = NULL;
3518
+
3519
+ // Deserialize message data.
3520
+ hr = BuffReadString(pbData, cbData, &iData, &sczPackageId);
3521
+ ExitOnFailure(hr, "Failed to read package id.");
3522
+
3523
+ hr = BuffReadString(pbData, cbData, &iData, &sczCompatiblePackageId);
3524
+ ExitOnFailure(hr, "Failed to read compatible package id.");
3525
+
3526
+ hr = PackageFindById(pPackages, sczPackageId, &pPackage);
3527
+ ExitOnFailure(hr, "Failed to find package: %ls", sczPackageId);
3528
+
3529
+ pCompatiblePackage = &pPackage->compatiblePackage;
3530
+
3531
+ if (!pCompatiblePackage->fDetected || !pCompatiblePackage->compatibleEntry.sczId || !pCompatiblePackage->sczCacheId || !*pCompatiblePackage->sczCacheId)
3532
+ {
3533
+ ExitWithRootFailure(hr, E_INVALIDARG, "Package '%ls' has no compatible package to clean.", sczPackageId);
3534
+ }
3535
+
3536
+ if (!sczCompatiblePackageId || !*sczCompatiblePackageId ||
3537
+ CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pCompatiblePackage->compatibleEntry.sczId, -1, sczCompatiblePackageId, -1))
3538
+ {
3539
+ ExitWithRootFailure(hr, E_INVALIDARG, "Package '%ls' has no compatible package with id: %ls", sczPackageId, sczCompatiblePackageId);
3540
+ }
3541
+
3542
+ // Remove the package from the cache.
3543
+ hr = CacheRemovePackage(pCache, TRUE, pCompatiblePackage->compatibleEntry.sczId, pCompatiblePackage->sczCacheId);
3544
+ ExitOnFailure(hr, "Failed to remove from cache compatible package: %ls", pCompatiblePackage->compatibleEntry.sczId);
3545
+
3546
+LExit:
3547
+ ReleaseStr(sczPackageId);
3548
+ ReleaseStr(sczCompatiblePackageId);
3549
+ return hr;
3550
+}
3551
+
3552
static HRESULT OnCleanPackage(
3553
__in BURN_CACHE* pCache,
3554
__in BURN_PACKAGES* pPackages,
src/burn/engine/elevation.h
+12
-5
@@ -127,6 +127,16 @@ HRESULT ElevationExecuteMsuPackage(
127
__in LPVOID pvContext,
128
__out BOOTSTRAPPER_APPLY_RESTART* pRestart
129
);
130
+HRESULT ElevationUninstallMsiCompatiblePackage(
131
+ __in HANDLE hPipe,
132
+ __in_opt HWND hwndParent,
133
+ __in BURN_EXECUTE_ACTION* pExecuteAction,
134
+ __in BURN_VARIABLES* pVariables,
135
+ __in BOOL fRollback,
136
+ __in PFN_MSIEXECUTEMESSAGEHANDLER pfnMessageHandler,
137
+ __in LPVOID pvContext,
138
+ __out BOOTSTRAPPER_APPLY_RESTART* pRestart
139
+ );
140
HRESULT ElevationExecutePackageProviderAction(
141
__in HANDLE hPipe,
142
__in BURN_EXECUTE_ACTION* pExecuteAction
@@ -135,12 +145,9 @@ HRESULT ElevationExecutePackageDependencyAction(
145
__in HANDLE hPipe,
146
__in BURN_EXECUTE_ACTION* pExecuteAction
147
);
138
-HRESULT ElevationLaunchElevatedChild(
148
+HRESULT ElevationCleanCompatiblePackage(
149
__in HANDLE hPipe,
140
- __in BURN_PACKAGE* pPackage,
141
- __in LPCWSTR wzPipeName,
142
- __in LPCWSTR wzPipeToken,
143
- __out DWORD* pdwChildPid
150
+ __in BURN_PACKAGE* pPackage
151
);
152
HRESULT ElevationCleanPackage(
153
__in HANDLE hPipe,
src/burn/engine/engine.mc
+21
-2
@@ -262,6 +262,13 @@ Detected forward compatible bundle: %1!ls!, type: %2!hs!, scope: %3!hs!, version
262
.
263
264
MessageId=108
265
+Severity=Success
266
+SymbolicName=MSG_DETECTED_COMPATIBLE_PACKAGE_FROM_PROVIDER
267
+Language=English
268
+Detected compatible package: %1!ls!, provider: %2!ls!, installed: %3!ls!, version: %4!ls!, chained: %5!ls!
269
+.
270
+
271
+MessageId=109
272
Severity=Warning
273
SymbolicName=MSG_DETECT_RELATED_BUNDLE_NOT_CACHED
274
Language=English
@@ -429,6 +436,13 @@ Language=English
436
Plan skipped related bundle: %1!ls!, type: %2!hs!, because it was previously scheduled.
437
.
438
439
+MessageId=215
440
+Severity=Success
441
+SymbolicName=MSG_PLANNED_ORPHAN_PACKAGE_FROM_PROVIDER
442
+Language=English
443
+Will remove orphan package: %1!ls!, installed: %2!ls!, chained: %3!ls!
444
+.
445
+
446
MessageId=216
447
Severity=Success
448
SymbolicName=MSG_PLAN_SKIPPED_RELATED_BUNDLE_EMBEDDED_BUNDLE_NEWER
@@ -604,7 +618,6 @@ Language=English
618
Failed to layout container: %2!ls! to layout directory: %3!ls!, error: %1!ls!.
619
.
620
607
-
621
MessageId=317
622
Severity=Error
623
SymbolicName=MSG_FAILED_LAYOUT_PAYLOAD
@@ -927,7 +940,6 @@ Language=English
940
Calculating whether to keep registration
941
.
942
930
-
943
MessageId=374
944
Severity=Success
945
SymbolicName=MSG_POST_APPLY_PACKAGE
@@ -1005,6 +1017,13 @@ Language=English
1017
Skipping the rest of non-vital rollback boundary, id: %1!ls!
1018
.
1019
1020
+MessageId=390
1021
+Severity=Success
1022
+SymbolicName=MSG_APPLYING_ORPHAN_COMPATIBLE_PACKAGE
1023
+Language=English
1024
+Applying %1!hs! compatible package: %2!ls!, parent package: %3!ls!, action: %4!hs!, arguments: '%5!ls!'
1025
+.
1026
+
1027
MessageId=399
1028
Severity=Success
1029
SymbolicName=MSG_APPLY_COMPLETE
src/burn/engine/logging.cpp
+43
@@ -227,6 +227,49 @@ extern "C" void LoggingIncrementPackageSequence()
227
++vdwPackageSequence;
228
}
229
230
+extern "C" HRESULT LoggingSetCompatiblePackageVariable(
231
+ __in BURN_PACKAGE* pPackage,
232
+ __in BURN_LOGGING* pLog,
233
+ __in BURN_VARIABLES* pVariables,
234
+ __out_opt LPWSTR* psczLogPath
235
+ )
236
+{
237
+ HRESULT hr = S_OK;
238
+ LPWSTR sczLogPathVariable = NULL;
239
+ LPWSTR sczLogPath = NULL;
240
+
241
+ // Make sure that no package log files are created when logging has been disabled via Log element.
242
+ if (BURN_LOGGING_STATE_DISABLED == pLog->state)
243
+ {
244
+ ExitFunction();
245
+ }
246
+
247
+ if (pPackage->sczLogPathVariable && *pPackage->sczLogPathVariable)
248
+ {
249
+ // Format a suitable log path variable from the original package.
250
+ hr = StrAllocFormatted(&sczLogPathVariable, L"%ls_Compatible", pPackage->sczLogPathVariable);
251
+ ExitOnFailure(hr, "Failed to format log path variable for compatible package.");
252
+
253
+ hr = StrAllocFormatted(&sczLogPath, L"%ls_%03u_%ls_%ls.%ls", pLog->sczPrefix, vdwPackageSequence, pPackage->sczId, pPackage->compatiblePackage.compatibleEntry.sczId, pLog->sczExtension);
254
+ ExitOnFailure(hr, "Failed to allocate path for package log.");
255
+
256
+ hr = VariableSetString(pVariables, sczLogPathVariable, sczLogPath, FALSE, FALSE);
257
+ ExitOnFailure(hr, "Failed to set log path into variable.");
258
+
259
+ if (psczLogPath)
260
+ {
261
+ hr = StrAllocString(psczLogPath, sczLogPath, 0);
262
+ ExitOnFailure(hr, "Failed to copy package log path.");
263
+ }
264
+ }
265
+
266
+LExit:
267
+ ReleaseStr(sczLogPathVariable);
268
+ ReleaseStr(sczLogPath);
269
+
270
+ return hr;
271
+}
272
+
273
extern "C" HRESULT LoggingSetPackageVariable(
274
__in BURN_PACKAGE* pPackage,
275
__in_z_opt LPCWSTR wzSuffix,
src/burn/engine/logging.h
+7
@@ -53,6 +53,13 @@ void LoggingOpenFailed();
53
54
void LoggingIncrementPackageSequence();
55
56
+HRESULT LoggingSetCompatiblePackageVariable(
57
+ __in BURN_PACKAGE* pPackage,
58
+ __in BURN_LOGGING* pLog,
59
+ __in BURN_VARIABLES* pVariables,
60
+ __out_opt LPWSTR* psczLogPath
61
+ );
62
+
63
HRESULT LoggingSetPackageVariable(
64
__in BURN_PACKAGE* pPackage,
65
__in_z_opt LPCWSTR wzSuffix,
src/burn/engine/msiengine.cpp
+181
@@ -506,6 +506,9 @@ extern "C" HRESULT MsiEngineDetectPackage(
506
{
507
BURN_RELATED_MSI* pRelatedMsi = &pPackage->Msi.rgRelatedMsis[i];
508
509
+ ReleaseVerutilVersion(pVersion);
510
+ pVersion = NULL;
511
+
512
for (DWORD iProduct = 0; ; ++iProduct)
513
{
514
// get product
@@ -708,6 +711,46 @@ extern "C" HRESULT MsiEngineDetectPackage(
711
hr = DependencyDetectChainPackage(pPackage, pRegistration);
712
ExitOnFailure(hr, "Failed to detect dependencies for MSI package.");
713
714
+ if (BOOTSTRAPPER_PACKAGE_STATE_PRESENT > pPackage->currentState)
715
+ {
716
+ hr = MsiEngineDetectCompatiblePackage(pPackage);
717
+ ExitOnFailure(hr, "Failed to detect compatible package for MSI package.");
718
+
719
+ if (BURN_PACKAGE_TYPE_MSI == pPackage->compatiblePackage.type)
720
+ {
721
+ LPCWSTR wzCompatibleProductCode = pPackage->compatiblePackage.compatibleEntry.sczId;
722
+ LPCWSTR wzCompatibleInstalledVersion = pPackage->compatiblePackage.Msi.sczVersion;
723
+
724
+ ReleaseVerutilVersion(pVersion);
725
+ pVersion = NULL;
726
+
727
+ hr = VerParseVersion(wzCompatibleInstalledVersion, 0, FALSE, &pVersion);
728
+ ExitOnFailure(hr, "Failed to parse dependency version: '%ls' for ProductCode: %ls", wzCompatibleInstalledVersion, wzCompatibleProductCode);
729
+
730
+ if (pVersion->fInvalid)
731
+ {
732
+ LogId(REPORT_WARNING, MSG_DETECTED_MSI_PACKAGE_INVALID_VERSION, wzCompatibleProductCode, wzCompatibleInstalledVersion);
733
+ }
734
+
735
+ pPackage->compatiblePackage.Msi.pVersion = pVersion;
736
+ pVersion = NULL;
737
+
738
+ // compare versions
739
+ hr = VerCompareParsedVersions(pPackage->Msi.pVersion, pPackage->compatiblePackage.Msi.pVersion, &nCompareResult);
740
+ ExitOnFailure(hr, "Failed to compare version '%ls' to dependency version: '%ls'", pPackage->Msi.pVersion->sczVersion, wzCompatibleInstalledVersion);
741
+
742
+ if (nCompareResult < 0)
743
+ {
744
+ pPackage->compatiblePackage.fPlannable = TRUE;
745
+
746
+ LogId(REPORT_STANDARD, MSG_DETECTED_COMPATIBLE_PACKAGE_FROM_PROVIDER, pPackage->sczId, pPackage->compatiblePackage.compatibleEntry.sczProviderKey, wzCompatibleProductCode, wzCompatibleInstalledVersion, pPackage->Msi.sczProductCode);
747
+
748
+ hr = UserExperienceOnDetectCompatibleMsiPackage(pUserExperience, pPackage->sczId, wzCompatibleProductCode, pPackage->compatiblePackage.Msi.pVersion);
749
+ ExitOnRootFailure(hr, "BA aborted detect compatible MSI package.");
750
+ }
751
+ }
752
+ }
753
+
754
LExit:
755
ReleaseStr(sczInstalledLanguage);
756
ReleaseStr(sczInstalledVersion);
@@ -716,8 +759,49 @@ LExit:
759
return hr;
760
}
761
762
+extern "C" HRESULT MsiEngineDetectCompatiblePackage(
763
+ __in BURN_PACKAGE* pPackage
764
+ )
765
+{
766
+ HRESULT hr = S_OK;
767
+ LPWSTR sczVersion = NULL;
768
+ LPWSTR sczCacheId = NULL;
769
+ LPCWSTR wzCompatibleProductCode = pPackage->compatiblePackage.compatibleEntry.sczId;
770
+
771
+ if (!pPackage->compatiblePackage.fDetected)
772
+ {
773
+ ExitFunction();
774
+ }
775
+
776
+ hr = WiuGetProductInfoEx(wzCompatibleProductCode, NULL, pPackage->fPerMachine ? MSIINSTALLCONTEXT_MACHINE : MSIINSTALLCONTEXT_USERUNMANAGED, INSTALLPROPERTY_VERSIONSTRING, &sczVersion);
777
+ if (HRESULT_FROM_WIN32(ERROR_UNKNOWN_PRODUCT) == hr || HRESULT_FROM_WIN32(ERROR_UNKNOWN_PROPERTY) == hr)
778
+ {
779
+ ExitFunction1(hr = S_OK);
780
+ }
781
+ ExitOnFailure(hr, "Failed to get product information for compatible ProductCode: %ls", wzCompatibleProductCode);
782
+
783
+ // Assume the package used the default cache ID generation from the binder.
784
+ hr = StrAllocFormatted(&sczCacheId, L"%lsv%ls", wzCompatibleProductCode, sczVersion);
785
+ ExitOnFailure(hr, "Failed to format cache ID for compatible package.");
786
+
787
+ pPackage->compatiblePackage.sczCacheId = sczCacheId;
788
+ sczCacheId = NULL;
789
+
790
+ pPackage->compatiblePackage.Msi.sczVersion = sczVersion;
791
+ sczVersion = NULL;
792
+
793
+ pPackage->compatiblePackage.type = BURN_PACKAGE_TYPE_MSI;
794
+
795
+LExit:
796
+ ReleaseStr(sczVersion);
797
+ ReleaseStr(sczCacheId);
798
+
799
+ return hr;
800
+}
801
+
802
extern "C" HRESULT MsiEnginePlanInitializePackage(
803
__in BURN_PACKAGE* pPackage,
804
+ __in BOOTSTRAPPER_ACTION overallAction,
805
__in BURN_VARIABLES* pVariables,
806
__in BURN_USER_EXPERIENCE* pUserExperience
807
)
@@ -747,6 +831,18 @@ extern "C" HRESULT MsiEnginePlanInitializePackage(
831
}
832
}
833
834
+ if (pPackage->compatiblePackage.fPlannable)
835
+ {
836
+ Assert(BURN_PACKAGE_TYPE_MSI == pPackage->compatiblePackage.type);
837
+
838
+ pPackage->compatiblePackage.fDefaultRequested = BOOTSTRAPPER_ACTION_UNINSTALL == overallAction;
839
+ pPackage->compatiblePackage.fRequested = pPackage->compatiblePackage.fDefaultRequested;
840
+
841
+ hr = UserExperienceOnPlanCompatibleMsiPackageBegin(pUserExperience, pPackage->sczId, pPackage->compatiblePackage.compatibleEntry.sczId, pPackage->compatiblePackage.Msi.pVersion, &pPackage->compatiblePackage.fRequested);
842
+ UserExperienceOnPlanCompatibleMsiPackageComplete(pUserExperience, pPackage->sczId, pPackage->compatiblePackage.compatibleEntry.sczId, hr, pPackage->compatiblePackage.fRequested);
843
+ ExitOnRootFailure(hr, "BA aborted plan compatible MSI package begin.");
844
+ }
845
+
846
LExit:
847
return hr;
848
}
@@ -989,6 +1085,17 @@ extern "C" HRESULT MsiEnginePlanAddPackage(
1085
LoggingSetPackageVariable(pPackage, NULL, FALSE, pLog, pVariables, &pAction->msiPackage.sczLogPath); // ignore errors.
1086
pAction->msiPackage.dwLoggingAttributes = pLog->dwAttributes;
1087
}
1088
+ else if (pPackage->compatiblePackage.fRemove)
1089
+ {
1090
+ hr = PlanAppendExecuteAction(pPlan, &pAction);
1091
+ ExitOnFailure(hr, "Failed to append execute action.");
1092
+
1093
+ pAction->type = BURN_EXECUTE_ACTION_TYPE_UNINSTALL_MSI_COMPATIBLE_PACKAGE;
1094
+ pAction->uninstallMsiCompatiblePackage.pParentPackage = pPackage;
1095
+ pAction->uninstallMsiCompatiblePackage.dwLoggingAttributes = pLog->dwAttributes;
1096
+
1097
+ LoggingSetCompatiblePackageVariable(pPackage, pLog, pVariables, &pAction->uninstallMsiCompatiblePackage.sczLogPath); // ignore errors.
1098
+ }
1099
1100
LExit:
1101
ReleaseMem(rgFeatureActions);
@@ -1246,6 +1353,80 @@ LExit:
1353
return hr;
1354
}
1355
1356
+extern "C" HRESULT MsiEngineUninstallCompatiblePackage(
1357
+ __in_opt HWND hwndParent,
1358
+ __in BURN_EXECUTE_ACTION* pExecuteAction,
1359
+ __in BURN_CACHE* /*pCache*/,
1360
+ __in BURN_VARIABLES* /*pVariables*/,
1361
+ __in BOOL fRollback,
1362
+ __in PFN_MSIEXECUTEMESSAGEHANDLER pfnMessageHandler,
1363
+ __in LPVOID pvContext,
1364
+ __out BOOTSTRAPPER_APPLY_RESTART* pRestart
1365
+ )
1366
+{
1367
+ HRESULT hr = S_OK;
1368
+ WIU_MSI_EXECUTE_CONTEXT context = { };
1369
+ WIU_RESTART restart = WIU_RESTART_NONE;
1370
+ LPWSTR sczProperties = NULL;
1371
+ BOOTSTRAPPER_ACTION_STATE action = BOOTSTRAPPER_ACTION_STATE_UNINSTALL;
1372
+ BURN_MSI_PROPERTY burnMsiProperty = BURN_MSI_PROPERTY_NONE;
1373
+ BOOTSTRAPPER_MSI_FILE_VERSIONING fileVersioning = BOOTSTRAPPER_MSI_FILE_VERSIONING_MISSING_OR_OLDER;
1374
+ BURN_PACKAGE* pParentPackage = pExecuteAction->uninstallMsiCompatiblePackage.pParentPackage;
1375
+ BURN_COMPATIBLE_PROVIDER_ENTRY* pCompatibleEntry = &pExecuteAction->uninstallMsiCompatiblePackage.pParentPackage->compatiblePackage.compatibleEntry;
1376
+
1377
+ // Default to "verbose" logging and set extra debug mode only if explicitly required.
1378
+ DWORD dwLogMode = WIU_LOG_DEFAULT | INSTALLLOGMODE_VERBOSE;
1379
+
1380
+ if (pExecuteAction->uninstallMsiCompatiblePackage.dwLoggingAttributes & BURN_LOGGING_ATTRIBUTE_EXTRADEBUG)
1381
+ {
1382
+ dwLogMode |= INSTALLLOGMODE_EXTRADEBUG;
1383
+ }
1384
+
1385
+ hr = WiuInitializeExternalUI(pfnMessageHandler, INSTALLUILEVEL_NONE, hwndParent, pvContext, fRollback, &context);
1386
+ ExitOnFailure(hr, "Failed to initialize external UI handler.");
1387
+
1388
+ if (pExecuteAction->uninstallMsiCompatiblePackage.sczLogPath && *pExecuteAction->uninstallMsiCompatiblePackage.sczLogPath)
1389
+ {
1390
+ hr = WiuEnableLog(dwLogMode, pExecuteAction->uninstallMsiCompatiblePackage.sczLogPath, INSTALLLOGATTRIBUTES_APPEND);
1391
+ ExitOnFailure(hr, "Failed to enable logging for compatible package: %ls to: %ls", pCompatibleEntry->sczId, pExecuteAction->uninstallMsiCompatiblePackage.sczLogPath);
1392
+ }
1393
+
1394
+ hr = MsiEngineConcatBurnProperties(action, burnMsiProperty, fileVersioning, TRUE, FALSE, &sczProperties);
1395
+ ExitOnFailure(hr, "Failed to add action property to argument string.");
1396
+
1397
+ LogId(REPORT_STANDARD, MSG_APPLYING_ORPHAN_COMPATIBLE_PACKAGE, LoggingRollbackOrExecute(fRollback), pCompatibleEntry->sczId, pParentPackage->sczId, LoggingActionStateToString(action), sczProperties ? sczProperties : L"");
1398
+
1399
+ hr = WiuConfigureProductEx(pCompatibleEntry->sczId, INSTALLLEVEL_DEFAULT, INSTALLSTATE_ABSENT, sczProperties, &restart);
1400
+ if (HRESULT_FROM_WIN32(ERROR_UNKNOWN_PRODUCT) == hr)
1401
+ {
1402
+ LogId(REPORT_STANDARD, MSG_ATTEMPTED_UNINSTALL_ABSENT_PACKAGE, pCompatibleEntry->sczId);
1403
+ hr = S_OK;
1404
+ }
1405
+ ExitOnFailure(hr, "Failed to uninstall compatible MSI package.");
1406
+
1407
+LExit:
1408
+ WiuUninitializeExternalUI(&context);
1409
+
1410
+ StrSecureZeroFreeString(sczProperties);
1411
+
1412
+ switch (restart)
1413
+ {
1414
+ case WIU_RESTART_NONE:
1415
+ *pRestart = BOOTSTRAPPER_APPLY_RESTART_NONE;
1416
+ break;
1417
+
1418
+ case WIU_RESTART_REQUIRED:
1419
+ *pRestart = BOOTSTRAPPER_APPLY_RESTART_REQUIRED;
1420
+ break;
1421
+
1422
+ case WIU_RESTART_INITIATED:
1423
+ *pRestart = BOOTSTRAPPER_APPLY_RESTART_INITIATED;
1424
+ break;
1425
+ }
1426
+
1427
+ return hr;
1428
+}
1429
+
1430
extern "C" HRESULT MsiEngineConcatBurnProperties(
1431
__in BOOTSTRAPPER_ACTION_STATE action,
1432
__in BURN_MSI_PROPERTY actionMsiProperty,
src/burn/engine/msiengine.h
+14
@@ -35,8 +35,12 @@ HRESULT MsiEngineDetectPackage(
35
__in BURN_REGISTRATION* pRegistration,
36
__in BURN_USER_EXPERIENCE* pUserExperience
37
);
38
+HRESULT MsiEngineDetectCompatiblePackage(
39
+ __in BURN_PACKAGE* pPackage
40
+ );
41
HRESULT MsiEnginePlanInitializePackage(
42
__in BURN_PACKAGE* pPackage,
43
+ __in BOOTSTRAPPER_ACTION overallAction,
44
__in BURN_VARIABLES* pVariables,
45
__in BURN_USER_EXPERIENCE* pUserExperience
46
);
@@ -71,6 +75,16 @@ HRESULT MsiEngineExecutePackage(
75
__in LPVOID pvContext,
76
__out BOOTSTRAPPER_APPLY_RESTART* pRestart
77
);
78
+HRESULT MsiEngineUninstallCompatiblePackage(
79
+ __in_opt HWND hwndParent,
80
+ __in BURN_EXECUTE_ACTION* pExecuteAction,
81
+ __in BURN_CACHE* pCache,
82
+ __in BURN_VARIABLES* pVariables,
83
+ __in BOOL fRollback,
84
+ __in PFN_MSIEXECUTEMESSAGEHANDLER pfnMessageHandler,
85
+ __in LPVOID pvContext,
86
+ __out BOOTSTRAPPER_APPLY_RESTART* pRestart
87
+ );
88
HRESULT MsiEngineConcatBurnProperties(
89
__in BOOTSTRAPPER_ACTION_STATE action,
90
__in BURN_MSI_PROPERTY actionMsiProperty,
src/burn/engine/package.cpp
+25
@@ -366,6 +366,31 @@ extern "C" void PackageUninitialize(
366
MsuEnginePackageUninitialize(pPackage); // TODO: Modularization
367
break;
368
}
369
+
370
+ PackageUninitializeCompatible(&pPackage->compatiblePackage);
371
+}
372
+
373
+extern "C" void PackageUninitializeCompatible(
374
+ __in BURN_COMPATIBLE_PACKAGE* pCompatiblePackage
375
+ )
376
+{
377
+ ReleaseStr(pCompatiblePackage->compatibleEntry.sczId);
378
+ ReleaseStr(pCompatiblePackage->compatibleEntry.sczName);
379
+ ReleaseStr(pCompatiblePackage->compatibleEntry.sczProviderKey);
380
+ ReleaseStr(pCompatiblePackage->compatibleEntry.sczVersion);
381
+
382
+ ReleaseStr(pCompatiblePackage->sczCacheId);
383
+
384
+ switch (pCompatiblePackage->type)
385
+ {
386
+ case BURN_PACKAGE_TYPE_MSI:
387
+ ReleaseStr(pCompatiblePackage->Msi.sczVersion);
388
+ ReleaseVerutilVersion(pCompatiblePackage->Msi.pVersion);
389
+ break;
390
+ }
391
+
392
+ // clear struct
393
+ memset(pCompatiblePackage, 0, sizeof(BURN_COMPATIBLE_PACKAGE));
394
}
395
396
extern "C" void PackagesUninitialize(
src/burn/engine/package.h
+34
@@ -147,6 +147,14 @@ typedef struct _BURN_MSIFEATURE
147
BOOTSTRAPPER_FEATURE_ACTION rollback; // only valid during Plan.
148
} BURN_MSIFEATURE;
149
150
+typedef struct _BURN_COMPATIBLE_PROVIDER_ENTRY
151
+{
152
+ LPWSTR sczProviderKey;
153
+ LPWSTR sczId;
154
+ LPWSTR sczName;
155
+ LPWSTR sczVersion;
156
+} BURN_COMPATIBLE_PROVIDER_ENTRY;
157
+
158
typedef struct _BURN_RELATED_MSI
159
{
160
LPWSTR sczUpgradeCode;
@@ -206,6 +214,27 @@ typedef struct _BURN_PATCH_TARGETCODE
214
BURN_PATCH_TARGETCODE_TYPE type;
215
} BURN_PATCH_TARGETCODE;
216
217
+typedef struct _BURN_COMPATIBLE_PACKAGE
218
+{
219
+ BOOL fDetected;
220
+ BOOL fPlannable;
221
+ BOOL fDefaultRequested;
222
+ BOOL fRequested;
223
+ BOOL fRemove;
224
+ LPWSTR sczCacheId;
225
+ BURN_COMPATIBLE_PROVIDER_ENTRY compatibleEntry;
226
+
227
+ BURN_PACKAGE_TYPE type;
228
+ union
229
+ {
230
+ struct
231
+ {
232
+ LPWSTR sczVersion;
233
+ VERUTIL_VERSION* pVersion;
234
+ } Msi;
235
+ };
236
+} BURN_COMPATIBLE_PACKAGE;
237
+
238
typedef struct _BURN_PACKAGE
239
{
240
LPWSTR sczId;
@@ -259,6 +288,8 @@ typedef struct _BURN_PACKAGE
288
BURN_DEPENDENCY_PROVIDER* rgDependencyProviders;
289
DWORD cDependencyProviders;
290
291
+ BURN_COMPATIBLE_PACKAGE compatiblePackage;
292
+
293
BURN_PACKAGE_TYPE type;
294
union
295
{
@@ -371,6 +402,9 @@ HRESULT PackagesParseFromXml(
402
void PackageUninitialize(
403
__in BURN_PACKAGE* pPackage
404
);
405
+void PackageUninitializeCompatible(
406
+ __in BURN_COMPATIBLE_PACKAGE* pCompatiblePackage
407
+ );
408
void PackagesUninitialize(
409
__in BURN_PACKAGES* pPackages
410
);
src/burn/engine/plan.cpp
+74
-9
@@ -96,6 +96,10 @@ static HRESULT AppendRollbackCacheAction(
96
__in BURN_PLAN* pPlan,
97
__out BURN_CACHE_ACTION** ppCacheAction
98
);
99
+static HRESULT AppendCleanAction(
100
+ __in BURN_PLAN* pPlan,
101
+ __out BURN_CLEAN_ACTION** ppCleanAction
102
+ );
103
static HRESULT ProcessPayloadGroup(
104
__in BURN_PLAN* pPlan,
105
__in BURN_PAYLOAD_GROUP* pPayloadGroup
@@ -286,6 +290,10 @@ extern "C" void PlanUninitializeExecuteAction(
290
case BURN_EXECUTE_ACTION_TYPE_PACKAGE_DEPENDENCY:
291
ReleaseStr(pExecuteAction->packageDependency.sczBundleProviderKey);
292
break;
293
+
294
+ case BURN_EXECUTE_ACTION_TYPE_UNINSTALL_MSI_COMPATIBLE_PACKAGE:
295
+ ReleaseStr(pExecuteAction->uninstallMsiCompatiblePackage.sczLogPath);
296
+ break;
297
}
298
}
299
@@ -823,6 +831,11 @@ static HRESULT PlanPackagesHelper(
831
BURN_PACKAGE* pPackage = rgPackages + iPackage;
832
833
UserExperienceOnPlannedPackage(pUX, pPackage->sczId, pPackage->execute, pPackage->rollback, pPackage->fPlannedCache, pPackage->fPlannedUncache);
834
+
835
+ if (pPackage->compatiblePackage.fPlannable)
836
+ {
837
+ UserExperienceOnPlannedCompatiblePackage(pUX, pPackage->sczId, pPackage->compatiblePackage.compatibleEntry.sczId, pPackage->compatiblePackage.fRemove);
838
+ }
839
}
840
841
LExit:
@@ -878,7 +891,7 @@ static HRESULT InitializePackage(
891
892
if (BURN_PACKAGE_TYPE_MSI == pPackage->type)
893
{
881
- hr = MsiEnginePlanInitializePackage(pPackage, pVariables, pUX);
894
+ hr = MsiEnginePlanInitializePackage(pPackage, pPlan->action, pVariables, pUX);
895
ExitOnFailure(hr, "Failed to initialize plan package: %ls", pPackage->sczId);
896
}
897
@@ -918,7 +931,7 @@ static HRESULT ProcessPackage(
931
}
932
else
933
{
921
- if (BOOTSTRAPPER_REQUEST_STATE_NONE != pPackage->requested)
934
+ if (BOOTSTRAPPER_REQUEST_STATE_NONE != pPackage->requested || pPackage->compatiblePackage.fRequested)
935
{
936
// If the package is in a requested state, plan it.
937
hr = PlanExecutePackage(fBundlePerMachine, pUX, pPlan, pPackage, pLog, pVariables);
@@ -1151,7 +1164,7 @@ extern "C" HRESULT PlanExecutePackage(
1164
ExitOnFailure(hr, "Failed to complete plan dependency actions for package: %ls", pPackage->sczId);
1165
1166
// If we are going to take any action on this package, add progress for it.
1154
- if (BOOTSTRAPPER_ACTION_STATE_NONE != pPackage->execute || BOOTSTRAPPER_ACTION_STATE_NONE != pPackage->rollback)
1167
+ if (BOOTSTRAPPER_ACTION_STATE_NONE != pPackage->execute || BOOTSTRAPPER_ACTION_STATE_NONE != pPackage->rollback || pPackage->compatiblePackage.fRemove)
1168
{
1169
LoggingIncrementPackageSequence();
1170
@@ -1560,12 +1573,10 @@ extern "C" HRESULT PlanCleanPackage(
1573
1574
if (fPlanCleanPackage)
1575
{
1563
- hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pPlan->rgCleanActions), pPlan->cCleanActions + 1, sizeof(BURN_CLEAN_ACTION), 5);
1564
- ExitOnFailure(hr, "Failed to grow plan's array of clean actions.");
1565
-
1566
- pCleanAction = pPlan->rgCleanActions + pPlan->cCleanActions;
1567
- ++pPlan->cCleanActions;
1576
+ hr = AppendCleanAction(pPlan, &pCleanAction);
1577
+ ExitOnFailure(hr, "Failed to append clean action to plan.");
1578
1579
+ pCleanAction->type = BURN_CLEAN_ACTION_TYPE_PACKAGE;
1580
pCleanAction->pPackage = pPackage;
1581
1582
pPackage->fPlannedUncache = TRUE;
@@ -1576,6 +1587,15 @@ extern "C" HRESULT PlanCleanPackage(
1587
}
1588
}
1589
1590
+ if (pPackage->compatiblePackage.fRemove)
1591
+ {
1592
+ hr = AppendCleanAction(pPlan, &pCleanAction);
1593
+ ExitOnFailure(hr, "Failed to append clean action to plan.");
1594
+
1595
+ pCleanAction->type = BURN_CLEAN_ACTION_TYPE_COMPATIBLE_PACKAGE;
1596
+ pCleanAction->pPackage = pPackage;
1597
+ }
1598
+
1599
LExit:
1600
return hr;
1601
}
@@ -2229,6 +2249,24 @@ LExit:
2249
return hr;
2250
}
2251
2252
+static HRESULT AppendCleanAction(
2253
+ __in BURN_PLAN* pPlan,
2254
+ __out BURN_CLEAN_ACTION** ppCleanAction
2255
+ )
2256
+{
2257
+ HRESULT hr = S_OK;
2258
+
2259
+ hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(&pPlan->rgCleanActions), pPlan->cCleanActions, 1, sizeof(BURN_CLEAN_ACTION), 5);
2260
+ ExitOnFailure(hr, "Failed to grow plan's array of clean actions.");
2261
+
2262
+
2263
+ *ppCleanAction = pPlan->rgCleanActions + pPlan->cCleanActions;
2264
+ ++pPlan->cCleanActions;
2265
+
2266
+LExit:
2267
+ return hr;
2268
+}
2269
+
2270
static HRESULT ProcessPayloadGroup(
2271
__in BURN_PLAN* pPlan,
2272
__in BURN_PAYLOAD_GROUP* pPayloadGroup
@@ -2505,6 +2543,8 @@ static HRESULT CalculateExecuteActions(
2543
ExitOnFailure(hr, "Invalid package type.");
2544
}
2545
2546
+ pPackage->compatiblePackage.fRemove = pPackage->compatiblePackage.fPlannable && pPackage->compatiblePackage.fRequested;
2547
+
2548
LExit:
2549
return hr;
2550
}
@@ -2622,6 +2662,10 @@ static void ExecuteActionLog(
2662
}
2663
break;
2664
2665
+ case BURN_EXECUTE_ACTION_TYPE_UNINSTALL_MSI_COMPATIBLE_PACKAGE:
2666
+ LogStringLine(PlanDumpLevel, "%ls action[%u]: UNINSTALL_MSI_COMPATIBLE_PACKAGE package id: %ls, compatible package id: %ls, cache id: %ls, log path: %ls, logging attrib: %u", wzBase, iAction, pAction->uninstallMsiCompatiblePackage.pParentPackage->sczId, pAction->uninstallMsiCompatiblePackage.pParentPackage->compatiblePackage.compatibleEntry.sczId, pAction->uninstallMsiCompatiblePackage.pParentPackage->compatiblePackage.sczCacheId, pAction->uninstallMsiCompatiblePackage.sczLogPath, pAction->uninstallMsiCompatiblePackage.dwLoggingAttributes);
2667
+ break;
2668
+
2669
case BURN_EXECUTE_ACTION_TYPE_MSP_TARGET:
2670
LogStringLine(PlanDumpLevel, "%ls action[%u]: MSP_TARGET package id: %ls, action: %hs, target product code: %ls, target per-machine: %hs, action msi property: %ls, ui level: %u, disable externaluihandler: %hs, file versioning: %hs, log path: %ls", wzBase, iAction, pAction->mspTarget.pPackage->sczId, LoggingActionStateToString(pAction->mspTarget.action), pAction->mspTarget.sczTargetProductCode, LoggingBoolToString(pAction->mspTarget.fPerMachineTarget), LoggingBurnMsiPropertyToString(pAction->mspTarget.actionMsiProperty), pAction->mspTarget.uiLevel, LoggingBoolToString(pAction->mspTarget.fDisableExternalUiHandler), LoggingMsiFileVersioningToString(pAction->mspTarget.fileVersioning), pAction->mspTarget.sczLogPath);
2671
for (DWORD j = 0; j < pAction->mspTarget.cOrderedPatches; ++j)
@@ -2669,6 +2713,27 @@ static void ExecuteActionLog(
2713
}
2714
}
2715
2716
+static void CleanActionLog(
2717
+ __in DWORD iAction,
2718
+ __in BURN_CLEAN_ACTION* pAction
2719
+ )
2720
+{
2721
+ switch (pAction->type)
2722
+ {
2723
+ case BURN_CLEAN_ACTION_TYPE_COMPATIBLE_PACKAGE:
2724
+ LogStringLine(PlanDumpLevel, " Clean action[%u]: CLEAN_COMPATIBLE_PACKAGE package id: %ls", iAction, pAction->pPackage->sczId);
2725
+ break;
2726
+
2727
+ case BURN_CLEAN_ACTION_TYPE_PACKAGE:
2728
+ LogStringLine(PlanDumpLevel, " Clean action[%u]: CLEAN_PACKAGE package id: %ls", iAction, pAction->pPackage->sczId);
2729
+ break;
2730
+
2731
+ default:
2732
+ AssertSz(FALSE, "Unknown clean action type.");
2733
+ break;
2734
+ }
2735
+}
2736
+
2737
extern "C" void PlanDump(
2738
__in BURN_PLAN* pPlan
2739
)
@@ -2709,7 +2774,7 @@ extern "C" void PlanDump(
2774
2775
for (DWORD i = 0; i < pPlan->cCleanActions; ++i)
2776
{
2712
- LogStringLine(PlanDumpLevel, " Clean action[%u]: CLEAN_PACKAGE package id: %ls", i, pPlan->rgCleanActions[i].pPackage->sczId);
2777
+ CleanActionLog(i, pPlan->rgCleanActions + i);
2778
}
2779
2780
for (DWORD i = 0; i < pPlan->cPlannedProviders; ++i)
src/burn/engine/plan.h
+9
-1
@@ -61,12 +61,13 @@ enum BURN_EXECUTE_ACTION_TYPE
61
BURN_EXECUTE_ACTION_TYPE_ROLLBACK_BOUNDARY_END,
62
BURN_EXECUTE_ACTION_TYPE_BEGIN_MSI_TRANSACTION,
63
BURN_EXECUTE_ACTION_TYPE_COMMIT_MSI_TRANSACTION,
64
+ BURN_EXECUTE_ACTION_TYPE_UNINSTALL_MSI_COMPATIBLE_PACKAGE,
65
};
66
67
enum BURN_CLEAN_ACTION_TYPE
68
{
69
BURN_CLEAN_ACTION_TYPE_NONE,
69
- BURN_CLEAN_ACTION_TYPE_BUNDLE,
70
+ BURN_CLEAN_ACTION_TYPE_COMPATIBLE_PACKAGE,
71
BURN_CLEAN_ACTION_TYPE_PACKAGE,
72
};
73
@@ -227,11 +228,18 @@ typedef struct _BURN_EXECUTE_ACTION
228
{
229
BURN_ROLLBACK_BOUNDARY* pRollbackBoundary;
230
} msiTransaction;
231
+ struct
232
+ {
233
+ BURN_PACKAGE* pParentPackage;
234
+ LPWSTR sczLogPath;
235
+ DWORD dwLoggingAttributes;
236
+ } uninstallMsiCompatiblePackage;
237
};
238
} BURN_EXECUTE_ACTION;
239
240
typedef struct _BURN_CLEAN_ACTION
241
{
242
+ BURN_CLEAN_ACTION_TYPE type;
243
BURN_PACKAGE* pPackage;
244
} BURN_CLEAN_ACTION;
245
src/burn/engine/registration.cpp
+4
@@ -423,6 +423,10 @@ extern "C" void RegistrationUninitialize(
423
ReleaseStr(pRegistration->sczBundlePackageAncestors);
424
RelatedBundlesUninitialize(&pRegistration->relatedBundles);
425
426
+ if (pRegistration->rgDependents)
427
+ {
428
+ ReleaseDependencyArray(pRegistration->rgDependents, pRegistration->cDependents);
429
+ }
430
// clear struct
431
memset(pRegistration, 0, sizeof(BURN_REGISTRATION));
432
}
src/burn/engine/userexperience.cpp
+117
-1
@@ -104,7 +104,7 @@ extern "C" HRESULT UserExperienceLoad(
104
args.pCommand = pCommand;
105
args.pfnBootstrapperEngineProc = EngineForApplicationProc;
106
args.pvBootstrapperEngineProcContext = pEngineContext;
107
- args.qwEngineAPIVersion = MAKEQWORDVERSION(2021, 12, 30, 0);
107
+ args.qwEngineAPIVersion = MAKEQWORDVERSION(2022, 1, 10, 0);
108
109
results.cbSize = sizeof(BOOTSTRAPPER_CREATE_RESULTS);
110
@@ -1015,6 +1015,36 @@ LExit:
1015
return hr;
1016
}
1017
1018
+EXTERN_C BAAPI UserExperienceOnDetectCompatibleMsiPackage(
1019
+ __in BURN_USER_EXPERIENCE* pUserExperience,
1020
+ __in_z LPCWSTR wzPackageId,
1021
+ __in_z LPCWSTR wzCompatiblePackageId,
1022
+ __in VERUTIL_VERSION* pCompatiblePackageVersion
1023
+ )
1024
+{
1025
+ HRESULT hr = S_OK;
1026
+ BA_ONDETECTCOMPATIBLEMSIPACKAGE_ARGS args = { };
1027
+ BA_ONDETECTCOMPATIBLEMSIPACKAGE_RESULTS results = { };
1028
+
1029
+ args.cbSize = sizeof(args);
1030
+ args.wzPackageId = wzPackageId;
1031
+ args.wzCompatiblePackageId = wzCompatiblePackageId;
1032
+ args.wzCompatiblePackageVersion = pCompatiblePackageVersion->sczVersion;
1033
+
1034
+ results.cbSize = sizeof(results);
1035
+
1036
+ hr = SendBAMessage(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTCOMPATIBLEMSIPACKAGE, &args, &results);
1037
+ ExitOnFailure(hr, "BA OnDetectCompatibleMsiPackage failed.");
1038
+
1039
+ if (results.fCancel)
1040
+ {
1041
+ hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT);
1042
+ }
1043
+
1044
+LExit:
1045
+ return hr;
1046
+}
1047
+
1048
EXTERN_C BAAPI UserExperienceOnDetectComplete(
1049
__in BURN_USER_EXPERIENCE* pUserExperience,
1050
__in HRESULT hrStatus,
@@ -1798,6 +1828,67 @@ LExit:
1828
return hr;
1829
}
1830
1831
+EXTERN_C BAAPI UserExperienceOnPlanCompatibleMsiPackageBegin(
1832
+ __in BURN_USER_EXPERIENCE* pUserExperience,
1833
+ __in_z LPCWSTR wzPackageId,
1834
+ __in_z LPCWSTR wzCompatiblePackageId,
1835
+ __in VERUTIL_VERSION* pCompatiblePackageVersion,
1836
+ __inout BOOL* pfRequested
1837
+ )
1838
+{
1839
+ HRESULT hr = S_OK;
1840
+ BA_ONPLANCOMPATIBLEMSIPACKAGEBEGIN_ARGS args = { };
1841
+ BA_ONPLANCOMPATIBLEMSIPACKAGEBEGIN_RESULTS results = { };
1842
+
1843
+ args.cbSize = sizeof(args);
1844
+ args.wzPackageId = wzPackageId;
1845
+ args.wzCompatiblePackageId = wzCompatiblePackageId;
1846
+ args.wzCompatiblePackageVersion = pCompatiblePackageVersion->sczVersion;
1847
+ args.fRecommendedRemove = *pfRequested;
1848
+
1849
+ results.cbSize = sizeof(results);
1850
+ results.fRequestRemove = *pfRequested;
1851
+
1852
+ hr = SendBAMessage(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANCOMPATIBLEMSIPACKAGEBEGIN, &args, &results);
1853
+ ExitOnFailure(hr, "BA OnPlanCompatibleMsiPackageBegin failed.");
1854
+
1855
+ if (results.fCancel)
1856
+ {
1857
+ hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT);
1858
+ }
1859
+ *pfRequested = results.fRequestRemove;
1860
+
1861
+LExit:
1862
+ return hr;
1863
+}
1864
+
1865
+EXTERN_C BAAPI UserExperienceOnPlanCompatibleMsiPackageComplete(
1866
+ __in BURN_USER_EXPERIENCE* pUserExperience,
1867
+ __in_z LPCWSTR wzPackageId,
1868
+ __in_z LPCWSTR wzCompatiblePackageId,
1869
+ __in HRESULT hrStatus,
1870
+ __in BOOL fRequested
1871
+ )
1872
+{
1873
+ HRESULT hr = S_OK;
1874
+ BA_ONPLANCOMPATIBLEMSIPACKAGECOMPLETE_ARGS args = { };
1875
+ BA_ONPLANCOMPATIBLEMSIPACKAGECOMPLETE_RESULTS results = { };
1876
+
1877
+ args.cbSize = sizeof(args);
1878
+ args.wzPackageId = wzPackageId;
1879
+ args.wzCompatiblePackageId = wzCompatiblePackageId;
1880
+ args.hrStatus = hrStatus;
1881
+ args.fRequestedRemove = fRequested;
1882
+
1883
+ results.cbSize = sizeof(results);
1884
+
1885
+ hr = SendBAMessage(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANCOMPATIBLEMSIPACKAGECOMPLETE, &args, &results);
1886
+ ExitOnFailure(hr, "BA OnPlanCompatibleMsiPackageComplete failed.");
1887
+
1888
+LExit:
1889
+ return hr;
1890
+}
1891
+
1892
EXTERN_C BAAPI UserExperienceOnPlanMsiFeature(
1893
__in BURN_USER_EXPERIENCE* pUserExperience,
1894
__in_z LPCWSTR wzPackageId,
@@ -1932,6 +2023,31 @@ LExit:
2023
return hr;
2024
}
2025
2026
+EXTERN_C BAAPI UserExperienceOnPlannedCompatiblePackage(
2027
+ __in BURN_USER_EXPERIENCE* pUserExperience,
2028
+ __in_z LPCWSTR wzPackageId,
2029
+ __in_z LPCWSTR wzCompatiblePackageId,
2030
+ __in BOOL fRemove
2031
+ )
2032
+{
2033
+ HRESULT hr = S_OK;
2034
+ BA_ONPLANNEDCOMPATIBLEPACKAGE_ARGS args = { };
2035
+ BA_ONPLANNEDCOMPATIBLEPACKAGE_RESULTS results = { };
2036
+
2037
+ args.cbSize = sizeof(args);
2038
+ args.wzPackageId = wzPackageId;
2039
+ args.wzCompatiblePackageId = wzCompatiblePackageId;
2040
+ args.fRemove = fRemove;
2041
+
2042
+ results.cbSize = sizeof(results);
2043
+
2044
+ hr = SendBAMessage(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANNEDCOMPATIBLEPACKAGE, &args, &results);
2045
+ ExitOnFailure(hr, "BA OnPlannedCompatiblePackage failed.");
2046
+
2047
+LExit:
2048
+ return hr;
2049
+}
2050
+
2051
EXTERN_C BAAPI UserExperienceOnPlannedPackage(
2052
__in BURN_USER_EXPERIENCE* pUserExperience,
2053
__in_z LPCWSTR wzPackageId,
src/burn/engine/userexperience.h
+26
@@ -248,6 +248,12 @@ BAAPI UserExperienceOnDetectBegin(
248
__in BOOL fInstalled,
249
__in DWORD cPackages
250
);
251
+BAAPI UserExperienceOnDetectCompatibleMsiPackage(
252
+ __in BURN_USER_EXPERIENCE* pUserExperience,
253
+ __in_z LPCWSTR wzPackageId,
254
+ __in_z LPCWSTR wzCompatiblePackageId,
255
+ __in VERUTIL_VERSION* pCompatiblePackageVersion
256
+ );
257
BAAPI UserExperienceOnDetectComplete(
258
__in BURN_USER_EXPERIENCE* pUserExperience,
259
__in HRESULT hrStatus,
@@ -414,6 +420,20 @@ BAAPI UserExperienceOnPlanBegin(
420
__in BURN_USER_EXPERIENCE* pUserExperience,
421
__in DWORD cPackages
422
);
423
+BAAPI UserExperienceOnPlanCompatibleMsiPackageBegin(
424
+ __in BURN_USER_EXPERIENCE* pUserExperience,
425
+ __in_z LPCWSTR wzPackageId,
426
+ __in_z LPCWSTR wzCompatiblePackageId,
427
+ __in VERUTIL_VERSION* pCompatiblePackageVersion,
428
+ __inout BOOL* pfRequested
429
+ );
430
+BAAPI UserExperienceOnPlanCompatibleMsiPackageComplete(
431
+ __in BURN_USER_EXPERIENCE* pUserExperience,
432
+ __in_z LPCWSTR wzPackageId,
433
+ __in_z LPCWSTR wzCompatiblePackageId,
434
+ __in HRESULT hrStatus,
435
+ __in BOOL fRequested
436
+ );
437
BAAPI UserExperienceOnPlanComplete(
438
__in BURN_USER_EXPERIENCE* pUserExperience,
439
__in HRESULT hrStatus
@@ -443,6 +463,12 @@ BAAPI UserExperienceOnPlanMsiPackage(
463
__inout BOOL* pfDisableExternalUiHandler,
464
__inout BOOTSTRAPPER_MSI_FILE_VERSIONING* pFileVersioning
465
);
466
+BAAPI UserExperienceOnPlannedCompatiblePackage(
467
+ __in BURN_USER_EXPERIENCE* pUserExperience,
468
+ __in_z LPCWSTR wzPackageId,
469
+ __in_z LPCWSTR wzCompatiblePackageId,
470
+ __in BOOL fRemove
471
+ );
472
BAAPI UserExperienceOnPlannedPackage(
473
__in BURN_USER_EXPERIENCE* pUserExperience,
474
__in_z LPCWSTR wzPackageId,
src/burn/test/BurnUnitTest/PlanTest.cpp
+132
-1
@@ -287,6 +287,74 @@ namespace Bootstrapper
287
ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[2], L"PackageC", BURN_PACKAGE_REGISTRATION_STATE_ABSENT, BURN_PACKAGE_REGISTRATION_STATE_ABSENT);
288
}
289
290
+ [Fact]
291
+ void OrphanCompatiblePackageTest()
292
+ {
293
+ HRESULT hr = S_OK;
294
+ BURN_ENGINE_STATE engineState = { };
295
+ BURN_ENGINE_STATE* pEngineState = &engineState;
296
+ BURN_PLAN* pPlan = &engineState.plan;
297
+
298
+ InitializeEngineStateForCorePlan(wzSingleMsiManifestFileName, pEngineState);
299
+ DetectPackagesAsAbsent(pEngineState);
300
+ DetectCompatibleMsiPackage(pEngineState->packages.rgPackages, L"{C24F3903-38E7-4D44-8037-D9856B3C5046}", L"2.0.0.0");
301
+
302
+ hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL);
303
+ NativeAssert::Succeeded(hr, "CorePlan failed");
304
+
305
+ Assert::Equal<DWORD>(BOOTSTRAPPER_ACTION_UNINSTALL, pPlan->action);
306
+ Assert::Equal<BOOL>(TRUE, pPlan->fPerMachine);
307
+ Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
308
+
309
+ BOOL fRollback = FALSE;
310
+ DWORD dwIndex = 0;
311
+ Assert::Equal(dwIndex, pPlan->cCacheActions);
312
+
313
+ fRollback = TRUE;
314
+ dwIndex = 0;
315
+ Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
316
+
317
+ Assert::Equal(0ull, pPlan->qwEstimatedSize);
318
+ Assert::Equal(0ull, pPlan->qwCacheSizeTotal);
319
+
320
+ fRollback = FALSE;
321
+ dwIndex = 0;
322
+ DWORD dwExecuteCheckpointId = 1;
323
+ ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
324
+ ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", BURN_DEPENDENCY_ACTION_UNREGISTER);
325
+ ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_UNREGISTER);
326
+ ValidateUninstallMsiCompatiblePackage(pPlan, fRollback, dwIndex++, L"PackageA", 0);
327
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
328
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
329
+ ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++);
330
+ Assert::Equal(dwIndex, pPlan->cExecuteActions);
331
+
332
+ fRollback = TRUE;
333
+ dwIndex = 0;
334
+ dwExecuteCheckpointId = 1;
335
+ ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
336
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
337
+ ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
338
+ ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++);
339
+ Assert::Equal(dwIndex, pPlan->cRollbackActions);
340
+
341
+ Assert::Equal(1ul, pPlan->cExecutePackagesTotal);
342
+ Assert::Equal(1ul, pPlan->cOverallProgressTicksTotal);
343
+
344
+ dwIndex = 0;
345
+ ValidateCleanAction(pPlan, dwIndex++, L"PackageA");
346
+ ValidateCleanCompatibleAction(pPlan, dwIndex++, L"PackageA");
347
+ Assert::Equal(dwIndex, pPlan->cCleanActions);
348
+
349
+ UINT uIndex = 0;
350
+ ValidatePlannedProvider(pPlan, uIndex++, L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", NULL);
351
+ ValidatePlannedProvider(pPlan, uIndex++, L"{64633047-D172-4BBB-B202-64337D15C952}", NULL);
352
+ Assert::Equal(uIndex, pPlan->cPlannedProviders);
353
+
354
+ Assert::Equal(1ul, pEngineState->packages.cPackages);
355
+ ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_ABSENT, BURN_PACKAGE_REGISTRATION_STATE_ABSENT);
356
+ }
357
+
358
[Fact]
359
void RelatedBundleMissingFromCacheTest()
360
{
@@ -1026,6 +1094,36 @@ namespace Bootstrapper
1094
}
1095
}
1096
1097
+ void DetectCompatibleMsiPackage(BURN_PACKAGE* pPackage, LPCWSTR wzProductCode, LPCWSTR wzVersion)
1098
+ {
1099
+ HRESULT hr = S_OK;
1100
+ Assert(BOOTSTRAPPER_PACKAGE_STATE_PRESENT > pPackage->currentState);
1101
+ Assert(0 < pPackage->cDependencyProviders);
1102
+ BURN_DEPENDENCY_PROVIDER* pProvider = pPackage->rgDependencyProviders;
1103
+ BURN_COMPATIBLE_PACKAGE* pCompatiblePackage = &pPackage->compatiblePackage;
1104
+ pCompatiblePackage->fDetected = TRUE;
1105
+ pCompatiblePackage->fPlannable = TRUE;
1106
+ pCompatiblePackage->type = BURN_PACKAGE_TYPE_MSI;
1107
+
1108
+ hr = StrAllocFormatted(&pCompatiblePackage->sczCacheId, L"%lsv%ls", wzProductCode, wzVersion);
1109
+ NativeAssert::Succeeded(hr, "Failed to format cache id");
1110
+
1111
+ hr = StrAllocString(&pCompatiblePackage->Msi.sczVersion, wzVersion, 0);
1112
+ NativeAssert::Succeeded(hr, "Failed to copy MSI version");
1113
+
1114
+ hr = VerParseVersion(wzVersion, 0, FALSE, &pCompatiblePackage->Msi.pVersion);
1115
+ NativeAssert::Succeeded(hr, "Failed to parse MSI version");
1116
+
1117
+ hr = StrAllocString(&pCompatiblePackage->compatibleEntry.sczId, wzProductCode, 0);
1118
+ NativeAssert::Succeeded(hr, "Failed to copy product code");
1119
+
1120
+ hr = StrAllocString(&pCompatiblePackage->compatibleEntry.sczVersion, wzVersion, 0);
1121
+ NativeAssert::Succeeded(hr, "Failed to copy version");
1122
+
1123
+ hr = StrAllocString(&pCompatiblePackage->compatibleEntry.sczProviderKey, pProvider->sczKey, 0);
1124
+ NativeAssert::Succeeded(hr, "Failed to copy provider key");
1125
+ }
1126
+
1127
void DetectPackageAsAbsent(BURN_PACKAGE* pPackage)
1128
{
1129
pPackage->currentState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT;
@@ -1261,10 +1359,27 @@ namespace Bootstrapper
1359
__in DWORD dwIndex,
1360
__in LPCWSTR wzPackageId
1361
)
1362
+ {
1363
+ BURN_CLEAN_ACTION* pCleanAction = ValidateCleanActionExists(pPlan, dwIndex);
1364
+ Assert::Equal<DWORD>(BURN_CLEAN_ACTION_TYPE_PACKAGE, pCleanAction->type);
1365
+ Assert::NotEqual((DWORD_PTR)0, (DWORD_PTR)pCleanAction->pPackage);
1366
+ NativeAssert::StringEqual(wzPackageId, pCleanAction->pPackage->sczId);
1367
+ }
1368
+
1369
+ BURN_CLEAN_ACTION* ValidateCleanActionExists(BURN_PLAN* pPlan, DWORD dwIndex)
1370
{
1371
Assert::InRange(dwIndex + 1ul, 1ul, pPlan->cCleanActions);
1372
+ return pPlan->rgCleanActions + dwIndex;
1373
+ }
1374
1267
- BURN_CLEAN_ACTION* pCleanAction = pPlan->rgCleanActions + dwIndex;
1375
+ void ValidateCleanCompatibleAction(
1376
+ __in BURN_PLAN* pPlan,
1377
+ __in DWORD dwIndex,
1378
+ __in LPCWSTR wzPackageId
1379
+ )
1380
+ {
1381
+ BURN_CLEAN_ACTION* pCleanAction = ValidateCleanActionExists(pPlan, dwIndex);
1382
+ Assert::Equal<DWORD>(BURN_CLEAN_ACTION_TYPE_COMPATIBLE_PACKAGE, pCleanAction->type);
1383
Assert::NotEqual((DWORD_PTR)0, (DWORD_PTR)pCleanAction->pPackage);
1384
NativeAssert::StringEqual(wzPackageId, pCleanAction->pPackage->sczId);
1385
}
@@ -1537,6 +1652,22 @@ namespace Bootstrapper
1652
NativeAssert::StringEqual(wzKey, pProvider->sczKey);
1653
NativeAssert::StringEqual(wzName, pProvider->sczName);
1654
}
1655
+
1656
+ void ValidateUninstallMsiCompatiblePackage(
1657
+ __in BURN_PLAN* pPlan,
1658
+ __in BOOL fRollback,
1659
+ __in DWORD dwIndex,
1660
+ __in_z LPCWSTR wzPackageId,
1661
+ __in DWORD dwLoggingAttributes
1662
+ )
1663
+ {
1664
+ BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex);
1665
+ Assert::Equal<DWORD>(BURN_EXECUTE_ACTION_TYPE_UNINSTALL_MSI_COMPATIBLE_PACKAGE, pAction->type);
1666
+ NativeAssert::StringEqual(wzPackageId, pAction->uninstallMsiCompatiblePackage.pParentPackage->sczId);
1667
+ NativeAssert::NotNull(pAction->msiPackage.sczLogPath);
1668
+ Assert::Equal<DWORD>(dwLoggingAttributes, pAction->uninstallMsiCompatiblePackage.dwLoggingAttributes);
1669
+ Assert::Equal<BOOL>(FALSE, pAction->fDeleted);
1670
+ }
1671
};
1672
}
1673
}
src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp
+46
@@ -1424,6 +1424,18 @@ public: // IBootstrapperApplication
1424
case BOOTSTRAPPER_APPLICATION_MESSAGE_ONSETUPDATECOMPLETE:
1425
OnSetUpdateCompleteFallback(reinterpret_cast<BA_ONSETUPDATECOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONSETUPDATECOMPLETE_RESULTS*>(pvResults));
1426
break;
1427
+ case BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTCOMPATIBLEMSIPACKAGE:
1428
+ OnDetectCompatibleMsiPackageFallback(reinterpret_cast<BA_ONDETECTCOMPATIBLEMSIPACKAGE_ARGS*>(pvArgs), reinterpret_cast<BA_ONDETECTCOMPATIBLEMSIPACKAGE_RESULTS*>(pvResults));
1429
+ break;
1430
+ case BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANCOMPATIBLEMSIPACKAGEBEGIN:
1431
+ OnPlanCompatibleMsiPackageBeginFallback(reinterpret_cast<BA_ONPLANCOMPATIBLEMSIPACKAGEBEGIN_ARGS*>(pvArgs), reinterpret_cast<BA_ONPLANCOMPATIBLEMSIPACKAGEBEGIN_RESULTS*>(pvResults));
1432
+ break;
1433
+ case BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANCOMPATIBLEMSIPACKAGECOMPLETE:
1434
+ OnPlanCompatibleMsiPackageCompleteFallback(reinterpret_cast<BA_ONPLANCOMPATIBLEMSIPACKAGECOMPLETE_ARGS*>(pvArgs), reinterpret_cast<BA_ONPLANCOMPATIBLEMSIPACKAGECOMPLETE_RESULTS*>(pvResults));
1435
+ break;
1436
+ case BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANNEDCOMPATIBLEPACKAGE:
1437
+ OnPlannedCompatiblePackageFallback(reinterpret_cast<BA_ONPLANNEDCOMPATIBLEPACKAGE_ARGS*>(pvArgs), reinterpret_cast<BA_ONPLANNEDCOMPATIBLEPACKAGE_RESULTS*>(pvResults));
1438
+ break;
1439
default:
1440
#ifdef DEBUG
1441
BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "WIXSTDBA: Forwarding unknown BA message: %d", message);
@@ -1611,6 +1623,14 @@ private: // privates
1623
m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONPLANPACKAGECOMPLETE, pArgs, pResults, m_pvBAFunctionsProcContext);
1624
}
1625
1626
+ void OnPlannedCompatiblePackageFallback(
1627
+ __in BA_ONPLANNEDCOMPATIBLEPACKAGE_ARGS* pArgs,
1628
+ __inout BA_ONPLANNEDCOMPATIBLEPACKAGE_RESULTS* pResults
1629
+ )
1630
+ {
1631
+ m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONPLANNEDCOMPATIBLEPACKAGE, pArgs, pResults, m_pvBAFunctionsProcContext);
1632
+ }
1633
+
1634
void OnPlannedPackageFallback(
1635
__in BA_ONPLANNEDPACKAGE_ARGS* pArgs,
1636
__inout BA_ONPLANNEDPACKAGE_RESULTS* pResults
@@ -2043,6 +2063,32 @@ private: // privates
2063
m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONSETUPDATECOMPLETE, pArgs, pResults, m_pvBAFunctionsProcContext);
2064
}
2065
2066
+ void OnDetectCompatibleMsiPackageFallback(
2067
+ __in BA_ONDETECTCOMPATIBLEMSIPACKAGE_ARGS* pArgs,
2068
+ __inout BA_ONDETECTCOMPATIBLEMSIPACKAGE_RESULTS* pResults
2069
+ )
2070
+ {
2071
+ m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONDETECTCOMPATIBLEMSIPACKAGE, pArgs, pResults, m_pvBAFunctionsProcContext);
2072
+ }
2073
+
2074
+ void OnPlanCompatibleMsiPackageBeginFallback(
2075
+ __in BA_ONPLANCOMPATIBLEMSIPACKAGEBEGIN_ARGS* pArgs,
2076
+ __inout BA_ONPLANCOMPATIBLEMSIPACKAGEBEGIN_RESULTS* pResults
2077
+ )
2078
+ {
2079
+ BOOL fRequestRemove = pResults->fRequestRemove;
2080
+ m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONPLANCOMPATIBLEMSIPACKAGEBEGIN, pArgs, pResults, m_pvBAFunctionsProcContext);
2081
+ BalLogId(BOOTSTRAPPER_LOG_LEVEL_STANDARD, MSG_WIXSTDBA_PLANNED_COMPATIBLE_MSI_PACKAGE, m_hModule, pArgs->wzPackageId, pArgs->wzCompatiblePackageId, LoggingBoolToString(fRequestRemove), LoggingBoolToString(pResults->fRequestRemove));
2082
+ }
2083
+
2084
+ void OnPlanCompatibleMsiPackageCompleteFallback(
2085
+ __in BA_ONPLANCOMPATIBLEMSIPACKAGECOMPLETE_ARGS* pArgs,
2086
+ __inout BA_ONPLANCOMPATIBLEMSIPACKAGECOMPLETE_RESULTS* pResults
2087
+ )
2088
+ {
2089
+ m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONPLANCOMPATIBLEMSIPACKAGECOMPLETE, pArgs, pResults, m_pvBAFunctionsProcContext);
2090
+ }
2091
+
2092
2093
public: //CBalBaseBootstrapperApplication
2094
virtual STDMETHODIMP Initialize(
src/ext/Bal/wixstdba/wixstdba.mc
+7
@@ -50,6 +50,13 @@ Language=English
50
WIXSTDBA: Planned related bundle: %1!ls!, wixstdba requested: %2!hs!, bafunctions requested: %3!hs!
51
.
52
53
+MessageId=4
54
+Severity=Success
55
+SymbolicName=MSG_WIXSTDBA_PLANNED_COMPATIBLE_MSI_PACKAGE
56
+Language=English
57
+WIXSTDBA: Planned compatible package: %2!ls! for %1!ls!, wixstdba requested remove: %3!hs!, bafunctions requested remove: %4!hs!
58
+.
59
+
60
MessageId=5
61
Severity=Success
62
SymbolicName=MSG_WIXSTDBA_PLANNED_TARGET_MSI_PACKAGE
src/test/burn/TestData/DependencyTests/BundleAv2/BundleAv2.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
+ <Import Project="..\BundleAv1\BundleA.props" />
4
+ <PropertyGroup>
5
+ <Version>2.0.0.0</Version>
6
+ </PropertyGroup>
7
+ <ItemGroup>
8
+ <ProjectReference Include="..\PackageAv2\PackageAv2.wixproj" />
9
+ <ProjectReference Include="..\..\TestBA\TestBAWixlib\testbawixlib.wixproj" />
10
+ </ItemGroup>
11
+ <ItemGroup>
12
+ <PackageReference Include="WixToolset.Bal.wixext" />
13
+ <PackageReference Include="WixToolset.NetFx.wixext" />
14
+ <PackageReference Include="WixToolset.Util.wixext" />
15
+ </ItemGroup>
16
+</Project>
\ No newline at end of file
src/test/burn/TestData/DependencyTests/BundleAv2/BundleAv2.wxs
new
+21
@@ -0,0 +1,21 @@
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 TestExeRegistryKey = Software\WiX\Tests\$(var.TestGroupName)\ExeA?>
4
+
5
+<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
6
+ <Fragment>
7
+ <util:RegistrySearch Root="HKLM" Key="$(var.TestExeRegistryKey)" Value="Version" Variable="ExeA_Version" />
8
+
9
+ <PackageGroup Id="BundlePackages">
10
+ <MsiPackage Id="PackageA" SourceFile="$(var.PackageAv2.TargetPath)" />
11
+ <ExePackage Id="ExeA" Cache="remove" PerMachine="yes"
12
+ DetectCondition="ExeA_Version AND ExeA_Version >= v$(var.Version)"
13
+ InstallArguments="/regw "HKLM\$(var.TestExeRegistryKey),Version,String,$(var.Version)""
14
+ RepairArguments="/regw "HKLM\$(var.TestExeRegistryKey),Version,String,$(var.Version)""
15
+ UninstallArguments="/regd "HKLM\$(var.TestExeRegistryKey),Version"">
16
+ <Provides Key="$(var.TestGroupName)_ExeA,v1.0" Version="$(var.Version)" />
17
+ <PayloadGroupRef Id="TestExePayloads" />
18
+ </ExePackage>
19
+ </PackageGroup>
20
+ </Fragment>
21
+</Wix>
src/test/burn/TestData/DependencyTests/PackageAv1/PackageA.props
-1
@@ -3,7 +3,6 @@
3
<PropertyGroup>
4
<PackageName>PackageA</PackageName>
5
<ProductComponentsRef>true</ProductComponentsRef>
6
- <ProductCode>{6F171EC9-0774-4974-A8D1-493EF53CAB74}</ProductCode>
6
<UpgradeCode>{45E933B7-B56A-44D5-8EEC-625EC199085E}</UpgradeCode>
7
</PropertyGroup>
8
<ItemGroup>
src/test/burn/TestData/DependencyTests/PackageAv1/PackageAv1.props
new
+7
@@ -0,0 +1,7 @@
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>
3
+ <Import Project="PackageA.props" />
4
+ <PropertyGroup>
5
+ <ProductCode>{6F171EC9-0774-4974-A8D1-493EF53CAB74}</ProductCode>
6
+ </PropertyGroup>
7
+</Project>
\ No newline at end of file
src/test/burn/TestData/DependencyTests/PackageAv1/PackageAv1.wixproj
+1
-1
@@ -1,6 +1,6 @@
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
- <Import Project="PackageA.props" />
3
+ <Import Project="PackageAv1.props" />
4
<ItemGroup>
5
<PackageReference Include="WixToolset.Dependency.wixext" />
6
</ItemGroup>
src/test/burn/TestData/DependencyTests/PackageAv1_0_1/PackageAv1_0_1.wixproj
+1
-1
@@ -1,6 +1,6 @@
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
- <Import Project="..\PackageAv1\PackageA.props" />
3
+ <Import Project="..\PackageAv1\PackageAv1.props" />
4
<PropertyGroup>
5
<Version>1.0.1.0</Version>
6
</PropertyGroup>
src/test/burn/TestData/DependencyTests/PackageAv1_0_2/PackageAv1_0_2.wixproj
+1
-1
@@ -1,6 +1,6 @@
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
- <Import Project="..\PackageAv1\PackageA.props" />
3
+ <Import Project="..\PackageAv1\PackageAv1.props" />
4
<PropertyGroup>
5
<Version>1.0.2.0</Version>
6
</PropertyGroup>
src/test/burn/TestData/DependencyTests/PackageAv2/PackageAv2.wixproj
new
+13
@@ -0,0 +1,13 @@
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
+ <Import Project="..\PackageAv1\PackageA.props" />
4
+ <PropertyGroup>
5
+ <Version>2.0.0.0</Version>
6
+ </PropertyGroup>
7
+ <ItemGroup>
8
+ <Compile Include="..\PackageAv1\ProductComponents.wxs" Link="ProductComponents.wxs" />
9
+ </ItemGroup>
10
+ <ItemGroup>
11
+ <PackageReference Include="WixToolset.Dependency.wixext" />
12
+ </ItemGroup>
13
+</Project>
\ No newline at end of file
src/test/burn/WixTestTools/BundleVerifier.cs
+2
-2
@@ -124,14 +124,14 @@ namespace WixTestTools
124
}
125
}
126
127
- public void VerifyPackageIsCached(string packageId)
127
+ public void VerifyPackageIsCached(string packageId, bool cached = true)
128
{
129
using var wixOutput = WixOutput.Read(this.BundlePdb);
130
var intermediate = Intermediate.Load(wixOutput);
131
var section = intermediate.Sections.Single();
132
var packageSymbol = section.Symbols.OfType<WixBundlePackageSymbol>().Single(p => p.Id.Id == packageId);
133
var cachePath = this.GetPackageCachePathForCacheId(packageSymbol.CacheId, packageSymbol.PerMachine == YesNoDefaultType.Yes);
134
- Assert.True(Directory.Exists(cachePath));
134
+ Assert.Equal(cached, Directory.Exists(cachePath));
135
}
136
137
public void VerifyExeTestRegistryRootDeleted(string name, bool x64 = false)
src/test/burn/WixToolsetTest.BurnE2E/DependencyTests.cs
+58
@@ -123,6 +123,64 @@ namespace WixToolsetTest.BurnE2E
123
bundleAv1.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.1.0");
124
}
125
126
+ [Fact]
127
+ public void UninstallsOrphanCompatiblePackages()
128
+ {
129
+ var testRegistryValueExe = "ExeA";
130
+
131
+ var packageAv1 = this.CreatePackageInstaller("PackageAv1");
132
+ var packageAv2 = this.CreatePackageInstaller("PackageAv2");
133
+ var packageB = this.CreatePackageInstaller("PackageB");
134
+ var bundleAv1 = this.CreateBundleInstaller("BundleAv1");
135
+ var bundleAv2 = this.CreateBundleInstaller("BundleAv2");
136
+ var bundleB = this.CreateBundleInstaller("BundleB");
137
+
138
+ packageAv1.VerifyInstalled(false);
139
+ packageAv2.VerifyInstalled(false);
140
+ packageB.VerifyInstalled(false);
141
+
142
+ bundleAv1.Install();
143
+ bundleAv1.VerifyRegisteredAndInPackageCache();
144
+
145
+ packageAv1.VerifyInstalled(true);
146
+ bundleAv1.VerifyPackageIsCached("PackageA");
147
+ bundleAv1.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.0.0");
148
+
149
+ bundleB.Install();
150
+ bundleB.VerifyRegisteredAndInPackageCache();
151
+
152
+ packageAv1.VerifyInstalled(true);
153
+ bundleAv1.VerifyPackageIsCached("PackageA");
154
+ bundleAv1.VerifyExeTestRegistryValue(testRegistryValueExe, "1.0.0.0");
155
+ packageB.VerifyInstalled(true);
156
+
157
+ bundleAv2.Install();
158
+ bundleAv2.VerifyRegisteredAndInPackageCache();
159
+ bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache();
160
+
161
+ packageAv1.VerifyInstalled(false);
162
+ bundleAv1.VerifyPackageIsCached("PackageA", false);
163
+ packageAv2.VerifyInstalled(true);
164
+ bundleAv2.VerifyPackageIsCached("PackageA");
165
+ bundleAv1.VerifyExeTestRegistryValue(testRegistryValueExe, "2.0.0.0");
166
+
167
+ bundleAv2.Uninstall();
168
+ bundleAv2.VerifyUnregisteredAndRemovedFromPackageCache();
169
+
170
+ packageAv2.VerifyInstalled(true);
171
+ bundleAv2.VerifyPackageIsCached("PackageA");
172
+ bundleAv1.VerifyExeTestRegistryValue(testRegistryValueExe, "2.0.0.0");
173
+
174
+ // Verify https://github.com/wixtoolset/issues/issues/3190
175
+ bundleB.Uninstall();
176
+
177
+ packageAv1.VerifyInstalled(false);
178
+ packageAv2.VerifyInstalled(false);
179
+ bundleAv2.VerifyPackageIsCached("PackageA", false);
180
+ packageB.VerifyInstalled(false);
181
+ bundleAv1.VerifyExeTestRegistryRootDeleted(testRegistryValueExe);
182
+ }
183
+
184
[Fact(Skip = "https://github.com/wixtoolset/issues/issues/6401")]
185
public void CanMinorUpgradeDependencyPackageFromPatchBundle()
186
{