From 5d6046bee5021052da4a666c1e2ceeb0f16af349 Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Fri, 16 Apr 2021 10:20:41 -0500 Subject: Replace OnResolveSource with OnCacheAcquireResolving Inactivate the engine during OnCacheAcquireBegin and Complete to allow setting the source from there. Fixes #3640 Contributes to #5253 --- .../inc/BootstrapperApplication.h | 63 +++--- src/engine/apply.cpp | 242 +++++++++++---------- src/engine/cache.cpp | 203 ++++++++++------- src/engine/cache.h | 9 +- src/engine/engine.mc | 32 +-- src/engine/externalengine.cpp | 43 ++-- src/engine/userexperience.cpp | 126 +++++++---- src/engine/userexperience.h | 26 ++- 8 files changed, 413 insertions(+), 331 deletions(-) diff --git a/src/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h b/src/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h index 2d086f38..cf330c29 100644 --- a/src/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h +++ b/src/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h @@ -54,8 +54,13 @@ enum BOOTSTRAPPER_RELATED_OPERATION enum BOOTSTRAPPER_CACHE_OPERATION { + // There is no source available. + BOOTSTRAPPER_CACHE_OPERATION_NONE, + // Copy the payload or container from the chosen local source. BOOTSTRAPPER_CACHE_OPERATION_COPY, + // Download the payload or container using the download URL. BOOTSTRAPPER_CACHE_OPERATION_DOWNLOAD, + // Extract the payload from the container. BOOTSTRAPPER_CACHE_OPERATION_EXTRACT, }; @@ -112,7 +117,7 @@ enum BOOTSTRAPPER_APPLICATION_MESSAGE BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEPACKAGEBEGIN, BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEACQUIREBEGIN, BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEACQUIREPROGRESS, - BOOTSTRAPPER_APPLICATION_MESSAGE_ONRESOLVESOURCE, + BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEACQUIRERESOLVING, BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEACQUIRECOMPLETE, BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEVERIFYBEGIN, BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEVERIFYCOMPLETE, @@ -158,7 +163,7 @@ enum BOOTSTRAPPER_APPLYCOMPLETE_ACTION enum BOOTSTRAPPER_CACHEACQUIRECOMPLETE_ACTION { BOOTSTRAPPER_CACHEACQUIRECOMPLETE_ACTION_NONE, - // Instructs the engine to try the acquisition of the package again. + // Instructs the engine to try the acquisition of the payload again. // Ignored if hrStatus is a success. BOOTSTRAPPER_CACHEACQUIRECOMPLETE_ACTION_RETRY, }; @@ -202,16 +207,6 @@ enum BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION_SUSPEND, }; -enum BOOTSTRAPPER_RESOLVESOURCE_ACTION -{ - // Instructs the engine that the source can't be found. - BOOTSTRAPPER_RESOLVESOURCE_ACTION_NONE, - // Instructs the engine to try the local source again. - BOOTSTRAPPER_RESOLVESOURCE_ACTION_RETRY, - // Instructs the engine to try the download source. - BOOTSTRAPPER_RESOLVESOURCE_ACTION_DOWNLOAD, -}; - enum BOOTSTRAPPER_SHUTDOWN_ACTION { BOOTSTRAPPER_SHUTDOWN_ACTION_NONE, @@ -315,14 +310,17 @@ struct BA_ONCACHEACQUIREBEGIN_ARGS DWORD cbSize; LPCWSTR wzPackageOrContainerId; LPCWSTR wzPayloadId; - BOOTSTRAPPER_CACHE_OPERATION operation; LPCWSTR wzSource; + LPCWSTR wzDownloadUrl; + LPCWSTR wzPayloadContainerId; + BOOTSTRAPPER_CACHE_OPERATION recommendation; }; struct BA_ONCACHEACQUIREBEGIN_RESULTS { DWORD cbSize; BOOL fCancel; + BOOTSTRAPPER_CACHE_OPERATION action; }; struct BA_ONCACHEACQUIRECOMPLETE_ARGS @@ -356,6 +354,28 @@ struct BA_ONCACHEACQUIREPROGRESS_RESULTS BOOL fCancel; }; +struct BA_ONCACHEACQUIRERESOLVING_ARGS +{ + DWORD cbSize; + LPCWSTR wzPackageOrContainerId; + LPCWSTR wzPayloadId; + LPCWSTR* rgSearchPaths; + DWORD cSearchPaths; + BOOL fFoundLocal; + DWORD dwRecommendedSearchPath; + LPCWSTR wzDownloadUrl; + LPCWSTR wzPayloadContainerId; + BOOTSTRAPPER_CACHE_OPERATION recommendation; +}; + +struct BA_ONCACHEACQUIRERESOLVING_RESULTS +{ + DWORD cbSize; + DWORD dwChosenSearchPath; + BOOTSTRAPPER_CACHE_OPERATION action; + BOOL fCancel; +}; + struct BA_ONCACHEBEGIN_ARGS { DWORD cbSize; @@ -1013,23 +1033,6 @@ struct BA_ONREGISTERCOMPLETE_RESULTS DWORD cbSize; }; -struct BA_ONRESOLVESOURCE_ARGS -{ - DWORD cbSize; - LPCWSTR wzPackageOrContainerId; - LPCWSTR wzPayloadId; - LPCWSTR wzLocalSource; - LPCWSTR wzDownloadSource; - BOOTSTRAPPER_RESOLVESOURCE_ACTION recommendation; -}; - -struct BA_ONRESOLVESOURCE_RESULTS -{ - DWORD cbSize; - BOOTSTRAPPER_RESOLVESOURCE_ACTION action; - BOOL fCancel; -}; - struct BA_ONROLLBACKMSITRANSACTIONBEGIN_ARGS { DWORD cbSize; diff --git a/src/engine/apply.cpp b/src/engine/apply.cpp index dffbc6d6..dc9f905b 100644 --- a/src/engine/apply.cpp +++ b/src/engine/apply.cpp @@ -23,6 +23,9 @@ typedef struct _BURN_CACHE_CONTEXT DWORD64 qwTotalCacheSize; DWORD64 qwSuccessfulCacheProgress; LPCWSTR wzLayoutDirectory; + LPWSTR* rgSearchPaths; + DWORD cSearchPaths; + DWORD cSearchPathsMax; } BURN_CACHE_CONTEXT; typedef struct _BURN_CACHE_ACQUIRE_PROGRESS_CONTEXT @@ -113,15 +116,6 @@ static HRESULT LayoutOrCacheContainerOrPayload( __in DWORD cTryAgainAttempts, __out BOOL* pfRetry ); -static HRESULT PromptForSource( - __in BURN_USER_EXPERIENCE* pUX, - __in_z LPCWSTR wzPackageOrContainerId, - __in_z_opt LPCWSTR wzPayloadId, - __in_z LPCWSTR wzLocalSource, - __in_z_opt LPCWSTR wzDownloadSource, - __out BOOL* pfRetry, - __out BOOL* pfDownload - ); static HRESULT CopyPayload( __in BURN_CACHE_ACQUIRE_PROGRESS_CONTEXT* pProgress, __in HANDLE hSourceFile, @@ -485,6 +479,9 @@ extern "C" HRESULT ApplyCache( cacheContext.qwTotalCacheSize = pPlan->qwCacheSizeTotal; cacheContext.wzLayoutDirectory = pPlan->sczLayoutDirectory; + hr = MemAllocArray(reinterpret_cast(&cacheContext.rgSearchPaths), sizeof(LPWSTR), BURN_CACHE_MAX_SEARCH_PATHS); + ExitOnNull(cacheContext.rgSearchPaths, hr, E_OUTOFMEMORY, "Failed to allocate cache search paths array."); + for (DWORD i = 0; i < pPlan->cCacheActions; ++i) { BURN_CACHE_ACTION* pCacheAction = pPlan->rgCacheActions + i; @@ -561,6 +558,12 @@ LExit: CacheCleanup(FALSE, pPlan->wzBundleId); + for (DWORD i = 0; i < cacheContext.cSearchPathsMax; ++i) + { + ReleaseNullStr(cacheContext.rgSearchPaths[i]); + } + ReleaseMem(cacheContext.rgSearchPaths); + UserExperienceOnCacheComplete(pUX, hr); return hr; } @@ -949,17 +952,8 @@ static HRESULT ApplyProcessPayload( { fRetry = FALSE; - if (pPayload->pContainer) - { - // TODO: only extract container if payload isn't already extracted - hr = ApplyExtractContainer(pContext, pPayload->pContainer); - ExitOnFailure(hr, "Failed to extract container for payload: %ls", pPayload->sczKey); - } - else - { - hr = AcquireContainerOrPayload(pContext, NULL, pPackage, pPayload); - LogExitOnFailure(hr, MSG_FAILED_ACQUIRE_PAYLOAD, "Failed to acquire payload: %ls to working path: %ls", pPayload->sczKey, pPayload->sczUnverifiedPath); - } + hr = AcquireContainerOrPayload(pContext, NULL, pPackage, pPayload); + LogExitOnFailure(hr, MSG_FAILED_ACQUIRE_PAYLOAD, "Failed to acquire payload: %ls to working path: %ls", pPayload->sczKey, pPayload->sczUnverifiedPath); pContext->qwSuccessfulCacheProgress += pPayload->qwFileSize; @@ -1054,8 +1048,10 @@ static HRESULT LayoutBundle( { HRESULT hr = S_OK; LPWSTR sczBundlePath = NULL; + LPWSTR sczBundleDownloadUrl = NULL; LPWSTR sczDestinationPath = NULL; int nEquivalentPaths = 0; + BOOTSTRAPPER_CACHE_OPERATION cacheOperation = BOOTSTRAPPER_CACHE_OPERATION_NONE; BURN_CACHE_ACQUIRE_PROGRESS_CONTEXT progress = { }; BOOL fRetry = FALSE; BOOL fRetryAcquire = FALSE; @@ -1096,7 +1092,7 @@ static HRESULT LayoutBundle( fRetryAcquire = FALSE; progress.fCancel = FALSE; - hr = UserExperienceOnCacheAcquireBegin(pContext->pUX, NULL, NULL, BOOTSTRAPPER_CACHE_OPERATION_COPY, sczBundlePath); + hr = UserExperienceOnCacheAcquireBegin(pContext->pUX, NULL, NULL, &sczBundlePath, &sczBundleDownloadUrl, NULL, &cacheOperation); ExitOnRootFailure(hr, "BA aborted cache acquire begin."); hr = CopyPayload(&progress, pContext->hSourceEngineFile, sczBundlePath, wzUnverifiedPath); @@ -1142,6 +1138,7 @@ static HRESULT LayoutBundle( LExit: ReleaseStr(sczDestinationPath); + ReleaseStr(sczBundleDownloadUrl); ReleaseStr(sczBundlePath); return hr; @@ -1160,11 +1157,16 @@ static HRESULT AcquireContainerOrPayload( int nEquivalentPaths = 0; LPCWSTR wzPackageOrContainerId = pContainer ? pContainer->sczId : pPackage ? pPackage->sczId : NULL; LPCWSTR wzPayloadId = pPayload ? pPayload->sczKey : NULL; + LPCWSTR wzPayloadContainerId = pPayload && pPayload->pContainer ? pPayload->pContainer->sczId : NULL; LPCWSTR wzDestinationPath = pContainer ? pContainer->sczUnverifiedPath: pPayload->sczUnverifiedPath; LPCWSTR wzRelativePath = pContainer ? pContainer->sczFilePath : pPayload->sczFilePath; - LPWSTR sczSourceFullPath = NULL; BURN_CACHE_ACQUIRE_PROGRESS_CONTEXT progress = { }; + BOOL fBeginCalled = FALSE; BOOL fRetry = FALSE; + DWORD dwChosenSearchPath = 0; + BOOTSTRAPPER_CACHE_OPERATION cacheOperation = BOOTSTRAPPER_CACHE_OPERATION_NONE; + LPWSTR* pwzDownloadUrl = pContainer ? &pContainer->downloadSource.sczUrl : &pPayload->downloadSource.sczUrl; + LPWSTR* pwzSourcePath = pContainer ? &pContainer->sczSourcePath : &pPayload->sczSourcePath; progress.pCacheContext = pContext; progress.pContainer = pContainer; @@ -1173,86 +1175,148 @@ static HRESULT AcquireContainerOrPayload( do { - LPCWSTR wzDownloadUrl = pContainer ? pContainer->downloadSource.sczUrl : pPayload->downloadSource.sczUrl; - LPCWSTR wzSourcePath = pContainer ? pContainer->sczSourcePath : pPayload->sczSourcePath; - BOOL fFoundLocal = FALSE; - BOOL fCopy = FALSE; - BOOL fDownload = FALSE; + pContext->cSearchPaths = 0; + dwChosenSearchPath = 0; fRetry = FALSE; progress.fCancel = FALSE; + fBeginCalled = TRUE; - hr = CacheFindLocalSource(wzSourcePath, wzDestinationPath, pContext->pVariables, &fFoundLocal, &sczSourceFullPath); - ExitOnFailure(hr, "Failed to search local source."); - - if (fFoundLocal) // the file exists locally, so copy it. - { - // If the source path and destination path are different, do the copy (otherwise there's no point). - hr = PathCompare(sczSourceFullPath, wzDestinationPath, &nEquivalentPaths); - ExitOnFailure(hr, "Failed to determine if payload source path was equivalent to the destination path."); + hr = UserExperienceOnCacheAcquireBegin(pContext->pUX, wzPackageOrContainerId, wzPayloadId, pwzSourcePath, pwzDownloadUrl, wzPayloadContainerId, &cacheOperation); + ExitOnRootFailure(hr, "BA aborted cache acquire begin."); - fCopy = (CSTR_EQUAL != nEquivalentPaths); - } - else // can't find the file locally, so prompt for source. + // Skip the Resolving event and probing local paths if the BA already knew it wanted to download or extract. + if (BOOTSTRAPPER_CACHE_OPERATION_DOWNLOAD != cacheOperation && + BOOTSTRAPPER_CACHE_OPERATION_EXTRACT != cacheOperation) { - DWORD dwLogId = pContainer ? (wzPayloadId ? MSG_PROMPT_CONTAINER_PAYLOAD_SOURCE : MSG_PROMPT_CONTAINER_SOURCE) : pPackage ? MSG_PROMPT_PACKAGE_PAYLOAD_SOURCE : MSG_PROMPT_BUNDLE_PAYLOAD_SOURCE; - LogId(REPORT_STANDARD, dwLogId, wzPackageOrContainerId ? wzPackageOrContainerId : L"", wzPayloadId ? wzPayloadId : L"", sczSourceFullPath); + hr = CacheGetLocalSourcePaths(wzRelativePath, *pwzSourcePath, wzDestinationPath, pContext->wzLayoutDirectory, pContext->pVariables, &pContext->rgSearchPaths, &pContext->cSearchPaths); + ExitOnFailure(hr, "Failed to search local source."); - hr = PromptForSource(pContext->pUX, wzPackageOrContainerId, wzPayloadId, sczSourceFullPath, wzDownloadUrl, &fRetry, &fDownload); + for (DWORD i = 0; i < pContext->cSearchPaths; ++i) + { + // If the file exists locally, choose it. + if (FileExistsEx(pContext->rgSearchPaths[i], NULL)) + { + dwChosenSearchPath = i; + + fFoundLocal = TRUE; + break; + } + } - // If the BA requested download then ensure a download url is available (it may have been set - // during PromptForSource so we need to check again). - if (fDownload) + if (BOOTSTRAPPER_CACHE_OPERATION_COPY == cacheOperation) + { + if (!fFoundLocal) + { + cacheOperation = BOOTSTRAPPER_CACHE_OPERATION_NONE; + } + } + else { - wzDownloadUrl = pContainer ? pContainer->downloadSource.sczUrl : pPayload->downloadSource.sczUrl; - if (!wzDownloadUrl || !*wzDownloadUrl) + if (fFoundLocal) // the file exists locally, so copy it. + { + cacheOperation = BOOTSTRAPPER_CACHE_OPERATION_COPY; + } + else if (wzPayloadContainerId) + { + cacheOperation = BOOTSTRAPPER_CACHE_OPERATION_EXTRACT; + } + else if (*pwzDownloadUrl && **pwzDownloadUrl) { - hr = E_INVALIDARG; + cacheOperation = BOOTSTRAPPER_CACHE_OPERATION_DOWNLOAD; } } - // Log the error - LogExitOnFailure(hr, MSG_PAYLOAD_FILE_NOT_PRESENT, "Failed while prompting for source (original path '%ls').", sczSourceFullPath); + // Let the BA have a chance to override the action, but their chance to change the source is during begin or complete. + hr = UserExperienceOnCacheAcquireResolving(pContext->pUX, wzPackageOrContainerId, wzPayloadId, pContext->rgSearchPaths, pContext->cSearchPaths, fFoundLocal, &dwChosenSearchPath, *pwzDownloadUrl, wzPayloadContainerId, &cacheOperation); + ExitOnRootFailure(hr, "BA aborted cache acquire resolving."); } - if (fCopy) + switch (cacheOperation) { - hr = UserExperienceOnCacheAcquireBegin(pContext->pUX, wzPackageOrContainerId, wzPayloadId, BOOTSTRAPPER_CACHE_OPERATION_COPY, sczSourceFullPath); - ExitOnRootFailure(hr, "BA aborted cache acquire begin."); + case BOOTSTRAPPER_CACHE_OPERATION_COPY: + // If the source path and destination path are different, do the copy (otherwise there's no point). + hr = PathCompare(pContext->rgSearchPaths[dwChosenSearchPath], wzDestinationPath, &nEquivalentPaths); + ExitOnFailure(hr, "Failed to determine if payload paths were equivalent, source: %ls, destination: %ls.", pContext->rgSearchPaths[dwChosenSearchPath], wzDestinationPath); - hr = CopyPayload(&progress, INVALID_HANDLE_VALUE, sczSourceFullPath, wzDestinationPath); - // Error handling happens after sending complete message to BA. + if (CSTR_EQUAL != nEquivalentPaths) + { + hr = CopyPayload(&progress, INVALID_HANDLE_VALUE, pContext->rgSearchPaths[dwChosenSearchPath], wzDestinationPath); + // Error handling happens after sending complete message to BA. + + // TODO: wait for verification? + // We successfully copied from a source location, set that as the last used source. + if (SUCCEEDED(hr)) + { + CacheSetLastUsedSource(pContext->pVariables, pContext->rgSearchPaths[dwChosenSearchPath], wzRelativePath); + } + } - // We successfully copied from a source location, set that as the last used source. - if (SUCCEEDED(hr)) + fBeginCalled = FALSE; + UserExperienceOnCacheAcquireComplete(pContext->pUX, wzPackageOrContainerId, wzPayloadId, hr, &fRetry); + if (fRetry) { - CacheSetLastUsedSource(pContext->pVariables, sczSourceFullPath, wzRelativePath); + hr = S_OK; } - } - else if (fDownload) - { - hr = UserExperienceOnCacheAcquireBegin(pContext->pUX, wzPackageOrContainerId, wzPayloadId, BOOTSTRAPPER_CACHE_OPERATION_DOWNLOAD, wzDownloadUrl); - ExitOnRootFailure(hr, "BA aborted cache download payload begin."); + ExitOnFailure(hr, "Failed to acquire payload from: '%ls' to working path: '%ls'", pContext->rgSearchPaths[dwChosenSearchPath], wzDestinationPath); + + break; + case BOOTSTRAPPER_CACHE_OPERATION_DOWNLOAD: hr = DownloadPayload(&progress, wzDestinationPath); // Error handling happens after sending complete message to BA. - } - if (fCopy || fDownload) - { + fBeginCalled = FALSE; + UserExperienceOnCacheAcquireComplete(pContext->pUX, wzPackageOrContainerId, wzPayloadId, hr, &fRetry); + if (fRetry) + { + hr = S_OK; + } + + ExitOnFailure(hr, "Failed to acquire payload from: '%ls' to working path: '%ls'", *pwzDownloadUrl, wzDestinationPath); + + break; + case BOOTSTRAPPER_CACHE_OPERATION_EXTRACT: + Assert(pPayload->pContainer); + + hr = ApplyExtractContainer(pContext, pPayload->pContainer); + // Error handling happens after sending complete message to BA. + + fBeginCalled = FALSE; + UserExperienceOnCacheAcquireComplete(pContext->pUX, wzPackageOrContainerId, wzPayloadId, hr, &fRetry); + if (fRetry) + { + hr = S_OK; + } + + ExitOnFailure(hr, "Failed to extract container for payload: %ls", wzPayloadId); + + break; + case BOOTSTRAPPER_CACHE_OPERATION_NONE: + hr = E_FILENOTFOUND; + LogErrorId(hr, MSG_RESOLVE_SOURCE_FAILED, wzPayloadId, pPackage ? pPackage->sczId : NULL, pContainer ? pContainer->sczId : NULL); + + fBeginCalled = FALSE; UserExperienceOnCacheAcquireComplete(pContext->pUX, wzPackageOrContainerId, wzPayloadId, hr, &fRetry); if (fRetry) { hr = S_OK; } + + ExitOnFailure(hr, "Failed to resolve source, payload: %ls, package: %ls, container: %ls", wzPayloadId, pPackage ? pPackage->sczId : NULL, pContainer ? pContainer->sczId : NULL); + + break; } - ExitOnFailure(hr, "Failed to acquire payload from: '%ls' to working path: '%ls'", fCopy ? sczSourceFullPath : wzDownloadUrl, wzDestinationPath); } while (fRetry); - ExitOnFailure(hr, "Failed to find external payload to cache."); LExit: - ReleaseStr(sczSourceFullPath); + if (fBeginCalled) + { + UserExperienceOnCacheAcquireComplete(pContext->pUX, wzPackageOrContainerId, wzPayloadId, hr, &fRetry); + } + + pContext->cSearchPathsMax = max(pContext->cSearchPaths, pContext->cSearchPathsMax); return hr; } @@ -1355,48 +1419,6 @@ LExit: return hr; } -static HRESULT PromptForSource( - __in BURN_USER_EXPERIENCE* pUX, - __in_z LPCWSTR wzPackageOrContainerId, - __in_z_opt LPCWSTR wzPayloadId, - __in_z LPCWSTR wzLocalSource, - __in_z_opt LPCWSTR wzDownloadSource, - __inout BOOL* pfRetry, - __inout BOOL* pfDownload - ) -{ - HRESULT hr = S_OK; - BOOTSTRAPPER_RESOLVESOURCE_ACTION action = BOOTSTRAPPER_RESOLVESOURCE_ACTION_NONE; - - hr = UserExperienceOnResolveSource(pUX, wzPackageOrContainerId, wzPayloadId, wzLocalSource, wzDownloadSource, &action); - if (FAILED(hr)) - { - ExitFunction(); - } - - switch (action) - { - case BOOTSTRAPPER_RESOLVESOURCE_ACTION_NONE: - hr = E_FILENOTFOUND; - break; - - case BOOTSTRAPPER_RESOLVESOURCE_ACTION_RETRY: - *pfRetry = TRUE; - break; - - case BOOTSTRAPPER_RESOLVESOURCE_ACTION_DOWNLOAD: - *pfDownload = TRUE; - break; - - default: - hr = E_INVALIDARG; - break; - } - -LExit: - return hr; -} - static HRESULT CopyPayload( __in BURN_CACHE_ACQUIRE_PROGRESS_CONTEXT* pProgress, __in HANDLE hSourceFile, diff --git a/src/engine/cache.cpp b/src/engine/cache.cpp index 6ac313e0..84b7f131 100644 --- a/src/engine/cache.cpp +++ b/src/engine/cache.cpp @@ -11,7 +11,7 @@ static const DWORD FILE_OPERATION_RETRY_WAIT = 2000; static BOOL vfInitializedCache = FALSE; static BOOL vfRunningFromCache = FALSE; -static LPWSTR vsczSourceProcessPath = NULL; +static LPWSTR vsczSourceProcessFolder = NULL; static LPWSTR vsczWorkingFolder = NULL; static LPWSTR vsczDefaultUserPackageCache = NULL; static LPWSTR vsczDefaultMachinePackageCache = NULL; @@ -140,8 +140,8 @@ extern "C" HRESULT CacheInitialize( wzSourceProcessPath = sczCurrentPath; } - hr = StrAllocString(&vsczSourceProcessPath, wzSourceProcessPath, 0); - ExitOnFailure(hr, "Failed to initialize cache source path."); + hr = PathGetDirectory(wzSourceProcessPath, &vsczSourceProcessFolder); + ExitOnFailure(hr, "Failed to initialize cache source folder."); // If we're not running from the cache, ensure the original source is set. if (!vfRunningFromCache) @@ -393,112 +393,166 @@ LExit: return hr; } -extern "C" HRESULT CacheFindLocalSource( +extern "C" HRESULT CacheGetLocalSourcePaths( + __in_z LPCWSTR wzRelativePath, __in_z LPCWSTR wzSourcePath, __in_z LPCWSTR wzDestinationPath, + __in_z_opt LPCWSTR wzLayoutDirectory, __in BURN_VARIABLES* pVariables, - __out BOOL* pfFound, - __out_z LPWSTR* psczSourceFullPath + __inout LPWSTR** prgSearchPaths, + __out DWORD* pcSearchPaths ) { HRESULT hr = S_OK; - LPWSTR sczSourceProcessFolder = NULL; LPWSTR sczCurrentPath = NULL; - LPWSTR sczLastSourcePath = NULL; LPWSTR sczLastSourceFolder = NULL; - LPWSTR sczLayoutPath = NULL; - LPWSTR sczLayoutFolder = NULL; - LPCWSTR rgwzSearchPaths[4] = { }; + LPWSTR* psczPath = NULL; + BOOL fPreferSourcePathLocation = FALSE; + BOOL fTryLastFolder = FALSE; + BOOL fTryRelativePath = FALSE; + BOOL fSourceIsAbsolute = FALSE; DWORD cSearchPaths = 0; - // If the source path provided is a full path, obviously that is where we should be looking. - if (PathIsAbsolute(wzSourcePath)) + AssertSz(vfInitializedCache, "Cache wasn't initialized"); + + hr = GetLastUsedSourceFolder(pVariables, &sczLastSourceFolder); + fPreferSourcePathLocation = !vfRunningFromCache || FAILED(hr); + fTryLastFolder = SUCCEEDED(hr) && sczLastSourceFolder && *sczLastSourceFolder && CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, vsczSourceProcessFolder, -1, sczLastSourceFolder, -1); + fTryRelativePath = CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, wzSourcePath, -1, wzRelativePath, -1); + fSourceIsAbsolute = PathIsAbsolute(wzSourcePath); + + // If the source path provided is a full path, try that first. + if (fSourceIsAbsolute) { - rgwzSearchPaths[0] = wzSourcePath; - cSearchPaths = 1; + hr = MemEnsureArraySize(reinterpret_cast(prgSearchPaths), cSearchPaths + 1, sizeof(LPWSTR), BURN_CACHE_MAX_SEARCH_PATHS); + ExitOnFailure(hr, "Failed to ensure size for search paths array."); + + psczPath = *prgSearchPaths + cSearchPaths; + ++cSearchPaths; + + hr = StrAllocString(psczPath, wzSourcePath, 0); + ExitOnFailure(hr, "Failed to copy absolute source path."); } - else + + // Try the destination path next. + hr = MemEnsureArraySize(reinterpret_cast(prgSearchPaths), cSearchPaths + 1, sizeof(LPWSTR), BURN_CACHE_MAX_SEARCH_PATHS); + ExitOnFailure(hr, "Failed to ensure size for search paths array."); + + psczPath = *prgSearchPaths + cSearchPaths; + ++cSearchPaths; + + hr = StrAllocString(psczPath, wzDestinationPath, 0); + ExitOnFailure(hr, "Failed to copy absolute source path."); + + if (!fSourceIsAbsolute) { - // Use the destination path first. - rgwzSearchPaths[0] = wzDestinationPath; - cSearchPaths = 1; - - // If we're not running from cache or we couldn't get the last source, use - // the source path location. In the case where we are in the bundle's - // package cache and couldn't find a last used source we unfortunately will - // be picking the package cache path which isn't likely to have what we are - // looking for. - hr = GetLastUsedSourceFolder(pVariables, &sczLastSourceFolder); - if (!vfRunningFromCache || FAILED(hr)) + // Calculate the source path location. + // In the case where we are in the bundle's package cache and + // couldn't find a last used source that will be the package cache path + // which isn't likely to have what we are looking for. + hr = MemEnsureArraySize(reinterpret_cast(prgSearchPaths), cSearchPaths + 1, sizeof(LPWSTR), BURN_CACHE_MAX_SEARCH_PATHS); + ExitOnFailure(hr, "Failed to ensure size for search paths array."); + + hr = PathConcat(vsczSourceProcessFolder, wzSourcePath, &sczCurrentPath); + ExitOnFailure(hr, "Failed to combine source process folder with source."); + + // If we're not running from cache or we couldn't get the last source, + // try the source path location next. + if (fPreferSourcePathLocation) { - hr = PathGetDirectory(vsczSourceProcessPath, &sczSourceProcessFolder); - ExitOnFailure(hr, "Failed to get current process directory."); + (*prgSearchPaths)[cSearchPaths] = sczCurrentPath; + ++cSearchPaths; + sczCurrentPath = NULL; + } - hr = PathConcat(sczSourceProcessFolder, wzSourcePath, &sczCurrentPath); + // If we have a last used source and it is not the source path location, + // add the last used source to the search path next. + if (fTryLastFolder) + { + hr = MemEnsureArraySize(reinterpret_cast(prgSearchPaths), cSearchPaths + 1, sizeof(LPWSTR), BURN_CACHE_MAX_SEARCH_PATHS); + ExitOnFailure(hr, "Failed to ensure size for search paths array."); + + psczPath = *prgSearchPaths + cSearchPaths; + ++cSearchPaths; + + hr = PathConcat(sczLastSourceFolder, wzSourcePath, psczPath); ExitOnFailure(hr, "Failed to combine last source with source."); + } - rgwzSearchPaths[cSearchPaths] = sczCurrentPath; + if (!fPreferSourcePathLocation) + { + (*prgSearchPaths)[cSearchPaths] = sczCurrentPath; ++cSearchPaths; + sczCurrentPath = NULL; } - // If we have a last used source and it does not duplicate the existing search path, - // add the last used source to the search path second. - if (sczLastSourceFolder && *sczLastSourceFolder) + // Also consider the layout directory if doing Layout. + if (wzLayoutDirectory) { - hr = PathConcat(sczLastSourceFolder, wzSourcePath, &sczLastSourcePath); - ExitOnFailure(hr, "Failed to combine last source with source."); + hr = MemEnsureArraySize(reinterpret_cast(prgSearchPaths), cSearchPaths + 1, sizeof(LPWSTR), BURN_CACHE_MAX_SEARCH_PATHS); + ExitOnFailure(hr, "Failed to ensure size for search paths array."); - if (1 == cSearchPaths || CSTR_EQUAL != ::CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, rgwzSearchPaths[1], -1, sczLastSourcePath, -1)) - { - rgwzSearchPaths[cSearchPaths] = sczLastSourcePath; - ++cSearchPaths; - } + psczPath = *prgSearchPaths + cSearchPaths; + ++cSearchPaths; + + hr = PathConcat(wzLayoutDirectory, wzSourcePath, psczPath); + ExitOnFailure(hr, "Failed to combine layout source with source."); } + } - // Also consider the layout directory if set on the command line or by the BA. - hr = VariableGetString(pVariables, BURN_BUNDLE_LAYOUT_DIRECTORY, &sczLayoutFolder); - if (E_NOTFOUND != hr) + if (fTryRelativePath) + { + hr = MemEnsureArraySize(reinterpret_cast(prgSearchPaths), cSearchPaths + 1, sizeof(LPWSTR), BURN_CACHE_MAX_SEARCH_PATHS); + ExitOnFailure(hr, "Failed to ensure size for search paths array."); + + hr = PathConcat(vsczSourceProcessFolder, wzRelativePath, &sczCurrentPath); + ExitOnFailure(hr, "Failed to combine source process folder with relative."); + + if (fPreferSourcePathLocation) { - ExitOnFailure(hr, "Failed to get bundle layout directory property."); + (*prgSearchPaths)[cSearchPaths] = sczCurrentPath; + ++cSearchPaths; + sczCurrentPath = NULL; + } - hr = PathConcat(sczLayoutFolder, wzSourcePath, &sczLayoutPath); - ExitOnFailure(hr, "Failed to combine layout source with source."); + if (fTryLastFolder) + { + hr = MemEnsureArraySize(reinterpret_cast(prgSearchPaths), cSearchPaths + 1, sizeof(LPWSTR), BURN_CACHE_MAX_SEARCH_PATHS); + ExitOnFailure(hr, "Failed to ensure size for search paths array."); - rgwzSearchPaths[cSearchPaths] = sczLayoutPath; + psczPath = *prgSearchPaths + cSearchPaths; ++cSearchPaths; + + hr = PathConcat(sczLastSourceFolder, wzRelativePath, psczPath); + ExitOnFailure(hr, "Failed to combine last source with relative."); } - } - *pfFound = FALSE; // assume we won't find the file locally. + if (!fPreferSourcePathLocation) + { + (*prgSearchPaths)[cSearchPaths] = sczCurrentPath; + ++cSearchPaths; + sczCurrentPath = NULL; + } - for (DWORD i = 0; i < cSearchPaths; ++i) - { - // If the file exists locally, copy its path. - if (FileExistsEx(rgwzSearchPaths[i], NULL)) + if (wzLayoutDirectory) { - hr = StrAllocString(psczSourceFullPath, rgwzSearchPaths[i], 0); - ExitOnFailure(hr, "Failed to copy source path."); + hr = MemEnsureArraySize(reinterpret_cast(prgSearchPaths), cSearchPaths + 1, sizeof(LPWSTR), BURN_CACHE_MAX_SEARCH_PATHS); + ExitOnFailure(hr, "Failed to ensure size for search paths array."); - *pfFound = TRUE; - break; - } - } + psczPath = *prgSearchPaths + cSearchPaths; + ++cSearchPaths; - // If nothing was found, return the first thing in our search path as the - // best path where we thought we should have found the file. - if (!*pfFound) - { - hr = StrAllocString(psczSourceFullPath, rgwzSearchPaths[0], 0); - ExitOnFailure(hr, "Failed to copy source path."); + hr = PathConcat(wzLayoutDirectory, wzSourcePath, psczPath); + ExitOnFailure(hr, "Failed to combine layout source with relative."); + } } LExit: ReleaseStr(sczCurrentPath); - ReleaseStr(sczSourceProcessFolder); ReleaseStr(sczLastSourceFolder); - ReleaseStr(sczLastSourcePath); - ReleaseStr(sczLayoutFolder); - ReleaseStr(sczLayoutPath); + + AssertSz(cSearchPaths <= BURN_CACHE_MAX_SEARCH_PATHS, "Got more than BURN_CACHE_MAX_SEARCH_PATHS search paths"); + *pcSearchPaths = cSearchPaths; return hr; } @@ -1079,7 +1133,7 @@ extern "C" void CacheUninitialize() ReleaseNullStr(vsczDefaultMachinePackageCache); ReleaseNullStr(vsczDefaultUserPackageCache); ReleaseNullStr(vsczWorkingFolder); - ReleaseNullStr(vsczSourceProcessPath); + ReleaseNullStr(vsczSourceProcessFolder); vfRunningFromCache = FALSE; vfInitializedCache = FALSE; @@ -1224,17 +1278,12 @@ static HRESULT GetLastUsedSourceFolder( ) { HRESULT hr = S_OK; - LPWSTR sczOriginalSource = NULL; hr = VariableGetString(pVariables, BURN_BUNDLE_LAST_USED_SOURCE, psczLastSource); if (E_NOTFOUND == hr) { // Try the original source folder. - hr = VariableGetString(pVariables, BURN_BUNDLE_ORIGINAL_SOURCE, &sczOriginalSource); - if (SUCCEEDED(hr)) - { - hr = PathGetDirectory(sczOriginalSource, psczLastSource); - } + hr = VariableGetString(pVariables, BURN_BUNDLE_ORIGINAL_SOURCE_FOLDER, psczLastSource); } return hr; diff --git a/src/engine/cache.h b/src/engine/cache.h index acc7acb7..eb964f58 100644 --- a/src/engine/cache.h +++ b/src/engine/cache.h @@ -1,6 +1,7 @@ #pragma once // 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. +#define BURN_CACHE_MAX_SEARCH_PATHS 7 #ifdef __cplusplus extern "C" { @@ -52,12 +53,14 @@ HRESULT CacheGetResumePath( __in_z LPCWSTR wzPayloadWorkingPath, __deref_out_z LPWSTR* psczResumePath ); -HRESULT CacheFindLocalSource( +HRESULT CacheGetLocalSourcePaths( + __in_z LPCWSTR wzRelativePath, __in_z LPCWSTR wzSourcePath, __in_z LPCWSTR wzDestinationPath, + __in_z_opt LPCWSTR wzLayoutDirectory, __in BURN_VARIABLES* pVariables, - __out BOOL* pfFound, - __out_z LPWSTR* psczSourceFullPath + __inout LPWSTR** prgSearchPaths, + __out DWORD* pcSearchPaths ); HRESULT CacheSetLastUsedSource( __in BURN_VARIABLES* pVariables, diff --git a/src/engine/engine.mc b/src/engine/engine.mc index c8b46806..f03bc1ea 100644 --- a/src/engine/engine.mc +++ b/src/engine/engine.mc @@ -151,9 +151,9 @@ Bundle global condition check didn't succeed - aborting without loading applicat MessageId=54 Severity=Error -SymbolicName=MSG_PAYLOAD_FILE_NOT_PRESENT +SymbolicName=MSG_RESOLVE_SOURCE_FAILED Language=English -Failed to resolve source for file: %2!ls!, error: %1!ls!. +Failed to resolve source for payload: %2!ls!, package: %3!ls!, container: %4!ls!, error: %1!ls!. . MessageId=55 @@ -724,34 +724,6 @@ Language=English Acquiring package: %1!ls!, payload: %2!ls!, %3!hs! from: %4!ls! . -MessageId=340 -Severity=Warning -SymbolicName=MSG_PROMPT_BUNDLE_PAYLOAD_SOURCE -Language=English -Prompt for source of bundle payload: %2!ls!, path: %3!ls! -. - -MessageId=341 -Severity=Warning -SymbolicName=MSG_PROMPT_CONTAINER_SOURCE -Language=English -Prompt for source of container: %1!ls!, path: %3!ls! -. - -MessageId=342 -Severity=Warning -SymbolicName=MSG_PROMPT_CONTAINER_PAYLOAD_SOURCE -Language=English -Prompt for source of container: %1!ls!, payload: %2!ls!, path: %3!ls! -. - -MessageId=343 -Severity=Warning -SymbolicName=MSG_PROMPT_PACKAGE_PAYLOAD_SOURCE -Language=English -Prompt for source of package: %1!ls!, payload: %2!ls!, path: %3!ls! -. - MessageId=348 Severity=Warning SymbolicName=MSG_APPLY_RETRYING_PACKAGE diff --git a/src/engine/externalengine.cpp b/src/engine/externalengine.cpp index 7e9bb25c..d6c44736 100644 --- a/src/engine/externalengine.cpp +++ b/src/engine/externalengine.cpp @@ -269,8 +269,7 @@ HRESULT ExternalEngineSetUpdate( ) { HRESULT hr = S_OK; - LPCWSTR sczId = NULL; - LPWSTR sczLocalSource = NULL; + LPWSTR sczFilePath = NULL; LPWSTR sczCommandline = NULL; UUID guid = { }; WCHAR wzGuid[39]; @@ -296,38 +295,30 @@ HRESULT ExternalEngineSetUpdate( { UpdateUninitialize(&pEngineState->update); - if (!wzLocalSource || !*wzLocalSource) - { - hr = StrAllocFormatted(&sczLocalSource, L"update\\%ls", pEngineState->registration.sczExecutableName); - ExitOnFailure(hr, "Failed to default local update source"); - } - 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); ExitOnFailure(hr, "Failed to recreate command-line for update bundle."); - // Per-user bundles would fail to use the downloaded update bundle, as the existing install would already be cached - // at the registration id's location. 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. - if (!pEngineState->registration.fPerMachine) + // Bundles would fail to use the downloaded update bundle, as the running bundle would be one of the search paths. + // 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. + rs = ::UuidCreate(&guid); + hr = HRESULT_FROM_RPC(rs); + ExitOnFailure(hr, "Failed to create bundle update guid."); + + if (!::StringFromGUID2(guid, wzGuid, countof(wzGuid))) { - rs = ::UuidCreate(&guid); - hr = HRESULT_FROM_RPC(rs); - ExitOnFailure(hr, "Failed to create bundle update guid."); + hr = E_OUTOFMEMORY; + ExitOnRootFailure(hr, "Failed to convert bundle update guid into string."); + } - if (!::StringFromGUID2(guid, wzGuid, countof(wzGuid))) - { - hr = E_OUTOFMEMORY; - ExitOnRootFailure(hr, "Failed to convert bundle update guid into string."); - } + hr = StrAllocFormatted(&sczFilePath, L"%ls\\%ls", wzGuid, pEngineState->registration.sczExecutableName); + ExitOnFailure(hr, "Failed to build bundle update file path."); - sczId = wzGuid; - } - else + if (!wzLocalSource || !*wzLocalSource) { - sczId = pEngineState->registration.sczId; + wzLocalSource = sczFilePath; } - 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); + 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); ExitOnFailure(hr, "Failed to set update bundle."); pEngineState->update.fUpdateAvailable = TRUE; @@ -337,7 +328,7 @@ LExit: ::LeaveCriticalSection(&pEngineState->userExperience.csEngineActive); ReleaseStr(sczCommandline); - ReleaseStr(sczLocalSource); + ReleaseStr(sczFilePath); return hr; } diff --git a/src/engine/userexperience.cpp b/src/engine/userexperience.cpp index b6bd65dc..f6ae1491 100644 --- a/src/engine/userexperience.cpp +++ b/src/engine/userexperience.cpp @@ -395,29 +395,46 @@ EXTERN_C BAAPI UserExperienceOnCacheAcquireBegin( __in BURN_USER_EXPERIENCE* pUserExperience, __in_z_opt LPCWSTR wzPackageOrContainerId, __in_z_opt LPCWSTR wzPayloadId, - __in BOOTSTRAPPER_CACHE_OPERATION operation, - __in_z LPCWSTR wzSource + __in_z LPWSTR* pwzSource, + __in_z LPWSTR* pwzDownloadUrl, + __in_z_opt LPCWSTR wzPayloadContainerId, + __out BOOTSTRAPPER_CACHE_OPERATION* pCacheOperation ) { HRESULT hr = S_OK; BA_ONCACHEACQUIREBEGIN_ARGS args = { }; BA_ONCACHEACQUIREBEGIN_RESULTS results = { }; + *pCacheOperation = BOOTSTRAPPER_CACHE_OPERATION_NONE; args.cbSize = sizeof(args); args.wzPackageOrContainerId = wzPackageOrContainerId; args.wzPayloadId = wzPayloadId; - args.operation = operation; - args.wzSource = wzSource; + args.wzSource = *pwzSource; + args.wzDownloadUrl = *pwzDownloadUrl; + args.wzPayloadContainerId = wzPayloadContainerId; + args.recommendation = *pCacheOperation; results.cbSize = sizeof(results); + results.action = *pCacheOperation; - hr = SendBAMessage(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEACQUIREBEGIN, &args, &results); + hr = SendBAMessageFromInactiveEngine(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEACQUIREBEGIN, &args, &results); ExitOnFailure(hr, "BA OnCacheAcquireBegin failed."); if (results.fCancel) { hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT); } + else + { + // Verify the BA requested an action that is possible. + if (BOOTSTRAPPER_CACHE_OPERATION_DOWNLOAD == results.action && *pwzDownloadUrl && **pwzDownloadUrl || + BOOTSTRAPPER_CACHE_OPERATION_EXTRACT == results.action && wzPayloadContainerId || + BOOTSTRAPPER_CACHE_OPERATION_COPY == results.action || + BOOTSTRAPPER_CACHE_OPERATION_NONE == results.action) + { + *pCacheOperation = results.action; + } + } LExit: return hr; @@ -444,7 +461,7 @@ EXTERN_C BAAPI UserExperienceOnCacheAcquireComplete( results.cbSize = sizeof(results); results.action = args.recommendation; - hr = SendBAMessage(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEACQUIRECOMPLETE, &args, &results); + hr = SendBAMessageFromInactiveEngine(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEACQUIRECOMPLETE, &args, &results); ExitOnFailure(hr, "BA OnCacheAcquireComplete failed."); if (FAILED(hrStatus)) @@ -490,6 +507,64 @@ LExit: return hr; } +EXTERN_C BAAPI UserExperienceOnCacheAcquireResolving( + __in BURN_USER_EXPERIENCE* pUserExperience, + __in_z_opt LPCWSTR wzPackageOrContainerId, + __in_z_opt LPCWSTR wzPayloadId, + __in_z LPWSTR* rgSearchPaths, + __in DWORD cSearchPaths, + __in BOOL fFoundLocal, + __in DWORD* pdwChosenSearchPath, + __in_z_opt LPCWSTR wzDownloadUrl, + __in_z_opt LPCWSTR wzPayloadContainerId, + __inout BOOTSTRAPPER_CACHE_OPERATION* pCacheOperation + ) +{ + HRESULT hr = S_OK; + BA_ONCACHEACQUIRERESOLVING_ARGS args = { }; + BA_ONCACHEACQUIRERESOLVING_RESULTS results = { }; + + args.cbSize = sizeof(args); + args.wzPackageOrContainerId = wzPackageOrContainerId; + args.wzPayloadId = wzPayloadId; + args.rgSearchPaths = const_cast(rgSearchPaths); + args.cSearchPaths = cSearchPaths; + args.fFoundLocal = fFoundLocal; + args.dwRecommendedSearchPath = *pdwChosenSearchPath; + args.wzDownloadUrl = wzDownloadUrl; + args.recommendation = *pCacheOperation; + + results.cbSize = sizeof(results); + results.dwChosenSearchPath = *pdwChosenSearchPath; + results.action = *pCacheOperation; + + hr = SendBAMessage(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONCACHEACQUIRERESOLVING, &args, &results); + ExitOnFailure(hr, "BA OnCacheAcquireResolving failed."); + + if (results.fCancel) + { + hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT); + } + else + { + // Verify the BA requested an action that is possible. + if (BOOTSTRAPPER_CACHE_OPERATION_DOWNLOAD == results.action && wzDownloadUrl && *wzDownloadUrl || + BOOTSTRAPPER_CACHE_OPERATION_EXTRACT == results.action && wzPayloadContainerId || + BOOTSTRAPPER_CACHE_OPERATION_NONE == results.action) + { + *pCacheOperation = results.action; + } + else if (BOOTSTRAPPER_CACHE_OPERATION_COPY == results.action && results.dwChosenSearchPath < cSearchPaths) + { + *pdwChosenSearchPath = results.dwChosenSearchPath; + *pCacheOperation = results.action; + } + } + +LExit: + return hr; +} + EXTERN_C BAAPI UserExperienceOnCacheBegin( __in BURN_USER_EXPERIENCE* pUserExperience ) @@ -1861,45 +1936,6 @@ LExit: return hr; } -EXTERN_C BAAPI UserExperienceOnResolveSource( - __in BURN_USER_EXPERIENCE* pUserExperience, - __in_z LPCWSTR wzPackageOrContainerId, - __in_z_opt LPCWSTR wzPayloadId, - __in_z LPCWSTR wzLocalSource, - __in_z_opt LPCWSTR wzDownloadSource, - __inout BOOTSTRAPPER_RESOLVESOURCE_ACTION* pAction - ) -{ - HRESULT hr = S_OK; - BA_ONRESOLVESOURCE_ARGS args = { }; - BA_ONRESOLVESOURCE_RESULTS results = { }; - - args.cbSize = sizeof(args); - args.wzPackageOrContainerId = wzPackageOrContainerId; - args.wzPayloadId = wzPayloadId; - args.wzLocalSource = wzLocalSource; - args.wzDownloadSource = wzDownloadSource; - args.recommendation = *pAction; - - results.cbSize = sizeof(results); - results.action = *pAction; - - hr = SendBAMessageFromInactiveEngine(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONRESOLVESOURCE, &args, &results); - ExitOnFailure(hr, "BA OnResolveSource failed."); - - if (results.fCancel) - { - hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT); - } - else - { - *pAction = results.action; - } - -LExit: - return hr; -} - EXTERN_C BAAPI UserExperienceOnRollbackMsiTransactionBegin( __in BURN_USER_EXPERIENCE* pUserExperience, __in LPCWSTR wzTransactionId diff --git a/src/engine/userexperience.h b/src/engine/userexperience.h index a1fb67a0..dd1fb086 100644 --- a/src/engine/userexperience.h +++ b/src/engine/userexperience.h @@ -126,8 +126,10 @@ BAAPI UserExperienceOnCacheAcquireBegin( __in BURN_USER_EXPERIENCE* pUserExperience, __in_z_opt LPCWSTR wzPackageOrContainerId, __in_z_opt LPCWSTR wzPayloadId, - __in BOOTSTRAPPER_CACHE_OPERATION operation, - __in_z LPCWSTR wzSource + __in_z LPWSTR* pwzSource, + __in_z LPWSTR* pwzDownloadUrl, + __in_z_opt LPCWSTR wzPayloadContainerId, + __out BOOTSTRAPPER_CACHE_OPERATION* pCacheOperation ); BAAPI UserExperienceOnCacheAcquireComplete( __in BURN_USER_EXPERIENCE* pUserExperience, @@ -144,6 +146,18 @@ BAAPI UserExperienceOnCacheAcquireProgress( __in DWORD64 dw64Total, __in DWORD dwOverallPercentage ); +BAAPI UserExperienceOnCacheAcquireResolving( + __in BURN_USER_EXPERIENCE* pUserExperience, + __in_z_opt LPCWSTR wzPackageOrContainerId, + __in_z_opt LPCWSTR wzPayloadId, + __in_z LPWSTR* rgSearchPaths, + __in DWORD cSearchPaths, + __in BOOL fFoundLocal, + __in DWORD* pdwChosenSearchPath, + __in_z_opt LPCWSTR wzDownloadUrl, + __in_z_opt LPCWSTR wzPayloadContainerId, + __inout BOOTSTRAPPER_CACHE_OPERATION* pCacheOperation + ); BAAPI UserExperienceOnCacheBegin( __in BURN_USER_EXPERIENCE* pUserExperience ); @@ -426,14 +440,6 @@ BAAPI UserExperienceOnRegisterComplete( __in BURN_USER_EXPERIENCE* pUserExperience, __in HRESULT hrStatus ); -BAAPI UserExperienceOnResolveSource( - __in BURN_USER_EXPERIENCE* pUserExperience, - __in_z LPCWSTR wzPackageOrContainerId, - __in_z_opt LPCWSTR wzPayloadId, - __in_z LPCWSTR wzLocalSource, - __in_z_opt LPCWSTR wzDownloadSource, - __inout BOOTSTRAPPER_RESOLVESOURCE_ACTION* pAction - ); BAAPI UserExperienceOnRollbackMsiTransactionBegin( __in BURN_USER_EXPERIENCE* pUserExperience, __in LPCWSTR wzTransactionId -- cgit v1.2.3-55-g6feb