From edccb203c421d2bd820062024088c6698424d9ee Mon Sep 17 00:00:00 2001 From: Bob Arnson Date: Wed, 4 Feb 2026 20:47:04 -0500 Subject: Support dual-purpose packages in Burn. Fixes https://github.com/wixtoolset/issues/issues/8958 --- src/burn/engine/apply.cpp | 2 +- src/burn/engine/baengine.cpp | 5 +- src/burn/engine/baengine.h | 1 + src/burn/engine/cache.cpp | 8 +- src/burn/engine/core.cpp | 42 ++++-- src/burn/engine/core.h | 5 +- src/burn/engine/dependency.cpp | 72 ++++++++-- src/burn/engine/elevation.cpp | 43 ++++-- src/burn/engine/engine.cpp | 7 +- src/burn/engine/engine.mc | 29 +++- src/burn/engine/engine.vcxproj | 17 +-- src/burn/engine/externalengine.cpp | 6 +- src/burn/engine/externalengine.h | 5 +- src/burn/engine/logging.cpp | 36 +++++ src/burn/engine/logging.h | 7 + src/burn/engine/msiengine.cpp | 49 ++++++- src/burn/engine/msiengine.h | 2 + src/burn/engine/mspengine.cpp | 4 +- src/burn/engine/package.cpp | 48 ++++++- src/burn/engine/package.h | 7 +- src/burn/engine/plan.cpp | 73 +++++++++- src/burn/engine/plan.h | 12 ++ src/burn/engine/registration.cpp | 287 +++++++++++++++++++++++-------------- src/burn/engine/registration.h | 11 +- src/burn/engine/relatedbundle.cpp | 4 +- src/burn/engine/uithread.cpp | 2 +- src/burn/engine/variable.cpp | 2 + 27 files changed, 597 insertions(+), 189 deletions(-) (limited to 'src/burn/engine') diff --git a/src/burn/engine/apply.cpp b/src/burn/engine/apply.cpp index e4e76a6c..68aded71 100644 --- a/src/burn/engine/apply.cpp +++ b/src/burn/engine/apply.cpp @@ -632,7 +632,7 @@ extern "C" HRESULT ApplyCache( { hr = ElevationCachePreparePackage(hPipe, pPackage); } - LogExitOnFailure(hr, MSG_CACHE_PREPARE_PACKAGE_FAILED, "Cache prepare package failed: %ls", pPackage->sczId, NULL, NULL); + LogExitOnFailure(hr, MSG_CACHE_PREPARE_PACKAGE_FAILED, "Cache prepare package failed: %ls", pPackage->sczId); } hr = ApplyCachePackage(&cacheContext, pPackage); diff --git a/src/burn/engine/baengine.cpp b/src/burn/engine/baengine.cpp index d1704ad9..e48f71c0 100644 --- a/src/burn/engine/baengine.cpp +++ b/src/burn/engine/baengine.cpp @@ -1134,12 +1134,15 @@ static HRESULT BAEnginePlan( hr = BuffReaderReadNumber(pReaderArgs, reinterpret_cast(&args.action)); ExitOnFailure(hr, "Failed to read plan action of BAEnginePlan args."); + hr = BuffReaderReadNumber(pReaderArgs, reinterpret_cast(&args.plannedScope)); + ExitOnFailure(hr, "Failed to read plan scope of BAEnginePlan args."); + // Read results. hr = BuffReaderReadNumber(pReaderResults, &results.dwApiVersion); ExitOnFailure(hr, "Failed to read API version of BAEnginePlan results."); // Execute. - hr = ExternalEnginePlan(pContext, args.action); + hr = ExternalEnginePlan(pContext, args.action, args.plannedScope); ExitOnFailure(hr, "Failed to plan in the engine."); // Pack result. diff --git a/src/burn/engine/baengine.h b/src/burn/engine/baengine.h index 97cfea9c..39e5ae0b 100644 --- a/src/burn/engine/baengine.h +++ b/src/burn/engine/baengine.h @@ -31,6 +31,7 @@ typedef struct _BAENGINE_ACTION struct { BOOTSTRAPPER_ACTION action; + BOOTSTRAPPER_SCOPE plannedScope; } plan; struct { diff --git a/src/burn/engine/cache.cpp b/src/burn/engine/cache.cpp index c85a1be4..21bd42be 100644 --- a/src/burn/engine/cache.cpp +++ b/src/burn/engine/cache.cpp @@ -36,8 +36,8 @@ static HRESULT SecurePerMachineCacheRoot( static HRESULT CreateCompletedPath( __in BURN_CACHE* pCache, __in BOOL fPerMachine, - __in LPCWSTR wzCacheId, - __in LPCWSTR wzFilePath, + __in_z LPCWSTR wzId, + __in_z_opt LPCWSTR wzFilePath, __out_z LPWSTR* psczCachePath ); static HRESULT CreateUnverifiedPath( @@ -1658,8 +1658,8 @@ LExit: static HRESULT CreateCompletedPath( __in BURN_CACHE* pCache, __in BOOL fPerMachine, - __in LPCWSTR wzId, - __in LPCWSTR wzFilePath, + __in_z LPCWSTR wzId, + __in_z_opt LPCWSTR wzFilePath, __out_z LPWSTR* psczCachePath ) { diff --git a/src/burn/engine/core.cpp b/src/burn/engine/core.cpp index 2dfa4857..7937bd65 100644 --- a/src/burn/engine/core.cpp +++ b/src/burn/engine/core.cpp @@ -379,7 +379,7 @@ extern "C" HRESULT CoreDetect( pEngineState->registration.fEligibleForCleanup = FALSE; } - LogId(REPORT_STANDARD, MSG_DETECTED_PACKAGE, pPackage->sczId, LoggingPackageStateToString(pPackage->currentState), LoggingBoolToString(pPackage->fCached), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->installRegistrationState), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->cacheRegistrationState)); + LogId(REPORT_STANDARD, MSG_DETECTED_PACKAGE, pPackage->sczId, LoggingPackageStateToString(pPackage->currentState), LoggingBoolToString(pPackage->fCached), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->installRegistrationState), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->cacheRegistrationState), LoggingPackageScopeToString(pPackage->scope)); if (BURN_PACKAGE_TYPE_MSI == pPackage->type) { @@ -424,8 +424,9 @@ LExit: extern "C" HRESULT CorePlan( __in BURN_ENGINE_STATE* pEngineState, - __in BOOTSTRAPPER_ACTION action - ) + __in BOOTSTRAPPER_ACTION action, + __in BOOTSTRAPPER_SCOPE plannedScope +) { HRESULT hr = S_OK; BOOL fPlanBegan = FALSE; @@ -433,7 +434,7 @@ extern "C" HRESULT CorePlan( BURN_PACKAGE* pForwardCompatibleBundlePackage = NULL; BOOL fContinuePlanning = TRUE; // assume we won't skip planning due to dependencies. - LogId(REPORT_STANDARD, MSG_PLAN_BEGIN, pEngineState->packages.cPackages, LoggingBurnActionToString(action)); + LogId(REPORT_STANDARD, MSG_PLAN_BEGIN, pEngineState->packages.cPackages, LoggingBurnActionToString(action), LoggingBundleScopeToString(plannedScope)); fPlanBegan = TRUE; hr = BACallbackOnPlanBegin(&pEngineState->userExperience, pEngineState->packages.cPackages); @@ -452,12 +453,13 @@ extern "C" HRESULT CorePlan( pEngineState->fPlanned = FALSE; PlanReset(&pEngineState->plan, &pEngineState->variables, &pEngineState->containers, &pEngineState->packages, &pEngineState->layoutPayloads); - hr = PlanSetVariables(action, &pEngineState->variables); - ExitOnFailure(hr, "Failed to update action."); + hr = PlanSetVariables(action, pEngineState->registration.scope, pEngineState->plan.plannedScope, &pEngineState->variables); + ExitOnFailure(hr, "Failed to update plan variables."); // Remember the overall action state in the plan since it shapes the changes // we make everywhere. pEngineState->plan.action = action; + pEngineState->plan.plannedScope = plannedScope; pEngineState->plan.pCache = &pEngineState->cache; pEngineState->plan.pCommand = &pEngineState->command; pEngineState->plan.pInternalCommand = &pEngineState->internalCommand; @@ -467,6 +469,17 @@ extern "C" HRESULT CorePlan( pEngineState->plan.fDisableRollback = pEngineState->fDisableRollback || BOOTSTRAPPER_ACTION_UNSAFE_UNINSTALL == pEngineState->plan.action; pEngineState->plan.fPlanPackageCacheRollback = BOOTSTRAPPER_REGISTRATION_TYPE_NONE == pEngineState->registration.detectedRegistrationType; + hr = PlanPackagesAndBundleScope(pEngineState->packages.rgPackages, pEngineState->packages.cPackages, pEngineState->plan.plannedScope, pEngineState->registration.scope, pEngineState->command.commandLineScope, &pEngineState->plan.plannedScope, &pEngineState->registration.fPerMachine); + ExitOnFailure(hr, "Failed to determine packages and bundle scope."); + + if (BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE_OR_PER_USER == pEngineState->registration.scope || BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER_OR_PER_MACHINE == pEngineState->registration.scope) + { + LogId(REPORT_STANDARD, MSG_PLAN_CONFIGURED_SCOPE, LoggingInstallScopeToString(pEngineState->registration.fPerMachine)); + } + + hr = RegistrationSetPaths(&pEngineState->registration, &pEngineState->cache); + ExitOnFailure(hr, "Failed to set registration paths."); + // Set resume commandline hr = PlanSetResumeCommand(&pEngineState->plan, &pEngineState->registration, &pEngineState->log); ExitOnFailure(hr, "Failed to set resume command"); @@ -475,7 +488,7 @@ extern "C" HRESULT CorePlan( ExitOnFailure(hr, "Failed to initialize the dependencies for the plan."); hr = RegistrationPlanInitialize(&pEngineState->registration); - ExitOnFailure(hr, "Failed to initialize registration for the plan."); + ExitOnFailure(hr, "Failed to initialize the plan for registration."); if (BOOTSTRAPPER_ACTION_LAYOUT == action) { @@ -556,6 +569,9 @@ extern "C" HRESULT CorePlan( LogPackages(pUpgradeBundlePackage, pForwardCompatibleBundlePackage, &pEngineState->packages, &pEngineState->registration.relatedBundles, action); } + hr = PlanSetVariables(action, pEngineState->registration.scope, pEngineState->plan.plannedScope, &pEngineState->variables); + ExitOnFailure(hr, "Failed to update plan variables after planning."); + PlanDump(&pEngineState->plan); LExit: @@ -1331,7 +1347,7 @@ extern "C" void CoreCleanup( ExitFunction(); } - hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL); + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_UNINSTALL, BOOTSTRAPPER_SCOPE_DEFAULT); ExitOnFailure(hr, "Plan during cleanup failed"); hr = CoreApply(pEngineState, pEngineState->hMessageWindow); @@ -1470,6 +1486,14 @@ extern "C" HRESULT CoreParseCommandLine( { pInternalCommand->fDisableSystemRestore = TRUE; } + else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"peruser", -1, TRUE)) + { + pCommand->commandLineScope = BOOTSTRAPPER_SCOPE_PER_USER; + } + else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"permachine", -1, TRUE)) + { + pCommand->commandLineScope = BOOTSTRAPPER_SCOPE_PER_MACHINE; + } else if (CSTR_EQUAL == ::CompareStringOrdinal(&argv[i][1], -1, L"originalsource", -1, TRUE)) { if (i + 1 >= argc) @@ -2346,7 +2370,7 @@ static void LogPackages( LogRollbackBoundary(pPackage->pRollbackBoundaryBackward); } - LogId(REPORT_STANDARD, MSG_PLANNED_PACKAGE, pPackage->sczId, LoggingPackageStateToString(pPackage->currentState), LoggingRequestStateToString(pPackage->defaultRequested), LoggingRequestStateToString(pPackage->requested), LoggingActionStateToString(pPackage->execute), LoggingActionStateToString(pPackage->rollback), LoggingCacheTypeToString(pPackage->authoredCacheType), LoggingCacheTypeToString(pPackage->cacheType), LoggingPlannedCacheToString(pPackage), LoggingBoolToString(pPackage->fPlannedUncache), LoggingDependencyActionToString(pPackage->dependencyExecute), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->expectedInstallRegistrationState), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->expectedCacheRegistrationState)); + LogId(REPORT_STANDARD, MSG_PLANNED_PACKAGE, pPackage->sczId, LoggingPackageStateToString(pPackage->currentState), LoggingRequestStateToString(pPackage->defaultRequested), LoggingRequestStateToString(pPackage->requested), LoggingActionStateToString(pPackage->execute), LoggingActionStateToString(pPackage->rollback), LoggingCacheTypeToString(pPackage->authoredCacheType), LoggingCacheTypeToString(pPackage->cacheType), LoggingPlannedCacheToString(pPackage), LoggingBoolToString(pPackage->fPlannedUncache), LoggingDependencyActionToString(pPackage->dependencyExecute), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->expectedInstallRegistrationState), LoggingPackageRegistrationStateToString(pPackage->fCanAffectRegistration, pPackage->expectedCacheRegistrationState), LoggingInstallScopeToString(pPackage->fPerMachine)); if (BURN_PACKAGE_TYPE_MSI == pPackage->type) { diff --git a/src/burn/engine/core.h b/src/burn/engine/core.h index cf615e35..75c0c941 100644 --- a/src/burn/engine/core.h +++ b/src/burn/engine/core.h @@ -45,7 +45,9 @@ const LPCWSTR BURN_BUNDLE_EXECUTE_PACKAGE_ACTION = L"WixBundleExecutePackageActi const LPCWSTR BURN_BUNDLE_FORCED_RESTART_PACKAGE = L"WixBundleForcedRestartPackage"; const LPCWSTR BURN_BUNDLE_INSTALLED = L"WixBundleInstalled"; const LPCWSTR BURN_BUNDLE_ELEVATED = L"WixBundleElevated"; +const LPCWSTR BURN_BUNDLE_PLANNED_SCOPE = L"WixBundlePlannedScope"; const LPCWSTR BURN_BUNDLE_PROVIDER_KEY = L"WixBundleProviderKey"; +const LPCWSTR BURN_BUNDLE_SCOPE = L"WixBundleScope"; const LPCWSTR BURN_BUNDLE_SOURCE_PROCESS_PATH = L"WixBundleSourceProcessPath"; const LPCWSTR BURN_BUNDLE_SOURCE_PROCESS_FOLDER = L"WixBundleSourceProcessFolder"; const LPCWSTR BURN_BUNDLE_TAG = L"WixBundleTag"; @@ -243,7 +245,8 @@ HRESULT CoreDetect( ); HRESULT CorePlan( __in BURN_ENGINE_STATE* pEngineState, - __in BOOTSTRAPPER_ACTION action + __in BOOTSTRAPPER_ACTION action, + __in BOOTSTRAPPER_SCOPE scope ); HRESULT CoreElevate( __in BURN_ENGINE_STATE* pEngineState, diff --git a/src/burn/engine/dependency.cpp b/src/burn/engine/dependency.cpp index 94a8a1e4..7cd0db9f 100644 --- a/src/burn/engine/dependency.cpp +++ b/src/burn/engine/dependency.cpp @@ -12,6 +12,7 @@ const LPCWSTR vcszIgnoreDependenciesDelim = L";"; static HRESULT DetectPackageDependents( __in BURN_PACKAGE* pPackage, + __in BOOL fPackagePerMachine, __in const BURN_REGISTRATION* pRegistration ); @@ -249,7 +250,22 @@ extern "C" HRESULT DependencyDetectProviderKeyBundleCode( { HRESULT hr = S_OK; - hr = DepGetProviderInformation(pRegistration->hkRoot, pRegistration->sczProviderKey, &pRegistration->sczDetectedProviderKeyBundleCode, NULL, NULL); + // For configurable packages, check both scopes because until planning, + // we can't know their planned scope. + if (pRegistration->hkRoot) + { + hr = DepGetProviderInformation(pRegistration->hkRoot, pRegistration->sczProviderKey, &pRegistration->sczDetectedProviderKeyBundleCode, NULL, NULL); + } + else + { + hr = DepGetProviderInformation(HKEY_LOCAL_MACHINE, pRegistration->sczProviderKey, &pRegistration->sczDetectedProviderKeyBundleCode, NULL, NULL); + + if (E_NOTFOUND == hr) + { + hr = DepGetProviderInformation(HKEY_CURRENT_USER, pRegistration->sczProviderKey, &pRegistration->sczDetectedProviderKeyBundleCode, NULL, NULL); + } + } + if (E_NOTFOUND == hr) { ReleaseNullStr(pRegistration->sczDetectedProviderKeyBundleCode); @@ -284,7 +300,21 @@ extern "C" HRESULT DependencyDetectBundle( hr = DependencyDetectProviderKeyBundleCode(pRegistration); ExitOnFailure(hr, "Failed to detect provider key bundle code."); - hr = DepCheckDependents(pRegistration->hkRoot, pRegistration->sczProviderKey, 0, NULL, &pRegistration->rgDependents, &pRegistration->cDependents); + // For configurable packages, check both scopes because until planning, + // we can't know their planned scope. + if (pRegistration->hkRoot) + { + hr = DepCheckDependents(pRegistration->hkRoot, pRegistration->sczProviderKey, 0, NULL, &pRegistration->rgDependents, &pRegistration->cDependents); + } + else + { + hr = DepCheckDependents(HKEY_LOCAL_MACHINE, pRegistration->sczProviderKey, 0, NULL, &pRegistration->rgDependents, &pRegistration->cDependents); + + if (E_NOTFOUND == hr) + { + hr = DepCheckDependents(HKEY_CURRENT_USER, pRegistration->sczProviderKey, 0, NULL, &pRegistration->rgDependents, &pRegistration->cDependents); + } + } ExitOnPathFailure(hr, fExists, "Failed dependents check on bundle."); if (pDependencies->fSelfDependent || pDependencies->fActiveParent) @@ -292,13 +322,13 @@ extern "C" HRESULT DependencyDetectBundle( for (DWORD i = 0; i < pRegistration->cDependents; ++i) { DEPENDENCY* pDependent = pRegistration->rgDependents + i; - - if (pDependencies->fActiveParent && CSTR_EQUAL == ::CompareStringOrdinal(pDependencies->wzActiveParent, -1, pDependent->sczKey, -1, TRUE)) + + if (pDependent && pDependencies->fActiveParent && CSTR_EQUAL == ::CompareStringOrdinal(pDependencies->wzActiveParent, -1, pDependent->sczKey, -1, TRUE)) { pRegistration->fParentRegisteredAsDependent = TRUE; } - if (pDependencies->fSelfDependent && CSTR_EQUAL == ::CompareStringOrdinal(pDependencies->wzSelfDependent, -1, pDependent->sczKey, -1, TRUE)) + if (pDependent && pDependencies->fSelfDependent && CSTR_EQUAL == ::CompareStringOrdinal(pDependencies->wzSelfDependent, -1, pDependent->sczKey, -1, TRUE)) { pRegistration->fSelfRegisteredAsDependent = TRUE; } @@ -316,11 +346,24 @@ extern "C" HRESULT DependencyDetectChainPackage( { HRESULT hr = S_OK; - hr = DetectPackageDependents(pPackage, pRegistration); - ExitOnFailure(hr, "Failed to detect dependents for package '%ls'", pPackage->sczId); + if (BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER_OR_PER_MACHINE == pPackage->scope || BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE_OR_PER_USER == pPackage->scope) + { + // For configurable packages, check both scopes because until planning, + // we can't know their planned scope. + hr = DetectPackageDependents(pPackage, /*fPerMachine*/TRUE, pRegistration); + ExitOnFailure(hr, "Failed to detect per-machine dependents for configurable package '%ls'", pPackage->sczId); + + hr = DetectPackageDependents(pPackage, /*fPerMachine*/FALSE, pRegistration); + ExitOnFailure(hr, "Failed to detect per-user dependents for configurable package '%ls'", pPackage->sczId); + } + else + { + hr = DetectPackageDependents(pPackage, pPackage->fPerMachine, pRegistration); + ExitOnFailure(hr, "Failed to detect dependents for %hs package '%ls'", LoggingInstallScopeToString(pPackage->fPerMachine), pPackage->sczId); + } hr = DependencyDetectCompatibleEntry(pPackage, pRegistration); - ExitOnFailure(hr, "Failed to detect compatible package for package '%ls'", pPackage->sczId); + ExitOnFailure(hr, "Failed to detect compatible package for %hs package '%ls'", LoggingInstallScopeToString(pPackage->fPerMachine), pPackage->sczId); LExit: return hr; @@ -336,7 +379,7 @@ extern "C" HRESULT DependencyDetectRelatedBundle( if (pRelatedBundle->fPlannable) { - hr = DetectPackageDependents(pPackage, pRegistration); + hr = DetectPackageDependents(pPackage, pPackage->fPerMachine, pRegistration); ExitOnFailure(hr, "Failed to detect dependents for related bundle '%ls'", pPackage->sczId); } @@ -626,7 +669,7 @@ LExit: } extern "C" HRESULT DependencyPlanPackage( - __in_opt DWORD *pdwInsertSequence, + __in_opt DWORD* pdwInsertSequence, __in const BURN_PACKAGE* pPackage, __in BURN_PLAN* pPlan ) @@ -946,18 +989,19 @@ LExit: static HRESULT DetectPackageDependents( __in BURN_PACKAGE* pPackage, + __in BOOL fPackagePerMachine, __in const BURN_REGISTRATION* pRegistration ) { HRESULT hr = S_OK; - HKEY hkHive = pPackage->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + HKEY hkHive = fPackagePerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; BOOL fCanIgnorePresence = pPackage->fCanAffectRegistration && 0 < pPackage->cDependencyProviders && (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pPackage->cacheRegistrationState || BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pPackage->installRegistrationState); BOOL fBundleRegisteredAsDependent = FALSE; // There's currently no point in getting the dependents if the scope doesn't match, // because they will just get ignored. - if (pRegistration->fPerMachine != pPackage->fPerMachine) + if (pRegistration->fPerMachine != fPackagePerMachine) { ExitFunction(); } @@ -979,7 +1023,7 @@ static HRESULT DetectPackageDependents( { DEPENDENCY* pDependent = pProvider->rgDependents + iDependent; - if (CSTR_EQUAL == ::CompareStringOrdinal(pRegistration->sczCode, -1, pDependent->sczKey, -1, TRUE)) + if (pDependent && CSTR_EQUAL == ::CompareStringOrdinal(pRegistration->sczCode, -1, pDependent->sczKey, -1, TRUE)) { pProvider->fBundleRegisteredAsDependent = TRUE; fBundleRegisteredAsDependent = TRUE; @@ -994,10 +1038,12 @@ static HRESULT DetectPackageDependents( { pPackage->cacheRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED; } + if (BURN_PACKAGE_REGISTRATION_STATE_PRESENT == pPackage->installRegistrationState) { pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_IGNORED; } + if (BURN_PACKAGE_TYPE_MSP == pPackage->type) { for (DWORD i = 0; i < pPackage->Msp.cTargetProductCodes; ++i) diff --git a/src/burn/engine/elevation.cpp b/src/burn/engine/elevation.cpp index ef87841f..711ce4af 100644 --- a/src/burn/engine/elevation.cpp +++ b/src/burn/engine/elevation.cpp @@ -1191,7 +1191,6 @@ extern "C" HRESULT ElevationExecuteMsiPackage( hr = VariableSerialize(pVariables, FALSE, &pbData, &cbData); ExitOnFailure(hr, "Failed to write variables."); - // send message context.pfnMessageHandler = pfnMessageHandler; context.pvContext = pvContext; @@ -2572,6 +2571,11 @@ static HRESULT OnSessionBegin( ExitOnFailure(hr, "Failed to read variables."); // Begin session in per-machine process. + pRegistration->fPerMachine = TRUE; + + hr = RegistrationSetPaths(pRegistration, pCache); + ExitOnFailure(hr, "Failed to set elevated registration paths."); + hr = RegistrationSessionBegin(sczEngineWorkingPath, pRegistration, pCache, pVariables, dwRegistrationOperations, qwEstimatedSize, (BOOTSTRAPPER_REGISTRATION_TYPE)dwRegistrationType); ExitOnFailure(hr, "Failed to begin registration session."); @@ -2657,6 +2661,8 @@ static HRESULT OnCachePreparePackage( { hr = PackageFindById(pPackages, scz, &pPackage); ExitOnFailure(hr, "Failed to find package: %ls", scz); + + pPackage->fPerMachine = TRUE; } else { @@ -2698,6 +2704,8 @@ static HRESULT OnCacheCompletePayload( { hr = PackageFindById(pPackages, scz, &pPackage); ExitOnFailure(hr, "Failed to find package: %ls", scz); + + pPackage->fPerMachine = TRUE; } hr = BuffReadString(pbData, cbData, &iData, &scz); @@ -2717,8 +2725,8 @@ static HRESULT OnCacheCompletePayload( if (pPackage && pPayload) // complete payload. { - hr = CacheCompletePayload(pCache, pPackage->fPerMachine, pPayload, pPackage->sczCacheId, sczUnverifiedPath, fMove, BurnCacheMessageHandler, ElevatedProgressRoutine, hPipe); - ExitOnFailure(hr, "Failed to cache payload: %ls", pPayload->sczKey); + hr = CacheCompletePayload(pCache, TRUE/*fPerMachine*/, pPayload, pPackage->sczCacheId, sczUnverifiedPath, fMove, BurnCacheMessageHandler, ElevatedProgressRoutine, hPipe); + ExitOnFailure(hr, "Failed to cache per-machine payload: %ls", pPayload->sczKey); } else { @@ -2755,6 +2763,8 @@ static HRESULT OnCacheVerifyPayload( { hr = PackageFindById(pPackages, scz, &pPackage); ExitOnFailure(hr, "Failed to find package: %ls", scz); + + pPackage->fPerMachine = TRUE; } hr = BuffReadString(pbData, cbData, &iData, &scz); @@ -2970,6 +2980,8 @@ static HRESULT OnExecuteBundlePackage( hr = PackageFindById(pPackages, sczPackage, &executeAction.bundlePackage.pPackage); ExitOnFailure(hr, "Failed to find package: %ls", sczPackage); + executeAction.bundlePackage.pPackage->fPerMachine = TRUE; + if (BURN_PACKAGE_TYPE_BUNDLE != executeAction.bundlePackage.pPackage->type) { ExitWithRootFailure(hr, E_INVALIDARG, "Package is not a BUNDLE package: %ls", sczPackage); @@ -3052,6 +3064,8 @@ static HRESULT OnExecuteExePackage( hr = PackageFindById(pPackages, sczPackage, &executeAction.exePackage.pPackage); ExitOnFailure(hr, "Failed to find package: %ls", sczPackage); + executeAction.exePackage.pPackage->fPerMachine = TRUE; + if (BURN_PACKAGE_TYPE_EXE != executeAction.exePackage.pPackage->type) { ExitWithRootFailure(hr, E_INVALIDARG, "Package is not an EXE package: %ls", sczPackage); @@ -3113,6 +3127,8 @@ static HRESULT OnExecuteMsiPackage( hr = PackageFindById(pPackages, sczPackage, &executeAction.msiPackage.pPackage); ExitOnFailure(hr, "Failed to find package: %ls", sczPackage); + executeAction.msiPackage.pPackage->fPerMachine = TRUE; + hr = BuffReadPointer(pbData, cbData, &iData, (DWORD_PTR*)&hwndParent); ExitOnFailure(hr, "Failed to read parent hwnd."); @@ -3205,6 +3221,8 @@ static HRESULT OnExecuteMspPackage( hr = PackageFindById(pPackages, sczPackage, &executeAction.mspTarget.pPackage); ExitOnFailure(hr, "Failed to find package: %ls", sczPackage); + executeAction.mspTarget.pPackage->fPerMachine = TRUE; + hr = BuffReadPointer(pbData, cbData, &iData, (DWORD_PTR*)&hwndParent); ExitOnFailure(hr, "Failed to read parent hwnd."); @@ -3246,6 +3264,8 @@ static HRESULT OnExecuteMspPackage( hr = PackageFindById(pPackages, sczPackage, &executeAction.mspTarget.rgOrderedPatches[i].pPackage); ExitOnFailure(hr, "Failed to find ordered patch package: %ls", sczPackage); + + executeAction.mspTarget.rgOrderedPatches[i].pPackage->fPerMachine = TRUE; } } @@ -3310,6 +3330,8 @@ static HRESULT OnExecuteMsuPackage( hr = PackageFindById(pPackages, sczPackage, &executeAction.msuPackage.pPackage); ExitOnFailure(hr, "Failed to find package: %ls", sczPackage); + executeAction.msuPackage.pPackage->fPerMachine = TRUE; + if (BURN_PACKAGE_TYPE_MSU != executeAction.msuPackage.pPackage->type) { ExitWithRootFailure(hr, E_INVALIDARG, "Package is not an MSU package: %ls", sczPackage); @@ -3371,6 +3393,8 @@ static HRESULT OnUninstallMsiCompatiblePackage( hr = PackageFindById(pPackages, sczPackageId, &pPackage); ExitOnFailure(hr, "Failed to find package: %ls", sczPackageId); + pPackage->fPerMachine = TRUE; + executeAction.uninstallMsiCompatiblePackage.pParentPackage = pPackage; pCompatiblePackage = &pPackage->compatiblePackage; @@ -3424,6 +3448,8 @@ static HRESULT OnExecutePackageProviderAction( } ExitOnFailure(hr, "Failed to find package: %ls", sczPackage); + executeAction.packageProvider.pPackage->fPerMachine; + hr = BuffReadNumber(pbData, cbData, &iData, (DWORD*)&fRollback); ExitOnFailure(hr, "Failed to read rollback flag."); @@ -3436,11 +3462,6 @@ static HRESULT OnExecutePackageProviderAction( ExitOnFailure(hr, "Failed to read provider action."); } - if (!executeAction.packageProvider.pPackage->fPerMachine) - { - ExitWithRootFailure(hr, E_INVALIDARG, "ExecutePackageProviderAction called for per-user package."); - } - // Execute the package provider action. hr = DependencyExecutePackageProviderAction(&executeAction, fRollback); ExitOnFailure(hr, "Failed to execute package provider action."); @@ -3479,6 +3500,8 @@ static HRESULT OnExecutePackageDependencyAction( } ExitOnFailure(hr, "Failed to find package: %ls", sczPackage); + executeAction.packageDependency.pPackage->fPerMachine = TRUE; + hr = BuffReadNumber(pbData, cbData, &iData, (DWORD*)&fRollback); ExitOnFailure(hr, "Failed to read rollback flag."); @@ -3784,6 +3807,8 @@ static HRESULT OnCleanCompatiblePackage( hr = PackageFindById(pPackages, sczPackageId, &pPackage); ExitOnFailure(hr, "Failed to find package: %ls", sczPackageId); + pPackage->fPerMachine = TRUE; + pCompatiblePackage = &pPackage->compatiblePackage; if (!pCompatiblePackage->fDetected || !pCompatiblePackage->compatibleEntry.sczId || !pCompatiblePackage->sczCacheId || !*pCompatiblePackage->sczCacheId) @@ -3826,6 +3851,8 @@ static HRESULT OnCleanPackage( hr = PackageFindById(pPackages, sczPackage, &pPackage); ExitOnFailure(hr, "Failed to find package: %ls", sczPackage); + pPackage->fPerMachine = TRUE; + // Remove the package from the cache. hr = CacheRemovePackage(pCache, TRUE, pPackage->sczId, pPackage->sczCacheId); ExitOnFailure(hr, "Failed to remove from cache package: %ls", pPackage->sczId); diff --git a/src/burn/engine/engine.cpp b/src/burn/engine/engine.cpp index d432f732..8423da41 100644 --- a/src/burn/engine/engine.cpp +++ b/src/burn/engine/engine.cpp @@ -16,11 +16,6 @@ static HRESULT InitializeEngineState( static void UninitializeEngineState( __in BURN_ENGINE_STATE* pEngineState ); -#if 0 -static HRESULT RunUntrusted( - __in BURN_ENGINE_STATE* pEngineState - ); -#endif static HRESULT RunNormal( __in HINSTANCE hInstance, __in BURN_ENGINE_STATE* pEngineState @@ -812,7 +807,7 @@ static HRESULT ProcessMessage( break; case WM_BURN_PLAN: - hr = CorePlan(pEngineState, pAction->plan.action); + hr = CorePlan(pEngineState, pAction->plan.action, pAction->plan.plannedScope); break; case WM_BURN_ELEVATE: diff --git a/src/burn/engine/engine.mc b/src/burn/engine/engine.mc index 776f7832..8e2f1a2e 100644 --- a/src/burn/engine/engine.mc +++ b/src/burn/engine/engine.mc @@ -271,7 +271,7 @@ MessageId=101 Severity=Success SymbolicName=MSG_DETECTED_PACKAGE Language=English -Detected package: %1!ls!, state: %2!hs!, cached: %3!hs!, install registration state: %4!hs!, cache registration state: %5!hs! +Detected package: %1!ls!, state: %2!hs!, authored scope: %6!hs!, cached: %3!hs!, install registration state: %4!hs!, cache registration state: %5!hs! . MessageId=102 @@ -404,14 +404,21 @@ MessageId=200 Severity=Success SymbolicName=MSG_PLAN_BEGIN Language=English -Plan begin, %1!u! packages, action: %2!hs! +Plan begin, %1!u! packages, action: %2!hs!, planned scope: %3!hs! +. + +MessageId=226 +Severity=Success +SymbolicName=MSG_PLAN_CONFIGURED_SCOPE +Language=English +Planned configurable scope: %1!hs! . MessageId=201 Severity=Success SymbolicName=MSG_PLANNED_PACKAGE Language=English -Planned package: %1!ls!, state: %2!hs!, default requested: %3!hs!, ba requested: %4!hs!, execute: %5!hs!, rollback: %6!hs!, default cache strategy: %7!hs!, ba requested strategy: %8!hs!, cache: %9!hs!, uncache: %10!hs!, dependency: %11!hs!, expected install registration state: %12!hs!, expected cache registration state: %13!hs! +Planned package: %1!ls!, state: %2!hs!, default requested: %3!hs!, ba requested: %4!hs!, execute: %5!hs!, rollback: %6!hs!, scope: %14!hs!, default cache strategy: %7!hs!, ba requested strategy: %8!hs!, cache: %9!hs!, uncache: %10!hs!, dependency: %11!hs!, expected install registration state: %12!hs!, expected cache registration state: %13!hs! . MessageId=203 @@ -782,7 +789,7 @@ MessageId=328 Severity=Warning SymbolicName=MSG_DEPENDENCY_PACKAGE_DEPENDENT Language=English -Found dependent: %1!ls!, name: %2!ls! + Found dependent: %1!ls!, name: %2!ls! . MessageId=329 @@ -1288,3 +1295,17 @@ SymbolicName=MSG_DEPENDENCY_PACKAGE_DEPENDENTS_OVERRIDDEN Language=English BA requested to uninstall package: %1!ls!, despite dependents: . +MessageId=702 +Severity=Warning +SymbolicName=MSG_SCOPE_IGNORED_BA_SCOPE +Language=English +Scope command-line switch ignored because the bootstrapper application already specified a scope. +. + +MessageId=703 +Severity=Warning +SymbolicName=MSG_SCOPE_IGNORED_UNCONFIGURABLE +Language=English +Scope command-line switch ignored because the bundle doesn't have any packages with configurable scope. +. + diff --git a/src/burn/engine/engine.vcxproj b/src/burn/engine/engine.vcxproj index 98556ea6..5ab9f1ce 100644 --- a/src/burn/engine/engine.vcxproj +++ b/src/burn/engine/engine.vcxproj @@ -1,6 +1,5 @@ - @@ -28,7 +27,6 @@ ARM64 - {8119537D-E1D9-6591-D51A-49768A2F9C37} StaticLibrary @@ -37,20 +35,15 @@ Native component of WixToolset.Burn ClCompile - - ..\..\api\burn\inc;$(BurnGeneratedHeaderDirectory);$(ProjectAdditionalIncludeDirectories) - - - @@ -97,7 +90,6 @@ - @@ -147,7 +139,6 @@ - Compiling message file... @@ -157,7 +148,6 @@ rc.exe -fo "$(OutDir)engine.res" "$(IntDir)engine.messages.rc" $(IntDir)engine.messages.h;$(IntDir)engine.messages.rc - $(SomeVerInfoMajor) @@ -172,11 +162,12 @@ rc.exe -fo "$(OutDir)engine.res" "$(IntDir)engine.messages.rc" - - + + + - + \ No newline at end of file diff --git a/src/burn/engine/externalengine.cpp b/src/burn/engine/externalengine.cpp index 352d184c..d4814dc1 100644 --- a/src/burn/engine/externalengine.cpp +++ b/src/burn/engine/externalengine.cpp @@ -633,8 +633,9 @@ LExit: HRESULT ExternalEnginePlan( __in BAENGINE_CONTEXT* pEngineContext, - __in const BOOTSTRAPPER_ACTION action - ) + __in const BOOTSTRAPPER_ACTION action, + __in const BOOTSTRAPPER_SCOPE plannedScope +) { HRESULT hr = S_OK; BAENGINE_ACTION* pAction = NULL; @@ -649,6 +650,7 @@ HRESULT ExternalEnginePlan( pAction->dwMessage = WM_BURN_PLAN; pAction->plan.action = action; + pAction->plan.plannedScope = plannedScope; hr = EnqueueAction(pEngineContext, &pAction); ExitOnFailure(hr, "Failed to enqueue plan action."); diff --git a/src/burn/engine/externalengine.h b/src/burn/engine/externalengine.h index 9b95e645..1053d0c0 100644 --- a/src/burn/engine/externalengine.h +++ b/src/burn/engine/externalengine.h @@ -146,8 +146,9 @@ HRESULT ExternalEngineDetect( HRESULT ExternalEnginePlan( __in BAENGINE_CONTEXT* pEngineContext, - __in const BOOTSTRAPPER_ACTION action - ); + __in const BOOTSTRAPPER_ACTION action, + __in const BOOTSTRAPPER_SCOPE plannedScope +); HRESULT ExternalEngineElevate( __in BAENGINE_CONTEXT* pEngineContext, diff --git a/src/burn/engine/logging.cpp b/src/burn/engine/logging.cpp index 52123499..47f52d27 100644 --- a/src/burn/engine/logging.cpp +++ b/src/burn/engine/logging.cpp @@ -968,6 +968,42 @@ extern "C" LPCSTR LoggingInstallScopeToString( return fPerMachine ? "PerMachine" : "PerUser"; } +extern "C" LPCSTR LoggingPackageScopeToString( + __in BOOTSTRAPPER_PACKAGE_SCOPE scope + ) +{ + switch (scope) + { + case BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE: + return "PerMachine"; + case BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE_OR_PER_USER: + return "PerMachineOrUser"; + case BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER_OR_PER_MACHINE: + return "PerUserOrMachine"; + case BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER: + return "PerUser"; + default: + return "Invalid"; + } +} + +extern "C" LPCSTR LoggingBundleScopeToString( + __in BOOTSTRAPPER_SCOPE scope + ) +{ + switch (scope) + { + case BOOTSTRAPPER_SCOPE_DEFAULT: + return "Default"; + case BOOTSTRAPPER_SCOPE_PER_MACHINE: + return "PerMachine"; + case BOOTSTRAPPER_SCOPE_PER_USER: + return "PerUser"; + default: + return "Invalid"; + } +} + // internal function declarations diff --git a/src/burn/engine/logging.h b/src/burn/engine/logging.h index b28a53d4..76103732 100644 --- a/src/burn/engine/logging.h +++ b/src/burn/engine/logging.h @@ -202,6 +202,13 @@ LPCSTR LoggingInstallScopeToString( __in BOOL fPerMachine ); +LPCSTR LoggingPackageScopeToString( + __in BOOTSTRAPPER_PACKAGE_SCOPE scope + ); + +LPCSTR LoggingBundleScopeToString( + __in BOOTSTRAPPER_SCOPE scope + ); #if defined(__cplusplus) } diff --git a/src/burn/engine/msiengine.cpp b/src/burn/engine/msiengine.cpp index a1379054..11bb8a0e 100644 --- a/src/burn/engine/msiengine.cpp +++ b/src/burn/engine/msiengine.cpp @@ -454,7 +454,18 @@ extern "C" HRESULT MsiEngineDetectPackage( // detect self by product code // TODO: what to do about MSIINSTALLCONTEXT_USERMANAGED? - hr = WiuGetProductInfoEx(pPackage->Msi.sczProductCode, NULL, pPackage->fPerMachine ? MSIINSTALLCONTEXT_MACHINE : MSIINSTALLCONTEXT_USERUNMANAGED, INSTALLPROPERTY_VERSIONSTRING, &sczInstalledVersion); + if (BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE_OR_PER_USER == pPackage->scope || BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER_OR_PER_MACHINE == pPackage->scope) + { + hr = WiuGetProductInfoEx(pPackage->Msi.sczProductCode, NULL, MSIINSTALLCONTEXT_MACHINE, INSTALLPROPERTY_VERSIONSTRING, &sczInstalledVersion); + if (FAILED(hr)) + { + hr = WiuGetProductInfoEx(pPackage->Msi.sczProductCode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, INSTALLPROPERTY_VERSIONSTRING, &sczInstalledVersion); + } + } + else + { + hr = WiuGetProductInfoEx(pPackage->Msi.sczProductCode, NULL, pPackage->scope == BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE ? MSIINSTALLCONTEXT_MACHINE : MSIINSTALLCONTEXT_USERUNMANAGED, INSTALLPROPERTY_VERSIONSTRING, &sczInstalledVersion); + } if (SUCCEEDED(hr)) { fDetectFeatures = TRUE; @@ -777,7 +788,18 @@ extern "C" HRESULT MsiEngineDetectCompatiblePackage( ExitFunction(); } - hr = WiuGetProductInfoEx(wzCompatibleProductCode, NULL, pPackage->fPerMachine ? MSIINSTALLCONTEXT_MACHINE : MSIINSTALLCONTEXT_USERUNMANAGED, INSTALLPROPERTY_VERSIONSTRING, &sczVersion); + if (BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE_OR_PER_USER == pPackage->scope || BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER_OR_PER_MACHINE == pPackage->scope) + { + hr = WiuGetProductInfoEx(wzCompatibleProductCode, NULL, MSIINSTALLCONTEXT_MACHINE, INSTALLPROPERTY_VERSIONSTRING, &sczVersion); + if (FAILED(hr)) + { + hr = WiuGetProductInfoEx(wzCompatibleProductCode, NULL, MSIINSTALLCONTEXT_USERUNMANAGED, INSTALLPROPERTY_VERSIONSTRING, &sczVersion); + } + } + else + { + hr = WiuGetProductInfoEx(wzCompatibleProductCode, NULL, pPackage->scope == BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE ? MSIINSTALLCONTEXT_MACHINE : MSIINSTALLCONTEXT_USERUNMANAGED, INSTALLPROPERTY_VERSIONSTRING, &sczVersion); + } if (HRESULT_FROM_WIN32(ERROR_UNKNOWN_PRODUCT) == hr || HRESULT_FROM_WIN32(ERROR_UNKNOWN_PROPERTY) == hr || E_INVALIDARG == hr) { ExitFunction1(hr = S_OK); @@ -1336,10 +1358,10 @@ extern "C" HRESULT MsiEngineExecutePackage( hr = ConcatPatchProperty(pCache, pPackage, fRollback, &sczObfuscatedProperties); ExitOnFailure(hr, "Failed to add patch properties to obfuscated argument string."); - hr = MsiEngineConcatBurnProperties(pExecuteAction->msiPackage.action, pExecuteAction->msiPackage.actionMsiProperty, pExecuteAction->msiPackage.fileVersioning, TRUE, 0 != pPackage->Msi.cFeatures, &sczProperties); + hr = MsiEngineConcatBurnProperties(pExecuteAction->msiPackage.action, pExecuteAction->msiPackage.actionMsiProperty, pExecuteAction->msiPackage.fileVersioning, TRUE, 0 != pPackage->Msi.cFeatures, pExecuteAction->msiPackage.pPackage->scope, pExecuteAction->msiPackage.pPackage->fPerMachine, &sczProperties); ExitOnFailure(hr, "Failed to add action property to argument string."); - hr = MsiEngineConcatBurnProperties(pExecuteAction->msiPackage.action, pExecuteAction->msiPackage.actionMsiProperty, pExecuteAction->msiPackage.fileVersioning, TRUE, 0 != pPackage->Msi.cFeatures, &sczObfuscatedProperties); + hr = MsiEngineConcatBurnProperties(pExecuteAction->msiPackage.action, pExecuteAction->msiPackage.actionMsiProperty, pExecuteAction->msiPackage.fileVersioning, TRUE, 0 != pPackage->Msi.cFeatures, pPackage->scope, pPackage->fPerMachine, &sczObfuscatedProperties); ExitOnFailure(hr, "Failed to add action property to obfuscated argument string."); LogId(REPORT_STANDARD, MSG_APPLYING_PACKAGE, LoggingRollbackOrExecute(fRollback), pPackage->sczId, LoggingActionStateToString(pExecuteAction->msiPackage.action), sczMsiPath, sczObfuscatedProperties ? sczObfuscatedProperties : L""); @@ -1449,7 +1471,7 @@ extern "C" HRESULT MsiEngineUninstallCompatiblePackage( ExitOnFailure(hr, "Failed to enable logging for compatible package: %ls to: %ls", pCompatibleEntry->sczId, pExecuteAction->uninstallMsiCompatiblePackage.sczLogPath); } - hr = MsiEngineConcatBurnProperties(action, burnMsiProperty, fileVersioning, TRUE, FALSE, &sczProperties); + hr = MsiEngineConcatBurnProperties(action, burnMsiProperty, fileVersioning, TRUE, FALSE, pParentPackage->scope, pParentPackage->fPerMachine, &sczProperties); ExitOnFailure(hr, "Failed to add action property to argument string."); LogId(REPORT_STANDARD, MSG_APPLYING_ORPHAN_COMPATIBLE_PACKAGE, LoggingRollbackOrExecute(fRollback), pCompatibleEntry->sczId, pParentPackage->sczId, LoggingActionStateToString(action), sczProperties ? sczProperties : L""); @@ -1491,6 +1513,8 @@ extern "C" HRESULT MsiEngineConcatBurnProperties( __in BOOTSTRAPPER_MSI_FILE_VERSIONING fileVersioning, __in BOOL fMsiPackage, __in BOOL fFeatureSelectionEnabled, + __in BOOTSTRAPPER_PACKAGE_SCOPE scope, + __in BOOL fPlannedPerMachineScope, __deref_out_z LPWSTR* psczProperties ) { @@ -1534,6 +1558,7 @@ extern "C" HRESULT MsiEngineConcatBurnProperties( break; } + // Append properties used by WixUI (and usable otherwise) to adjust internal UI behavior. switch (actionMsiProperty) { case BURN_MSI_PROPERTY_INSTALL: @@ -1581,6 +1606,20 @@ extern "C" HRESULT MsiEngineConcatBurnProperties( ExitOnFailure(hr, "Failed to add reinstall mode."); } + if (BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER_OR_PER_MACHINE == scope || BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE_OR_PER_USER == scope) + { + if (fPlannedPerMachineScope) + { + hr = StrAllocConcatFormattedSecure(psczProperties, L" MSIINSTALLPERUSER=\"\""); + ExitOnFailure(hr, "Failed to add per-machine scope properties."); + } + else + { + hr = StrAllocConcatFormattedSecure(psczProperties, L" MSIINSTALLPERUSER=\"1\""); + ExitOnFailure(hr, "Failed to add per-user scope properties."); + } + } + hr = StrAllocConcatSecure(psczProperties, L" REBOOT=ReallySuppress", 0); ExitOnFailure(hr, "Failed to add reboot suppression property."); diff --git a/src/burn/engine/msiengine.h b/src/burn/engine/msiengine.h index 862c4f6a..d4660dc8 100644 --- a/src/burn/engine/msiengine.h +++ b/src/burn/engine/msiengine.h @@ -93,6 +93,8 @@ HRESULT MsiEngineConcatBurnProperties( __in BOOTSTRAPPER_MSI_FILE_VERSIONING fileVersioning, __in BOOL fMsiPackage, __in BOOL fFeatureSelectionEnabled, + __in BOOTSTRAPPER_PACKAGE_SCOPE scope, + __in BOOL fPlannedPerMachineScope, __deref_out_z LPWSTR* psczProperties ); HRESULT MsiEngineConcatPackageProperties( diff --git a/src/burn/engine/mspengine.cpp b/src/burn/engine/mspengine.cpp index e8ef7fcb..18be3cc6 100644 --- a/src/burn/engine/mspengine.cpp +++ b/src/burn/engine/mspengine.cpp @@ -676,10 +676,10 @@ extern "C" HRESULT MspEngineExecutePackage( } // Always add Burn properties last. - hr = MsiEngineConcatBurnProperties(pExecuteAction->mspTarget.action, pExecuteAction->mspTarget.actionMsiProperty, pExecuteAction->mspTarget.fileVersioning, FALSE, FALSE, &sczProperties); + hr = MsiEngineConcatBurnProperties(pExecuteAction->mspTarget.action, pExecuteAction->mspTarget.actionMsiProperty, pExecuteAction->mspTarget.fileVersioning, FALSE, FALSE, pExecuteAction->mspTarget.pPackage->scope, pExecuteAction->mspTarget.pPackage->fPerMachine, &sczProperties); ExitOnFailure(hr, "Failed to add action property to argument string."); - hr = MsiEngineConcatBurnProperties(pExecuteAction->mspTarget.action, pExecuteAction->mspTarget.actionMsiProperty, pExecuteAction->mspTarget.fileVersioning, FALSE, FALSE, &sczObfuscatedProperties); + hr = MsiEngineConcatBurnProperties(pExecuteAction->mspTarget.action, pExecuteAction->mspTarget.actionMsiProperty, pExecuteAction->mspTarget.fileVersioning, FALSE, FALSE, pExecuteAction->mspTarget.pPackage->scope, pExecuteAction->mspTarget.pPackage->fPerMachine, &sczObfuscatedProperties); ExitOnFailure(hr, "Failed to add action property to obfuscated argument string."); LogId(REPORT_STANDARD, MSG_APPLYING_PATCH_PACKAGE, pExecuteAction->mspTarget.pPackage->sczId, LoggingActionStateToString(pExecuteAction->mspTarget.action), sczPatches, sczObfuscatedProperties, pExecuteAction->mspTarget.sczTargetProductCode); diff --git a/src/burn/engine/package.cpp b/src/burn/engine/package.cpp index 3bf676ba..61b73dc6 100644 --- a/src/burn/engine/package.cpp +++ b/src/burn/engine/package.cpp @@ -154,9 +154,12 @@ extern "C" HRESULT PackagesParseFromXml( hr = XmlGetAttributeUInt64(pixnNode, L"InstallSize", &pPackage->qwInstallSize); ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @InstallSize."); - // @PerMachine - hr = XmlGetYesNoAttribute(pixnNode, L"PerMachine", &pPackage->fPerMachine); - ExitOnRequiredXmlQueryFailure(hr, "Failed to get @PerMachine."); + // @Scope + hr = PackageParseScopeFromXml(pixnNode, &pPackage->scope); + ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Scope."); + + // Shortcut for static per-machine or per-user packages. + pPackage->fPerMachine = BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE == pPackage->scope; // @Permanent hr = XmlGetYesNoAttribute(pixnNode, L"Permanent", &pPackage->fPermanent); @@ -593,6 +596,45 @@ LExit: return hr; } +extern "C" HRESULT PackageParseScopeFromXml( + __in IXMLDOMNode* pixn, + __in BOOTSTRAPPER_PACKAGE_SCOPE* pScope +) +{ + HRESULT hr = S_OK; + LPWSTR scz = NULL; + + hr = XmlGetAttributeEx(pixn, L"Scope", &scz); + ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Scope."); + + if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, scz, -1, L"perMachine", -1)) + { + *pScope = BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE; + } + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, scz, -1, L"perUser", -1)) + { + *pScope = BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER; + } + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, scz, -1, L"perUserOrMachine", -1)) + { + *pScope = BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER_OR_PER_MACHINE; + } + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, scz, -1, L"perMachineOrUser", -1)) + { + *pScope = BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE_OR_PER_USER; + } + else + { + hr = E_UNEXPECTED; + ExitOnRootFailure(hr, "Invalid scope: %ls", scz); + } + +LExit: + ReleaseStr(scz); + + return hr; +} + // internal function declarations diff --git a/src/burn/engine/package.h b/src/burn/engine/package.h index d596d7c0..5397e9cc 100644 --- a/src/burn/engine/package.h +++ b/src/burn/engine/package.h @@ -268,7 +268,8 @@ typedef struct _BURN_PACKAGE LPWSTR sczInstallCondition; LPWSTR sczRepairCondition; - BOOL fPerMachine; + BOOTSTRAPPER_PACKAGE_SCOPE scope; + BOOL fPerMachine; // only valid after Plan (for PUOM/PMOU packages). BOOL fPermanent; BOOL fVital; BOOL fCanAffectRegistration; @@ -483,6 +484,10 @@ HRESULT PackageFindRollbackBoundaryById( __in_z LPCWSTR wzId, __out BURN_ROLLBACK_BOUNDARY** ppRollbackBoundary ); +HRESULT PackageParseScopeFromXml( + __in IXMLDOMNode* pixn, + __in BOOTSTRAPPER_PACKAGE_SCOPE* pScope + ); #if defined(__cplusplus) diff --git a/src/burn/engine/plan.cpp b/src/burn/engine/plan.cpp index edc09033..6c46269b 100644 --- a/src/burn/engine/plan.cpp +++ b/src/burn/engine/plan.cpp @@ -278,7 +278,7 @@ extern "C" void PlanReset( } } - PlanSetVariables(BOOTSTRAPPER_ACTION_UNKNOWN, pVariables); + PlanSetVariables(BOOTSTRAPPER_ACTION_UNKNOWN, BOOTSTRAPPER_PACKAGE_SCOPE_INVALID, BOOTSTRAPPER_SCOPE_DEFAULT, pVariables); } extern "C" void PlanUninitializeExecuteAction( @@ -332,6 +332,8 @@ extern "C" void PlanUninitializeExecuteAction( extern "C" HRESULT PlanSetVariables( __in BOOTSTRAPPER_ACTION action, + __in BOOTSTRAPPER_PACKAGE_SCOPE authoredScope, + __in BOOTSTRAPPER_SCOPE plannedScope, __in BURN_VARIABLES* pVariables ) { @@ -340,6 +342,12 @@ extern "C" HRESULT PlanSetVariables( hr = VariableSetNumeric(pVariables, BURN_BUNDLE_ACTION, action, TRUE); ExitOnFailure(hr, "Failed to set the bundle action built-in variable."); + hr = VariableSetNumeric(pVariables, BURN_BUNDLE_SCOPE, authoredScope, TRUE); + ExitOnFailure(hr, "Failed to set the bundle authored scope built-in variable."); + + hr = VariableSetNumeric(pVariables, BURN_BUNDLE_PLANNED_SCOPE, plannedScope, TRUE); + ExitOnFailure(hr, "Failed to set the bundle planned scope built-in variable."); + LExit: return hr; } @@ -812,6 +820,66 @@ LExit: return hr; } +extern "C" HRESULT PlanPackagesAndBundleScope( + __in BURN_PACKAGE* rgPackages, + __in DWORD cPackages, + __in BOOTSTRAPPER_SCOPE scope, + __in BOOTSTRAPPER_PACKAGE_SCOPE authoredScope, + __in BOOTSTRAPPER_SCOPE commandLineScope, + __out BOOTSTRAPPER_SCOPE* pResultingScope, + __out BOOL* pfRegistrationPerMachine +) +{ + HRESULT hr = S_OK; + BOOL fRegistrationPerMachine = TRUE; + + // If a scope was specified on the command line and the BA didn't set a scope, + // let the command-line switch override. + if (BOOTSTRAPPER_SCOPE_DEFAULT != commandLineScope) + { + if (BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE_OR_PER_USER == authoredScope || BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER_OR_PER_MACHINE == authoredScope) + { + if (BOOTSTRAPPER_SCOPE_DEFAULT == scope) + { + scope = commandLineScope; + } + else + { + LogId(REPORT_STANDARD, MSG_SCOPE_IGNORED_BA_SCOPE); + } + } + else + { + LogId(REPORT_STANDARD, MSG_SCOPE_IGNORED_UNCONFIGURABLE); + } + } + + for (DWORD i = 0; i < cPackages; ++i) + { + BURN_PACKAGE* pPackage = rgPackages + i; + + pPackage->fPerMachine = + (BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE == pPackage->scope) + || (BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE_OR_PER_USER == pPackage->scope && + (BOOTSTRAPPER_SCOPE_DEFAULT == scope || BOOTSTRAPPER_SCOPE_PER_MACHINE == scope)) + || (BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER_OR_PER_MACHINE == pPackage->scope && + BOOTSTRAPPER_SCOPE_PER_MACHINE == scope); + + // Any per-user package makes the registration per-user as well. + if (!pPackage->fPerMachine) + { + fRegistrationPerMachine = FALSE; + } + } + + *pResultingScope = scope; + *pfRegistrationPerMachine = fRegistrationPerMachine; + +//LExit: + return hr; +} + + static HRESULT PlanPackagesHelper( __in BURN_PACKAGE* rgPackages, __in DWORD cPackages, @@ -2971,7 +3039,7 @@ static void ExecuteActionLog( break; case BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE: - LogStringLine(PlanDumpLevel, "%ls action[%u]: MSI_PACKAGE package id: %ls, action: %hs, action msi property: %ls, ui level: %u, disable externaluihandler: %hs, file versioning: %hs, log path: %ls, logging attrib: %u", wzBase, iAction, pAction->msiPackage.pPackage->sczId, LoggingActionStateToString(pAction->msiPackage.action), LoggingBurnMsiPropertyToString(pAction->msiPackage.actionMsiProperty), pAction->msiPackage.uiLevel, LoggingBoolToString(pAction->msiPackage.fDisableExternalUiHandler), LoggingMsiFileVersioningToString(pAction->msiPackage.fileVersioning), pAction->msiPackage.sczLogPath, pAction->msiPackage.dwLoggingAttributes); + LogStringLine(PlanDumpLevel, "%ls action[%u]: MSI_PACKAGE package id: %ls, scope: %hs, action: %hs, action msi property: %ls, ui level: %u, disable externaluihandler: %hs, file versioning: %hs, log path: %ls, logging attrib: %u", wzBase, iAction, pAction->msiPackage.pPackage->sczId, LoggingPackageScopeToString(pAction->msiPackage.pPackage->scope), LoggingActionStateToString(pAction->msiPackage.action), LoggingBurnMsiPropertyToString(pAction->msiPackage.actionMsiProperty), pAction->msiPackage.uiLevel, LoggingBoolToString(pAction->msiPackage.fDisableExternalUiHandler), LoggingMsiFileVersioningToString(pAction->msiPackage.fileVersioning), pAction->msiPackage.sczLogPath, pAction->msiPackage.dwLoggingAttributes); for (DWORD j = 0; j < pAction->msiPackage.pPackage->Msi.cSlipstreamMspPackages; ++j) { const BURN_SLIPSTREAM_MSP* pSlipstreamMsp = pAction->msiPackage.pPackage->Msi.rgSlipstreamMsps + j; @@ -3083,6 +3151,7 @@ extern "C" void PlanDump( LogStringLine(PlanDumpLevel, " bundle code: %ls", pPlan->wzBundleCode); LogStringLine(PlanDumpLevel, " bundle provider key: %ls", pPlan->wzBundleProviderKey); LogStringLine(PlanDumpLevel, " use-forward-compatible: %hs", LoggingTrueFalseToString(pPlan->fEnabledForwardCompatibleBundle)); + LogStringLine(PlanDumpLevel, " planned scope: %hs", LoggingBundleScopeToString(pPlan->plannedScope)); LogStringLine(PlanDumpLevel, " per-machine: %hs", LoggingTrueFalseToString(pPlan->fPerMachine)); LogStringLine(PlanDumpLevel, " can affect machine state: %hs", LoggingTrueFalseToString(pPlan->fCanAffectMachineState)); LogStringLine(PlanDumpLevel, " disable-rollback: %hs", LoggingTrueFalseToString(pPlan->fDisableRollback)); diff --git a/src/burn/engine/plan.h b/src/burn/engine/plan.h index 03b1423d..a20d7c76 100644 --- a/src/burn/engine/plan.h +++ b/src/burn/engine/plan.h @@ -249,6 +249,7 @@ typedef struct _BURN_CLEAN_ACTION typedef struct _BURN_PLAN { BOOTSTRAPPER_ACTION action; + BOOTSTRAPPER_SCOPE plannedScope; BURN_CACHE* pCache; BOOTSTRAPPER_COMMAND* pCommand; BURN_ENGINE_COMMAND* pInternalCommand; @@ -328,6 +329,8 @@ void PlanUninitializeExecuteAction( ); HRESULT PlanSetVariables( __in BOOTSTRAPPER_ACTION action, + __in BOOTSTRAPPER_PACKAGE_SCOPE authoredScope, + __in BOOTSTRAPPER_SCOPE plannedScope, __in BURN_VARIABLES* pVariables ); HRESULT PlanDefaultRelatedBundlePlanType( @@ -479,6 +482,15 @@ HRESULT PlanSetResumeCommand( void PlanDump( __in BURN_PLAN* pPlan ); +HRESULT PlanPackagesAndBundleScope( + __in BURN_PACKAGE* rgPackages, + __in DWORD cPackages, + __in BOOTSTRAPPER_SCOPE scope, + __in BOOTSTRAPPER_PACKAGE_SCOPE authoredScope, + __in BOOTSTRAPPER_SCOPE commandLineScope, + __out BOOTSTRAPPER_SCOPE* pResultingScope, + __out BOOL* pfPerMachine +); #if defined(__cplusplus) } diff --git a/src/burn/engine/registration.cpp b/src/burn/engine/registration.cpp index 9733e92c..fa1b024a 100644 --- a/src/burn/engine/registration.cpp +++ b/src/burn/engine/registration.cpp @@ -39,10 +39,6 @@ static HRESULT ParseSoftwareTagsFromXml( __out BURN_SOFTWARE_TAG** prgSoftwareTags, __out DWORD* pcSoftwareTags ); -static HRESULT SetPaths( - __in BURN_REGISTRATION* pRegistration, - __in BURN_CACHE* pCache - ); static HRESULT GetBundleManufacturer( __in BURN_REGISTRATION* pRegistration, __in BURN_VARIABLES* pVariables, @@ -108,6 +104,15 @@ static HRESULT UpdateEstimatedSize( ); static BOOL IsWuRebootPending(); static BOOL IsRegistryRebootPending(); +static HRESULT RegistrationDetectResumeTypeByHive( + __in HKEY hkRegistrationRoot, + __in BURN_REGISTRATION* pRegistration, + __out BOOTSTRAPPER_RESUME_TYPE* pResumeType +); +static HRESULT DetectInstalled( + __in BURN_REGISTRATION* pRegistration, + __in HKEY hkRoot +); // function definitions @@ -163,9 +168,9 @@ extern "C" HRESULT RegistrationParseFromXml( hr = XmlGetAttributeEx(pixnRegistrationNode, L"ExecutableName", &pRegistration->sczExecutableName); ExitOnRequiredXmlQueryFailure(hr, "Failed to get @ExecutableName."); - // @PerMachine - hr = XmlGetYesNoAttribute(pixnRegistrationNode, L"PerMachine", &pRegistration->fPerMachine); - ExitOnRequiredXmlQueryFailure(hr, "Failed to get @PerMachine."); + // @Scope + hr = PackageParseScopeFromXml(pixnRegistrationNode, &pRegistration->scope); + ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Scope."); // select ARP node hr = XmlSelectSingleNode(pixnRegistrationNode, L"Arp", &pixnArpNode); @@ -285,8 +290,18 @@ extern "C" HRESULT RegistrationParseFromXml( ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Classification."); } - hr = SetPaths(pRegistration, pCache); - ExitOnFailure(hr, "Failed to set registration paths."); + // Handle the easy case of build-time bundle scope early. + if (BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE == pRegistration->scope || BOOTSTRAPPER_PACKAGE_SCOPE_PER_USER == pRegistration->scope) + { + pRegistration->fPerMachine = BOOTSTRAPPER_PACKAGE_SCOPE_PER_MACHINE == pRegistration->scope; + + hr = RegistrationSetPaths(pRegistration, pCache); + ExitOnFailure(hr, "Failed to set registration paths for fixed scope."); + } + else + { + pRegistration->hkRoot = reinterpret_cast(0ull); + } LExit: ReleaseObject(pixnRegistrationNode); @@ -452,31 +467,28 @@ LExit: extern "C" HRESULT RegistrationDetectInstalled( __in BURN_REGISTRATION* pRegistration - ) +) { HRESULT hr = S_OK; - HKEY hkRegistration = NULL; - DWORD dwInstalled = 0; - pRegistration->fCached = FileExistsEx(pRegistration->sczCacheExecutablePath, NULL); - pRegistration->detectedRegistrationType = BOOTSTRAPPER_REGISTRATION_TYPE_NONE; - - // open registration key - hr = RegOpen(pRegistration->hkRoot, pRegistration->sczRegistrationKey, KEY_QUERY_VALUE, &hkRegistration); - if (SUCCEEDED(hr)) + if (pRegistration->hkRoot) { - hr = RegReadNumber(hkRegistration, REGISTRY_BUNDLE_INSTALLED, &dwInstalled); - - pRegistration->detectedRegistrationType = (1 == dwInstalled) ? BOOTSTRAPPER_REGISTRATION_TYPE_FULL : BOOTSTRAPPER_REGISTRATION_TYPE_INPROGRESS; + hr = DetectInstalled(pRegistration, pRegistration->hkRoot); } - - // Not finding the key or value is okay. - if (E_FILENOTFOUND == hr || E_PATHNOTFOUND == hr) + else { - hr = S_OK; + // For PUOM/PMOU bundles, check per-machine then fall back to per-user. + hr = DetectInstalled(pRegistration, HKEY_LOCAL_MACHINE); + ExitOnFailure(hr, "Failed to detect HKEY_LOCAL_MACHINE bundle registration install state."); + + if (BOOTSTRAPPER_REGISTRATION_TYPE_NONE == pRegistration->detectedRegistrationType) + { + hr = DetectInstalled(pRegistration, HKEY_CURRENT_USER); + ExitOnFailure(hr, "Failed to detect HKEY_CURRENT_USER bundle registration install state."); + } } - ReleaseRegKey(hkRegistration); +LExit: return hr; } @@ -488,63 +500,26 @@ extern "C" HRESULT RegistrationDetectInstalled( extern "C" HRESULT RegistrationDetectResumeType( __in BURN_REGISTRATION* pRegistration, __out BOOTSTRAPPER_RESUME_TYPE* pResumeType - ) +) { HRESULT hr = S_OK; - HKEY hkRegistration = NULL; - BOOL fExists = FALSE; - DWORD dwResume = 0; - // open registration key - hr = RegOpen(pRegistration->hkRoot, pRegistration->sczRegistrationKey, KEY_QUERY_VALUE, &hkRegistration); - ExitOnPathFailure(hr, fExists, "Failed to open registration key."); - - if (!fExists) + if (pRegistration->hkRoot) { - *pResumeType = BOOTSTRAPPER_RESUME_TYPE_NONE; - ExitFunction(); + hr = RegistrationDetectResumeTypeByHive(pRegistration->hkRoot, pRegistration, pResumeType); } - - // read Resume value - hr = RegReadNumber(hkRegistration, L"Resume", &dwResume); - ExitOnPathFailure(hr, fExists, "Failed to read Resume value."); - - if (!fExists) - { - *pResumeType = BOOTSTRAPPER_RESUME_TYPE_INVALID; - ExitFunction(); - } - - switch (dwResume) + else { - case BURN_RESUME_MODE_ACTIVE: - // a previous run was interrupted - *pResumeType = BOOTSTRAPPER_RESUME_TYPE_INTERRUPTED; - break; - - case BURN_RESUME_MODE_SUSPEND: - *pResumeType = BOOTSTRAPPER_RESUME_TYPE_SUSPEND; - break; - - case BURN_RESUME_MODE_ARP: - *pResumeType = BOOTSTRAPPER_RESUME_TYPE_ARP; - break; - - case BURN_RESUME_MODE_REBOOT_PENDING: - // The volatile pending registry doesn't exist (checked above) which means - // the system was successfully restarted. - *pResumeType = BOOTSTRAPPER_RESUME_TYPE_REBOOT; - break; + hr = RegistrationDetectResumeTypeByHive(HKEY_LOCAL_MACHINE, pRegistration, pResumeType); - default: - // the value stored in the registry is not valid - *pResumeType = BOOTSTRAPPER_RESUME_TYPE_INVALID; - break; + if (BOOTSTRAPPER_RESUME_TYPE_NONE == *pResumeType) + { + hr = RegistrationDetectResumeTypeByHive(HKEY_CURRENT_USER, pRegistration, pResumeType); + } } + ExitOnFailure(hr, "Failed to find bundle registration: %ls", pRegistration->sczRegistrationKey); LExit: - ReleaseRegKey(hkRegistration); - return hr; } @@ -889,7 +864,7 @@ extern "C" HRESULT RegistrationSessionEnd( // Open registration key. hr = RegOpen(pRegistration->hkRoot, pRegistration->sczRegistrationKey, KEY_WRITE, &hkRegistration); - ExitOnFailure(hr, "Failed to open registration key."); + ExitOnFailure(hr, "Failed to open registration key for ending session."); // update display name hr = UpdateBundleNameRegistration(pRegistration, pVariables, hkRegistration, BOOTSTRAPPER_REGISTRATION_TYPE_INPROGRESS == registrationType); @@ -1068,6 +1043,39 @@ extern "C" HRESULT RegistrationGetResumeCommandLine( return hr; } +extern "C" HRESULT RegistrationSetPaths( + __in BURN_REGISTRATION* pRegistration, + __in BURN_CACHE* pCache + ) +{ + HRESULT hr = S_OK; + LPWSTR sczCacheDirectory = NULL; + + // save registration key root + pRegistration->hkRoot = pRegistration->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + + // build uninstall registry key path + hr = StrAllocFormatted(&pRegistration->sczRegistrationKey, L"%ls\\%ls", BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY, pRegistration->sczCode); + ExitOnFailure(hr, "Failed to build uninstall registry key path."); + + // build cache directory + hr = CacheGetCompletedPath(pCache, pRegistration->fPerMachine, pRegistration->sczCode, &sczCacheDirectory); + ExitOnFailure(hr, "Failed to build cache directory."); + + // build cached executable path + hr = PathConcatRelativeToFullyQualifiedBase(sczCacheDirectory, pRegistration->sczExecutableName, &pRegistration->sczCacheExecutablePath); + ExitOnFailure(hr, "Failed to build cached executable path."); + + // build state file path + hr = StrAllocFormatted(&pRegistration->sczStateFile, L"%ls\\state.rsm", sczCacheDirectory); + ExitOnFailure(hr, "Failed to build state file path."); + +LExit: + ReleaseStr(sczCacheDirectory); + + return hr; +} + // internal helper functions @@ -1141,38 +1149,6 @@ LExit: return hr; } -static HRESULT SetPaths( - __in BURN_REGISTRATION* pRegistration, - __in BURN_CACHE* pCache - ) -{ - HRESULT hr = S_OK; - LPWSTR sczCacheDirectory = NULL; - - // save registration key root - pRegistration->hkRoot = pRegistration->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; - - // build uninstall registry key path - hr = StrAllocFormatted(&pRegistration->sczRegistrationKey, L"%ls\\%ls", BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY, pRegistration->sczCode); - ExitOnFailure(hr, "Failed to build uninstall registry key path."); - - // build cache directory - hr = CacheGetCompletedPath(pCache, pRegistration->fPerMachine, pRegistration->sczCode, &sczCacheDirectory); - ExitOnFailure(hr, "Failed to build cache directory."); - - // build cached executable path - hr = PathConcatRelativeToFullyQualifiedBase(sczCacheDirectory, pRegistration->sczExecutableName, &pRegistration->sczCacheExecutablePath); - ExitOnFailure(hr, "Failed to build cached executable path."); - - // build state file path - hr = StrAllocFormatted(&pRegistration->sczStateFile, L"%ls\\state.rsm", sczCacheDirectory); - ExitOnFailure(hr, "Failed to build state file path."); - -LExit: - ReleaseStr(sczCacheDirectory); - return hr; -} - static HRESULT GetBundleManufacturer( __in BURN_REGISTRATION* pRegistration, __in BURN_VARIABLES* pVariables, @@ -1703,3 +1679,102 @@ static BOOL IsRegistryRebootPending() return fRebootPending; } + +static HRESULT RegistrationDetectResumeTypeByHive( + __in HKEY hkRegistrationRoot, + __in BURN_REGISTRATION* pRegistration, + __out BOOTSTRAPPER_RESUME_TYPE* pResumeType +) +{ + HRESULT hr = S_OK; + HKEY hkRegistration = NULL; + BOOL fExists = FALSE; + DWORD dwResume = 0; + + *pResumeType = BOOTSTRAPPER_RESUME_TYPE_NONE; + + // open registration key + hr = RegOpen(hkRegistrationRoot, pRegistration->sczRegistrationKey, KEY_QUERY_VALUE, &hkRegistration); + ExitOnPathFailure(hr, fExists, "Failed to open registration key."); + + if (!fExists) + { + *pResumeType = BOOTSTRAPPER_RESUME_TYPE_NONE; + ExitFunction(); + } + + // read Resume value + hr = RegReadNumber(hkRegistration, L"Resume", &dwResume); + ExitOnPathFailure(hr, fExists, "Failed to read Resume value."); + + if (!fExists) + { + *pResumeType = BOOTSTRAPPER_RESUME_TYPE_INVALID; + ExitFunction(); + } + + switch (dwResume) + { + case BURN_RESUME_MODE_ACTIVE: + // a previous run was interrupted + *pResumeType = BOOTSTRAPPER_RESUME_TYPE_INTERRUPTED; + break; + + case BURN_RESUME_MODE_SUSPEND: + *pResumeType = BOOTSTRAPPER_RESUME_TYPE_SUSPEND; + break; + + case BURN_RESUME_MODE_ARP: + *pResumeType = BOOTSTRAPPER_RESUME_TYPE_ARP; + break; + + case BURN_RESUME_MODE_REBOOT_PENDING: + // The volatile pending registry doesn't exist (checked above) which means + // the system was successfully restarted. + *pResumeType = BOOTSTRAPPER_RESUME_TYPE_REBOOT; + break; + + default: + // the value stored in the registry is not valid + *pResumeType = BOOTSTRAPPER_RESUME_TYPE_INVALID; + break; + } + +LExit: + ReleaseRegKey(hkRegistration); + + return hr; +} + +static HRESULT DetectInstalled( + __in BURN_REGISTRATION* pRegistration, + __in HKEY hkRoot +) +{ + HRESULT hr = S_OK; + HKEY hkRegistration = NULL; + DWORD dwInstalled = 0; + + pRegistration->fCached = pRegistration->sczCacheExecutablePath && FileExistsEx(pRegistration->sczCacheExecutablePath, NULL); + pRegistration->detectedRegistrationType = BOOTSTRAPPER_REGISTRATION_TYPE_NONE; + + // open registration key + hr = RegOpen(hkRoot, pRegistration->sczRegistrationKey, KEY_QUERY_VALUE, &hkRegistration); + if (SUCCEEDED(hr)) + { + hr = RegReadNumber(hkRegistration, REGISTRY_BUNDLE_INSTALLED, &dwInstalled); + + pRegistration->detectedRegistrationType = (1 == dwInstalled) ? BOOTSTRAPPER_REGISTRATION_TYPE_FULL : BOOTSTRAPPER_REGISTRATION_TYPE_INPROGRESS; + } + + // Not finding the key or value is okay. + if (E_FILENOTFOUND == hr || E_PATHNOTFOUND == hr) + { + hr = S_OK; + } + + ReleaseRegKey(hkRegistration); + + return hr; +} + diff --git a/src/burn/engine/registration.h b/src/burn/engine/registration.h index 326f21c6..e83b75b6 100644 --- a/src/burn/engine/registration.h +++ b/src/burn/engine/registration.h @@ -94,11 +94,12 @@ typedef struct _BURN_SOFTWARE_TAGS typedef struct _BURN_REGISTRATION { - BOOL fPerMachine; + BOOL fPerMachine; // For PUOM/PMOU bundles, only valid after planning. BOOL fForceSystemComponent; BOOL fDisableResume; BOOL fCached; BOOTSTRAPPER_REGISTRATION_TYPE detectedRegistrationType; + BOOTSTRAPPER_PACKAGE_SCOPE scope; LPWSTR sczCode; LPWSTR sczTag; @@ -167,7 +168,7 @@ HRESULT RegistrationParseFromXml( __in BURN_REGISTRATION* pRegistration, __in BURN_CACHE* pCache, __in IXMLDOMNode* pixnBundle - ); +); void RegistrationUninitialize( __in BURN_REGISTRATION* pRegistration ); @@ -191,7 +192,7 @@ HRESULT RegistrationDetectRelatedBundles( ); HRESULT RegistrationPlanInitialize( __in BURN_REGISTRATION* pRegistration - ); +); HRESULT RegistrationSessionBegin( __in_z LPCWSTR wzEngineWorkingPath, __in BURN_REGISTRATION* pRegistration, @@ -225,6 +226,10 @@ HRESULT RegistrationGetResumeCommandLine( __in const BURN_REGISTRATION* pRegistration, __deref_out_z LPWSTR* psczResumeCommandLine ); +HRESULT RegistrationSetPaths( + __in BURN_REGISTRATION* pRegistration, + __in BURN_CACHE* pCache + ); #if defined(__cplusplus) diff --git a/src/burn/engine/relatedbundle.cpp b/src/burn/engine/relatedbundle.cpp index c9aa7170..d0b97af0 100644 --- a/src/burn/engine/relatedbundle.cpp +++ b/src/burn/engine/relatedbundle.cpp @@ -22,7 +22,7 @@ static __callback int __cdecl CompareRelatedBundlesPlan( ); static BUNDLE_QUERY_CALLBACK_RESULT CALLBACK QueryRelatedBundlesCallback( __in const BUNDLE_QUERY_RELATED_BUNDLE_RESULT* pBundle, - __in_opt LPVOID pvContext + __in LPVOID pvContext ); static HRESULT LoadIfRelatedBundle( __in const BUNDLE_QUERY_RELATED_BUNDLE_RESULT* pBundle, @@ -258,7 +258,7 @@ static __callback int __cdecl CompareRelatedBundlesPlan( static BUNDLE_QUERY_CALLBACK_RESULT CALLBACK QueryRelatedBundlesCallback( __in const BUNDLE_QUERY_RELATED_BUNDLE_RESULT* pBundle, - __in_opt LPVOID pvContext + __in LPVOID pvContext ) { HRESULT hr = S_OK; diff --git a/src/burn/engine/uithread.cpp b/src/burn/engine/uithread.cpp index 9beb9f80..1f7db965 100644 --- a/src/burn/engine/uithread.cpp +++ b/src/burn/engine/uithread.cpp @@ -123,7 +123,7 @@ static DWORD WINAPI ThreadProc( info.pEngineState = pEngineState; // Create the window to handle reboots without activating it. - hWnd = ::CreateWindowExW(WS_EX_NOACTIVATE, wc.lpszClassName, NULL, WS_POPUP, 0, 0, 0, 0, HWND_DESKTOP, NULL, pContext->hInstance, &info); + hWnd = ::CreateWindowExW(WS_EX_NOACTIVATE, wc.lpszClassName, BURN_UITHREAD_CLASS_WINDOW, WS_POPUP, 0, 0, 0, 0, HWND_DESKTOP, NULL, pContext->hInstance, &info); ExitOnNullWithLastError(hWnd, hr, "Failed to create Burn UI thread window."); ::ShowWindow(hWnd, SW_SHOWNA); diff --git a/src/burn/engine/variable.cpp b/src/burn/engine/variable.cpp index a795d76c..1b7dc4d1 100644 --- a/src/burn/engine/variable.cpp +++ b/src/burn/engine/variable.cpp @@ -305,6 +305,8 @@ extern "C" HRESULT VariableInitialize( {BURN_BUNDLE_TAG, InitializeVariableString, (DWORD_PTR)L"", FALSE, TRUE}, {BURN_BUNDLE_UILEVEL, InitializeVariableNumeric, 0, FALSE, TRUE}, {BURN_BUNDLE_VERSION, InitializeVariableVersion, (DWORD_PTR)L"0", FALSE, TRUE}, + {BURN_BUNDLE_SCOPE, InitializeVariableNumeric, 0, FALSE, TRUE}, + {BURN_BUNDLE_PLANNED_SCOPE, InitializeVariableNumeric, 0, FALSE, TRUE}, }; const WELL_KNOWN_VARIABLE_DECLARATION vrgWellKnownVariableNames[] = -- cgit v1.2.3-55-g6feb