Detect related bundles for BundlePackages.
Sean Hall committed
Apr 1, 2022 at 15:44 UTC
39b9a6112c2ff97f31f195749e2142538e47a2eb
38 files changed
+773
-238
src/api/burn/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h
+17
@@ -226,6 +226,7 @@ enum BOOTSTRAPPER_APPLICATION_MESSAGE
226
BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANRELATEDBUNDLETYPE,
227
BOOTSTRAPPER_APPLICATION_MESSAGE_ONAPPLYDOWNGRADE,
228
BOOTSTRAPPER_APPLICATION_MESSAGE_ONEXECUTEPROCESSCANCEL,
229
+ BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTRELATEDBUNDLEPACKAGE,
230
};
231
232
enum BOOTSTRAPPER_APPLYCOMPLETE_ACTION
@@ -793,6 +794,22 @@ struct BA_ONDETECTRELATEDBUNDLE_RESULTS
794
BOOL fCancel;
795
};
796
797
+struct BA_ONDETECTRELATEDBUNDLEPACKAGE_ARGS
798
+{
799
+ DWORD cbSize;
800
+ LPCWSTR wzPackageId;
801
+ LPCWSTR wzBundleId;
802
+ BOOTSTRAPPER_RELATION_TYPE relationType;
803
+ BOOL fPerMachine;
804
+ LPCWSTR wzVersion;
805
+};
806
+
807
+struct BA_ONDETECTRELATEDBUNDLEPACKAGE_RESULTS
808
+{
809
+ DWORD cbSize;
810
+ BOOL fCancel;
811
+};
812
+
813
struct BA_ONDETECTRELATEDMSIPACKAGE_ARGS
814
{
815
DWORD cbSize;
src/api/burn/WixToolset.Mba.Core/BootstrapperApplication.cs
+25
@@ -283,6 +283,9 @@ namespace WixToolset.Mba.Core
283
/// <inheritdoc/>
284
public event EventHandler<ExecuteProcessCancelEventArgs> ExecuteProcessCancel;
285
286
+ /// <inheritdoc/>
287
+ public event EventHandler<DetectRelatedBundlePackageEventArgs> DetectRelatedBundlePackage;
288
+
289
/// <summary>
290
/// Entry point that is called when the bootstrapper application is ready to run.
291
/// </summary>
@@ -1385,6 +1388,19 @@ namespace WixToolset.Mba.Core
1388
}
1389
}
1390
1391
+ /// <summary>
1392
+ /// Called by the engine, raises the <see cref="DetectRelatedBundlePackage"/> event.
1393
+ /// </summary>
1394
+ /// <param name="args">Additional arguments for this event.</param>
1395
+ protected virtual void OnDetectRelatedBundlePackage(DetectRelatedBundlePackageEventArgs args)
1396
+ {
1397
+ EventHandler<DetectRelatedBundlePackageEventArgs> handler = this.DetectRelatedBundlePackage;
1398
+ if (null != handler)
1399
+ {
1400
+ handler(this, args);
1401
+ }
1402
+ }
1403
+
1404
#region IBootstrapperApplication Members
1405
1406
int IBootstrapperApplication.BAProc(int message, IntPtr pvArgs, IntPtr pvResults, IntPtr pvContext)
@@ -2144,6 +2160,15 @@ namespace WixToolset.Mba.Core
2160
return args.HResult;
2161
}
2162
2163
+ int IBootstrapperApplication.OnDetectRelatedBundlePackage(string wzPackageId, string wzProductCode, RelationType relationType, bool fPerMachine, string wzVersion, ref bool fCancel)
2164
+ {
2165
+ DetectRelatedBundlePackageEventArgs args = new DetectRelatedBundlePackageEventArgs(wzPackageId, wzProductCode, relationType, fPerMachine, wzVersion, fCancel);
2166
+ this.OnDetectRelatedBundlePackage(args);
2167
+
2168
+ fCancel = args.Cancel;
2169
+ return args.HResult;
2170
+ }
2171
+
2172
#endregion
2173
}
2174
}
src/api/burn/WixToolset.Mba.Core/EventArgs.cs
+65
-87
@@ -2030,10 +2030,7 @@ namespace WixToolset.Mba.Core
2030
[Serializable]
2031
public class LaunchApprovedExeBeginEventArgs : CancellableHResultEventArgs
2032
{
2033
- /// <summary>
2034
- ///
2035
- /// </summary>
2036
- /// <param name="cancelRecommendation"></param>
2033
+ /// <summary />
2034
public LaunchApprovedExeBeginEventArgs(bool cancelRecommendation)
2035
: base(cancelRecommendation)
2036
{
@@ -2046,27 +2043,18 @@ namespace WixToolset.Mba.Core
2043
[Serializable]
2044
public class LaunchApprovedExeCompleteEventArgs : StatusEventArgs
2045
{
2049
- private int processId;
2050
-
2051
- /// <summary>
2052
- ///
2053
- /// </summary>
2054
- /// <param name="hrStatus"></param>
2055
- /// <param name="processId"></param>
2046
+ /// <summary />
2047
public LaunchApprovedExeCompleteEventArgs(int hrStatus, int processId)
2048
: base(hrStatus)
2049
{
2059
- this.processId = processId;
2050
+ this.ProcessId = processId;
2051
}
2052
2053
/// <summary>
2054
/// Gets the ProcessId of the process that was launched.
2055
/// This is only valid if the status reports success.
2056
/// </summary>
2066
- public int ProcessId
2067
- {
2068
- get { return this.processId; }
2069
- }
2057
+ public int ProcessId { get; private set; }
2058
}
2059
2060
/// <summary>
@@ -2075,26 +2063,17 @@ namespace WixToolset.Mba.Core
2063
[Serializable]
2064
public class BeginMsiTransactionBeginEventArgs : CancellableHResultEventArgs
2065
{
2078
- private string transactionId;
2079
-
2080
- /// <summary>
2081
- ///
2082
- /// </summary>
2083
- /// <param name="transactionId"></param>
2084
- /// <param name="cancelRecommendation"></param>
2066
+ /// <summary />
2067
public BeginMsiTransactionBeginEventArgs(string transactionId, bool cancelRecommendation)
2068
: base(cancelRecommendation)
2069
{
2088
- this.transactionId = transactionId;
2070
+ this.TransactionId = transactionId;
2071
}
2072
2073
/// <summary>
2074
/// Gets the MSI transaction Id.
2075
/// </summary>
2094
- public string TransactionId
2095
- {
2096
- get { return this.transactionId; }
2097
- }
2076
+ public string TransactionId { get; private set; }
2077
}
2078
2079
/// <summary>
@@ -2103,26 +2082,17 @@ namespace WixToolset.Mba.Core
2082
[Serializable]
2083
public class BeginMsiTransactionCompleteEventArgs : StatusEventArgs
2084
{
2106
- private string transactionId;
2107
-
2108
- /// <summary>
2109
- ///
2110
- /// </summary>
2111
- /// <param name="transactionId"></param>
2112
- /// <param name="hrStatus"></param>
2085
+ /// <summary />
2086
public BeginMsiTransactionCompleteEventArgs(string transactionId, int hrStatus)
2087
: base(hrStatus)
2088
{
2116
- this.transactionId = transactionId;
2089
+ this.TransactionId = transactionId;
2090
}
2091
2092
/// <summary>
2093
/// Gets the MSI transaction Id.
2094
/// </summary>
2122
- public string TransactionId
2123
- {
2124
- get { return this.transactionId; }
2125
- }
2095
+ public string TransactionId { get; private set; }
2096
}
2097
2098
/// <summary>
@@ -2131,26 +2101,17 @@ namespace WixToolset.Mba.Core
2101
[Serializable]
2102
public class CommitMsiTransactionBeginEventArgs : CancellableHResultEventArgs
2103
{
2134
- private string transactionId;
2135
-
2136
- /// <summary>
2137
- ///
2138
- /// </summary>
2139
- /// <param name="transactionId"></param>
2140
- /// <param name="cancelRecommendation"></param>
2104
+ /// <summary />
2105
public CommitMsiTransactionBeginEventArgs(string transactionId, bool cancelRecommendation)
2106
: base(cancelRecommendation)
2107
{
2144
- this.transactionId = transactionId;
2108
+ this.TransactionId = transactionId;
2109
}
2110
2111
/// <summary>
2112
/// Gets the MSI transaction Id.
2113
/// </summary>
2150
- public string TransactionId
2151
- {
2152
- get { return this.transactionId; }
2153
- }
2114
+ public string TransactionId { get; private set; }
2115
}
2116
2117
/// <summary>
@@ -2159,26 +2120,17 @@ namespace WixToolset.Mba.Core
2120
[Serializable]
2121
public class CommitMsiTransactionCompleteEventArgs : StatusEventArgs
2122
{
2162
- private string transactionId;
2163
-
2164
- /// <summary>
2165
- ///
2166
- /// </summary>
2167
- /// <param name="transactionId"></param>
2168
- /// <param name="hrStatus"></param>
2123
+ /// <summary />
2124
public CommitMsiTransactionCompleteEventArgs(string transactionId, int hrStatus)
2125
: base(hrStatus)
2126
{
2172
- this.transactionId = transactionId;
2127
+ this.TransactionId = transactionId;
2128
}
2129
2130
/// <summary>
2131
/// Gets the MSI transaction Id.
2132
/// </summary>
2178
- public string TransactionId
2179
- {
2180
- get { return this.transactionId; }
2181
- }
2133
+ public string TransactionId { get; private set; }
2134
}
2135
2136
/// <summary>
@@ -2187,24 +2139,16 @@ namespace WixToolset.Mba.Core
2139
[Serializable]
2140
public class RollbackMsiTransactionBeginEventArgs : HResultEventArgs
2141
{
2190
- private string transactionId;
2191
-
2192
- /// <summary>
2193
- ///
2194
- /// </summary>
2195
- /// <param name="transactionId"></param>
2142
+ /// <summary />
2143
public RollbackMsiTransactionBeginEventArgs(string transactionId)
2144
{
2198
- this.transactionId = transactionId;
2145
+ this.TransactionId = transactionId;
2146
}
2147
2148
/// <summary>
2149
/// Gets the MSI transaction Id.
2150
/// </summary>
2204
- public string TransactionId
2205
- {
2206
- get { return this.transactionId; }
2207
- }
2151
+ public string TransactionId { get; private set; }
2152
}
2153
2154
/// <summary>
@@ -2213,26 +2157,17 @@ namespace WixToolset.Mba.Core
2157
[Serializable]
2158
public class RollbackMsiTransactionCompleteEventArgs : StatusEventArgs
2159
{
2216
- private string transactionId;
2217
-
2218
- /// <summary>
2219
- ///
2220
- /// </summary>
2221
- /// <param name="transactionId"></param>
2222
- /// <param name="hrStatus"></param>
2160
+ /// <summary />
2161
public RollbackMsiTransactionCompleteEventArgs(string transactionId, int hrStatus)
2162
: base(hrStatus)
2163
{
2226
- this.transactionId = transactionId;
2164
+ this.TransactionId = transactionId;
2165
}
2166
2167
/// <summary>
2168
/// Gets the MSI transaction Id.
2169
/// </summary>
2232
- public string TransactionId
2233
- {
2234
- get { return this.transactionId; }
2235
- }
2170
+ public string TransactionId { get; private set; }
2171
}
2172
2173
/// <summary>
@@ -2524,4 +2459,47 @@ namespace WixToolset.Mba.Core
2459
/// </summary>
2460
public BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION Action { get; set; }
2461
}
2462
+
2463
+ /// <summary>
2464
+ /// Event arguments for <see cref="IDefaultBootstrapperApplication.DetectRelatedBundlePackage"/>
2465
+ /// </summary>
2466
+ [Serializable]
2467
+ public class DetectRelatedBundlePackageEventArgs : CancellableHResultEventArgs
2468
+ {
2469
+ /// <summary />
2470
+ public DetectRelatedBundlePackageEventArgs(string packageId, string productCode, RelationType relationType, bool perMachine, string version, bool cancelRecommendation)
2471
+ : base(cancelRecommendation)
2472
+ {
2473
+ this.PackageId = packageId;
2474
+ this.ProductCode = productCode;
2475
+ this.RelationType = relationType;
2476
+ this.PerMachine = perMachine;
2477
+ this.Version = version;
2478
+ }
2479
+
2480
+ /// <summary>
2481
+ /// Gets the identity of the product's package detected.
2482
+ /// </summary>
2483
+ public string PackageId { get; private set; }
2484
+
2485
+ /// <summary>
2486
+ /// Gets the identity of the related bundle detected.
2487
+ /// </summary>
2488
+ public string ProductCode { get; private set; }
2489
+
2490
+ /// <summary>
2491
+ /// Gets the relationship type of the related bundle.
2492
+ /// </summary>
2493
+ public RelationType RelationType { get; private set; }
2494
+
2495
+ /// <summary>
2496
+ /// Gets whether the detected bundle is per machine.
2497
+ /// </summary>
2498
+ public bool PerMachine { get; private set; }
2499
+
2500
+ /// <summary>
2501
+ /// Gets the version of the related bundle detected.
2502
+ /// </summary>
2503
+ public string Version { get; private set; }
2504
+ }
2505
}
src/api/burn/WixToolset.Mba.Core/IBootstrapperApplication.cs
+14
@@ -1182,6 +1182,20 @@ namespace WixToolset.Mba.Core
1182
[MarshalAs(UnmanagedType.I4)] BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION recommendation,
1183
[MarshalAs(UnmanagedType.I4)] ref BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION pAction
1184
);
1185
+
1186
+ /// <summary>
1187
+ /// See <see cref="IDefaultBootstrapperApplication.DetectRelatedBundlePackage"/>.
1188
+ /// </summary>
1189
+ [PreserveSig]
1190
+ [return: MarshalAs(UnmanagedType.I4)]
1191
+ int OnDetectRelatedBundlePackage(
1192
+ [MarshalAs(UnmanagedType.LPWStr)] string wzPackageId,
1193
+ [MarshalAs(UnmanagedType.LPWStr)] string wzBundleId,
1194
+ [MarshalAs(UnmanagedType.U4)] RelationType relationType,
1195
+ [MarshalAs(UnmanagedType.Bool)] bool fPerMachine,
1196
+ [MarshalAs(UnmanagedType.LPWStr)] string wzVersion,
1197
+ [MarshalAs(UnmanagedType.Bool)] ref bool fCancel
1198
+ );
1199
}
1200
1201
/// <summary>
src/api/burn/WixToolset.Mba.Core/IDefaultBootstrapperApplication.cs
+9
-4
@@ -36,15 +36,15 @@ namespace WixToolset.Mba.Core
36
37
/// <summary>
38
/// Fired when the engine has begun acquiring the payload or container.
39
- /// The BA can change the source using <see cref="IEngine.SetLocalSource(string, string, string)"/>
40
- /// or <see cref="IEngine.SetDownloadSource(string, string, string, string, string)"/>.
39
+ /// The BA can change the source using <see cref="IEngine.SetLocalSource(String, String, String)"/>
40
+ /// or <see cref="IEngine.SetDownloadSource(String, String, String, String, String)"/>.
41
/// </summary>
42
event EventHandler<CacheAcquireBeginEventArgs> CacheAcquireBegin;
43
44
/// <summary>
45
/// Fired when the engine has completed the acquisition of the payload or container.
46
- /// The BA can change the source using <see cref="IEngine.SetLocalSource(string, string, string)"/>
47
- /// or <see cref="IEngine.SetDownloadSource(string, string, string, string, string)"/>.
46
+ /// The BA can change the source using <see cref="IEngine.SetLocalSource(String, String, String)"/>
47
+ /// or <see cref="IEngine.SetDownloadSource(String, String, String, String, String)"/>.
48
/// </summary>
49
event EventHandler<CacheAcquireCompleteEventArgs> CacheAcquireComplete;
50
@@ -178,6 +178,11 @@ namespace WixToolset.Mba.Core
178
/// </summary>
179
event EventHandler<DetectRelatedBundleEventArgs> DetectRelatedBundle;
180
181
+ /// <summary>
182
+ /// Fired when a related bundle has been detected for a bundle package.
183
+ /// </summary>
184
+ event EventHandler<DetectRelatedBundlePackageEventArgs> DetectRelatedBundlePackage;
185
+
186
/// <summary>
187
/// Fired when a related MSI package has been detected for a package.
188
/// </summary>
src/api/burn/WixToolset.Mba.Core/PackageInfo.cs
+13
-4
@@ -56,6 +56,11 @@ namespace WixToolset.Mba.Core
56
///
57
/// </summary>
58
UpdateBundle,
59
+
60
+ /// <summary>
61
+ ///
62
+ /// </summary>
63
+ ChainBundle,
64
}
65
66
/// <summary>
@@ -220,7 +225,11 @@ namespace WixToolset.Mba.Core
225
return null;
226
}
227
223
- if (attributeValue.Equals("Exe", StringComparison.InvariantCulture))
228
+ if (attributeValue.Equals("Bundle", StringComparison.InvariantCulture))
229
+ {
230
+ return PackageType.ChainBundle;
231
+ }
232
+ else if (attributeValue.Equals("Exe", StringComparison.InvariantCulture))
233
{
234
return PackageType.Exe;
235
}
@@ -268,7 +277,7 @@ namespace WixToolset.Mba.Core
277
package.Type = PackageType.UpgradeBundle;
278
break;
279
default:
271
- throw new Exception(string.Format("Unknown related bundle type: {0}", relationType));
280
+ throw new Exception(String.Format("Unknown related bundle type: {0}", relationType));
281
}
282
283
return package;
@@ -302,7 +311,7 @@ namespace WixToolset.Mba.Core
311
312
if (!packagesById.TryGetValue(id, out var ipackage))
313
{
305
- throw new Exception(string.Format("Failed to find package specified in WixBalPackageInfo: {0}", id));
314
+ throw new Exception(String.Format("Failed to find package specified in WixBalPackageInfo: {0}", id));
315
}
316
317
var package = (PackageInfo)ipackage;
@@ -322,7 +331,7 @@ namespace WixToolset.Mba.Core
331
332
if (!packagesById.TryGetValue(id, out var ipackage))
333
{
325
- throw new Exception(string.Format("Failed to find package specified in WixMbaPrereqInformation: {0}", id));
334
+ throw new Exception(String.Format("Failed to find package specified in WixMbaPrereqInformation: {0}", id));
335
}
336
337
var package = (PackageInfo)ipackage;
src/api/burn/balutil/balinfo.cpp
+5
-1
@@ -433,7 +433,11 @@ static HRESULT ParsePackagesFromXml(
433
hr = XmlGetAttributeEx(pNode, L"PackageType", &scz);
434
ExitOnFailure(hr, "Failed to get package type for package.");
435
436
- if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, L"Exe", -1, scz, -1))
436
+ if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, L"Bundle", -1, scz, -1))
437
+ {
438
+ prgPackages[iPackage].type = BAL_INFO_PACKAGE_TYPE_BUNDLE_CHAIN;
439
+ }
440
+ else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, L"Exe", -1, scz, -1))
441
{
442
prgPackages[iPackage].type = BAL_INFO_PACKAGE_TYPE_EXE;
443
}
src/api/burn/balutil/inc/BAFunctions.h
+1
@@ -92,6 +92,7 @@ enum BA_FUNCTIONS_MESSAGE
92
BA_FUNCTIONS_MESSAGE_ONPLANRELATEDBUNDLETYPE = BOOTSTRAPPER_APPLICATION_MESSAGE_ONPLANRELATEDBUNDLETYPE,
93
BA_FUNCTIONS_MESSAGE_ONAPPLYDOWNGRADE = BOOTSTRAPPER_APPLICATION_MESSAGE_ONAPPLYDOWNGRADE,
94
BA_FUNCTIONS_MESSAGE_ONEXECUTEPROCESSCANCEL = BOOTSTRAPPER_APPLICATION_MESSAGE_ONEXECUTEPROCESSCANCEL,
95
+ BA_FUNCTIONS_MESSAGE_ONDETECTRELATEDBUNDLEPACKAGE = BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTRELATEDBUNDLEPACKAGE,
96
97
BA_FUNCTIONS_MESSAGE_ONTHEMELOADED = 1024,
98
BA_FUNCTIONS_MESSAGE_WNDPROC,
src/api/burn/balutil/inc/BalBaseBAFunctions.h
+12
@@ -887,6 +887,18 @@ public: // IBootstrapperApplication
887
return S_OK;
888
}
889
890
+ virtual STDMETHODIMP OnDetectRelatedBundlePackage(
891
+ __in_z LPCWSTR /*wzPackageId*/,
892
+ __in_z LPCWSTR /*wzBundleId*/,
893
+ __in BOOTSTRAPPER_RELATION_TYPE /*relationType*/,
894
+ __in BOOL /*fPerMachine*/,
895
+ __in LPCWSTR /*wzVersion*/,
896
+ __inout BOOL* /*pfCancel*/
897
+ )
898
+ {
899
+ return S_OK;
900
+ }
901
+
902
public: // IBAFunctions
903
virtual STDMETHODIMP OnPlan(
904
)
src/api/burn/balutil/inc/BalBaseBAFunctionsProc.h
+1
@@ -163,6 +163,7 @@ static HRESULT WINAPI BalBaseBAFunctionsProc(
163
case BA_FUNCTIONS_MESSAGE_ONPLANRELATEDBUNDLETYPE:
164
case BA_FUNCTIONS_MESSAGE_ONAPPLYDOWNGRADE:
165
case BA_FUNCTIONS_MESSAGE_ONEXECUTEPROCESSCANCEL:
166
+ case BA_FUNCTIONS_MESSAGE_ONDETECTRELATEDBUNDLEPACKAGE:
167
hr = BalBaseBootstrapperApplicationProc((BOOTSTRAPPER_APPLICATION_MESSAGE)message, pvArgs, pvResults, pvContext);
168
break;
169
case BA_FUNCTIONS_MESSAGE_ONTHEMELOADED:
src/api/burn/balutil/inc/BalBaseBootstrapperApplication.h
+13
@@ -1087,6 +1087,19 @@ public: // IBootstrapperApplication
1087
return S_OK;
1088
}
1089
1090
+ virtual STDMETHODIMP OnDetectRelatedBundlePackage(
1091
+ __in_z LPCWSTR /*wzPackageId*/,
1092
+ __in_z LPCWSTR /*wzBundleId*/,
1093
+ __in BOOTSTRAPPER_RELATION_TYPE /*relationType*/,
1094
+ __in BOOL /*fPerMachine*/,
1095
+ __in LPCWSTR /*wzVersion*/,
1096
+ __inout BOOL* pfCancel
1097
+ )
1098
+ {
1099
+ *pfCancel |= CheckCanceled();
1100
+ return S_OK;
1101
+ }
1102
+
1103
public: //CBalBaseBootstrapperApplication
1104
virtual STDMETHODIMP Initialize(
1105
__in const BOOTSTRAPPER_CREATE_ARGS* pCreateArgs
src/api/burn/balutil/inc/BalBaseBootstrapperApplicationProc.h
+12
@@ -756,6 +756,15 @@ static HRESULT BalBaseBAProcOnApplyDowngrade(
756
return pBA->OnApplyDowngrade(pArgs->hrRecommended, &pResults->hrStatus);
757
}
758
759
+static HRESULT BalBaseBAProcOnDetectRelatedBundlePackage(
760
+ __in IBootstrapperApplication* pBA,
761
+ __in BA_ONDETECTRELATEDBUNDLEPACKAGE_ARGS* pArgs,
762
+ __inout BA_ONDETECTRELATEDBUNDLEPACKAGE_RESULTS* pResults
763
+ )
764
+{
765
+ return pBA->OnDetectRelatedBundlePackage(pArgs->wzPackageId, pArgs->wzBundleId, pArgs->relationType, pArgs->fPerMachine, pArgs->wzVersion, &pResults->fCancel);
766
+}
767
+
768
/*******************************************************************
769
BalBaseBootstrapperApplicationProc - requires pvContext to be of type IBootstrapperApplication.
770
Provides a default mapping between the new message based BA interface and
@@ -1024,6 +1033,9 @@ static HRESULT WINAPI BalBaseBootstrapperApplicationProc(
1033
case BOOTSTRAPPER_APPLICATION_MESSAGE_ONEXECUTEPROCESSCANCEL:
1034
hr = BalBaseBAProcOnExecuteProcessCancel(pBA, reinterpret_cast<BA_ONEXECUTEPROCESSCANCEL_ARGS*>(pvArgs), reinterpret_cast<BA_ONEXECUTEPROCESSCANCEL_RESULTS*>(pvResults));
1035
break;
1036
+ case BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTRELATEDBUNDLEPACKAGE:
1037
+ hr = BalBaseBAProcOnDetectRelatedBundlePackage(pBA, reinterpret_cast<BA_ONDETECTRELATEDBUNDLEPACKAGE_ARGS*>(pvArgs), reinterpret_cast<BA_ONDETECTRELATEDBUNDLEPACKAGE_RESULTS*>(pvResults));
1038
+ break;
1039
}
1040
}
1041
src/api/burn/balutil/inc/IBootstrapperApplication.h
+10
@@ -723,4 +723,14 @@ DECLARE_INTERFACE_IID_(IBootstrapperApplication, IUnknown, "53C31D56-49C0-426B-A
723
__in BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION recommendation,
724
__inout BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION* pAction
725
) = 0;
726
+
727
+ // OnDetectRelatedBundlePackage - called when the engine detects a related bundle for a BundlePackage.
728
+ STDMETHOD(OnDetectRelatedBundlePackage)(
729
+ __in_z LPCWSTR wzPackageId,
730
+ __in_z LPCWSTR wzBundleId,
731
+ __in BOOTSTRAPPER_RELATION_TYPE relationType,
732
+ __in BOOL fPerMachine,
733
+ __in_z LPCWSTR wzVersion,
734
+ __inout BOOL* pfCancel
735
+ ) = 0;
736
};
src/api/burn/balutil/inc/balinfo.h
+1
@@ -17,6 +17,7 @@ typedef enum BAL_INFO_PACKAGE_TYPE
17
BAL_INFO_PACKAGE_TYPE_BUNDLE_ADDON,
18
BAL_INFO_PACKAGE_TYPE_BUNDLE_PATCH,
19
BAL_INFO_PACKAGE_TYPE_BUNDLE_UPDATE,
20
+ BAL_INFO_PACKAGE_TYPE_BUNDLE_CHAIN,
21
} BAL_INFO_PACKAGE_TYPE;
22
23
typedef enum _BAL_INFO_RESTART
src/api/wix/WixToolset.Data/Symbols/SymbolDefinitions.cs
+4
@@ -142,6 +142,7 @@ namespace WixToolset.Data
142
WixBundlePackageCommandLine,
143
WixBundlePackageExitCode,
144
WixBundlePackageGroup,
145
+ WixBundlePackageRelatedBundle,
146
WixBundlePatchTargetCode,
147
WixBundlePayload,
148
WixBundlePayloadGroup,
@@ -618,6 +619,9 @@ namespace WixToolset.Data
619
case SymbolDefinitionType.WixBundlePackageGroup:
620
return SymbolDefinitions.WixBundlePackageGroup;
621
622
+ case SymbolDefinitionType.WixBundlePackageRelatedBundle:
623
+ return SymbolDefinitions.WixBundlePackageRelatedBundle;
624
+
625
case SymbolDefinitionType.WixBundlePatchTargetCode:
626
return SymbolDefinitions.WixBundlePatchTargetCode;
627
src/api/wix/WixToolset.Data/Symbols/WixBundleBundlePackageSymbol.cs
+8
@@ -12,6 +12,7 @@ namespace WixToolset.Data
12
{
13
new IntermediateFieldDefinition(nameof(WixBundleBundlePackageSymbolFields.Attributes), IntermediateFieldType.Number),
14
new IntermediateFieldDefinition(nameof(WixBundleBundlePackageSymbolFields.BundleId), IntermediateFieldType.String),
15
+ new IntermediateFieldDefinition(nameof(WixBundleBundlePackageSymbolFields.Version), IntermediateFieldType.String),
16
new IntermediateFieldDefinition(nameof(WixBundleBundlePackageSymbolFields.InstallCommand), IntermediateFieldType.String),
17
new IntermediateFieldDefinition(nameof(WixBundleBundlePackageSymbolFields.RepairCommand), IntermediateFieldType.String),
18
new IntermediateFieldDefinition(nameof(WixBundleBundlePackageSymbolFields.UninstallCommand), IntermediateFieldType.String),
@@ -28,6 +29,7 @@ namespace WixToolset.Data.Symbols
29
{
30
Attributes,
31
BundleId,
32
+ Version,
33
InstallCommand,
34
RepairCommand,
35
UninstallCommand,
@@ -65,6 +67,12 @@ namespace WixToolset.Data.Symbols
67
set => this.Set((int)WixBundleBundlePackageSymbolFields.BundleId, value);
68
}
69
70
+ public string Version
71
+ {
72
+ get => (string)this.Fields[(int)WixBundleBundlePackageSymbolFields.Version];
73
+ set => this.Set((int)WixBundleBundlePackageSymbolFields.Version, value);
74
+ }
75
+
76
public string InstallCommand
77
{
78
get => (string)this.Fields[(int)WixBundleBundlePackageSymbolFields.InstallCommand];
src/api/wix/WixToolset.Data/Symbols/WixBundlePackageRelatedBundleSymbol.cs
new
+60
@@ -0,0 +1,60 @@
1
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
+
3
+namespace WixToolset.Data
4
+{
5
+ using WixToolset.Data.Symbols;
6
+
7
+ public static partial class SymbolDefinitions
8
+ {
9
+ public static readonly IntermediateSymbolDefinition WixBundlePackageRelatedBundle = new IntermediateSymbolDefinition(
10
+ SymbolDefinitionType.WixBundlePackageRelatedBundle,
11
+ new[]
12
+ {
13
+ new IntermediateFieldDefinition(nameof(WixBundlePackageRelatedBundleSymbolFields.PackageRef), IntermediateFieldType.String),
14
+ new IntermediateFieldDefinition(nameof(WixBundlePackageRelatedBundleSymbolFields.BundleId), IntermediateFieldType.String),
15
+ new IntermediateFieldDefinition(nameof(WixBundlePackageRelatedBundleSymbolFields.Action), IntermediateFieldType.Number),
16
+ },
17
+ typeof(WixBundlePackageRelatedBundleSymbol));
18
+ }
19
+}
20
+
21
+namespace WixToolset.Data.Symbols
22
+{
23
+ public enum WixBundlePackageRelatedBundleSymbolFields
24
+ {
25
+ PackageRef,
26
+ BundleId,
27
+ Action,
28
+ }
29
+
30
+ public class WixBundlePackageRelatedBundleSymbol : IntermediateSymbol
31
+ {
32
+ public WixBundlePackageRelatedBundleSymbol() : base(SymbolDefinitions.WixBundlePackageRelatedBundle, null, null)
33
+ {
34
+ }
35
+
36
+ public WixBundlePackageRelatedBundleSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(SymbolDefinitions.WixBundlePackageRelatedBundle, sourceLineNumber, id)
37
+ {
38
+ }
39
+
40
+ public IntermediateField this[WixBundlePackageRelatedBundleSymbolFields index] => this.Fields[(int)index];
41
+
42
+ public string PackageRef
43
+ {
44
+ get => (string)this.Fields[(int)WixBundlePackageRelatedBundleSymbolFields.PackageRef];
45
+ set => this.Set((int)WixBundlePackageRelatedBundleSymbolFields.PackageRef, value);
46
+ }
47
+
48
+ public string BundleId
49
+ {
50
+ get => (string)this.Fields[(int)WixBundlePackageRelatedBundleSymbolFields.BundleId];
51
+ set => this.Set((int)WixBundlePackageRelatedBundleSymbolFields.BundleId, value);
52
+ }
53
+
54
+ public RelatedBundleActionType Action
55
+ {
56
+ get => (RelatedBundleActionType)this.Fields[(int)WixBundlePackageRelatedBundleSymbolFields.Action].AsNumber();
57
+ set => this.Set((int)WixBundlePackageRelatedBundleSymbolFields.Action, (int)value);
58
+ }
59
+ }
60
+}
src/burn/engine/bundlepackageengine.cpp
+254
-23
@@ -2,6 +2,18 @@
2
3
#include "precomp.h"
4
5
+typedef struct _BUNDLE_QUERY_CONTEXT
6
+{
7
+ BURN_PACKAGE* pPackage;
8
+ BURN_USER_EXPERIENCE* pUserExperience;
9
+ BOOL fSelfFound;
10
+ BOOL fNewerFound;
11
+} BUNDLE_QUERY_CONTEXT;
12
+
13
+static BUNDLE_QUERY_CALLBACK_RESULT CALLBACK QueryRelatedBundlesCallback(
14
+ __in const BUNDLE_QUERY_RELATED_BUNDLE_RESULT* pBundle,
15
+ __in_opt LPVOID pvContext
16
+ );
17
static HRESULT ExecuteBundle(
18
__in BURN_CACHE* pCache,
19
__in BURN_VARIABLES* pVariables,
@@ -35,6 +47,18 @@ extern "C" HRESULT BundlePackageEngineParsePackageFromXml(
47
hr = XmlGetAttributeEx(pixnBundlePackage, L"BundleId", &pPackage->Bundle.sczBundleId);
48
ExitOnRequiredXmlQueryFailure(hr, "Failed to get @BundleId.");
49
50
+ // @Version
51
+ hr = XmlGetAttributeEx(pixnBundlePackage, L"Version", &scz);
52
+ ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Version.");
53
+
54
+ hr = VerParseVersion(scz, 0, FALSE, &pPackage->Bundle.pVersion);
55
+ ExitOnFailure(hr, "Failed to parse @Version: %ls", scz);
56
+
57
+ if (pPackage->Bundle.pVersion->fInvalid)
58
+ {
59
+ LogId(REPORT_WARNING, MSG_MANIFEST_INVALID_VERSION, scz);
60
+ }
61
+
62
// @InstallArguments
63
hr = XmlGetAttributeEx(pixnBundlePackage, L"InstallArguments", &pPackage->Bundle.sczInstallArguments);
64
ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @InstallArguments.");
@@ -55,6 +79,9 @@ extern "C" HRESULT BundlePackageEngineParsePackageFromXml(
79
hr = XmlGetYesNoAttribute(pixnBundlePackage, L"Win64", &pPackage->Bundle.fWin64);
80
ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Win64.");
81
82
+ hr = BundlePackageEngineParseRelatedCodes(pixnBundlePackage, &pPackage->Bundle.rgsczDetectCodes, &pPackage->Bundle.cDetectCodes, &pPackage->Bundle.rgsczUpgradeCodes, &pPackage->Bundle.cUpgradeCodes, &pPackage->Bundle.rgsczAddonCodes, &pPackage->Bundle.cAddonCodes, &pPackage->Bundle.rgsczPatchCodes, &pPackage->Bundle.cPatchCodes);
83
+ ExitOnFailure(hr, "Failed to parse related codes.");
84
+
85
hr = ExeEngineParseExitCodesFromXml(pixnBundlePackage, &pPackage->Bundle.rgExitCodes, &pPackage->Bundle.cExitCodes);
86
ExitOnFailure(hr, "Failed to parse exit codes.");
87
@@ -70,11 +97,101 @@ LExit:
97
return hr;
98
}
99
100
+
101
+extern "C" HRESULT BundlePackageEngineParseRelatedCodes(
102
+ __in IXMLDOMNode* pixnBundle,
103
+ __in LPWSTR** prgsczDetectCodes,
104
+ __in DWORD* pcDetectCodes,
105
+ __in LPWSTR** prgsczUpgradeCodes,
106
+ __in DWORD* pcUpgradeCodes,
107
+ __in LPWSTR** prgsczAddonCodes,
108
+ __in DWORD* pcAddonCodes,
109
+ __in LPWSTR** prgsczPatchCodes,
110
+ __in DWORD* pcPatchCodes
111
+ )
112
+{
113
+ HRESULT hr = S_OK;
114
+ IXMLDOMNodeList* pixnNodes = NULL;
115
+ IXMLDOMNode* pixnElement = NULL;
116
+ LPWSTR sczAction = NULL;
117
+ LPWSTR sczId = NULL;
118
+ DWORD cElements = 0;
119
+
120
+ hr = XmlSelectNodes(pixnBundle, L"RelatedBundle", &pixnNodes);
121
+ ExitOnFailure(hr, "Failed to get RelatedBundle nodes");
122
+
123
+ hr = pixnNodes->get_length((long*)&cElements);
124
+ ExitOnFailure(hr, "Failed to get RelatedBundle element count.");
125
+
126
+ for (DWORD i = 0; i < cElements; ++i)
127
+ {
128
+ hr = XmlNextElement(pixnNodes, &pixnElement, NULL);
129
+ ExitOnFailure(hr, "Failed to get next RelatedBundle element.");
130
+
131
+ hr = XmlGetAttributeEx(pixnElement, L"Action", &sczAction);
132
+ ExitOnFailure(hr, "Failed to get @Action.");
133
+
134
+ hr = XmlGetAttributeEx(pixnElement, L"Id", &sczId);
135
+ ExitOnFailure(hr, "Failed to get @Id.");
136
+
137
+ if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Detect", -1))
138
+ {
139
+ hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczDetectCodes), *pcDetectCodes, 1, sizeof(LPWSTR), 5);
140
+ ExitOnFailure(hr, "Failed to resize Detect code array");
141
+
142
+ *prgsczDetectCodes[*pcDetectCodes] = sczId;
143
+ sczId = NULL;
144
+ *pcDetectCodes += 1;
145
+ }
146
+ else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Upgrade", -1))
147
+ {
148
+ hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczUpgradeCodes), *pcUpgradeCodes, 1, sizeof(LPWSTR), 5);
149
+ ExitOnFailure(hr, "Failed to resize Upgrade code array");
150
+
151
+ *prgsczUpgradeCodes[*pcUpgradeCodes] = sczId;
152
+ sczId = NULL;
153
+ *pcUpgradeCodes += 1;
154
+ }
155
+ else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Addon", -1))
156
+ {
157
+ hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczAddonCodes), *pcAddonCodes, 1, sizeof(LPWSTR), 5);
158
+ ExitOnFailure(hr, "Failed to resize Addon code array");
159
+
160
+ *prgsczAddonCodes[*pcAddonCodes] = sczId;
161
+ sczId = NULL;
162
+ *pcAddonCodes += 1;
163
+ }
164
+ else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Patch", -1))
165
+ {
166
+ hr = MemEnsureArraySizeForNewItems(reinterpret_cast<LPVOID*>(prgsczPatchCodes), *pcPatchCodes, 1, sizeof(LPWSTR), 5);
167
+ ExitOnFailure(hr, "Failed to resize Patch code array");
168
+
169
+ *prgsczPatchCodes[*pcPatchCodes] = sczId;
170
+ sczId = NULL;
171
+ *pcPatchCodes += 1;
172
+ }
173
+ else
174
+ {
175
+ hr = E_INVALIDARG;
176
+ ExitOnFailure(hr, "Invalid value for @Action: %ls", sczAction);
177
+ }
178
+ }
179
+
180
+LExit:
181
+ ReleaseObject(pixnNodes);
182
+ ReleaseObject(pixnElement);
183
+ ReleaseStr(sczAction);
184
+ ReleaseStr(sczId);
185
+
186
+ return hr;
187
+}
188
+
189
extern "C" void BundlePackageEnginePackageUninitialize(
190
__in BURN_PACKAGE* pPackage
191
)
192
{
193
ReleaseStr(pPackage->Bundle.sczBundleId);
194
+ ReleaseVerutilVersion(pPackage->Bundle.pVersion);
195
ReleaseStr(pPackage->Bundle.sczRegistrationKey);
196
ReleaseStr(pPackage->Bundle.sczInstallArguments);
197
ReleaseStr(pPackage->Bundle.sczRepairArguments);
@@ -92,45 +209,95 @@ extern "C" void BundlePackageEnginePackageUninitialize(
209
MemFree(pPackage->Bundle.rgCommandLineArguments);
210
}
211
212
+ for (DWORD i = 0; i < pPackage->Bundle.cDetectCodes; ++i)
213
+ {
214
+ ReleaseStr(pPackage->Bundle.rgsczDetectCodes[i]);
215
+ }
216
+ ReleaseMem(pPackage->Bundle.rgsczDetectCodes);
217
+
218
+ for (DWORD i = 0; i < pPackage->Bundle.cUpgradeCodes; ++i)
219
+ {
220
+ ReleaseStr(pPackage->Bundle.rgsczUpgradeCodes[i]);
221
+ }
222
+ ReleaseMem(pPackage->Bundle.rgsczUpgradeCodes);
223
+
224
+ for (DWORD i = 0; i < pPackage->Bundle.cAddonCodes; ++i)
225
+ {
226
+ ReleaseStr(pPackage->Bundle.rgsczAddonCodes[i]);
227
+ }
228
+ ReleaseMem(pPackage->Bundle.rgsczAddonCodes);
229
+
230
+ for (DWORD i = 0; i < pPackage->Bundle.cPatchCodes; ++i)
231
+ {
232
+ ReleaseStr(pPackage->Bundle.rgsczPatchCodes[i]);
233
+ }
234
+ ReleaseMem(pPackage->Bundle.rgsczPatchCodes);
235
+
236
// clear struct
237
memset(&pPackage->Bundle, 0, sizeof(pPackage->Bundle));
238
}
239
240
extern "C" HRESULT BundlePackageEngineDetectPackage(
100
- __in BURN_PACKAGE* pPackage
241
+ __in BURN_PACKAGE* pPackage,
242
+ __in BURN_REGISTRATION* /*pRegistration*/,
243
+ __in BURN_USER_EXPERIENCE* pUserExperience
244
)
245
{
246
HRESULT hr = S_OK;
104
- HKEY hkRegistration = NULL;
105
- DWORD dwInstalled = 0;
106
- BOOL fDetected = FALSE;
107
- HKEY hkRoot = pPackage->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
108
- REG_KEY_BITNESS bitness = pPackage->Bundle.fWin64 ? REG_KEY_64BIT : REG_KEY_32BIT;
109
-
110
- // TODO: detect all related bundles, so that the Obsolete state can be detected.
111
- hr = RegOpenEx(hkRoot, pPackage->Bundle.sczRegistrationKey, KEY_QUERY_VALUE, bitness, &hkRegistration);
112
- if (SUCCEEDED(hr))
247
+ BUNDLE_QUERY_CONTEXT queryContext = { };
248
+
249
+ queryContext.pPackage = pPackage;
250
+ queryContext.pUserExperience = pUserExperience;
251
+
252
+ hr = BundleQueryRelatedBundles(
253
+ BUNDLE_INSTALL_CONTEXT_MACHINE,
254
+ const_cast<LPCWSTR*>(pPackage->Bundle.rgsczDetectCodes),
255
+ pPackage->Bundle.cDetectCodes,
256
+ const_cast<LPCWSTR*>(pPackage->Bundle.rgsczUpgradeCodes),
257
+ pPackage->Bundle.cUpgradeCodes,
258
+ const_cast<LPCWSTR*>(pPackage->Bundle.rgsczAddonCodes),
259
+ pPackage->Bundle.cAddonCodes,
260
+ const_cast<LPCWSTR*>(pPackage->Bundle.rgsczPatchCodes),
261
+ pPackage->Bundle.cPatchCodes,
262
+ QueryRelatedBundlesCallback,
263
+ &queryContext);
264
+ ExitOnFailure(hr, "Failed to query per-machine related bundle packages.");
265
+
266
+ hr = BundleQueryRelatedBundles(
267
+ BUNDLE_INSTALL_CONTEXT_USER,
268
+ const_cast<LPCWSTR*>(pPackage->Bundle.rgsczDetectCodes),
269
+ pPackage->Bundle.cDetectCodes,
270
+ const_cast<LPCWSTR*>(pPackage->Bundle.rgsczUpgradeCodes),
271
+ pPackage->Bundle.cUpgradeCodes,
272
+ const_cast<LPCWSTR*>(pPackage->Bundle.rgsczAddonCodes),
273
+ pPackage->Bundle.cAddonCodes,
274
+ const_cast<LPCWSTR*>(pPackage->Bundle.rgsczPatchCodes),
275
+ pPackage->Bundle.cPatchCodes,
276
+ QueryRelatedBundlesCallback,
277
+ &queryContext);
278
+ ExitOnFailure(hr, "Failed to query per-user related bundle packages.");
279
+
280
+ if (queryContext.fNewerFound)
281
{
114
- hr = RegReadNumber(hkRegistration, REGISTRY_BUNDLE_INSTALLED, &dwInstalled);
282
+ pPackage->currentState = queryContext.fSelfFound ? BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED : BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE;
283
}
116
-
117
- // Not finding the key or value is okay.
118
- if (E_FILENOTFOUND == hr || E_PATHNOTFOUND == hr)
284
+ else
285
{
120
- hr = S_OK;
286
+ pPackage->currentState = queryContext.fSelfFound ? BOOTSTRAPPER_PACKAGE_STATE_PRESENT : BOOTSTRAPPER_PACKAGE_STATE_ABSENT;
287
}
288
123
- fDetected = (1 == dwInstalled);
124
-
125
- // update detect state
126
- pPackage->currentState = fDetected ? BOOTSTRAPPER_PACKAGE_STATE_PRESENT : BOOTSTRAPPER_PACKAGE_STATE_ABSENT;
127
-
289
if (pPackage->fCanAffectRegistration)
290
{
291
pPackage->installRegistrationState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT < pPackage->currentState ? BURN_PACKAGE_REGISTRATION_STATE_PRESENT : BURN_PACKAGE_REGISTRATION_STATE_ABSENT;
292
}
293
133
- ReleaseRegKey(hkRegistration);
294
+ // TODO: The bundle is registering itself as a dependent when installed as a chain package, which prevents us from uninstalling it.
295
+ //hr = DependencyDetectChainPackage(pPackage, pRegistration);
296
+ //ExitOnFailure(hr, "Failed to detect dependencies for BUNDLE package.");
297
+
298
+ // TODO: uninstalling compatible Bundles like MsiEngine supports?
299
+
300
+LExit:
301
return hr;
302
}
303
@@ -148,7 +315,8 @@ extern "C" HRESULT BundlePackageEnginePlanCalculatePackage(
315
// execute action
316
switch (pPackage->currentState)
317
{
151
- case BOOTSTRAPPER_PACKAGE_STATE_PRESENT:
318
+ case BOOTSTRAPPER_PACKAGE_STATE_PRESENT: __fallthrough;
319
+ case BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED:
320
switch (pPackage->requested)
321
{
322
case BOOTSTRAPPER_REQUEST_STATE_PRESENT:
@@ -173,6 +341,7 @@ extern "C" HRESULT BundlePackageEnginePlanCalculatePackage(
341
}
342
break;
343
344
+ case BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE: __fallthrough;
345
case BOOTSTRAPPER_PACKAGE_STATE_ABSENT:
346
switch (pPackage->requested)
347
{
@@ -200,7 +369,8 @@ extern "C" HRESULT BundlePackageEnginePlanCalculatePackage(
369
{
370
switch (pPackage->currentState)
371
{
203
- case BOOTSTRAPPER_PACKAGE_STATE_PRESENT:
372
+ case BOOTSTRAPPER_PACKAGE_STATE_PRESENT: __fallthrough;
373
+ case BOOTSTRAPPER_PACKAGE_STATE_SUPERSEDED:
374
switch (pPackage->requested)
375
{
376
case BOOTSTRAPPER_REQUEST_STATE_PRESENT: __fallthrough;
@@ -218,6 +388,7 @@ extern "C" HRESULT BundlePackageEnginePlanCalculatePackage(
388
}
389
break;
390
391
+ case BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE: __fallthrough;
392
case BOOTSTRAPPER_PACKAGE_STATE_ABSENT:
393
switch (pPackage->requested)
394
{
@@ -481,6 +652,66 @@ LExit:
652
return;
653
}
654
655
+static BUNDLE_QUERY_CALLBACK_RESULT CALLBACK QueryRelatedBundlesCallback(
656
+ __in const BUNDLE_QUERY_RELATED_BUNDLE_RESULT* pBundle,
657
+ __in_opt LPVOID pvContext
658
+ )
659
+{
660
+ HRESULT hr = S_OK;
661
+ BUNDLE_QUERY_CALLBACK_RESULT result = BUNDLE_QUERY_CALLBACK_RESULT_CONTINUE;
662
+ LPWSTR sczBundleVersion = NULL;
663
+ VERUTIL_VERSION* pVersion = NULL;
664
+ int nCompare = 0;
665
+ BUNDLE_QUERY_CONTEXT* pContext = reinterpret_cast<BUNDLE_QUERY_CONTEXT*>(pvContext);
666
+ BURN_PACKAGE* pPackage = pContext->pPackage;
667
+ BOOTSTRAPPER_RELATION_TYPE relationType = RelatedBundleConvertRelationType(pBundle->relationType);
668
+ BOOL fPerMachine = BUNDLE_INSTALL_CONTEXT_MACHINE == pBundle->installContext;
669
+
670
+ if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, pBundle->wzBundleId, -1, pPackage->Bundle.sczBundleId, -1))
671
+ {
672
+ Assert(BOOTSTRAPPER_RELATION_UPGRADE == relationType);
673
+ Assert(pPackage->Bundle.fWin64 == (REG_KEY_64BIT == pBundle->regBitness));
674
+
675
+ pContext->fSelfFound = TRUE;
676
+ }
677
+
678
+ hr = RegReadString(pBundle->hkBundle, BURN_REGISTRATION_REGISTRY_BUNDLE_VERSION, &sczBundleVersion);
679
+ ExitOnFailure(hr, "Failed to read version from registry for related bundle package: %ls", pBundle->wzBundleId);
680
+
681
+ hr = VerParseVersion(sczBundleVersion, 0, FALSE, &pVersion);
682
+ ExitOnFailure(hr, "Failed to parse related bundle package version: %ls", sczBundleVersion);
683
+
684
+ if (pVersion->fInvalid)
685
+ {
686
+ LogId(REPORT_WARNING, MSG_RELATED_PACKAGE_INVALID_VERSION, pBundle->wzBundleId, sczBundleVersion);
687
+ }
688
+
689
+ if (BOOTSTRAPPER_RELATION_UPGRADE == relationType)
690
+ {
691
+ hr = VerCompareParsedVersions(pPackage->Bundle.pVersion, pVersion, &nCompare);
692
+ ExitOnFailure(hr, "Failed to compare related bundle package version: %ls", pVersion->sczVersion);
693
+
694
+ if (nCompare < 0)
695
+ {
696
+ pContext->fNewerFound = TRUE;
697
+ }
698
+ }
699
+
700
+ result = BUNDLE_QUERY_CALLBACK_RESULT_CANCEL;
701
+
702
+ // Pass to BA.
703
+ hr = UserExperienceOnDetectRelatedBundlePackage(pContext->pUserExperience, pPackage->sczId, pBundle->wzBundleId, relationType, fPerMachine, pVersion);
704
+ ExitOnRootFailure(hr, "BA aborted detect related BUNDLE package.");
705
+
706
+ result = BUNDLE_QUERY_CALLBACK_RESULT_CONTINUE;
707
+
708
+LExit:
709
+ ReleaseVerutilVersion(pVersion);
710
+ ReleaseStr(sczBundleVersion);
711
+
712
+ return result;
713
+}
714
+
715
static HRESULT ExecuteBundle(
716
__in BURN_CACHE* pCache,
717
__in BURN_VARIABLES* pVariables,
src/burn/engine/bundlepackageengine.h
+14
-1
@@ -13,11 +13,24 @@ HRESULT BundlePackageEngineParsePackageFromXml(
13
__in IXMLDOMNode* pixnBundlePackage,
14
__in BURN_PACKAGE* pPackage
15
);
16
+HRESULT BundlePackageEngineParseRelatedCodes(
17
+ __in IXMLDOMNode* pixnBundle,
18
+ __in LPWSTR** prgsczDetectCodes,
19
+ __in DWORD* pcDetectCodes,
20
+ __in LPWSTR** prgsczUpgradeCodes,
21
+ __in DWORD* pcUpgradeCodes,
22
+ __in LPWSTR** prgsczAddonCodes,
23
+ __in DWORD* pcAddonCodes,
24
+ __in LPWSTR** prgsczPatchCodes,
25
+ __in DWORD* pcPatchCodes
26
+ );
27
void BundlePackageEnginePackageUninitialize(
28
__in BURN_PACKAGE* pPackage
29
);
30
HRESULT BundlePackageEngineDetectPackage(
20
- __in BURN_PACKAGE* pPackage
31
+ __in BURN_PACKAGE* pPackage,
32
+ __in BURN_REGISTRATION* pRegistration,
33
+ __in BURN_USER_EXPERIENCE* pUserExperience
34
);
35
HRESULT BundlePackageEnginePlanCalculatePackage(
36
__in BURN_PACKAGE* pPackage
src/burn/engine/core.cpp
+1
-1
@@ -2121,7 +2121,7 @@ static HRESULT DetectPackage(
2121
switch (pPackage->type)
2122
{
2123
case BURN_PACKAGE_TYPE_BUNDLE:
2124
- hr = BundlePackageEngineDetectPackage(pPackage);
2124
+ hr = BundlePackageEngineDetectPackage(pPackage, &pEngineState->registration, &pEngineState->userExperience);
2125
break;
2126
2127
case BURN_PACKAGE_TYPE_EXE:
src/burn/engine/package.h
+16
-3
@@ -303,14 +303,23 @@ typedef struct _BURN_PACKAGE
303
struct
304
{
305
LPWSTR sczBundleId;
306
+ VERUTIL_VERSION* pVersion;
307
LPWSTR sczRegistrationKey;
308
LPWSTR sczInstallArguments;
309
LPWSTR sczRepairArguments;
310
LPWSTR sczUninstallArguments;
311
311
- LPWSTR sczIgnoreDependencies;
312
- LPCWSTR wzAncestors; // points directly into engine state.
313
- LPCWSTR wzEngineWorkingDirectory; // points directly into engine state.
312
+ LPWSTR* rgsczDetectCodes;
313
+ DWORD cDetectCodes;
314
+
315
+ LPWSTR* rgsczUpgradeCodes;
316
+ DWORD cUpgradeCodes;
317
+
318
+ LPWSTR* rgsczAddonCodes;
319
+ DWORD cAddonCodes;
320
+
321
+ LPWSTR* rgsczPatchCodes;
322
+ DWORD cPatchCodes;
323
324
BOOL fWin64;
325
BOOL fSupportsBurnProtocol;
@@ -320,6 +329,10 @@ typedef struct _BURN_PACKAGE
329
330
BURN_EXE_COMMAND_LINE_ARGUMENT* rgCommandLineArguments;
331
DWORD cCommandLineArguments;
332
+
333
+ LPWSTR sczIgnoreDependencies;
334
+ LPCWSTR wzAncestors; // points directly into engine state.
335
+ LPCWSTR wzEngineWorkingDirectory; // points directly into engine state.
336
} Bundle;
337
struct
338
{
src/burn/engine/registration.cpp
+1
-86
@@ -71,10 +71,6 @@ static HRESULT UpdateResumeMode(
71
__in BOOTSTRAPPER_REGISTRATION_TYPE registrationType,
72
__in BOOL fRestartInitiated
73
);
74
-static HRESULT ParseRelatedCodes(
75
- __in BURN_REGISTRATION* pRegistration,
76
- __in IXMLDOMNode* pixnBundle
77
- );
74
static HRESULT FormatUpdateRegistrationKey(
75
__in BURN_REGISTRATION* pRegistration,
76
__out_z LPWSTR* psczKey
@@ -143,7 +139,7 @@ extern "C" HRESULT RegistrationParseFromXml(
139
hr = XmlGetAttributeEx(pixnRegistrationNode, L"Tag", &pRegistration->sczTag);
140
ExitOnFailure(hr, "Failed to get @Tag.");
141
146
- hr = ParseRelatedCodes(pRegistration, pixnBundle);
142
+ hr = BundlePackageEngineParseRelatedCodes(pixnBundle, &pRegistration->rgsczDetectCodes, &pRegistration->cDetectCodes, &pRegistration->rgsczUpgradeCodes, &pRegistration->cUpgradeCodes, &pRegistration->rgsczAddonCodes, &pRegistration->cAddonCodes, &pRegistration->rgsczPatchCodes, &pRegistration->cPatchCodes);
143
ExitOnFailure(hr, "Failed to parse related bundles");
144
145
// @Version
@@ -1395,87 +1391,6 @@ LExit:
1391
return hr;
1392
}
1393
1398
-static HRESULT ParseRelatedCodes(
1399
- __in BURN_REGISTRATION* pRegistration,
1400
- __in IXMLDOMNode* pixnBundle
1401
- )
1402
-{
1403
- HRESULT hr = S_OK;
1404
- IXMLDOMNodeList* pixnNodes = NULL;
1405
- IXMLDOMNode* pixnElement = NULL;
1406
- LPWSTR sczAction = NULL;
1407
- LPWSTR sczId = NULL;
1408
- DWORD cElements = 0;
1409
-
1410
- hr = XmlSelectNodes(pixnBundle, L"RelatedBundle", &pixnNodes);
1411
- ExitOnFailure(hr, "Failed to get RelatedBundle nodes");
1412
-
1413
- hr = pixnNodes->get_length((long*)&cElements);
1414
- ExitOnFailure(hr, "Failed to get RelatedBundle element count.");
1415
-
1416
- for (DWORD i = 0; i < cElements; ++i)
1417
- {
1418
- hr = XmlNextElement(pixnNodes, &pixnElement, NULL);
1419
- ExitOnFailure(hr, "Failed to get next RelatedBundle element.");
1420
-
1421
- hr = XmlGetAttributeEx(pixnElement, L"Action", &sczAction);
1422
- ExitOnFailure(hr, "Failed to get @Action.");
1423
-
1424
- hr = XmlGetAttributeEx(pixnElement, L"Id", &sczId);
1425
- ExitOnFailure(hr, "Failed to get @Id.");
1426
-
1427
- if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Detect", -1))
1428
- {
1429
- hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pRegistration->rgsczDetectCodes), pRegistration->cDetectCodes + 1, sizeof(LPWSTR), 5);
1430
- ExitOnFailure(hr, "Failed to resize Detect code array in registration");
1431
-
1432
- pRegistration->rgsczDetectCodes[pRegistration->cDetectCodes] = sczId;
1433
- sczId = NULL;
1434
- ++pRegistration->cDetectCodes;
1435
- }
1436
- else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Upgrade", -1))
1437
- {
1438
- hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pRegistration->rgsczUpgradeCodes), pRegistration->cUpgradeCodes + 1, sizeof(LPWSTR), 5);
1439
- ExitOnFailure(hr, "Failed to resize Upgrade code array in registration");
1440
-
1441
- pRegistration->rgsczUpgradeCodes[pRegistration->cUpgradeCodes] = sczId;
1442
- sczId = NULL;
1443
- ++pRegistration->cUpgradeCodes;
1444
- }
1445
- else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Addon", -1))
1446
- {
1447
- hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pRegistration->rgsczAddonCodes), pRegistration->cAddonCodes + 1, sizeof(LPWSTR), 5);
1448
- ExitOnFailure(hr, "Failed to resize Addon code array in registration");
1449
-
1450
- pRegistration->rgsczAddonCodes[pRegistration->cAddonCodes] = sczId;
1451
- sczId = NULL;
1452
- ++pRegistration->cAddonCodes;
1453
- }
1454
- else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczAction, -1, L"Patch", -1))
1455
- {
1456
- hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pRegistration->rgsczPatchCodes), pRegistration->cPatchCodes + 1, sizeof(LPWSTR), 5);
1457
- ExitOnFailure(hr, "Failed to resize Patch code array in registration");
1458
-
1459
- pRegistration->rgsczPatchCodes[pRegistration->cPatchCodes] = sczId;
1460
- sczId = NULL;
1461
- ++pRegistration->cPatchCodes;
1462
- }
1463
- else
1464
- {
1465
- hr = E_INVALIDARG;
1466
- ExitOnFailure(hr, "Invalid value for @Action: %ls", sczAction);
1467
- }
1468
- }
1469
-
1470
-LExit:
1471
- ReleaseObject(pixnNodes);
1472
- ReleaseObject(pixnElement);
1473
- ReleaseStr(sczAction);
1474
- ReleaseStr(sczId);
1475
-
1476
- return hr;
1477
-}
1478
-
1394
static HRESULT FormatUpdateRegistrationKey(
1395
__in BURN_REGISTRATION* pRegistration,
1396
__out_z LPWSTR* psczKey
src/burn/engine/relatedbundle.cpp
+25
-25
@@ -143,6 +143,30 @@ extern "C" void RelatedBundlesSortPlan(
143
qsort_s(pRelatedBundles->rgpPlanSortedRelatedBundles, pRelatedBundles->cRelatedBundles, sizeof(BURN_RELATED_BUNDLE*), CompareRelatedBundlesPlan, NULL);
144
}
145
146
+extern "C" BOOTSTRAPPER_RELATION_TYPE RelatedBundleConvertRelationType(
147
+ __in BUNDLE_RELATION_TYPE relationType
148
+ )
149
+{
150
+ switch (relationType)
151
+ {
152
+ case BUNDLE_RELATION_DETECT:
153
+ return BOOTSTRAPPER_RELATION_DETECT;
154
+ case BUNDLE_RELATION_UPGRADE:
155
+ return BOOTSTRAPPER_RELATION_UPGRADE;
156
+ case BUNDLE_RELATION_ADDON:
157
+ return BOOTSTRAPPER_RELATION_ADDON;
158
+ case BUNDLE_RELATION_PATCH:
159
+ return BOOTSTRAPPER_RELATION_PATCH;
160
+ case BUNDLE_RELATION_DEPENDENT_ADDON:
161
+ return BOOTSTRAPPER_RELATION_DEPENDENT_ADDON;
162
+ case BUNDLE_RELATION_DEPENDENT_PATCH:
163
+ return BOOTSTRAPPER_RELATION_DEPENDENT_PATCH;
164
+ default:
165
+ AssertSz(BUNDLE_RELATION_NONE == relationType, "Unknown BUNDLE_RELATION_TYPE");
166
+ return BOOTSTRAPPER_RELATION_NONE;
167
+ }
168
+}
169
+
170
171
// internal helper functions
172
@@ -248,30 +272,6 @@ LExit:
272
return result;
273
}
274
251
-static BOOTSTRAPPER_RELATION_TYPE ConvertRelationType(
252
- __in BUNDLE_RELATION_TYPE relationType
253
- )
254
-{
255
- switch (relationType)
256
- {
257
- case BUNDLE_RELATION_DETECT:
258
- return BOOTSTRAPPER_RELATION_DETECT;
259
- case BUNDLE_RELATION_UPGRADE:
260
- return BOOTSTRAPPER_RELATION_UPGRADE;
261
- case BUNDLE_RELATION_ADDON:
262
- return BOOTSTRAPPER_RELATION_ADDON;
263
- case BUNDLE_RELATION_PATCH:
264
- return BOOTSTRAPPER_RELATION_PATCH;
265
- case BUNDLE_RELATION_DEPENDENT_ADDON:
266
- return BOOTSTRAPPER_RELATION_DEPENDENT_ADDON;
267
- case BUNDLE_RELATION_DEPENDENT_PATCH:
268
- return BOOTSTRAPPER_RELATION_DEPENDENT_PATCH;
269
- default:
270
- AssertSz(BUNDLE_RELATION_NONE == relationType, "Unknown BUNDLE_RELATION_TYPE");
271
- return BOOTSTRAPPER_RELATION_NONE;
272
- }
273
-}
274
-
275
static HRESULT LoadIfRelatedBundle(
276
__in const BUNDLE_QUERY_RELATED_BUNDLE_RESULT* pBundle,
277
__in BURN_REGISTRATION* pRegistration,
@@ -280,7 +280,7 @@ static HRESULT LoadIfRelatedBundle(
280
{
281
HRESULT hr = S_OK;
282
BOOL fPerMachine = BUNDLE_INSTALL_CONTEXT_MACHINE == pBundle->installContext;
283
- BOOTSTRAPPER_RELATION_TYPE relationType = ConvertRelationType(pBundle->relationType);
283
+ BOOTSTRAPPER_RELATION_TYPE relationType = RelatedBundleConvertRelationType(pBundle->relationType);
284
BURN_RELATED_BUNDLE* pRelatedBundle = NULL;
285
286
// If we found our bundle id, it's not a related bundle.
src/burn/engine/relatedbundle.h
+3
@@ -25,6 +25,9 @@ void RelatedBundlesSortDetect(
25
void RelatedBundlesSortPlan(
26
__in BURN_RELATED_BUNDLES* pRelatedBundles
27
);
28
+BOOTSTRAPPER_RELATION_TYPE RelatedBundleConvertRelationType(
29
+ __in BUNDLE_RELATION_TYPE relationType
30
+ );
31
32
#if defined(__cplusplus)
33
}
src/burn/engine/userexperience.cpp
+35
-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(2022, 3, 17, 0);
107
+ args.qwEngineAPIVersion = MAKEQWORDVERSION(2022, 3, 31, 0);
108
109
results.cbSize = sizeof(BOOTSTRAPPER_CREATE_RESULTS);
110
@@ -1247,6 +1247,40 @@ LExit:
1247
return hr;
1248
}
1249
1250
+EXTERN_C BAAPI UserExperienceOnDetectRelatedBundlePackage(
1251
+ __in BURN_USER_EXPERIENCE* pUserExperience,
1252
+ __in_z LPCWSTR wzPackageId,
1253
+ __in_z LPCWSTR wzBundleId,
1254
+ __in BOOTSTRAPPER_RELATION_TYPE relationType,
1255
+ __in BOOL fPerMachine,
1256
+ __in VERUTIL_VERSION* pVersion
1257
+ )
1258
+{
1259
+ HRESULT hr = S_OK;
1260
+ BA_ONDETECTRELATEDBUNDLEPACKAGE_ARGS args = { };
1261
+ BA_ONDETECTRELATEDBUNDLEPACKAGE_RESULTS results = { };
1262
+
1263
+ args.cbSize = sizeof(args);
1264
+ args.wzPackageId = wzPackageId;
1265
+ args.wzBundleId = wzBundleId;
1266
+ args.relationType = relationType;
1267
+ args.fPerMachine = fPerMachine;
1268
+ args.wzVersion = pVersion->sczVersion;
1269
+
1270
+ results.cbSize = sizeof(results);
1271
+
1272
+ hr = SendBAMessage(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTRELATEDBUNDLEPACKAGE, &args, &results);
1273
+ ExitOnFailure(hr, "BA OnDetectRelatedBundlePackage failed.");
1274
+
1275
+ if (results.fCancel)
1276
+ {
1277
+ hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT);
1278
+ }
1279
+
1280
+LExit:
1281
+ return hr;
1282
+}
1283
+
1284
EXTERN_C BAAPI UserExperienceOnDetectRelatedMsiPackage(
1285
__in BURN_USER_EXPERIENCE* pUserExperience,
1286
__in_z LPCWSTR wzPackageId,
src/burn/engine/userexperience.h
+8
@@ -298,6 +298,14 @@ BAAPI UserExperienceOnDetectRelatedBundle(
298
__in VERUTIL_VERSION* pVersion,
299
__in BOOL fMissingFromCache
300
);
301
+BAAPI UserExperienceOnDetectRelatedBundlePackage(
302
+ __in BURN_USER_EXPERIENCE* pUserExperience,
303
+ __in_z LPCWSTR wzPackageId,
304
+ __in_z LPCWSTR wzBundleId,
305
+ __in BOOTSTRAPPER_RELATION_TYPE relationType,
306
+ __in BOOL fPerMachine,
307
+ __in VERUTIL_VERSION* pVersion
308
+ );
309
BAAPI UserExperienceOnDetectRelatedMsiPackage(
310
__in BURN_USER_EXPERIENCE* pUserExperience,
311
__in_z LPCWSTR wzPackageId,
src/burn/test/BurnUnitTest/TestData/PlanTest/BundlePackage_Multiple_manifest.xml
+1
-1
@@ -1 +1 @@
1
-<?xml version="1.0" encoding="utf-8"?><BurnManifest xmlns="http://wixtoolset.org/schemas/v4/2008/Burn"><Log PathVariable="WixBundleLog" Prefix="~BundlePackageTests_MultipleBundlePackagesBundle" Extension=".log" /><RelatedBundle Id="{86D214FB-8D74-456C-99B3-6557ECA6159C}" Action="Upgrade" /><Variable Id="TestGroupName" Value="BundlePackageTests" Type="string" Hidden="no" Persisted="no" /><Variable Id="WixBundleInProgressName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSource" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSourceFolder" Hidden="no" Persisted="yes" /><Variable Id="WixBundleLastUsedSource" Hidden="no" Persisted="yes" /><RegistrySearch Id="NETFRAMEWORK45" Variable="NETFRAMEWORK45" Root="HKLM" Key="SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" Value="Release" Type="value" VariableType="string" /><UX><Payload Id="WixManagedBootstrapperApplicationHost" FilePath="mbahost.dll" SourcePath="u30" /><Payload Id="payO60IVK4ATGzPpMz3rwVbUWl6DyU" FilePath="WixToolset.Mba.Host.config" SourcePath="u0" /><Payload Id="payxj4zDAKL2NVlz4ohp0GvwFHepyI" FilePath="TestBA.dll" SourcePath="u1" /><Payload Id="pay1hOSAUC8_D633cD2TXpIXCL30OU" FilePath="mbanative.dll" SourcePath="u2" /><Payload Id="payujy6Izl_BlUNfHt2eI.ADfjYAv4" FilePath="WixToolset.Mba.Core.dll" SourcePath="u3" /><Payload Id="payR4EbR4OTDZpPEycWaSSM_gZRBWM" FilePath="mbapreq.thm" SourcePath="u4" /><Payload Id="paylVCy2Ecl8pHPdJTCQZryUG4T9us" FilePath="mbapreq.png" SourcePath="u5" /><Payload Id="payTaG4B_lob1aLcKFaOqSSG3MPMpU" FilePath="mbapreq.wxl" SourcePath="u6" /><Payload Id="payZwIGuiezVTitZOoZKxyh2DdRSGs" FilePath="1028\mbapreq.wxl" SourcePath="u7" /><Payload Id="pay.herBWX.LlOh8jLsx24aWdunV_0" FilePath="1029\mbapreq.wxl" SourcePath="u8" /><Payload Id="pay8DkMszYsoxxdgX14huLDMYXylQg" FilePath="1030\mbapreq.wxl" SourcePath="u9" /><Payload Id="payPaHpoTeOdkW.TK99IDwktNLhTAg" FilePath="1031\mbapreq.wxl" SourcePath="u10" /><Payload Id="pay45AtAzterLTMzZgdxxtuYvaiXwU" FilePath="1032\mbapreq.wxl" SourcePath="u11" /><Payload Id="payA2VEKIqhePyNIEmr14eyH3JoVLc" FilePath="1035\mbapreq.wxl" SourcePath="u12" /><Payload Id="payvre23ObscjzhcaFIifUAkXMdPa8" FilePath="1036\mbapreq.wxl" SourcePath="u13" /><Payload Id="paytxUV3vuBbG2c.a9c.d_sZX2x6wA" FilePath="1038\mbapreq.wxl" SourcePath="u14" /><Payload Id="payYvMWRK9xelo5.sQn7jRkJIaBp9A" FilePath="1040\mbapreq.wxl" SourcePath="u15" /><Payload Id="pay68KKSApyQimbA25t6kSbqhdeH10" FilePath="1041\mbapreq.wxl" SourcePath="u16" /><Payload Id="paypiqxaHpYZqx.9eDVjQrj1igLbRY" FilePath="1042\mbapreq.wxl" SourcePath="u17" /><Payload Id="payTO0YwZzxKpbqdrBVUcVRTu3BFe8" FilePath="1043\mbapreq.wxl" SourcePath="u18" /><Payload Id="payIXg2ldBJukRzhqWolJVOEbTmF34" FilePath="1044\mbapreq.wxl" SourcePath="u19" /><Payload Id="payOHIZbSkIvrpwKkkXI173tv3u3B4" FilePath="1045\mbapreq.wxl" SourcePath="u20" /><Payload Id="payQRQ_UZl_R2UtV0xDXB2yeH2bg3E" FilePath="1046\mbapreq.wxl" SourcePath="u21" /><Payload Id="payhrejLLBfc1i27iN._QPhQ4K337I" FilePath="1049\mbapreq.wxl" SourcePath="u22" /><Payload Id="payqEzaDNzxB68vGp29jgDcCos6dvg" FilePath="1051\mbapreq.wxl" SourcePath="u23" /><Payload Id="paydz8Vk8xSTyYohgGXTSIxWGXL5.Q" FilePath="1053\mbapreq.wxl" SourcePath="u24" /><Payload Id="pay0HRUZTlbC3taSOffJBsEj92Br8Y" FilePath="1055\mbapreq.wxl" SourcePath="u25" /><Payload Id="payIvUOkc_EMH7laMFehefNolV8hZo" FilePath="1060\mbapreq.wxl" SourcePath="u26" /><Payload Id="payLFhOb.rHuk4sW5CYAPMShG0NjGI" FilePath="2052\mbapreq.wxl" SourcePath="u27" /><Payload Id="payqIKCmERK7Nhxx_nNXvRxdKqKDbI" FilePath="2070\mbapreq.wxl" SourcePath="u28" /><Payload Id="payqeWUzIVaEqjuRXN0z8ECC3Y4tCc" FilePath="3082\mbapreq.wxl" SourcePath="u29" /><Payload Id="paylfeHEjJSSTnNzY9QMZM2Ye3Ipy4" FilePath="mbapreq.dll" SourcePath="u31" /><Payload Id="payDPxs6uy8nbky.R7zhir2RRAfc.c" FilePath="WixToolset.Mba.Host.dll" SourcePath="u32" /><Payload Id="uxTxMXPVMXwQrPTMIGa5WGt93w0Ns" FilePath="BootstrapperApplicationData.xml" SourcePath="u33" /><Payload Id="uxYRbgitOs0K878jn5L_z7LdJ21KI" FilePath="BundleExtensionData.xml" SourcePath="u34" /></UX><Container Id="WixAttachedContainer" FileSize="15696370" Hash="0F9966B421400E481D394DB4C4D7F0F92548E5BEB79B98880C926E817E8C1F381EC8A17053E2E66AE7132A3C9ECE441629E6A1FB3452C5C9282280C40252F141" FilePath="MultipleBundlePackagesBundle.exe" AttachedIndex="1" Attached="yes" Primary="yes" /><Payload Id="NetFx48Web" FilePath="redist\ndp48-web.exe" FileSize="1439328" CertificateRootPublicKeyIdentifier="F49F9B33E25E33CCA0BFB15A62B7C29FFAB3880B" CertificateRootThumbprint="ABDCA79AF9DD48A0EA702AD45260B3C03093FB4B" DownloadUrl="https://go.microsoft.com/fwlink/?LinkId=2085155" Packaging="external" SourcePath="redist\ndp48-web.exe" /><Payload Id="PackageA" FilePath="BundleA.exe" FileSize="5241635" Hash="20E1AFF76DE4693CB2876DC6BCCA0152DB16BE49AEDE2CD581C03FC39AB89DEA12BC25CB435F06E4D7D2B4443CE8A8935D5E92E2E49A4981B60A273980E4B29B" Packaging="embedded" SourcePath="a0" Container="WixAttachedContainer" /><Payload Id="PackageB" FilePath="BundleB_x64.exe" FileSize="10450821" Hash="43A58873D61D6E0FA83F6C5266F2F05FEA9BC85D11C195493B7FD9F0B4AA799C1EFCB78D76DCED32124D2EC62A4E7114B62CDE6F0B87E42A7E28CDBB0DA0FF8E" Packaging="embedded" SourcePath="a1" Container="WixAttachedContainer" /><RollbackBoundary Id="WixDefaultBoundary" Vital="yes" Transaction="no" /><Registration Id="{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}" ExecutableName="MultipleBundlePackagesBundle.exe" PerMachine="yes" Tag="" Version="1.0.0.0" ProviderKey="{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}"><Arp Register="yes" DisplayName="~BundlePackageTests - MultipleBundlePackagesBundle" DisplayVersion="1.0.0.0" /></Registration><Chain><ExePackage Id="NetFx48Web" Cache="remove" CacheId="642721C60D52051C7F3434D8710FE3406A7CFE10B2B39E90EA847719ED1697D7C614F2DF44AD50412B1DF8C98DD78FDC57CA1D047D28C81AC158092E5FB18040" InstallSize="1439328" Size="1439328" PerMachine="yes" Permanent="yes" Vital="yes" RollbackBoundaryForward="WixDefaultBoundary" LogPathVariable="NetFx48WebLog" RollbackLogPathVariable="WixBundleRollbackLog_NetFx48Web" DetectCondition="NETFRAMEWORK45 >= 528040" InstallArguments="/q /norestart /log "[NetFx48WebLog].html"" UninstallArguments="" Uninstallable="no" RepairArguments="" Repairable="no" Protocol="netfx4"><PayloadRef Id="NetFx48Web" /></ExePackage><BundlePackage Id="PackageA" Cache="keep" CacheId="{B39CEE4D-CCD7-4797-BE3A-6613BD1DC4BE}v1.0.0.0" InstallSize="2169" Size="5241635" PerMachine="yes" Permanent="no" Vital="yes" LogPathVariable="WixBundleLog_PackageA" RollbackLogPathVariable="WixBundleRollbackLog_PackageA" BundleId="{B39CEE4D-CCD7-4797-BE3A-6613BD1DC4BE}" InstallArguments="" UninstallArguments="" RepairArguments="" SupportsBurnProtocol="yes" Win64="no"><Provides Key="{B39CEE4D-CCD7-4797-BE3A-6613BD1DC4BE}" Version="1.0.0.0" DisplayName="~BasicFunctionalityTests - BundleA" Imported="yes" /><PayloadRef Id="PackageA" /></BundlePackage><BundlePackage Id="PackageB" Cache="keep" CacheId="{7506235A-7C59-4750-82C7-EB460A87ED3A}v1.0.0.0" InstallSize="1441497" Size="10450821" PerMachine="yes" Permanent="no" Vital="yes" RollbackBoundaryBackward="WixDefaultBoundary" LogPathVariable="WixBundleLog_PackageB" RollbackLogPathVariable="WixBundleRollbackLog_PackageB" BundleId="{7506235A-7C59-4750-82C7-EB460A87ED3A}" InstallArguments="" UninstallArguments="" RepairArguments="" SupportsBurnProtocol="yes" Win64="yes"><Provides Key="{7506235A-7C59-4750-82C7-EB460A87ED3A}" Version="1.0.0.0" DisplayName="~BasicFunctionalityTests - BundleB_x64" Imported="yes" /><PayloadRef Id="PackageB" /></BundlePackage></Chain><CommandLine Variables="upperCase" /></BurnManifest>
\ No newline at end of file
1
+<?xml version="1.0" encoding="utf-8"?><BurnManifest xmlns="http://wixtoolset.org/schemas/v4/2008/Burn"><Log PathVariable="WixBundleLog" Prefix="~BundlePackageTests_MultipleBundlePackagesBundle" Extension=".log" /><RelatedBundle Id="{86D214FB-8D74-456C-99B3-6557ECA6159C}" Action="Upgrade" /><Variable Id="TestGroupName" Value="BundlePackageTests" Type="string" Hidden="no" Persisted="no" /><Variable Id="WixBundleInProgressName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSource" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSourceFolder" Hidden="no" Persisted="yes" /><Variable Id="WixBundleLastUsedSource" Hidden="no" Persisted="yes" /><RegistrySearch Id="NETFRAMEWORK45" Variable="NETFRAMEWORK45" Root="HKLM" Key="SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" Value="Release" Type="value" VariableType="string" /><UX><Payload Id="WixManagedBootstrapperApplicationHost" FilePath="mbahost.dll" SourcePath="u30" /><Payload Id="payO60IVK4ATGzPpMz3rwVbUWl6DyU" FilePath="WixToolset.Mba.Host.config" SourcePath="u0" /><Payload Id="payxj4zDAKL2NVlz4ohp0GvwFHepyI" FilePath="TestBA.dll" SourcePath="u1" /><Payload Id="pay1hOSAUC8_D633cD2TXpIXCL30OU" FilePath="mbanative.dll" SourcePath="u2" /><Payload Id="payujy6Izl_BlUNfHt2eI.ADfjYAv4" FilePath="WixToolset.Mba.Core.dll" SourcePath="u3" /><Payload Id="payR4EbR4OTDZpPEycWaSSM_gZRBWM" FilePath="mbapreq.thm" SourcePath="u4" /><Payload Id="paylVCy2Ecl8pHPdJTCQZryUG4T9us" FilePath="mbapreq.png" SourcePath="u5" /><Payload Id="payTaG4B_lob1aLcKFaOqSSG3MPMpU" FilePath="mbapreq.wxl" SourcePath="u6" /><Payload Id="payZwIGuiezVTitZOoZKxyh2DdRSGs" FilePath="1028\mbapreq.wxl" SourcePath="u7" /><Payload Id="pay.herBWX.LlOh8jLsx24aWdunV_0" FilePath="1029\mbapreq.wxl" SourcePath="u8" /><Payload Id="pay8DkMszYsoxxdgX14huLDMYXylQg" FilePath="1030\mbapreq.wxl" SourcePath="u9" /><Payload Id="payPaHpoTeOdkW.TK99IDwktNLhTAg" FilePath="1031\mbapreq.wxl" SourcePath="u10" /><Payload Id="pay45AtAzterLTMzZgdxxtuYvaiXwU" FilePath="1032\mbapreq.wxl" SourcePath="u11" /><Payload Id="payA2VEKIqhePyNIEmr14eyH3JoVLc" FilePath="1035\mbapreq.wxl" SourcePath="u12" /><Payload Id="payvre23ObscjzhcaFIifUAkXMdPa8" FilePath="1036\mbapreq.wxl" SourcePath="u13" /><Payload Id="paytxUV3vuBbG2c.a9c.d_sZX2x6wA" FilePath="1038\mbapreq.wxl" SourcePath="u14" /><Payload Id="payYvMWRK9xelo5.sQn7jRkJIaBp9A" FilePath="1040\mbapreq.wxl" SourcePath="u15" /><Payload Id="pay68KKSApyQimbA25t6kSbqhdeH10" FilePath="1041\mbapreq.wxl" SourcePath="u16" /><Payload Id="paypiqxaHpYZqx.9eDVjQrj1igLbRY" FilePath="1042\mbapreq.wxl" SourcePath="u17" /><Payload Id="payTO0YwZzxKpbqdrBVUcVRTu3BFe8" FilePath="1043\mbapreq.wxl" SourcePath="u18" /><Payload Id="payIXg2ldBJukRzhqWolJVOEbTmF34" FilePath="1044\mbapreq.wxl" SourcePath="u19" /><Payload Id="payOHIZbSkIvrpwKkkXI173tv3u3B4" FilePath="1045\mbapreq.wxl" SourcePath="u20" /><Payload Id="payQRQ_UZl_R2UtV0xDXB2yeH2bg3E" FilePath="1046\mbapreq.wxl" SourcePath="u21" /><Payload Id="payhrejLLBfc1i27iN._QPhQ4K337I" FilePath="1049\mbapreq.wxl" SourcePath="u22" /><Payload Id="payqEzaDNzxB68vGp29jgDcCos6dvg" FilePath="1051\mbapreq.wxl" SourcePath="u23" /><Payload Id="paydz8Vk8xSTyYohgGXTSIxWGXL5.Q" FilePath="1053\mbapreq.wxl" SourcePath="u24" /><Payload Id="pay0HRUZTlbC3taSOffJBsEj92Br8Y" FilePath="1055\mbapreq.wxl" SourcePath="u25" /><Payload Id="payIvUOkc_EMH7laMFehefNolV8hZo" FilePath="1060\mbapreq.wxl" SourcePath="u26" /><Payload Id="payLFhOb.rHuk4sW5CYAPMShG0NjGI" FilePath="2052\mbapreq.wxl" SourcePath="u27" /><Payload Id="payqIKCmERK7Nhxx_nNXvRxdKqKDbI" FilePath="2070\mbapreq.wxl" SourcePath="u28" /><Payload Id="payqeWUzIVaEqjuRXN0z8ECC3Y4tCc" FilePath="3082\mbapreq.wxl" SourcePath="u29" /><Payload Id="paylfeHEjJSSTnNzY9QMZM2Ye3Ipy4" FilePath="mbapreq.dll" SourcePath="u31" /><Payload Id="payDPxs6uy8nbky.R7zhir2RRAfc.c" FilePath="WixToolset.Mba.Host.dll" SourcePath="u32" /><Payload Id="uxTxMXPVMXwQrPTMIGa5WGt93w0Ns" FilePath="BootstrapperApplicationData.xml" SourcePath="u33" /><Payload Id="uxYRbgitOs0K878jn5L_z7LdJ21KI" FilePath="BundleExtensionData.xml" SourcePath="u34" /></UX><Container Id="WixAttachedContainer" FileSize="15696370" Hash="0F9966B421400E481D394DB4C4D7F0F92548E5BEB79B98880C926E817E8C1F381EC8A17053E2E66AE7132A3C9ECE441629E6A1FB3452C5C9282280C40252F141" FilePath="MultipleBundlePackagesBundle.exe" AttachedIndex="1" Attached="yes" Primary="yes" /><Payload Id="NetFx48Web" FilePath="redist\ndp48-web.exe" FileSize="1439328" CertificateRootPublicKeyIdentifier="F49F9B33E25E33CCA0BFB15A62B7C29FFAB3880B" CertificateRootThumbprint="ABDCA79AF9DD48A0EA702AD45260B3C03093FB4B" DownloadUrl="https://go.microsoft.com/fwlink/?LinkId=2085155" Packaging="external" SourcePath="redist\ndp48-web.exe" /><Payload Id="PackageA" FilePath="BundleA.exe" FileSize="5241635" Hash="20E1AFF76DE4693CB2876DC6BCCA0152DB16BE49AEDE2CD581C03FC39AB89DEA12BC25CB435F06E4D7D2B4443CE8A8935D5E92E2E49A4981B60A273980E4B29B" Packaging="embedded" SourcePath="a0" Container="WixAttachedContainer" /><Payload Id="PackageB" FilePath="BundleB_x64.exe" FileSize="10450821" Hash="43A58873D61D6E0FA83F6C5266F2F05FEA9BC85D11C195493B7FD9F0B4AA799C1EFCB78D76DCED32124D2EC62A4E7114B62CDE6F0B87E42A7E28CDBB0DA0FF8E" Packaging="embedded" SourcePath="a1" Container="WixAttachedContainer" /><RollbackBoundary Id="WixDefaultBoundary" Vital="yes" Transaction="no" /><Registration Id="{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}" ExecutableName="MultipleBundlePackagesBundle.exe" PerMachine="yes" Tag="" Version="1.0.0.0" ProviderKey="{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}"><Arp Register="yes" DisplayName="~BundlePackageTests - MultipleBundlePackagesBundle" DisplayVersion="1.0.0.0" /></Registration><Chain><ExePackage Id="NetFx48Web" Cache="remove" CacheId="642721C60D52051C7F3434D8710FE3406A7CFE10B2B39E90EA847719ED1697D7C614F2DF44AD50412B1DF8C98DD78FDC57CA1D047D28C81AC158092E5FB18040" InstallSize="1439328" Size="1439328" PerMachine="yes" Permanent="yes" Vital="yes" RollbackBoundaryForward="WixDefaultBoundary" LogPathVariable="NetFx48WebLog" RollbackLogPathVariable="WixBundleRollbackLog_NetFx48Web" DetectCondition="NETFRAMEWORK45 >= 528040" InstallArguments="/q /norestart /log "[NetFx48WebLog].html"" UninstallArguments="" Uninstallable="no" RepairArguments="" Repairable="no" Protocol="netfx4"><PayloadRef Id="NetFx48Web" /></ExePackage><BundlePackage Id="PackageA" Cache="keep" CacheId="{B39CEE4D-CCD7-4797-BE3A-6613BD1DC4BE}v1.0.0.0" InstallSize="2169" Size="5241635" Version="1.0.0.0" PerMachine="yes" Permanent="no" Vital="yes" LogPathVariable="WixBundleLog_PackageA" RollbackLogPathVariable="WixBundleRollbackLog_PackageA" BundleId="{B39CEE4D-CCD7-4797-BE3A-6613BD1DC4BE}" InstallArguments="" UninstallArguments="" RepairArguments="" SupportsBurnProtocol="yes" Win64="no"><Provides Key="{B39CEE4D-CCD7-4797-BE3A-6613BD1DC4BE}" Version="1.0.0.0" DisplayName="~BasicFunctionalityTests - BundleA" Imported="yes" /><RelatedBundle Id="{8C7E2C47-1EE7-4BBE-99A2-EAB7F3693F48}" Action="Upgrade" /><PayloadRef Id="PackageA" /></BundlePackage><BundlePackage Id="PackageB" Cache="keep" CacheId="{7506235A-7C59-4750-82C7-EB460A87ED3A}v1.0.0.0" InstallSize="1441497" Size="10450821" Version="1.0.0.0" PerMachine="yes" Permanent="no" Vital="yes" RollbackBoundaryBackward="WixDefaultBoundary" LogPathVariable="WixBundleLog_PackageB" RollbackLogPathVariable="WixBundleRollbackLog_PackageB" BundleId="{7506235A-7C59-4750-82C7-EB460A87ED3A}" InstallArguments="" UninstallArguments="" RepairArguments="" SupportsBurnProtocol="yes" Win64="yes"><Provides Key="{7506235A-7C59-4750-82C7-EB460A87ED3A}" Version="1.0.0.0" DisplayName="~BasicFunctionalityTests - BundleB_x64" Imported="yes" /><RelatedBundle Id="{79F45B7A-D990-46E4-819B-078D87C3321A}" Action="Upgrade" /><PayloadRef Id="PackageB" /></BundlePackage></Chain><CommandLine Variables="upperCase" /></BurnManifest>
src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp
+11
@@ -1489,6 +1489,9 @@ public: // IBootstrapperApplication
1489
case BOOTSTRAPPER_APPLICATION_MESSAGE_ONAPPLYDOWNGRADE:
1490
OnApplyDowngradeFallback(reinterpret_cast<BA_ONAPPLYDOWNGRADE_ARGS*>(pvArgs), reinterpret_cast<BA_ONAPPLYDOWNGRADE_RESULTS*>(pvResults));
1491
break;
1492
+ case BOOTSTRAPPER_APPLICATION_MESSAGE_ONDETECTRELATEDBUNDLEPACKAGE:
1493
+ OnDetectRelatedBundlePackageFallback(reinterpret_cast<BA_ONDETECTRELATEDBUNDLEPACKAGE_ARGS*>(pvArgs), reinterpret_cast<BA_ONDETECTRELATEDBUNDLEPACKAGE_RESULTS*>(pvResults));
1494
+ break;
1495
default:
1496
#ifdef DEBUG
1497
BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "WIXSTDBA: Forwarding unknown BA message: %d", message);
@@ -2178,6 +2181,14 @@ private: // privates
2181
m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONEXECUTEPROCESSCANCEL, pArgs, pResults, m_pvBAFunctionsProcContext);
2182
}
2183
2184
+ void OnDetectRelatedBundlePackageFallback(
2185
+ __in BA_ONDETECTRELATEDBUNDLEPACKAGE_ARGS* pArgs,
2186
+ __inout BA_ONDETECTRELATEDBUNDLEPACKAGE_RESULTS* pResults
2187
+ )
2188
+ {
2189
+ m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONDETECTRELATEDBUNDLEPACKAGE, pArgs, pResults, m_pvBAFunctionsProcContext);
2190
+ }
2191
+
2192
2193
public: //CBalBaseBootstrapperApplication
2194
virtual STDMETHODIMP Initialize(
src/test/burn/TestData/BundlePackageTests/UpgradeBundlePackageBundlev1/UpgradeBundlePackageBundle.props
new
+14
@@ -0,0 +1,14 @@
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
+ <PropertyGroup>
4
+ <OutputType>Bundle</OutputType>
5
+ <BA>hyperlinkLicense</BA>
6
+ <UpgradeCode>{B9636854-B76B-4171-B63D-7C659F61DE3D}</UpgradeCode>
7
+ </PropertyGroup>
8
+ <ItemGroup>
9
+ <Compile Include="..\..\Templates\Bundle.wxs" Link="Bundle.wxs" />
10
+ </ItemGroup>
11
+ <ItemGroup>
12
+ <PackageReference Include="WixToolset.Bal.wixext" />
13
+ </ItemGroup>
14
+</Project>
src/test/burn/TestData/BundlePackageTests/UpgradeBundlePackageBundlev1/UpgradeBundlePackageBundlev1.wixproj
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 Sdk="WixToolset.Sdk">
3
+ <Import Project="UpgradeBundlePackageBundle.props" />
4
+ <ItemGroup>
5
+ <ProjectReference Include="..\..\UpgradeRelatedBundleTests\BundleAv1\BundleAv1.wixproj" />
6
+ </ItemGroup>
7
+</Project>
\ No newline at end of file
src/test/burn/TestData/BundlePackageTests/UpgradeBundlePackageBundlev1/UpgradeBundlePackageBundlev1.wxs
new
+10
@@ -0,0 +1,10 @@
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
+
4
+<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5
+ <Fragment>
6
+ <PackageGroup Id="BundlePackages">
7
+ <BundlePackage Id="PackageA" SourceFile="$(var.BundleAv1.TargetPath)" />
8
+ </PackageGroup>
9
+ </Fragment>
10
+</Wix>
src/test/burn/TestData/BundlePackageTests/UpgradeBundlePackageBundlev2/UpgradeBundlePackageBundlev2.wixproj
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 Sdk="WixToolset.Sdk">
3
+ <Import Project="..\UpgradeBundlePackageBundlev1\UpgradeBundlePackageBundle.props" />
4
+ <ItemGroup>
5
+ <ProjectReference Include="..\..\UpgradeRelatedBundleTests\BundleAv2\BundleAv2.wixproj" />
6
+ </ItemGroup>
7
+</Project>
\ No newline at end of file
src/test/burn/TestData/BundlePackageTests/UpgradeBundlePackageBundlev2/UpgradeBundlePackageBundlev2.wxs
new
+10
@@ -0,0 +1,10 @@
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
+
4
+<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5
+ <Fragment>
6
+ <PackageGroup Id="BundlePackages">
7
+ <BundlePackage Id="PackageA" SourceFile="$(var.BundleAv2.TargetPath)" />
8
+ </PackageGroup>
9
+ </Fragment>
10
+</Wix>
src/test/burn/WixToolsetTest.BurnE2E/BundlePackageTests.cs
+30
@@ -45,7 +45,37 @@ namespace WixToolsetTest.BurnE2E
45
// Source file should *not* be installed
46
Assert.False(File.Exists(packageA32SourceCodeFilePath), $"PackageA payload should have been removed by uninstall from: {packageA32SourceCodeFilePath}");
47
Assert.False(File.Exists(packageA64SourceCodeFilePath), $"PackageA_x64 payload should have been removed by uninstall from: {packageA64SourceCodeFilePath}");
48
+ }
49
+
50
+ [Fact]
51
+ public void CanInstallUpgradeBundlePackage()
52
+ {
53
+ var bundleAv1 = this.CreateBundleInstaller(@"..\UpgradeRelatedBundleTests\BundleAv1");
54
+ var bundleAv2 = this.CreateBundleInstaller(@"..\UpgradeRelatedBundleTests\BundleAv2");
55
+ var upgradeBundlePackageBundlev2 = this.CreateBundleInstaller("UpgradeBundlePackageBundlev2");
56
+
57
+ bundleAv1.Install();
58
+ bundleAv1.VerifyRegisteredAndInPackageCache();
59
+
60
+ upgradeBundlePackageBundlev2.Install();
61
+ upgradeBundlePackageBundlev2.VerifyRegisteredAndInPackageCache();
62
+ bundleAv2.VerifyRegisteredAndInPackageCache();
63
+ bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache();
64
+ }
65
+
66
+ [Fact]
67
+ public void CanSkipObsoleteBundlePackage()
68
+ {
69
+ var bundleAv1 = this.CreateBundleInstaller(@"..\UpgradeRelatedBundleTests\BundleAv1");
70
+ var bundleAv2 = this.CreateBundleInstaller(@"..\UpgradeRelatedBundleTests\BundleAv2");
71
+ var upgradeBundlePackageBundlev1 = this.CreateBundleInstaller("UpgradeBundlePackageBundlev1");
72
+
73
+ bundleAv2.Install();
74
+ bundleAv2.VerifyRegisteredAndInPackageCache();
75
76
+ upgradeBundlePackageBundlev1.Install();
77
+ upgradeBundlePackageBundlev1.VerifyUnregisteredAndRemovedFromPackageCache();
78
+ bundleAv1.VerifyUnregisteredAndRemovedFromPackageCache();
79
}
80
}
81
}
src/wix/WixToolset.Core.Burn/Bind/GenerateManifestDataFromIRCommand.cs
+1
@@ -82,6 +82,7 @@ namespace WixToolset.Core.Burn.Bind
82
case SymbolDefinitionType.WixBundlePackageCommandLine:
83
case SymbolDefinitionType.WixBundlePackageExitCode:
84
case SymbolDefinitionType.WixBundlePackageGroup:
85
+ case SymbolDefinitionType.WixBundlePackageRelatedBundle:
86
case SymbolDefinitionType.WixBundlePatchTargetCode:
87
case SymbolDefinitionType.WixBundlePayload:
88
case SymbolDefinitionType.WixBundlePayloadGroup:
src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs
+12
@@ -319,6 +319,7 @@ namespace WixToolset.Core.Burn.Bundles
319
var targetCodesByPatch = this.Section.Symbols.OfType<WixBundlePatchTargetCodeSymbol>().ToLookup(r => r.PackageRef);
320
var msiFeaturesByPackage = this.Section.Symbols.OfType<WixBundleMsiFeatureSymbol>().ToLookup(r => r.PackageRef);
321
var msiPropertiesByPackage = this.Section.Symbols.OfType<WixBundleMsiPropertySymbol>().ToLookup(r => r.PackageRef);
322
+ var relatedBundlesByPackage = this.Section.Symbols.OfType<WixBundlePackageRelatedBundleSymbol>().ToLookup(r => r.PackageRef);
323
var relatedPackagesByPackage = this.Section.Symbols.OfType<WixBundleRelatedPackageSymbol>().ToLookup(r => r.PackageRef);
324
var slipstreamMspsByPackage = this.Section.Symbols.OfType<WixBundleSlipstreamMspSymbol>().ToLookup(r => r.TargetPackageRef);
325
var exitCodesByPackage = this.Section.Symbols.OfType<WixBundlePackageExitCodeSymbol>().ToLookup(r => r.ChainPackageId);
@@ -384,6 +385,7 @@ namespace WixToolset.Core.Burn.Bundles
385
if (package.SpecificPackageSymbol is WixBundleBundlePackageSymbol bundlePackage) // BUNDLE
386
{
387
writer.WriteAttributeString("BundleId", bundlePackage.BundleId);
388
+ writer.WriteAttributeString("Version", bundlePackage.Version);
389
writer.WriteAttributeString("InstallArguments", bundlePackage.InstallCommand);
390
writer.WriteAttributeString("UninstallArguments", bundlePackage.UninstallCommand);
391
writer.WriteAttributeString("RepairArguments", bundlePackage.RepairCommand);
@@ -536,6 +538,16 @@ namespace WixToolset.Core.Burn.Bundles
538
writer.WriteEndElement();
539
}
540
541
+ var packageRelatedBundles = relatedBundlesByPackage[package.PackageId];
542
+
543
+ foreach (var relatedBundle in packageRelatedBundles)
544
+ {
545
+ writer.WriteStartElement("RelatedBundle");
546
+ writer.WriteAttributeString("Id", relatedBundle.BundleId);
547
+ writer.WriteAttributeString("Action", relatedBundle.Action.ToString());
548
+ writer.WriteEndElement();
549
+ }
550
+
551
var packageRelatedPackages = relatedPackagesByPackage[package.PackageId];
552
553
foreach (var related in packageRelatedPackages)
src/wix/WixToolset.Core.Burn/Bundles/ProcessBundlePackageCommand.cs
+25
@@ -102,6 +102,8 @@ namespace WixToolset.Core.Burn.Bundles
102
103
var version = registrationElement.GetAttribute("Version");
104
packagePayload.Version = version;
105
+ bundlePackage.Version = version;
106
+ this.Facade.PackageSymbol.Version = version;
107
108
if (String.IsNullOrEmpty(this.Facade.PackageSymbol.CacheId))
109
{
@@ -125,6 +127,8 @@ namespace WixToolset.Core.Burn.Bundles
127
128
this.ProcessPackages(document, namespaceManager);
129
130
+ this.ProcessRelatedBundles(document, namespaceManager);
131
+
132
// TODO: Add payloads?
133
}
134
}
@@ -148,5 +152,26 @@ namespace WixToolset.Core.Burn.Bundles
152
153
this.Facade.PackageSymbol.InstallSize = packageInstallSize;
154
}
155
+
156
+ private void ProcessRelatedBundles(XmlDocument document, XmlNamespaceManager namespaceManager)
157
+ {
158
+ foreach (XmlElement relatedBundleElement in document.SelectNodes("/burn:BurnManifest/burn:RelatedBundle", namespaceManager))
159
+ {
160
+ var id = relatedBundleElement.GetAttribute("Id");
161
+
162
+ if (!Enum.TryParse(relatedBundleElement.GetAttribute("Action"), out RelatedBundleActionType action))
163
+ {
164
+ // TODO: warning
165
+ continue;
166
+ }
167
+
168
+ this.Section.AddSymbol(new WixBundlePackageRelatedBundleSymbol
169
+ {
170
+ PackageRef = this.Facade.PackageId,
171
+ BundleId = id,
172
+ Action = action,
173
+ });
174
+ }
175
+ }
176
}
177
}
src/wix/test/WixToolsetTest.CoreIntegration/BundlePackageFixture.cs
+18
-1
@@ -95,7 +95,11 @@ namespace WixToolsetTest.CoreIntegration
95
.ToArray();
96
WixAssert.CompareLineByLine(new string[]
97
{
98
- $"<BundlePackage Id='chain.exe' Cache='keep' CacheId='{chainBundleId}v1.0.0.0' InstallSize='34' Size='*' PerMachine='yes' Permanent='no' Vital='yes' RollbackBoundaryForward='WixDefaultBoundary' RollbackBoundaryBackward='WixDefaultBoundary' LogPathVariable='WixBundleLog_chain.exe' RollbackLogPathVariable='WixBundleRollbackLog_chain.exe' BundleId='{chainBundleId}' InstallArguments='' UninstallArguments='' RepairArguments='' SupportsBurnProtocol='yes' Win64='no'><Provides Key='MyProviderKey,v1.0' Version='1.0.0.0' DisplayName='BurnBundle' Imported='yes' /><PayloadRef Id='chain.exe' /></BundlePackage>",
98
+ $"<BundlePackage Id='chain.exe' Cache='keep' CacheId='{chainBundleId}v1.0.0.0' InstallSize='34' Size='*' PerMachine='yes' Permanent='no' Vital='yes' RollbackBoundaryForward='WixDefaultBoundary' RollbackBoundaryBackward='WixDefaultBoundary' LogPathVariable='WixBundleLog_chain.exe' RollbackLogPathVariable='WixBundleRollbackLog_chain.exe' BundleId='{chainBundleId}' Version='1.0.0.0' InstallArguments='' UninstallArguments='' RepairArguments='' SupportsBurnProtocol='yes' Win64='no'>" +
99
+ "<Provides Key='MyProviderKey,v1.0' Version='1.0.0.0' DisplayName='BurnBundle' Imported='yes' />" +
100
+ "<RelatedBundle Id='{B94478B1-E1F3-4700-9CE8-6AA090854AEC}' Action='Upgrade' />" +
101
+ "<PayloadRef Id='chain.exe' />" +
102
+ "</BundlePackage>",
103
}, bundlePackages);
104
105
var registrations = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Registration")
@@ -108,6 +112,19 @@ namespace WixToolsetTest.CoreIntegration
112
"<Arp Register='yes' DisplayName='BundlePackageBundle' DisplayVersion='1.0.1.0' Publisher='Example Corporation' />" +
113
"</Registration>"
114
}, registrations);
115
+
116
+ ignoreAttributesByElementName = new Dictionary<string, List<string>>
117
+ {
118
+ { "WixPackageProperties", new List<string> { "DownloadSize", "PackageSize" } },
119
+ };
120
+ var packageElements = extractResult.SelectBADataNodes("/ba:BootstrapperApplicationData/ba:WixPackageProperties")
121
+ .Cast<XmlElement>()
122
+ .Select(e => e.GetTestXml(ignoreAttributesByElementName))
123
+ .ToArray();
124
+ WixAssert.CompareLineByLine(new string[]
125
+ {
126
+ "<WixPackageProperties Package='chain.exe' Vital='yes' DisplayName='BurnBundle' Description='BurnBundle' DownloadSize='*' PackageSize='*' InstalledSize='34' PackageType='Bundle' Permanent='no' LogPathVariable='WixBundleLog_chain.exe' RollbackLogPathVariable='WixBundleRollbackLog_chain.exe' Compressed='yes' Version='1.0.0.0' Cache='keep' />",
127
+ }, packageElements);
128
}
129
}
130
}