@joebigelow / wix / commits / 5d6046be

Replace OnResolveSource with OnCacheAcquireResolving

Inactivate the engine during OnCacheAcquireBegin and Complete to allow setting the source from there. Fixes #3640 Contributes to #5253

Sean Hall committed Apr 16, 2021 at 10:20 UTC 5d6046bee5021052da4a666c1e2ceeb0f16af349
8 files changed +413 -331
src/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h
+33 -30
@@ -54,8 +54,13 @@ enum BOOTSTRAPPER_RELATED_OPERATION
54
55 enum BOOTSTRAPPER_CACHE_OPERATION
56 {
57 + // There is no source available.
58 + BOOTSTRAPPER_CACHE_OPERATION_NONE,
59 + // Copy the payload or container from the chosen local source.
60 BOOTSTRAPPER_CACHE_OPERATION_COPY,
61 + // Download the payload or container using the download URL.
62 BOOTSTRAPPER_CACHE_OPERATION_DOWNLOAD,
63 + // Extract the payload from the container.
64 BOOTSTRAPPER_CACHE_OPERATION_EXTRACT,
65 };
66
@@ -112,7 +117,7 @@ enum BOOTSTRAPPER_APPLICATION_MESSAGE
117 BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEPACKAGEBEGIN,
118 BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEACQUIREBEGIN,
119 BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEACQUIREPROGRESS,
115 - BOOTSTRAPPER_APPLICATION_MESSAGE_ONRESOLVESOURCE,
120 + BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEACQUIRERESOLVING,
121 BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEACQUIRECOMPLETE,
122 BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEVERIFYBEGIN,
123 BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEVERIFYCOMPLETE,
@@ -158,7 +163,7 @@ enum BOOTSTRAPPER_APPLYCOMPLETE_ACTION
163 enum BOOTSTRAPPER_CACHEACQUIRECOMPLETE_ACTION
164 {
165 BOOTSTRAPPER_CACHEACQUIRECOMPLETE_ACTION_NONE,
161 - // Instructs the engine to try the acquisition of the package again.
166 + // Instructs the engine to try the acquisition of the payload again.
167 // Ignored if hrStatus is a success.
168 BOOTSTRAPPER_CACHEACQUIRECOMPLETE_ACTION_RETRY,
169 };
@@ -202,16 +207,6 @@ enum BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION
207 BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION_SUSPEND,
208 };
209
205 -enum BOOTSTRAPPER_RESOLVESOURCE_ACTION
206 -{
207 - // Instructs the engine that the source can't be found.
208 - BOOTSTRAPPER_RESOLVESOURCE_ACTION_NONE,
209 - // Instructs the engine to try the local source again.
210 - BOOTSTRAPPER_RESOLVESOURCE_ACTION_RETRY,
211 - // Instructs the engine to try the download source.
212 - BOOTSTRAPPER_RESOLVESOURCE_ACTION_DOWNLOAD,
213 -};
214 -
210 enum BOOTSTRAPPER_SHUTDOWN_ACTION
211 {
212 BOOTSTRAPPER_SHUTDOWN_ACTION_NONE,
@@ -315,14 +310,17 @@ struct BA_ONCACHEACQUIREBEGIN_ARGS
310 DWORD cbSize;
311 LPCWSTR wzPackageOrContainerId;
312 LPCWSTR wzPayloadId;
318 - BOOTSTRAPPER_CACHE_OPERATION operation;
313 LPCWSTR wzSource;
314 + LPCWSTR wzDownloadUrl;
315 + LPCWSTR wzPayloadContainerId;
316 + BOOTSTRAPPER_CACHE_OPERATION recommendation;
317 };
318
319 struct BA_ONCACHEACQUIREBEGIN_RESULTS
320 {
321 DWORD cbSize;
322 BOOL fCancel;
323 + BOOTSTRAPPER_CACHE_OPERATION action;
324 };
325
326 struct BA_ONCACHEACQUIRECOMPLETE_ARGS
@@ -356,6 +354,28 @@ struct BA_ONCACHEACQUIREPROGRESS_RESULTS
354 BOOL fCancel;
355 };
356
357 +struct BA_ONCACHEACQUIRERESOLVING_ARGS
358 +{
359 + DWORD cbSize;
360 + LPCWSTR wzPackageOrContainerId;
361 + LPCWSTR wzPayloadId;
362 + LPCWSTR* rgSearchPaths;
363 + DWORD cSearchPaths;
364 + BOOL fFoundLocal;
365 + DWORD dwRecommendedSearchPath;
366 + LPCWSTR wzDownloadUrl;
367 + LPCWSTR wzPayloadContainerId;
368 + BOOTSTRAPPER_CACHE_OPERATION recommendation;
369 +};
370 +
371 +struct BA_ONCACHEACQUIRERESOLVING_RESULTS
372 +{
373 + DWORD cbSize;
374 + DWORD dwChosenSearchPath;
375 + BOOTSTRAPPER_CACHE_OPERATION action;
376 + BOOL fCancel;
377 +};
378 +
379 struct BA_ONCACHEBEGIN_ARGS
380 {
381 DWORD cbSize;
@@ -1013,23 +1033,6 @@ struct BA_ONREGISTERCOMPLETE_RESULTS
1033 DWORD cbSize;
1034 };
1035
1016 -struct BA_ONRESOLVESOURCE_ARGS
1017 -{
1018 - DWORD cbSize;
1019 - LPCWSTR wzPackageOrContainerId;
1020 - LPCWSTR wzPayloadId;
1021 - LPCWSTR wzLocalSource;
1022 - LPCWSTR wzDownloadSource;
1023 - BOOTSTRAPPER_RESOLVESOURCE_ACTION recommendation;
1024 -};
1025 -
1026 -struct BA_ONRESOLVESOURCE_RESULTS
1027 -{
1028 - DWORD cbSize;
1029 - BOOTSTRAPPER_RESOLVESOURCE_ACTION action;
1030 - BOOL fCancel;
1031 -};
1032 -
1036 struct BA_ONROLLBACKMSITRANSACTIONBEGIN_ARGS
1037 {
1038 DWORD cbSize;
src/engine/apply.cpp
+132 -110
@@ -23,6 +23,9 @@ typedef struct _BURN_CACHE_CONTEXT
23 DWORD64 qwTotalCacheSize;
24 DWORD64 qwSuccessfulCacheProgress;
25 LPCWSTR wzLayoutDirectory;
26 + LPWSTR* rgSearchPaths;
27 + DWORD cSearchPaths;
28 + DWORD cSearchPathsMax;
29 } BURN_CACHE_CONTEXT;
30
31 typedef struct _BURN_CACHE_ACQUIRE_PROGRESS_CONTEXT
@@ -113,15 +116,6 @@ static HRESULT LayoutOrCacheContainerOrPayload(
116 __in DWORD cTryAgainAttempts,
117 __out BOOL* pfRetry
118 );
116 -static HRESULT PromptForSource(
117 - __in BURN_USER_EXPERIENCE* pUX,
118 - __in_z LPCWSTR wzPackageOrContainerId,
119 - __in_z_opt LPCWSTR wzPayloadId,
120 - __in_z LPCWSTR wzLocalSource,
121 - __in_z_opt LPCWSTR wzDownloadSource,
122 - __out BOOL* pfRetry,
123 - __out BOOL* pfDownload
124 - );
119 static HRESULT CopyPayload(
120 __in BURN_CACHE_ACQUIRE_PROGRESS_CONTEXT* pProgress,
121 __in HANDLE hSourceFile,
@@ -485,6 +479,9 @@ extern "C" HRESULT ApplyCache(
479 cacheContext.qwTotalCacheSize = pPlan->qwCacheSizeTotal;
480 cacheContext.wzLayoutDirectory = pPlan->sczLayoutDirectory;
481
482 + hr = MemAllocArray(reinterpret_cast<LPVOID*>(&cacheContext.rgSearchPaths), sizeof(LPWSTR), BURN_CACHE_MAX_SEARCH_PATHS);
483 + ExitOnNull(cacheContext.rgSearchPaths, hr, E_OUTOFMEMORY, "Failed to allocate cache search paths array.");
484 +
485 for (DWORD i = 0; i < pPlan->cCacheActions; ++i)
486 {
487 BURN_CACHE_ACTION* pCacheAction = pPlan->rgCacheActions + i;
@@ -561,6 +558,12 @@ LExit:
558
559 CacheCleanup(FALSE, pPlan->wzBundleId);
560
561 + for (DWORD i = 0; i < cacheContext.cSearchPathsMax; ++i)
562 + {
563 + ReleaseNullStr(cacheContext.rgSearchPaths[i]);
564 + }
565 + ReleaseMem(cacheContext.rgSearchPaths);
566 +
567 UserExperienceOnCacheComplete(pUX, hr);
568 return hr;
569 }
@@ -949,17 +952,8 @@ static HRESULT ApplyProcessPayload(
952 {
953 fRetry = FALSE;
954
952 - if (pPayload->pContainer)
953 - {
954 - // TODO: only extract container if payload isn't already extracted
955 - hr = ApplyExtractContainer(pContext, pPayload->pContainer);
956 - ExitOnFailure(hr, "Failed to extract container for payload: %ls", pPayload->sczKey);
957 - }
958 - else
959 - {
960 - hr = AcquireContainerOrPayload(pContext, NULL, pPackage, pPayload);
961 - LogExitOnFailure(hr, MSG_FAILED_ACQUIRE_PAYLOAD, "Failed to acquire payload: %ls to working path: %ls", pPayload->sczKey, pPayload->sczUnverifiedPath);
962 - }
955 + hr = AcquireContainerOrPayload(pContext, NULL, pPackage, pPayload);
956 + LogExitOnFailure(hr, MSG_FAILED_ACQUIRE_PAYLOAD, "Failed to acquire payload: %ls to working path: %ls", pPayload->sczKey, pPayload->sczUnverifiedPath);
957
958 pContext->qwSuccessfulCacheProgress += pPayload->qwFileSize;
959
@@ -1054,8 +1048,10 @@ static HRESULT LayoutBundle(
1048 {
1049 HRESULT hr = S_OK;
1050 LPWSTR sczBundlePath = NULL;
1051 + LPWSTR sczBundleDownloadUrl = NULL;
1052 LPWSTR sczDestinationPath = NULL;
1053 int nEquivalentPaths = 0;
1054 + BOOTSTRAPPER_CACHE_OPERATION cacheOperation = BOOTSTRAPPER_CACHE_OPERATION_NONE;
1055 BURN_CACHE_ACQUIRE_PROGRESS_CONTEXT progress = { };
1056 BOOL fRetry = FALSE;
1057 BOOL fRetryAcquire = FALSE;
@@ -1096,7 +1092,7 @@ static HRESULT LayoutBundle(
1092 fRetryAcquire = FALSE;
1093 progress.fCancel = FALSE;
1094
1099 - hr = UserExperienceOnCacheAcquireBegin(pContext->pUX, NULL, NULL, BOOTSTRAPPER_CACHE_OPERATION_COPY, sczBundlePath);
1095 + hr = UserExperienceOnCacheAcquireBegin(pContext->pUX, NULL, NULL, &sczBundlePath, &sczBundleDownloadUrl, NULL, &cacheOperation);
1096 ExitOnRootFailure(hr, "BA aborted cache acquire begin.");
1097
1098 hr = CopyPayload(&progress, pContext->hSourceEngineFile, sczBundlePath, wzUnverifiedPath);
@@ -1142,6 +1138,7 @@ static HRESULT LayoutBundle(
1138
1139 LExit:
1140 ReleaseStr(sczDestinationPath);
1141 + ReleaseStr(sczBundleDownloadUrl);
1142 ReleaseStr(sczBundlePath);
1143
1144 return hr;
@@ -1160,11 +1157,16 @@ static HRESULT AcquireContainerOrPayload(
1157 int nEquivalentPaths = 0;
1158 LPCWSTR wzPackageOrContainerId = pContainer ? pContainer->sczId : pPackage ? pPackage->sczId : NULL;
1159 LPCWSTR wzPayloadId = pPayload ? pPayload->sczKey : NULL;
1160 + LPCWSTR wzPayloadContainerId = pPayload && pPayload->pContainer ? pPayload->pContainer->sczId : NULL;
1161 LPCWSTR wzDestinationPath = pContainer ? pContainer->sczUnverifiedPath: pPayload->sczUnverifiedPath;
1162 LPCWSTR wzRelativePath = pContainer ? pContainer->sczFilePath : pPayload->sczFilePath;
1165 - LPWSTR sczSourceFullPath = NULL;
1163 BURN_CACHE_ACQUIRE_PROGRESS_CONTEXT progress = { };
1164 + BOOL fBeginCalled = FALSE;
1165 BOOL fRetry = FALSE;
1166 + DWORD dwChosenSearchPath = 0;
1167 + BOOTSTRAPPER_CACHE_OPERATION cacheOperation = BOOTSTRAPPER_CACHE_OPERATION_NONE;
1168 + LPWSTR* pwzDownloadUrl = pContainer ? &pContainer->downloadSource.sczUrl : &pPayload->downloadSource.sczUrl;
1169 + LPWSTR* pwzSourcePath = pContainer ? &pContainer->sczSourcePath : &pPayload->sczSourcePath;
1170
1171 progress.pCacheContext = pContext;
1172 progress.pContainer = pContainer;
@@ -1173,86 +1175,148 @@ static HRESULT AcquireContainerOrPayload(
1175
1176 do
1177 {
1176 - LPCWSTR wzDownloadUrl = pContainer ? pContainer->downloadSource.sczUrl : pPayload->downloadSource.sczUrl;
1177 - LPCWSTR wzSourcePath = pContainer ? pContainer->sczSourcePath : pPayload->sczSourcePath;
1178 -
1178 BOOL fFoundLocal = FALSE;
1180 - BOOL fCopy = FALSE;
1181 - BOOL fDownload = FALSE;
1179
1180 + pContext->cSearchPaths = 0;
1181 + dwChosenSearchPath = 0;
1182 fRetry = FALSE;
1183 progress.fCancel = FALSE;
1184 + fBeginCalled = TRUE;
1185
1186 - hr = CacheFindLocalSource(wzSourcePath, wzDestinationPath, pContext->pVariables, &fFoundLocal, &sczSourceFullPath);
1187 - ExitOnFailure(hr, "Failed to search local source.");
1188 -
1189 - if (fFoundLocal) // the file exists locally, so copy it.
1190 - {
1191 - // If the source path and destination path are different, do the copy (otherwise there's no point).
1192 - hr = PathCompare(sczSourceFullPath, wzDestinationPath, &nEquivalentPaths);
1193 - ExitOnFailure(hr, "Failed to determine if payload source path was equivalent to the destination path.");
1186 + hr = UserExperienceOnCacheAcquireBegin(pContext->pUX, wzPackageOrContainerId, wzPayloadId, pwzSourcePath, pwzDownloadUrl, wzPayloadContainerId, &cacheOperation);
1187 + ExitOnRootFailure(hr, "BA aborted cache acquire begin.");
1188
1195 - fCopy = (CSTR_EQUAL != nEquivalentPaths);
1196 - }
1197 - else // can't find the file locally, so prompt for source.
1189 + // Skip the Resolving event and probing local paths if the BA already knew it wanted to download or extract.
1190 + if (BOOTSTRAPPER_CACHE_OPERATION_DOWNLOAD != cacheOperation &&
1191 + BOOTSTRAPPER_CACHE_OPERATION_EXTRACT != cacheOperation)
1192 {
1199 - DWORD dwLogId = pContainer ? (wzPayloadId ? MSG_PROMPT_CONTAINER_PAYLOAD_SOURCE : MSG_PROMPT_CONTAINER_SOURCE) : pPackage ? MSG_PROMPT_PACKAGE_PAYLOAD_SOURCE : MSG_PROMPT_BUNDLE_PAYLOAD_SOURCE;
1200 - LogId(REPORT_STANDARD, dwLogId, wzPackageOrContainerId ? wzPackageOrContainerId : L"", wzPayloadId ? wzPayloadId : L"", sczSourceFullPath);
1193 + hr = CacheGetLocalSourcePaths(wzRelativePath, *pwzSourcePath, wzDestinationPath, pContext->wzLayoutDirectory, pContext->pVariables, &pContext->rgSearchPaths, &pContext->cSearchPaths);
1194 + ExitOnFailure(hr, "Failed to search local source.");
1195
1202 - hr = PromptForSource(pContext->pUX, wzPackageOrContainerId, wzPayloadId, sczSourceFullPath, wzDownloadUrl, &fRetry, &fDownload);
1196 + for (DWORD i = 0; i < pContext->cSearchPaths; ++i)
1197 + {
1198 + // If the file exists locally, choose it.
1199 + if (FileExistsEx(pContext->rgSearchPaths[i], NULL))
1200 + {
1201 + dwChosenSearchPath = i;
1202 +
1203 + fFoundLocal = TRUE;
1204 + break;
1205 + }
1206 + }
1207
1204 - // If the BA requested download then ensure a download url is available (it may have been set
1205 - // during PromptForSource so we need to check again).
1206 - if (fDownload)
1208 + if (BOOTSTRAPPER_CACHE_OPERATION_COPY == cacheOperation)
1209 + {
1210 + if (!fFoundLocal)
1211 + {
1212 + cacheOperation = BOOTSTRAPPER_CACHE_OPERATION_NONE;
1213 + }
1214 + }
1215 + else
1216 {
1208 - wzDownloadUrl = pContainer ? pContainer->downloadSource.sczUrl : pPayload->downloadSource.sczUrl;
1209 - if (!wzDownloadUrl || !*wzDownloadUrl)
1217 + if (fFoundLocal) // the file exists locally, so copy it.
1218 + {
1219 + cacheOperation = BOOTSTRAPPER_CACHE_OPERATION_COPY;
1220 + }
1221 + else if (wzPayloadContainerId)
1222 + {
1223 + cacheOperation = BOOTSTRAPPER_CACHE_OPERATION_EXTRACT;
1224 + }
1225 + else if (*pwzDownloadUrl && **pwzDownloadUrl)
1226 {
1211 - hr = E_INVALIDARG;
1227 + cacheOperation = BOOTSTRAPPER_CACHE_OPERATION_DOWNLOAD;
1228 }
1229 }
1230
1215 - // Log the error
1216 - LogExitOnFailure(hr, MSG_PAYLOAD_FILE_NOT_PRESENT, "Failed while prompting for source (original path '%ls').", sczSourceFullPath);
1231 + // Let the BA have a chance to override the action, but their chance to change the source is during begin or complete.
1232 + hr = UserExperienceOnCacheAcquireResolving(pContext->pUX, wzPackageOrContainerId, wzPayloadId, pContext->rgSearchPaths, pContext->cSearchPaths, fFoundLocal, &dwChosenSearchPath, *pwzDownloadUrl, wzPayloadContainerId, &cacheOperation);
1233 + ExitOnRootFailure(hr, "BA aborted cache acquire resolving.");
1234 }
1235
1219 - if (fCopy)
1236 + switch (cacheOperation)
1237 {
1221 - hr = UserExperienceOnCacheAcquireBegin(pContext->pUX, wzPackageOrContainerId, wzPayloadId, BOOTSTRAPPER_CACHE_OPERATION_COPY, sczSourceFullPath);
1222 - ExitOnRootFailure(hr, "BA aborted cache acquire begin.");
1238 + case BOOTSTRAPPER_CACHE_OPERATION_COPY:
1239 + // If the source path and destination path are different, do the copy (otherwise there's no point).
1240 + hr = PathCompare(pContext->rgSearchPaths[dwChosenSearchPath], wzDestinationPath, &nEquivalentPaths);
1241 + ExitOnFailure(hr, "Failed to determine if payload paths were equivalent, source: %ls, destination: %ls.", pContext->rgSearchPaths[dwChosenSearchPath], wzDestinationPath);
1242
1224 - hr = CopyPayload(&progress, INVALID_HANDLE_VALUE, sczSourceFullPath, wzDestinationPath);
1225 - // Error handling happens after sending complete message to BA.
1243 + if (CSTR_EQUAL != nEquivalentPaths)
1244 + {
1245 + hr = CopyPayload(&progress, INVALID_HANDLE_VALUE, pContext->rgSearchPaths[dwChosenSearchPath], wzDestinationPath);
1246 + // Error handling happens after sending complete message to BA.
1247 +
1248 + // TODO: wait for verification?
1249 + // We successfully copied from a source location, set that as the last used source.
1250 + if (SUCCEEDED(hr))
1251 + {
1252 + CacheSetLastUsedSource(pContext->pVariables, pContext->rgSearchPaths[dwChosenSearchPath], wzRelativePath);
1253 + }
1254 + }
1255
1227 - // We successfully copied from a source location, set that as the last used source.
1228 - if (SUCCEEDED(hr))
1256 + fBeginCalled = FALSE;
1257 + UserExperienceOnCacheAcquireComplete(pContext->pUX, wzPackageOrContainerId, wzPayloadId, hr, &fRetry);
1258 + if (fRetry)
1259 {
1230 - CacheSetLastUsedSource(pContext->pVariables, sczSourceFullPath, wzRelativePath);
1260 + hr = S_OK;
1261 }
1232 - }
1233 - else if (fDownload)
1234 - {
1235 - hr = UserExperienceOnCacheAcquireBegin(pContext->pUX, wzPackageOrContainerId, wzPayloadId, BOOTSTRAPPER_CACHE_OPERATION_DOWNLOAD, wzDownloadUrl);
1236 - ExitOnRootFailure(hr, "BA aborted cache download payload begin.");
1262
1263 + ExitOnFailure(hr, "Failed to acquire payload from: '%ls' to working path: '%ls'", pContext->rgSearchPaths[dwChosenSearchPath], wzDestinationPath);
1264 +
1265 + break;
1266 + case BOOTSTRAPPER_CACHE_OPERATION_DOWNLOAD:
1267 hr = DownloadPayload(&progress, wzDestinationPath);
1268 // Error handling happens after sending complete message to BA.
1240 - }
1269
1242 - if (fCopy || fDownload)
1243 - {
1270 + fBeginCalled = FALSE;
1271 + UserExperienceOnCacheAcquireComplete(pContext->pUX, wzPackageOrContainerId, wzPayloadId, hr, &fRetry);
1272 + if (fRetry)
1273 + {
1274 + hr = S_OK;
1275 + }
1276 +
1277 + ExitOnFailure(hr, "Failed to acquire payload from: '%ls' to working path: '%ls'", *pwzDownloadUrl, wzDestinationPath);
1278 +
1279 + break;
1280 + case BOOTSTRAPPER_CACHE_OPERATION_EXTRACT:
1281 + Assert(pPayload->pContainer);
1282 +
1283 + hr = ApplyExtractContainer(pContext, pPayload->pContainer);
1284 + // Error handling happens after sending complete message to BA.
1285 +
1286 + fBeginCalled = FALSE;
1287 + UserExperienceOnCacheAcquireComplete(pContext->pUX, wzPackageOrContainerId, wzPayloadId, hr, &fRetry);
1288 + if (fRetry)
1289 + {
1290 + hr = S_OK;
1291 + }
1292 +
1293 + ExitOnFailure(hr, "Failed to extract container for payload: %ls", wzPayloadId);
1294 +
1295 + break;
1296 + case BOOTSTRAPPER_CACHE_OPERATION_NONE:
1297 + hr = E_FILENOTFOUND;
1298 + LogErrorId(hr, MSG_RESOLVE_SOURCE_FAILED, wzPayloadId, pPackage ? pPackage->sczId : NULL, pContainer ? pContainer->sczId : NULL);
1299 +
1300 + fBeginCalled = FALSE;
1301 UserExperienceOnCacheAcquireComplete(pContext->pUX, wzPackageOrContainerId, wzPayloadId, hr, &fRetry);
1302 if (fRetry)
1303 {
1304 hr = S_OK;
1305 }
1306 +
1307 + ExitOnFailure(hr, "Failed to resolve source, payload: %ls, package: %ls, container: %ls", wzPayloadId, pPackage ? pPackage->sczId : NULL, pContainer ? pContainer->sczId : NULL);
1308 +
1309 + break;
1310 }
1250 - ExitOnFailure(hr, "Failed to acquire payload from: '%ls' to working path: '%ls'", fCopy ? sczSourceFullPath : wzDownloadUrl, wzDestinationPath);
1311 } while (fRetry);
1252 - ExitOnFailure(hr, "Failed to find external payload to cache.");
1312
1313 LExit:
1255 - ReleaseStr(sczSourceFullPath);
1314 + if (fBeginCalled)
1315 + {
1316 + UserExperienceOnCacheAcquireComplete(pContext->pUX, wzPackageOrContainerId, wzPayloadId, hr, &fRetry);
1317 + }
1318 +
1319 + pContext->cSearchPathsMax = max(pContext->cSearchPaths, pContext->cSearchPathsMax);
1320
1321 return hr;
1322 }
@@ -1355,48 +1419,6 @@ LExit:
1419 return hr;
1420 }
1421
1358 -static HRESULT PromptForSource(
1359 - __in BURN_USER_EXPERIENCE* pUX,
1360 - __in_z LPCWSTR wzPackageOrContainerId,
1361 - __in_z_opt LPCWSTR wzPayloadId,
1362 - __in_z LPCWSTR wzLocalSource,
1363 - __in_z_opt LPCWSTR wzDownloadSource,
1364 - __inout BOOL* pfRetry,
1365 - __inout BOOL* pfDownload
1366 - )
1367 -{
1368 - HRESULT hr = S_OK;
1369 - BOOTSTRAPPER_RESOLVESOURCE_ACTION action = BOOTSTRAPPER_RESOLVESOURCE_ACTION_NONE;
1370 -
1371 - hr = UserExperienceOnResolveSource(pUX, wzPackageOrContainerId, wzPayloadId, wzLocalSource, wzDownloadSource, &action);
1372 - if (FAILED(hr))
1373 - {
1374 - ExitFunction();
1375 - }
1376 -
1377 - switch (action)
1378 - {
1379 - case BOOTSTRAPPER_RESOLVESOURCE_ACTION_NONE:
1380 - hr = E_FILENOTFOUND;
1381 - break;
1382 -
1383 - case BOOTSTRAPPER_RESOLVESOURCE_ACTION_RETRY:
1384 - *pfRetry = TRUE;
1385 - break;
1386 -
1387 - case BOOTSTRAPPER_RESOLVESOURCE_ACTION_DOWNLOAD:
1388 - *pfDownload = TRUE;
1389 - break;
1390 -
1391 - default:
1392 - hr = E_INVALIDARG;
1393 - break;
1394 - }
1395 -
1396 -LExit:
1397 - return hr;
1398 -}
1399 -
1422 static HRESULT CopyPayload(
1423 __in BURN_CACHE_ACQUIRE_PROGRESS_CONTEXT* pProgress,
1424 __in HANDLE hSourceFile,
src/engine/cache.cpp
+126 -77
@@ -11,7 +11,7 @@ static const DWORD FILE_OPERATION_RETRY_WAIT = 2000;
11
12 static BOOL vfInitializedCache = FALSE;
13 static BOOL vfRunningFromCache = FALSE;
14 -static LPWSTR vsczSourceProcessPath = NULL;
14 +static LPWSTR vsczSourceProcessFolder = NULL;
15 static LPWSTR vsczWorkingFolder = NULL;
16 static LPWSTR vsczDefaultUserPackageCache = NULL;
17 static LPWSTR vsczDefaultMachinePackageCache = NULL;
@@ -140,8 +140,8 @@ extern "C" HRESULT CacheInitialize(
140 wzSourceProcessPath = sczCurrentPath;
141 }
142
143 - hr = StrAllocString(&vsczSourceProcessPath, wzSourceProcessPath, 0);
144 - ExitOnFailure(hr, "Failed to initialize cache source path.");
143 + hr = PathGetDirectory(wzSourceProcessPath, &vsczSourceProcessFolder);
144 + ExitOnFailure(hr, "Failed to initialize cache source folder.");
145
146 // If we're not running from the cache, ensure the original source is set.
147 if (!vfRunningFromCache)
@@ -393,112 +393,166 @@ LExit:
393 return hr;
394 }
395
396 -extern "C" HRESULT CacheFindLocalSource(
396 +extern "C" HRESULT CacheGetLocalSourcePaths(
397 + __in_z LPCWSTR wzRelativePath,
398 __in_z LPCWSTR wzSourcePath,
399 __in_z LPCWSTR wzDestinationPath,
400 + __in_z_opt LPCWSTR wzLayoutDirectory,
401 __in BURN_VARIABLES* pVariables,
400 - __out BOOL* pfFound,
401 - __out_z LPWSTR* psczSourceFullPath
402 + __inout LPWSTR** prgSearchPaths,
403 + __out DWORD* pcSearchPaths
404 )
405 {
406 HRESULT hr = S_OK;
405 - LPWSTR sczSourceProcessFolder = NULL;
407 LPWSTR sczCurrentPath = NULL;
407 - LPWSTR sczLastSourcePath = NULL;
408 LPWSTR sczLastSourceFolder = NULL;
409 - LPWSTR sczLayoutPath = NULL;
410 - LPWSTR sczLayoutFolder = NULL;
411 - LPCWSTR rgwzSearchPaths[4] = { };
409 + LPWSTR* psczPath = NULL;
410 + BOOL fPreferSourcePathLocation = FALSE;
411 + BOOL fTryLastFolder = FALSE;
412 + BOOL fTryRelativePath = FALSE;
413 + BOOL fSourceIsAbsolute = FALSE;
414 DWORD cSearchPaths = 0;
415
414 - // If the source path provided is a full path, obviously that is where we should be looking.
415 - if (PathIsAbsolute(wzSourcePath))
416 + AssertSz(vfInitializedCache, "Cache wasn't initialized");
417 +
418 + hr = GetLastUsedSourceFolder(pVariables, &sczLastSourceFolder);
419 + fPreferSourcePathLocation = !vfRunningFromCache || FAILED(hr);
420 + fTryLastFolder = SUCCEEDED(hr) && sczLastSourceFolder && *sczLastSourceFolder && CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, vsczSourceProcessFolder, -1, sczLastSourceFolder, -1);
421 + fTryRelativePath = CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, wzSourcePath, -1, wzRelativePath, -1);
422 + fSourceIsAbsolute = PathIsAbsolute(wzSourcePath);
423 +
424 + // If the source path provided is a full path, try that first.
425 + if (fSourceIsAbsolute)
426 {
417 - rgwzSearchPaths[0] = wzSourcePath;
418 - cSearchPaths = 1;
427 + hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(prgSearchPaths), cSearchPaths + 1, sizeof(LPWSTR), BURN_CACHE_MAX_SEARCH_PATHS);
428 + ExitOnFailure(hr, "Failed to ensure size for search paths array.");
429 +
430 + psczPath = *prgSearchPaths + cSearchPaths;
431 + ++cSearchPaths;
432 +
433 + hr = StrAllocString(psczPath, wzSourcePath, 0);
434 + ExitOnFailure(hr, "Failed to copy absolute source path.");
435 }
420 - else
436 +
437 + // Try the destination path next.
438 + hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(prgSearchPaths), cSearchPaths + 1, sizeof(LPWSTR), BURN_CACHE_MAX_SEARCH_PATHS);
439 + ExitOnFailure(hr, "Failed to ensure size for search paths array.");
440 +
441 + psczPath = *prgSearchPaths + cSearchPaths;
442 + ++cSearchPaths;
443 +
444 + hr = StrAllocString(psczPath, wzDestinationPath, 0);
445 + ExitOnFailure(hr, "Failed to copy absolute source path.");
446 +
447 + if (!fSourceIsAbsolute)
448 {
422 - // Use the destination path first.
423 - rgwzSearchPaths[0] = wzDestinationPath;
424 - cSearchPaths = 1;
425 -
426 - // If we're not running from cache or we couldn't get the last source, use
427 - // the source path location. In the case where we are in the bundle's
428 - // package cache and couldn't find a last used source we unfortunately will
429 - // be picking the package cache path which isn't likely to have what we are
430 - // looking for.
431 - hr = GetLastUsedSourceFolder(pVariables, &sczLastSourceFolder);
432 - if (!vfRunningFromCache || FAILED(hr))
449 + // Calculate the source path location.
450 + // In the case where we are in the bundle's package cache and
451 + // couldn't find a last used source that will be the package cache path
452 + // which isn't likely to have what we are looking for.
453 + hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(prgSearchPaths), cSearchPaths + 1, sizeof(LPWSTR), BURN_CACHE_MAX_SEARCH_PATHS);
454 + ExitOnFailure(hr, "Failed to ensure size for search paths array.");
455 +
456 + hr = PathConcat(vsczSourceProcessFolder, wzSourcePath, &sczCurrentPath);
457 + ExitOnFailure(hr, "Failed to combine source process folder with source.");
458 +
459 + // If we're not running from cache or we couldn't get the last source,
460 + // try the source path location next.
461 + if (fPreferSourcePathLocation)
462 {
434 - hr = PathGetDirectory(vsczSourceProcessPath, &sczSourceProcessFolder);
435 - ExitOnFailure(hr, "Failed to get current process directory.");
463 + (*prgSearchPaths)[cSearchPaths] = sczCurrentPath;
464 + ++cSearchPaths;
465 + sczCurrentPath = NULL;
466 + }
467
437 - hr = PathConcat(sczSourceProcessFolder, wzSourcePath, &sczCurrentPath);
468 + // If we have a last used source and it is not the source path location,
469 + // add the last used source to the search path next.
470 + if (fTryLastFolder)
471 + {
472 + hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(prgSearchPaths), cSearchPaths + 1, sizeof(LPWSTR), BURN_CACHE_MAX_SEARCH_PATHS);
473 + ExitOnFailure(hr, "Failed to ensure size for search paths array.");
474 +
475 + psczPath = *prgSearchPaths + cSearchPaths;
476 + ++cSearchPaths;
477 +
478 + hr = PathConcat(sczLastSourceFolder, wzSourcePath, psczPath);
479 ExitOnFailure(hr, "Failed to combine last source with source.");
480 + }
481
440 - rgwzSearchPaths[cSearchPaths] = sczCurrentPath;
482 + if (!fPreferSourcePathLocation)
483 + {
484 + (*prgSearchPaths)[cSearchPaths] = sczCurrentPath;
485 ++cSearchPaths;
486 + sczCurrentPath = NULL;
487 }
488
444 - // If we have a last used source and it does not duplicate the existing search path,
445 - // add the last used source to the search path second.
446 - if (sczLastSourceFolder && *sczLastSourceFolder)
489 + // Also consider the layout directory if doing Layout.
490 + if (wzLayoutDirectory)
491 {
448 - hr = PathConcat(sczLastSourceFolder, wzSourcePath, &sczLastSourcePath);
449 - ExitOnFailure(hr, "Failed to combine last source with source.");
492 + hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(prgSearchPaths), cSearchPaths + 1, sizeof(LPWSTR), BURN_CACHE_MAX_SEARCH_PATHS);
493 + ExitOnFailure(hr, "Failed to ensure size for search paths array.");
494
451 - if (1 == cSearchPaths || CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, rgwzSearchPaths[1], -1, sczLastSourcePath, -1))
452 - {
453 - rgwzSearchPaths[cSearchPaths] = sczLastSourcePath;
454 - ++cSearchPaths;
455 - }
495 + psczPath = *prgSearchPaths + cSearchPaths;
496 + ++cSearchPaths;
497 +
498 + hr = PathConcat(wzLayoutDirectory, wzSourcePath, psczPath);
499 + ExitOnFailure(hr, "Failed to combine layout source with source.");
500 }
501 + }
502
458 - // Also consider the layout directory if set on the command line or by the BA.
459 - hr = VariableGetString(pVariables, BURN_BUNDLE_LAYOUT_DIRECTORY, &sczLayoutFolder);
460 - if (E_NOTFOUND != hr)
503 + if (fTryRelativePath)
504 + {
505 + hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(prgSearchPaths), cSearchPaths + 1, sizeof(LPWSTR), BURN_CACHE_MAX_SEARCH_PATHS);
506 + ExitOnFailure(hr, "Failed to ensure size for search paths array.");
507 +
508 + hr = PathConcat(vsczSourceProcessFolder, wzRelativePath, &sczCurrentPath);
509 + ExitOnFailure(hr, "Failed to combine source process folder with relative.");
510 +
511 + if (fPreferSourcePathLocation)
512 {
462 - ExitOnFailure(hr, "Failed to get bundle layout directory property.");
513 + (*prgSearchPaths)[cSearchPaths] = sczCurrentPath;
514 + ++cSearchPaths;
515 + sczCurrentPath = NULL;
516 + }
517
464 - hr = PathConcat(sczLayoutFolder, wzSourcePath, &sczLayoutPath);
465 - ExitOnFailure(hr, "Failed to combine layout source with source.");
518 + if (fTryLastFolder)
519 + {
520 + hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(prgSearchPaths), cSearchPaths + 1, sizeof(LPWSTR), BURN_CACHE_MAX_SEARCH_PATHS);
521 + ExitOnFailure(hr, "Failed to ensure size for search paths array.");
522
467 - rgwzSearchPaths[cSearchPaths] = sczLayoutPath;
523 + psczPath = *prgSearchPaths + cSearchPaths;
524 ++cSearchPaths;
525 +
526 + hr = PathConcat(sczLastSourceFolder, wzRelativePath, psczPath);
527 + ExitOnFailure(hr, "Failed to combine last source with relative.");
528 }
470 - }
529
472 - *pfFound = FALSE; // assume we won't find the file locally.
530 + if (!fPreferSourcePathLocation)
531 + {
532 + (*prgSearchPaths)[cSearchPaths] = sczCurrentPath;
533 + ++cSearchPaths;
534 + sczCurrentPath = NULL;
535 + }
536
474 - for (DWORD i = 0; i < cSearchPaths; ++i)
475 - {
476 - // If the file exists locally, copy its path.
477 - if (FileExistsEx(rgwzSearchPaths[i], NULL))
537 + if (wzLayoutDirectory)
538 {
479 - hr = StrAllocString(psczSourceFullPath, rgwzSearchPaths[i], 0);
480 - ExitOnFailure(hr, "Failed to copy source path.");
539 + hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(prgSearchPaths), cSearchPaths + 1, sizeof(LPWSTR), BURN_CACHE_MAX_SEARCH_PATHS);
540 + ExitOnFailure(hr, "Failed to ensure size for search paths array.");
541
482 - *pfFound = TRUE;
483 - break;
484 - }
485 - }
542 + psczPath = *prgSearchPaths + cSearchPaths;
543 + ++cSearchPaths;
544
487 - // If nothing was found, return the first thing in our search path as the
488 - // best path where we thought we should have found the file.
489 - if (!*pfFound)
490 - {
491 - hr = StrAllocString(psczSourceFullPath, rgwzSearchPaths[0], 0);
492 - ExitOnFailure(hr, "Failed to copy source path.");
545 + hr = PathConcat(wzLayoutDirectory, wzSourcePath, psczPath);
546 + ExitOnFailure(hr, "Failed to combine layout source with relative.");
547 + }
548 }
549
550 LExit:
551 ReleaseStr(sczCurrentPath);
497 - ReleaseStr(sczSourceProcessFolder);
552 ReleaseStr(sczLastSourceFolder);
499 - ReleaseStr(sczLastSourcePath);
500 - ReleaseStr(sczLayoutFolder);
501 - ReleaseStr(sczLayoutPath);
553 +
554 + AssertSz(cSearchPaths <= BURN_CACHE_MAX_SEARCH_PATHS, "Got more than BURN_CACHE_MAX_SEARCH_PATHS search paths");
555 + *pcSearchPaths = cSearchPaths;
556
557 return hr;
558 }
@@ -1079,7 +1133,7 @@ extern "C" void CacheUninitialize()
1133 ReleaseNullStr(vsczDefaultMachinePackageCache);
1134 ReleaseNullStr(vsczDefaultUserPackageCache);
1135 ReleaseNullStr(vsczWorkingFolder);
1082 - ReleaseNullStr(vsczSourceProcessPath);
1136 + ReleaseNullStr(vsczSourceProcessFolder);
1137
1138 vfRunningFromCache = FALSE;
1139 vfInitializedCache = FALSE;
@@ -1224,17 +1278,12 @@ static HRESULT GetLastUsedSourceFolder(
1278 )
1279 {
1280 HRESULT hr = S_OK;
1227 - LPWSTR sczOriginalSource = NULL;
1281
1282 hr = VariableGetString(pVariables, BURN_BUNDLE_LAST_USED_SOURCE, psczLastSource);
1283 if (E_NOTFOUND == hr)
1284 {
1285 // Try the original source folder.
1233 - hr = VariableGetString(pVariables, BURN_BUNDLE_ORIGINAL_SOURCE, &sczOriginalSource);
1234 - if (SUCCEEDED(hr))
1235 - {
1236 - hr = PathGetDirectory(sczOriginalSource, psczLastSource);
1237 - }
1286 + hr = VariableGetString(pVariables, BURN_BUNDLE_ORIGINAL_SOURCE_FOLDER, psczLastSource);
1287 }
1288
1289 return hr;
src/engine/cache.h
+6 -3
@@ -1,6 +1,7 @@
1 #pragma once
2 // 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.
3
4 +#define BURN_CACHE_MAX_SEARCH_PATHS 7
5
6 #ifdef __cplusplus
7 extern "C" {
@@ -52,12 +53,14 @@ HRESULT CacheGetResumePath(
53 __in_z LPCWSTR wzPayloadWorkingPath,
54 __deref_out_z LPWSTR* psczResumePath
55 );
55 -HRESULT CacheFindLocalSource(
56 +HRESULT CacheGetLocalSourcePaths(
57 + __in_z LPCWSTR wzRelativePath,
58 __in_z LPCWSTR wzSourcePath,
59 __in_z LPCWSTR wzDestinationPath,
60 + __in_z_opt LPCWSTR wzLayoutDirectory,
61 __in BURN_VARIABLES* pVariables,
59 - __out BOOL* pfFound,
60 - __out_z LPWSTR* psczSourceFullPath
62 + __inout LPWSTR** prgSearchPaths,
63 + __out DWORD* pcSearchPaths
64 );
65 HRESULT CacheSetLastUsedSource(
66 __in BURN_VARIABLES* pVariables,
src/engine/engine.mc
+2 -30
@@ -151,9 +151,9 @@ Bundle global condition check didn't succeed - aborting without loading applicat
151
152 MessageId=54
153 Severity=Error
154 -SymbolicName=MSG_PAYLOAD_FILE_NOT_PRESENT
154 +SymbolicName=MSG_RESOLVE_SOURCE_FAILED
155 Language=English
156 -Failed to resolve source for file: %2!ls!, error: %1!ls!.
156 +Failed to resolve source for payload: %2!ls!, package: %3!ls!, container: %4!ls!, error: %1!ls!.
157 .
158
159 MessageId=55
@@ -724,34 +724,6 @@ Language=English
724 Acquiring package: %1!ls!, payload: %2!ls!, %3!hs! from: %4!ls!
725 .
726
727 -MessageId=340
728 -Severity=Warning
729 -SymbolicName=MSG_PROMPT_BUNDLE_PAYLOAD_SOURCE
730 -Language=English
731 -Prompt for source of bundle payload: %2!ls!, path: %3!ls!
732 -.
733 -
734 -MessageId=341
735 -Severity=Warning
736 -SymbolicName=MSG_PROMPT_CONTAINER_SOURCE
737 -Language=English
738 -Prompt for source of container: %1!ls!, path: %3!ls!
739 -.
740 -
741 -MessageId=342
742 -Severity=Warning
743 -SymbolicName=MSG_PROMPT_CONTAINER_PAYLOAD_SOURCE
744 -Language=English
745 -Prompt for source of container: %1!ls!, payload: %2!ls!, path: %3!ls!
746 -.
747 -
748 -MessageId=343
749 -Severity=Warning
750 -SymbolicName=MSG_PROMPT_PACKAGE_PAYLOAD_SOURCE
751 -Language=English
752 -Prompt for source of package: %1!ls!, payload: %2!ls!, path: %3!ls!
753 -.
754 -
727 MessageId=348
728 Severity=Warning
729 SymbolicName=MSG_APPLY_RETRYING_PACKAGE
src/engine/externalengine.cpp
+17 -26
@@ -269,8 +269,7 @@ HRESULT ExternalEngineSetUpdate(
269 )
270 {
271 HRESULT hr = S_OK;
272 - LPCWSTR sczId = NULL;
273 - LPWSTR sczLocalSource = NULL;
272 + LPWSTR sczFilePath = NULL;
273 LPWSTR sczCommandline = NULL;
274 UUID guid = { };
275 WCHAR wzGuid[39];
@@ -296,38 +295,30 @@ HRESULT ExternalEngineSetUpdate(
295 {
296 UpdateUninitialize(&pEngineState->update);
297
299 - if (!wzLocalSource || !*wzLocalSource)
300 - {
301 - hr = StrAllocFormatted(&sczLocalSource, L"update\\%ls", pEngineState->registration.sczExecutableName);
302 - ExitOnFailure(hr, "Failed to default local update source");
303 - }
304 -
298 hr = CoreRecreateCommandLine(&sczCommandline, BOOTSTRAPPER_ACTION_INSTALL, pEngineState->command.display, pEngineState->command.restart, BOOTSTRAPPER_RELATION_NONE, FALSE, pEngineState->registration.sczActiveParent, pEngineState->registration.sczAncestors, NULL, pEngineState->command.wzCommandLine);
299 ExitOnFailure(hr, "Failed to recreate command-line for update bundle.");
300
308 - // Per-user bundles would fail to use the downloaded update bundle, as the existing install would already be cached
309 - // at the registration id's location. Here I am generating a random guid, but in the future it would be nice if the
310 - // feed would provide the ID of the update.
311 - if (!pEngineState->registration.fPerMachine)
301 + // Bundles would fail to use the downloaded update bundle, as the running bundle would be one of the search paths.
302 + // Here I am generating a random guid, but in the future it would be nice if the feed would provide the ID of the update.
303 + rs = ::UuidCreate(&guid);
304 + hr = HRESULT_FROM_RPC(rs);
305 + ExitOnFailure(hr, "Failed to create bundle update guid.");
306 +
307 + if (!::StringFromGUID2(guid, wzGuid, countof(wzGuid)))
308 {
313 - rs = ::UuidCreate(&guid);
314 - hr = HRESULT_FROM_RPC(rs);
315 - ExitOnFailure(hr, "Failed to create bundle update guid.");
309 + hr = E_OUTOFMEMORY;
310 + ExitOnRootFailure(hr, "Failed to convert bundle update guid into string.");
311 + }
312
317 - if (!::StringFromGUID2(guid, wzGuid, countof(wzGuid)))
318 - {
319 - hr = E_OUTOFMEMORY;
320 - ExitOnRootFailure(hr, "Failed to convert bundle update guid into string.");
321 - }
313 + hr = StrAllocFormatted(&sczFilePath, L"%ls\\%ls", wzGuid, pEngineState->registration.sczExecutableName);
314 + ExitOnFailure(hr, "Failed to build bundle update file path.");
315
323 - sczId = wzGuid;
324 - }
325 - else
316 + if (!wzLocalSource || !*wzLocalSource)
317 {
327 - sczId = pEngineState->registration.sczId;
318 + wzLocalSource = sczFilePath;
319 }
320
330 - hr = PseudoBundleInitialize(FILEMAKEVERSION(rmj, rmm, rup, rpr), &pEngineState->update.package, FALSE, sczId, BOOTSTRAPPER_RELATION_UPDATE, BOOTSTRAPPER_PACKAGE_STATE_ABSENT, FALSE, pEngineState->registration.sczExecutableName, sczLocalSource ? sczLocalSource : wzLocalSource, wzDownloadSource, qwSize, TRUE, sczCommandline, NULL, NULL, NULL, rgbHash, cbHash);
321 + hr = PseudoBundleInitialize(FILEMAKEVERSION(rmj, rmm, rup, rpr), &pEngineState->update.package, FALSE, pEngineState->registration.sczId, BOOTSTRAPPER_RELATION_UPDATE, BOOTSTRAPPER_PACKAGE_STATE_ABSENT, FALSE, sczFilePath, wzLocalSource, wzDownloadSource, qwSize, TRUE, sczCommandline, NULL, NULL, NULL, rgbHash, cbHash);
322 ExitOnFailure(hr, "Failed to set update bundle.");
323
324 pEngineState->update.fUpdateAvailable = TRUE;
@@ -337,7 +328,7 @@ LExit:
328 ::LeaveCriticalSection(&pEngineState->userExperience.csEngineActive);
329
330 ReleaseStr(sczCommandline);
340 - ReleaseStr(sczLocalSource);
331 + ReleaseStr(sczFilePath);
332
333 return hr;
334 }
src/engine/userexperience.cpp
+81 -45
@@ -395,29 +395,46 @@ EXTERN_C BAAPI UserExperienceOnCacheAcquireBegin(
395 __in BURN_USER_EXPERIENCE* pUserExperience,
396 __in_z_opt LPCWSTR wzPackageOrContainerId,
397 __in_z_opt LPCWSTR wzPayloadId,
398 - __in BOOTSTRAPPER_CACHE_OPERATION operation,
399 - __in_z LPCWSTR wzSource
398 + __in_z LPWSTR* pwzSource,
399 + __in_z LPWSTR* pwzDownloadUrl,
400 + __in_z_opt LPCWSTR wzPayloadContainerId,
401 + __out BOOTSTRAPPER_CACHE_OPERATION* pCacheOperation
402 )
403 {
404 HRESULT hr = S_OK;
405 BA_ONCACHEACQUIREBEGIN_ARGS args = { };
406 BA_ONCACHEACQUIREBEGIN_RESULTS results = { };
407 + *pCacheOperation = BOOTSTRAPPER_CACHE_OPERATION_NONE;
408
409 args.cbSize = sizeof(args);
410 args.wzPackageOrContainerId = wzPackageOrContainerId;
411 args.wzPayloadId = wzPayloadId;
409 - args.operation = operation;
410 - args.wzSource = wzSource;
412 + args.wzSource = *pwzSource;
413 + args.wzDownloadUrl = *pwzDownloadUrl;
414 + args.wzPayloadContainerId = wzPayloadContainerId;
415 + args.recommendation = *pCacheOperation;
416
417 results.cbSize = sizeof(results);
418 + results.action = *pCacheOperation;
419
414 - hr = SendBAMessage(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEACQUIREBEGIN, &args, &results);
420 + hr = SendBAMessageFromInactiveEngine(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEACQUIREBEGIN, &args, &results);
421 ExitOnFailure(hr, "BA OnCacheAcquireBegin failed.");
422
423 if (results.fCancel)
424 {
425 hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT);
426 }
427 + else
428 + {
429 + // Verify the BA requested an action that is possible.
430 + if (BOOTSTRAPPER_CACHE_OPERATION_DOWNLOAD == results.action && *pwzDownloadUrl && **pwzDownloadUrl ||
431 + BOOTSTRAPPER_CACHE_OPERATION_EXTRACT == results.action && wzPayloadContainerId ||
432 + BOOTSTRAPPER_CACHE_OPERATION_COPY == results.action ||
433 + BOOTSTRAPPER_CACHE_OPERATION_NONE == results.action)
434 + {
435 + *pCacheOperation = results.action;
436 + }
437 + }
438
439 LExit:
440 return hr;
@@ -444,7 +461,7 @@ EXTERN_C BAAPI UserExperienceOnCacheAcquireComplete(
461 results.cbSize = sizeof(results);
462 results.action = args.recommendation;
463
447 - hr = SendBAMessage(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEACQUIRECOMPLETE, &args, &results);
464 + hr = SendBAMessageFromInactiveEngine(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEACQUIRECOMPLETE, &args, &results);
465 ExitOnFailure(hr, "BA OnCacheAcquireComplete failed.");
466
467 if (FAILED(hrStatus))
@@ -490,6 +507,64 @@ LExit:
507 return hr;
508 }
509
510 +EXTERN_C BAAPI UserExperienceOnCacheAcquireResolving(
511 + __in BURN_USER_EXPERIENCE* pUserExperience,
512 + __in_z_opt LPCWSTR wzPackageOrContainerId,
513 + __in_z_opt LPCWSTR wzPayloadId,
514 + __in_z LPWSTR* rgSearchPaths,
515 + __in DWORD cSearchPaths,
516 + __in BOOL fFoundLocal,
517 + __in DWORD* pdwChosenSearchPath,
518 + __in_z_opt LPCWSTR wzDownloadUrl,
519 + __in_z_opt LPCWSTR wzPayloadContainerId,
520 + __inout BOOTSTRAPPER_CACHE_OPERATION* pCacheOperation
521 + )
522 +{
523 + HRESULT hr = S_OK;
524 + BA_ONCACHEACQUIRERESOLVING_ARGS args = { };
525 + BA_ONCACHEACQUIRERESOLVING_RESULTS results = { };
526 +
527 + args.cbSize = sizeof(args);
528 + args.wzPackageOrContainerId = wzPackageOrContainerId;
529 + args.wzPayloadId = wzPayloadId;
530 + args.rgSearchPaths = const_cast<LPCWSTR*>(rgSearchPaths);
531 + args.cSearchPaths = cSearchPaths;
532 + args.fFoundLocal = fFoundLocal;
533 + args.dwRecommendedSearchPath = *pdwChosenSearchPath;
534 + args.wzDownloadUrl = wzDownloadUrl;
535 + args.recommendation = *pCacheOperation;
536 +
537 + results.cbSize = sizeof(results);
538 + results.dwChosenSearchPath = *pdwChosenSearchPath;
539 + results.action = *pCacheOperation;
540 +
541 + hr = SendBAMessage(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEACQUIRERESOLVING, &args, &results);
542 + ExitOnFailure(hr, "BA OnCacheAcquireResolving failed.");
543 +
544 + if (results.fCancel)
545 + {
546 + hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT);
547 + }
548 + else
549 + {
550 + // Verify the BA requested an action that is possible.
551 + if (BOOTSTRAPPER_CACHE_OPERATION_DOWNLOAD == results.action && wzDownloadUrl && *wzDownloadUrl ||
552 + BOOTSTRAPPER_CACHE_OPERATION_EXTRACT == results.action && wzPayloadContainerId ||
553 + BOOTSTRAPPER_CACHE_OPERATION_NONE == results.action)
554 + {
555 + *pCacheOperation = results.action;
556 + }
557 + else if (BOOTSTRAPPER_CACHE_OPERATION_COPY == results.action && results.dwChosenSearchPath < cSearchPaths)
558 + {
559 + *pdwChosenSearchPath = results.dwChosenSearchPath;
560 + *pCacheOperation = results.action;
561 + }
562 + }
563 +
564 +LExit:
565 + return hr;
566 +}
567 +
568 EXTERN_C BAAPI UserExperienceOnCacheBegin(
569 __in BURN_USER_EXPERIENCE* pUserExperience
570 )
@@ -1861,45 +1936,6 @@ LExit:
1936 return hr;
1937 }
1938
1864 -EXTERN_C BAAPI UserExperienceOnResolveSource(
1865 - __in BURN_USER_EXPERIENCE* pUserExperience,
1866 - __in_z LPCWSTR wzPackageOrContainerId,
1867 - __in_z_opt LPCWSTR wzPayloadId,
1868 - __in_z LPCWSTR wzLocalSource,
1869 - __in_z_opt LPCWSTR wzDownloadSource,
1870 - __inout BOOTSTRAPPER_RESOLVESOURCE_ACTION* pAction
1871 - )
1872 -{
1873 - HRESULT hr = S_OK;
1874 - BA_ONRESOLVESOURCE_ARGS args = { };
1875 - BA_ONRESOLVESOURCE_RESULTS results = { };
1876 -
1877 - args.cbSize = sizeof(args);
1878 - args.wzPackageOrContainerId = wzPackageOrContainerId;
1879 - args.wzPayloadId = wzPayloadId;
1880 - args.wzLocalSource = wzLocalSource;
1881 - args.wzDownloadSource = wzDownloadSource;
1882 - args.recommendation = *pAction;
1883 -
1884 - results.cbSize = sizeof(results);
1885 - results.action = *pAction;
1886 -
1887 - hr = SendBAMessageFromInactiveEngine(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONRESOLVESOURCE, &args, &results);
1888 - ExitOnFailure(hr, "BA OnResolveSource failed.");
1889 -
1890 - if (results.fCancel)
1891 - {
1892 - hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT);
1893 - }
1894 - else
1895 - {
1896 - *pAction = results.action;
1897 - }
1898 -
1899 -LExit:
1900 - return hr;
1901 -}
1902 -
1939 EXTERN_C BAAPI UserExperienceOnRollbackMsiTransactionBegin(
1940 __in BURN_USER_EXPERIENCE* pUserExperience,
1941 __in LPCWSTR wzTransactionId
src/engine/userexperience.h
+16 -10
@@ -126,8 +126,10 @@ BAAPI UserExperienceOnCacheAcquireBegin(
126 __in BURN_USER_EXPERIENCE* pUserExperience,
127 __in_z_opt LPCWSTR wzPackageOrContainerId,
128 __in_z_opt LPCWSTR wzPayloadId,
129 - __in BOOTSTRAPPER_CACHE_OPERATION operation,
130 - __in_z LPCWSTR wzSource
129 + __in_z LPWSTR* pwzSource,
130 + __in_z LPWSTR* pwzDownloadUrl,
131 + __in_z_opt LPCWSTR wzPayloadContainerId,
132 + __out BOOTSTRAPPER_CACHE_OPERATION* pCacheOperation
133 );
134 BAAPI UserExperienceOnCacheAcquireComplete(
135 __in BURN_USER_EXPERIENCE* pUserExperience,
@@ -144,6 +146,18 @@ BAAPI UserExperienceOnCacheAcquireProgress(
146 __in DWORD64 dw64Total,
147 __in DWORD dwOverallPercentage
148 );
149 +BAAPI UserExperienceOnCacheAcquireResolving(
150 + __in BURN_USER_EXPERIENCE* pUserExperience,
151 + __in_z_opt LPCWSTR wzPackageOrContainerId,
152 + __in_z_opt LPCWSTR wzPayloadId,
153 + __in_z LPWSTR* rgSearchPaths,
154 + __in DWORD cSearchPaths,
155 + __in BOOL fFoundLocal,
156 + __in DWORD* pdwChosenSearchPath,
157 + __in_z_opt LPCWSTR wzDownloadUrl,
158 + __in_z_opt LPCWSTR wzPayloadContainerId,
159 + __inout BOOTSTRAPPER_CACHE_OPERATION* pCacheOperation
160 + );
161 BAAPI UserExperienceOnCacheBegin(
162 __in BURN_USER_EXPERIENCE* pUserExperience
163 );
@@ -426,14 +440,6 @@ BAAPI UserExperienceOnRegisterComplete(
440 __in BURN_USER_EXPERIENCE* pUserExperience,
441 __in HRESULT hrStatus
442 );
429 -BAAPI UserExperienceOnResolveSource(
430 - __in BURN_USER_EXPERIENCE* pUserExperience,
431 - __in_z LPCWSTR wzPackageOrContainerId,
432 - __in_z_opt LPCWSTR wzPayloadId,
433 - __in_z LPCWSTR wzLocalSource,
434 - __in_z_opt LPCWSTR wzDownloadSource,
435 - __inout BOOTSTRAPPER_RESOLVESOURCE_ACTION* pAction
436 - );
443 BAAPI UserExperienceOnRollbackMsiTransactionBegin(
444 __in BURN_USER_EXPERIENCE* pUserExperience,
445 __in LPCWSTR wzTransactionId