From 386a3578413ba16b3c0615d47870ee44a0e461f6 Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Wed, 30 Mar 2022 17:08:40 -0500 Subject: Implement BundlePackage. 3693 --- src/burn/engine/apply.cpp | 102 ++++++++ src/burn/engine/bundlepackageengine.cpp | 272 ++++++++++++++++++++- src/burn/engine/bundlepackageengine.h | 26 ++ src/burn/engine/core.cpp | 16 +- src/burn/engine/core.h | 1 + src/burn/engine/elevation.cpp | 176 ++++++++++++- src/burn/engine/elevation.h | 9 + src/burn/engine/exeengine.cpp | 24 +- src/burn/engine/logging.cpp | 2 + src/burn/engine/package.cpp | 18 +- src/burn/engine/package.h | 4 +- src/burn/engine/plan.cpp | 24 +- src/burn/engine/plan.h | 8 + src/burn/engine/registration.cpp | 5 +- src/burn/engine/registration.h | 2 + src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj | 1 + src/burn/test/BurnUnitTest/PlanTest.cpp | 141 ++++++++++- .../PlanTest/BundlePackage_Multiple_manifest.xml | 1 + 18 files changed, 765 insertions(+), 67 deletions(-) create mode 100644 src/burn/test/BurnUnitTest/TestData/PlanTest/BundlePackage_Multiple_manifest.xml (limited to 'src/burn') diff --git a/src/burn/engine/apply.cpp b/src/burn/engine/apply.cpp index 6af5c040..9ee7b58c 100644 --- a/src/burn/engine/apply.cpp +++ b/src/burn/engine/apply.cpp @@ -216,6 +216,15 @@ static HRESULT DoRestoreRelatedBundleActions( __in BURN_EXECUTE_CONTEXT* pContext, __out BOOTSTRAPPER_APPLY_RESTART* pRestart ); +static HRESULT ExecuteBundlePackage( + __in BURN_ENGINE_STATE* pEngineState, + __in BURN_EXECUTE_ACTION* pExecuteAction, + __in BURN_EXECUTE_CONTEXT* pContext, + __in BOOL fRollback, + __out BOOL* pfRetry, + __out BOOL* pfSuspend, + __out BOOTSTRAPPER_APPLY_RESTART* pRestart + ); static HRESULT ExecuteExePackage( __in BURN_ENGINE_STATE* pEngineState, __in BURN_EXECUTE_ACTION* pExecuteAction, @@ -732,6 +741,9 @@ extern "C" HRESULT ApplyExecute( case BURN_EXECUTE_ACTION_TYPE_RELATED_BUNDLE: wzId = pExecuteAction->relatedBundle.pRelatedBundle->package.sczId; break; + case BURN_EXECUTE_ACTION_TYPE_BUNDLE_PACKAGE: + wzId = pExecuteAction->bundlePackage.pPackage->sczId; + break; case BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE: wzId = pExecuteAction->exePackage.pPackage->sczId; break; @@ -2352,6 +2364,11 @@ static HRESULT DoExecuteAction( ExitOnFailure(hr, "Failed to execute related bundle."); break; + case BURN_EXECUTE_ACTION_TYPE_BUNDLE_PACKAGE: + hr = ExecuteBundlePackage(pEngineState, pExecuteAction, pContext, FALSE, &fRetry, pfSuspend, &restart); + ExitOnFailure(hr, "Failed to execute BUNDLE package."); + break; + case BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE: hr = ExecuteExePackage(pEngineState, pExecuteAction, pContext, FALSE, &fRetry, pfSuspend, &restart); ExitOnFailure(hr, "Failed to execute EXE package."); @@ -2479,6 +2496,11 @@ static HRESULT DoRollbackActions( ExitOnFailure(hr, "Failed to execute related bundle."); break; + case BURN_EXECUTE_ACTION_TYPE_BUNDLE_PACKAGE: + hr = ExecuteBundlePackage(pEngineState, pRollbackAction, pContext, TRUE, &fRetryIgnored, &fSuspendIgnored, &restart); + IgnoreRollbackError(hr, "Failed to rollback BUNDLE package."); + break; + case BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE: hr = ExecuteExePackage(pEngineState, pRollbackAction, pContext, TRUE, &fRetryIgnored, &fSuspendIgnored, &restart); IgnoreRollbackError(hr, "Failed to rollback EXE package."); @@ -2682,6 +2704,86 @@ LExit: return hr; } +static HRESULT ExecuteBundlePackage( + __in BURN_ENGINE_STATE* pEngineState, + __in BURN_EXECUTE_ACTION* pExecuteAction, + __in BURN_EXECUTE_CONTEXT* pContext, + __in BOOL fRollback, + __out BOOL* pfRetry, + __out BOOL* pfSuspend, + __out BOOTSTRAPPER_APPLY_RESTART* pRestart + ) +{ + HRESULT hr = S_OK; + HRESULT hrExecute = S_OK; + GENERIC_EXECUTE_MESSAGE message = { }; + int nResult = 0; + BOOL fBeginCalled = FALSE; + BOOL fExecuted = FALSE; + BURN_PACKAGE* pPackage = pExecuteAction->bundlePackage.pPackage; + + Assert(pContext->fRollback == fRollback); + + if (ShouldSkipPackage(pPackage, fRollback)) + { + ExitFunction1(hr = S_OK); + } + + pContext->wzExecutingPackageId = pPackage->sczId; + fBeginCalled = TRUE; + + // Send package execute begin to BA. + hr = UserExperienceOnExecutePackageBegin(&pEngineState->userExperience, pPackage->sczId, !fRollback, pExecuteAction->bundlePackage.action, INSTALLUILEVEL_NOCHANGE, FALSE); + ExitOnRootFailure(hr, "BA aborted execute BUNDLE package begin."); + + message.type = GENERIC_EXECUTE_MESSAGE_PROGRESS; + message.dwUIHint = MB_OKCANCEL; + message.progress.dwPercentage = fRollback ? 100 : 0; + nResult = GenericExecuteMessageHandler(&message, pContext); + hr = UserExperienceInterpretExecuteResult(&pEngineState->userExperience, fRollback, message.dwUIHint, nResult); + ExitOnRootFailure(hr, "BA aborted BUNDLE progress."); + + fExecuted = TRUE; + + // Execute package. + if (pPackage->fPerMachine) + { + hrExecute = ElevationExecuteBundlePackage(pEngineState->companionConnection.hPipe, pExecuteAction, &pEngineState->variables, fRollback, GenericExecuteMessageHandler, pContext, pRestart); + ExitOnFailure(hrExecute, "Failed to configure per-machine BUNDLE package."); + } + else + { + hrExecute = BundlePackageEngineExecutePackage(pExecuteAction, pContext->pCache, &pEngineState->variables, fRollback, GenericExecuteMessageHandler, pContext, pRestart); + ExitOnFailure(hrExecute, "Failed to configure per-user BUNDLE package."); + } + + message.type = GENERIC_EXECUTE_MESSAGE_PROGRESS; + message.dwUIHint = MB_OKCANCEL; + message.progress.dwPercentage = fRollback ? 0 : 100; + nResult = GenericExecuteMessageHandler(&message, pContext); + hr = UserExperienceInterpretExecuteResult(&pEngineState->userExperience, fRollback, message.dwUIHint, nResult); + ExitOnRootFailure(hr, "BA aborted BUNDLE progress."); + + pContext->cExecutedPackages += fRollback ? -1 : 1; + + hr = ReportOverallProgressTicks(&pEngineState->userExperience, fRollback, pEngineState->plan.cOverallProgressTicksTotal, pContext->pApplyContext); + ExitOnRootFailure(hr, "BA aborted BUNDLE package execute progress."); + +LExit: + if (fExecuted) + { + BundlePackageEngineUpdateInstallRegistrationState(pExecuteAction, hrExecute); + } + + if (fBeginCalled) + { + pPackage->fAbandonedProcess = pContext->fAbandonedProcess; + hr = ExecutePackageComplete(&pEngineState->userExperience, &pEngineState->variables, pPackage->sczId, pPackage->fVital, pPackage->fAbandonedProcess, hr, hrExecute, fRollback, pRestart, pfRetry, pfSuspend); + } + + return hr; +} + static HRESULT ExecuteExePackage( __in BURN_ENGINE_STATE* pEngineState, __in BURN_EXECUTE_ACTION* pExecuteAction, diff --git a/src/burn/engine/bundlepackageengine.cpp b/src/burn/engine/bundlepackageengine.cpp index 89488b91..f3badfc1 100644 --- a/src/burn/engine/bundlepackageengine.cpp +++ b/src/burn/engine/bundlepackageengine.cpp @@ -2,16 +2,80 @@ #include "precomp.h" +static HRESULT ExecuteBundle( + __in BURN_CACHE* pCache, + __in BURN_VARIABLES* pVariables, + __in BOOL fRollback, + __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, + __in LPVOID pvContext, + __in BOOTSTRAPPER_ACTION_STATE action, + __in BOOTSTRAPPER_RELATION_TYPE relationType, + __in BURN_PACKAGE* pPackage, + __in_z_opt LPCWSTR wzIgnoreDependencies, + __in_z_opt LPCWSTR wzAncestors, + __in_z_opt LPCWSTR wzEngineWorkingDirectory, + __out BOOTSTRAPPER_APPLY_RESTART* pRestart + ); static BOOTSTRAPPER_RELATION_TYPE ConvertRelationType( __in BOOTSTRAPPER_RELATED_BUNDLE_PLAN_TYPE relationType ); // function definitions +extern "C" HRESULT BundlePackageEngineParsePackageFromXml( + __in IXMLDOMNode* pixnBundlePackage, + __in BURN_PACKAGE* pPackage + ) +{ + HRESULT hr = S_OK; + BOOL fFoundXml = FALSE; + LPWSTR scz = NULL; + + // @DetectCondition + hr = XmlGetAttributeEx(pixnBundlePackage, L"BundleId", &pPackage->Bundle.sczBundleId); + ExitOnRequiredXmlQueryFailure(hr, "Failed to get @BundleId."); + + // @InstallArguments + hr = XmlGetAttributeEx(pixnBundlePackage, L"InstallArguments", &pPackage->Bundle.sczInstallArguments); + ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @InstallArguments."); + + // @UninstallArguments + hr = XmlGetAttributeEx(pixnBundlePackage, L"UninstallArguments", &pPackage->Bundle.sczUninstallArguments); + ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @UninstallArguments."); + + // @RepairArguments + hr = XmlGetAttributeEx(pixnBundlePackage, L"RepairArguments", &pPackage->Bundle.sczRepairArguments); + ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @RepairArguments."); + + // @SupportsBurnProtocol + hr = XmlGetYesNoAttribute(pixnBundlePackage, L"SupportsBurnProtocol", &pPackage->Bundle.fSupportsBurnProtocol); + ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @SupportsBurnProtocol."); + + // @Win64 + hr = XmlGetYesNoAttribute(pixnBundlePackage, L"Win64", &pPackage->Bundle.fWin64); + ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Win64."); + + hr = ExeEngineParseExitCodesFromXml(pixnBundlePackage, &pPackage->Bundle.rgExitCodes, &pPackage->Bundle.cExitCodes); + ExitOnFailure(hr, "Failed to parse exit codes."); + + hr = ExeEngineParseCommandLineArgumentsFromXml(pixnBundlePackage, &pPackage->Bundle.rgCommandLineArguments, &pPackage->Bundle.cCommandLineArguments); + ExitOnFailure(hr, "Failed to parse command lines."); + + hr = StrAllocFormatted(&pPackage->Bundle.sczRegistrationKey, L"%ls\\%ls", BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY, pPackage->Bundle.sczBundleId); + ExitOnFailure(hr, "Failed to build uninstall registry key path."); + +LExit: + ReleaseStr(scz); + + return hr; +} + extern "C" void BundlePackageEnginePackageUninitialize( __in BURN_PACKAGE* pPackage ) { + ReleaseStr(pPackage->Bundle.sczBundleId); + ReleaseStr(pPackage->Bundle.sczRegistrationKey); ReleaseStr(pPackage->Bundle.sczInstallArguments); ReleaseStr(pPackage->Bundle.sczRepairArguments); ReleaseStr(pPackage->Bundle.sczUninstallArguments); @@ -32,6 +96,44 @@ extern "C" void BundlePackageEnginePackageUninitialize( memset(&pPackage->Bundle, 0, sizeof(pPackage->Bundle)); } +extern "C" HRESULT BundlePackageEngineDetectPackage( + __in BURN_PACKAGE* pPackage + ) +{ + HRESULT hr = S_OK; + HKEY hkRegistration = NULL; + DWORD dwInstalled = 0; + BOOL fDetected = FALSE; + HKEY hkRoot = pPackage->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + REG_KEY_BITNESS bitness = pPackage->Bundle.fWin64 ? REG_KEY_64BIT : REG_KEY_32BIT; + + // TODO: detect all related bundles, so that the Obsolete state can be detected. + hr = RegOpenEx(hkRoot, pPackage->Bundle.sczRegistrationKey, KEY_QUERY_VALUE, bitness, &hkRegistration); + if (SUCCEEDED(hr)) + { + hr = RegReadNumber(hkRegistration, REGISTRY_BUNDLE_INSTALLED, &dwInstalled); + } + + // Not finding the key or value is okay. + if (E_FILENOTFOUND == hr || E_PATHNOTFOUND == hr) + { + hr = S_OK; + } + + fDetected = (1 == dwInstalled); + + // update detect state + pPackage->currentState = fDetected ? BOOTSTRAPPER_PACKAGE_STATE_PRESENT : BOOTSTRAPPER_PACKAGE_STATE_ABSENT; + + if (pPackage->fCanAffectRegistration) + { + pPackage->installRegistrationState = BOOTSTRAPPER_PACKAGE_STATE_ABSENT < pPackage->currentState ? BURN_PACKAGE_REGISTRATION_STATE_PRESENT : BURN_PACKAGE_REGISTRATION_STATE_ABSENT; + } + + ReleaseRegKey(hkRegistration); + return hr; +} + // // PlanCalculate - calculates the execute and rollback state for the requested package state. // @@ -151,6 +253,79 @@ LExit: // // PlanAdd - adds the calculated execute and rollback actions for the package. // +extern "C" HRESULT BundlePackageEnginePlanAddPackage( + __in BURN_PACKAGE* pPackage, + __in BURN_PLAN* pPlan, + __in BURN_LOGGING* pLog, + __in BURN_VARIABLES* pVariables + ) +{ + HRESULT hr = S_OK; + BURN_EXECUTE_ACTION* pAction = NULL; + + hr = DependencyPlanPackage(NULL, pPackage, pPlan); + ExitOnFailure(hr, "Failed to plan package dependency actions."); + + // add rollback action + if (BOOTSTRAPPER_ACTION_STATE_NONE != pPackage->rollback) + { + hr = PlanAppendRollbackAction(pPlan, &pAction); + ExitOnFailure(hr, "Failed to append rollback action."); + + pAction->type = BURN_EXECUTE_ACTION_TYPE_BUNDLE_PACKAGE; + pAction->bundlePackage.pPackage = pPackage; + pAction->bundlePackage.action = pPackage->rollback; + + if (pPackage->Bundle.wzAncestors) + { + hr = StrAllocString(&pAction->bundlePackage.sczAncestors, pPackage->Bundle.wzAncestors, 0); + ExitOnFailure(hr, "Failed to allocate the list of ancestors."); + } + + if (pPackage->Bundle.wzEngineWorkingDirectory) + { + hr = StrAllocString(&pAction->bundlePackage.sczEngineWorkingDirectory, pPackage->Bundle.wzEngineWorkingDirectory, 0); + ExitOnFailure(hr, "Failed to allocate the custom working directory."); + } + + LoggingSetPackageVariable(pPackage, NULL, TRUE, pLog, pVariables, NULL); // ignore errors. + + hr = PlanExecuteCheckpoint(pPlan); + ExitOnFailure(hr, "Failed to append execute checkpoint."); + } + + // add execute action + if (BOOTSTRAPPER_ACTION_STATE_NONE != pPackage->execute) + { + hr = PlanAppendExecuteAction(pPlan, &pAction); + ExitOnFailure(hr, "Failed to append execute action."); + + pAction->type = BURN_EXECUTE_ACTION_TYPE_BUNDLE_PACKAGE; + pAction->bundlePackage.pPackage = pPackage; + pAction->bundlePackage.action = pPackage->execute; + + if (pPackage->Bundle.wzAncestors) + { + hr = StrAllocString(&pAction->bundlePackage.sczAncestors, pPackage->Bundle.wzAncestors, 0); + ExitOnFailure(hr, "Failed to allocate the list of ancestors."); + } + + if (pPackage->Bundle.wzEngineWorkingDirectory) + { + hr = StrAllocString(&pAction->bundlePackage.sczEngineWorkingDirectory, pPackage->Bundle.wzEngineWorkingDirectory, 0); + ExitOnFailure(hr, "Failed to allocate the custom working directory."); + } + + LoggingSetPackageVariable(pPackage, NULL, FALSE, pLog, pVariables, NULL); // ignore errors. + } + +LExit: + return hr; +} + +// +// PlanAdd - adds the calculated execute and rollback actions for the related bundle. +// extern "C" HRESULT BundlePackageEnginePlanAddRelatedBundle( __in_opt DWORD *pdwInsertSequence, __in BURN_RELATED_BUNDLE* pRelatedBundle, @@ -164,7 +339,7 @@ extern "C" HRESULT BundlePackageEnginePlanAddRelatedBundle( BURN_PACKAGE* pPackage = &pRelatedBundle->package; hr = DependencyPlanPackage(pdwInsertSequence, pPackage, pPlan); - ExitOnFailure(hr, "Failed to plan package dependency actions."); + ExitOnFailure(hr, "Failed to plan related bundle dependency actions."); // add execute action if (BOOTSTRAPPER_ACTION_STATE_NONE != pPackage->execute) @@ -240,6 +415,26 @@ LExit: return hr; } +extern "C" HRESULT BundlePackageEngineExecutePackage( + __in BURN_EXECUTE_ACTION* pExecuteAction, + __in BURN_CACHE* pCache, + __in BURN_VARIABLES* pVariables, + __in BOOL fRollback, + __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, + __in LPVOID pvContext, + __out BOOTSTRAPPER_APPLY_RESTART* pRestart + ) +{ + BOOTSTRAPPER_ACTION_STATE action = pExecuteAction->bundlePackage.action; + LPCWSTR wzIgnoreDependencies = pExecuteAction->bundlePackage.sczIgnoreDependencies; + LPCWSTR wzAncestors = pExecuteAction->bundlePackage.sczAncestors; + LPCWSTR wzEngineWorkingDirectory = pExecuteAction->bundlePackage.sczEngineWorkingDirectory; + BOOTSTRAPPER_RELATION_TYPE relationType = BOOTSTRAPPER_RELATION_CHAIN_PACKAGE; + BURN_PACKAGE* pPackage = pExecuteAction->bundlePackage.pPackage; + + return ExecuteBundle(pCache, pVariables, fRollback, pfnGenericMessageHandler, pvContext, action, relationType, pPackage, wzIgnoreDependencies, wzAncestors, wzEngineWorkingDirectory, pRestart); +} + extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle( __in BURN_EXECUTE_ACTION* pExecuteAction, __in BURN_CACHE* pCache, @@ -249,6 +444,57 @@ extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle( __in LPVOID pvContext, __out BOOTSTRAPPER_APPLY_RESTART* pRestart ) +{ + BOOTSTRAPPER_ACTION_STATE action = pExecuteAction->relatedBundle.action; + LPCWSTR wzIgnoreDependencies = pExecuteAction->relatedBundle.sczIgnoreDependencies; + LPCWSTR wzAncestors = pExecuteAction->relatedBundle.sczAncestors; + LPCWSTR wzEngineWorkingDirectory = pExecuteAction->relatedBundle.sczEngineWorkingDirectory; + BURN_RELATED_BUNDLE* pRelatedBundle = pExecuteAction->relatedBundle.pRelatedBundle; + BOOTSTRAPPER_RELATION_TYPE relationType = ConvertRelationType(pRelatedBundle->planRelationType); + BURN_PACKAGE* pPackage = &pRelatedBundle->package; + + return ExecuteBundle(pCache, pVariables, fRollback, pfnGenericMessageHandler, pvContext, action, relationType, pPackage, wzIgnoreDependencies, wzAncestors, wzEngineWorkingDirectory, pRestart); +} + +extern "C" void BundlePackageEngineUpdateInstallRegistrationState( + __in BURN_EXECUTE_ACTION* pAction, + __in HRESULT hrExecute + ) +{ + BURN_PACKAGE* pPackage = pAction->bundlePackage.pPackage; + + if (FAILED(hrExecute) || !pPackage->fCanAffectRegistration) + { + ExitFunction(); + } + + if (BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pAction->bundlePackage.action) + { + pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_ABSENT; + } + else + { + pPackage->installRegistrationState = BURN_PACKAGE_REGISTRATION_STATE_PRESENT; + } + +LExit: + return; +} + +static HRESULT ExecuteBundle( + __in BURN_CACHE* pCache, + __in BURN_VARIABLES* pVariables, + __in BOOL fRollback, + __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, + __in LPVOID pvContext, + __in BOOTSTRAPPER_ACTION_STATE action, + __in BOOTSTRAPPER_RELATION_TYPE relationType, + __in BURN_PACKAGE* pPackage, + __in_z_opt LPCWSTR wzIgnoreDependencies, + __in_z_opt LPCWSTR wzAncestors, + __in_z_opt LPCWSTR wzEngineWorkingDirectory, + __out BOOTSTRAPPER_APPLY_RESTART* pRestart + ) { HRESULT hr = S_OK; LPCWSTR wzArguments = NULL; @@ -264,10 +510,6 @@ extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle( PROCESS_INFORMATION pi = { }; DWORD dwExitCode = 0; GENERIC_EXECUTE_MESSAGE message = { }; - BOOTSTRAPPER_ACTION_STATE action = pExecuteAction->relatedBundle.action; - BURN_RELATED_BUNDLE* pRelatedBundle = pExecuteAction->relatedBundle.pRelatedBundle; - BOOTSTRAPPER_RELATION_TYPE relationType = ConvertRelationType(pRelatedBundle->planRelationType); - BURN_PACKAGE* pPackage = &pRelatedBundle->package; BURN_PAYLOAD* pPackagePayload = pPackage->payloads.rgItems[0].pPayload; LPCWSTR wzRelationTypeCommandLine = CoreRelationTypeToCommandLineString(relationType); LPCWSTR wzOperationCommandLine = NULL; @@ -376,21 +618,29 @@ extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle( } // Add the list of dependencies to ignore, if any, to the burn command line. - if (pExecuteAction->relatedBundle.sczIgnoreDependencies) + if (BOOTSTRAPPER_RELATION_CHAIN_PACKAGE == relationType) { - hr = StrAllocConcatFormatted(&sczBaseCommand, L" -%ls=%ls", BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES, pExecuteAction->relatedBundle.sczIgnoreDependencies); + hr = StrAllocConcatFormatted(&sczBaseCommand, L" -%ls=ALL", BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES); + ExitOnFailure(hr, "Failed to append the list of dependencies to ignore to the command line."); + } + else if (wzIgnoreDependencies) + { + hr = StrAllocConcatFormatted(&sczBaseCommand, L" -%ls=%ls", BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES, wzIgnoreDependencies); ExitOnFailure(hr, "Failed to append the list of dependencies to ignore to the command line."); } // Add the list of ancestors, if any, to the burn command line. - if (pExecuteAction->relatedBundle.sczAncestors) + if (wzAncestors) { - hr = StrAllocConcatFormatted(&sczBaseCommand, L" -%ls=%ls", BURN_COMMANDLINE_SWITCH_ANCESTORS, pExecuteAction->relatedBundle.sczAncestors); + hr = StrAllocConcatFormatted(&sczBaseCommand, L" -%ls=%ls", BURN_COMMANDLINE_SWITCH_ANCESTORS, wzAncestors); ExitOnFailure(hr, "Failed to append the list of ancestors to the command line."); } - hr = CoreAppendEngineWorkingDirectoryToCommandLine(pExecuteAction->relatedBundle.sczEngineWorkingDirectory, &sczBaseCommand, NULL); - ExitOnFailure(hr, "Failed to append the custom working directory to the bundlepackage command line."); + if (wzEngineWorkingDirectory) + { + hr = CoreAppendEngineWorkingDirectoryToCommandLine(wzEngineWorkingDirectory, &sczBaseCommand, NULL); + ExitOnFailure(hr, "Failed to append the custom working directory to the bundlepackage command line."); + } hr = CoreAppendFileHandleSelfToCommandLine(sczExecutablePath, &hExecutableFile, &sczBaseCommand, NULL); ExitOnFailure(hr, "Failed to append %ls", BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF); diff --git a/src/burn/engine/bundlepackageengine.h b/src/burn/engine/bundlepackageengine.h index 0d59907d..9271ac6a 100644 --- a/src/burn/engine/bundlepackageengine.h +++ b/src/burn/engine/bundlepackageengine.h @@ -9,12 +9,25 @@ extern "C" { // function declarations +HRESULT BundlePackageEngineParsePackageFromXml( + __in IXMLDOMNode* pixnBundlePackage, + __in BURN_PACKAGE* pPackage + ); void BundlePackageEnginePackageUninitialize( __in BURN_PACKAGE* pPackage ); +HRESULT BundlePackageEngineDetectPackage( + __in BURN_PACKAGE* pPackage + ); HRESULT BundlePackageEnginePlanCalculatePackage( __in BURN_PACKAGE* pPackage ); +HRESULT BundlePackageEnginePlanAddPackage( + __in BURN_PACKAGE* pPackage, + __in BURN_PLAN* pPlan, + __in BURN_LOGGING* pLog, + __in BURN_VARIABLES* pVariables + ); HRESULT BundlePackageEnginePlanAddRelatedBundle( __in_opt DWORD *pdwInsertSequence, __in BURN_RELATED_BUNDLE* pRelatedBundle, @@ -22,6 +35,15 @@ HRESULT BundlePackageEnginePlanAddRelatedBundle( __in BURN_LOGGING* pLog, __in BURN_VARIABLES* pVariables ); +HRESULT BundlePackageEngineExecutePackage( + __in BURN_EXECUTE_ACTION* pExecuteAction, + __in BURN_CACHE* pCache, + __in BURN_VARIABLES* pVariables, + __in BOOL fRollback, + __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, + __in LPVOID pvContext, + __out BOOTSTRAPPER_APPLY_RESTART* pRestart + ); HRESULT BundlePackageEngineExecuteRelatedBundle( __in BURN_EXECUTE_ACTION* pExecuteAction, __in BURN_CACHE* pCache, @@ -31,6 +53,10 @@ HRESULT BundlePackageEngineExecuteRelatedBundle( __in LPVOID pvContext, __out BOOTSTRAPPER_APPLY_RESTART* pRestart ); +void BundlePackageEngineUpdateInstallRegistrationState( + __in BURN_EXECUTE_ACTION* pAction, + __in HRESULT hrExecute + ); #if defined(__cplusplus) diff --git a/src/burn/engine/core.cpp b/src/burn/engine/core.cpp index 551843f2..3370ad05 100644 --- a/src/burn/engine/core.cpp +++ b/src/burn/engine/core.cpp @@ -956,6 +956,9 @@ extern "C" LPCWSTR CoreRelationTypeToCommandLineString( case BOOTSTRAPPER_RELATION_DEPENDENT_PATCH: wzRelationTypeCommandLine = BURN_COMMANDLINE_SWITCH_RELATED_DEPENDENT_PATCH; break; + case BOOTSTRAPPER_RELATION_CHAIN_PACKAGE: + wzRelationTypeCommandLine = BURN_COMMANDLINE_SWITCH_RELATED_CHAIN_PACKAGE; + break; case BOOTSTRAPPER_RELATION_NONE: __fallthrough; default: wzRelationTypeCommandLine = NULL; @@ -1709,6 +1712,12 @@ extern "C" HRESULT CoreParseCommandLine( LogId(REPORT_STANDARD, MSG_BURN_RUN_BY_RELATED_BUNDLE, LoggingRelationTypeToString(pCommand->relationType)); } + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, BURN_COMMANDLINE_SWITCH_RELATED_CHAIN_PACKAGE, -1)) + { + pCommand->relationType = BOOTSTRAPPER_RELATION_CHAIN_PACKAGE; + + LogId(REPORT_STANDARD, MSG_BURN_RUN_BY_RELATED_BUNDLE, LoggingRelationTypeToString(pCommand->relationType)); + } else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, BURN_COMMANDLINE_SWITCH_PASSTHROUGH, -1)) { pCommand->fPassthrough = TRUE; @@ -2111,6 +2120,10 @@ static HRESULT DetectPackage( // Use the correct engine to detect the package. switch (pPackage->type) { + case BURN_PACKAGE_TYPE_BUNDLE: + hr = BundlePackageEngineDetectPackage(pPackage); + break; + case BURN_PACKAGE_TYPE_EXE: hr = ExeEngineDetectPackage(pPackage, &pEngineState->registration, &pEngineState->variables); break; @@ -2128,8 +2141,7 @@ static HRESULT DetectPackage( break; default: - hr = E_NOTIMPL; - ExitOnRootFailure(hr, "Package type not supported by detect yet."); + ExitWithRootFailure(hr, E_NOTIMPL, "Package type not supported by detect yet."); } LExit: diff --git a/src/burn/engine/core.h b/src/burn/engine/core.h index cee71aec..556124d6 100644 --- a/src/burn/engine/core.h +++ b/src/burn/engine/core.h @@ -27,6 +27,7 @@ const LPCWSTR BURN_COMMANDLINE_SWITCH_RELATED_DEPENDENT_ADDON = L"burn.related.d const LPCWSTR BURN_COMMANDLINE_SWITCH_RELATED_PATCH = L"burn.related.patch"; const LPCWSTR BURN_COMMANDLINE_SWITCH_RELATED_DEPENDENT_PATCH = L"burn.related.dependent.patch"; const LPCWSTR BURN_COMMANDLINE_SWITCH_RELATED_UPDATE = L"burn.related.update"; +const LPCWSTR BURN_COMMANDLINE_SWITCH_RELATED_CHAIN_PACKAGE = L"burn.related.chain.package"; const LPCWSTR BURN_COMMANDLINE_SWITCH_PASSTHROUGH = L"burn.passthrough"; const LPCWSTR BURN_COMMANDLINE_SWITCH_DISABLE_UNELEVATE = L"burn.disable.unelevate"; const LPCWSTR BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES = L"burn.ignoredependencies"; diff --git a/src/burn/engine/elevation.cpp b/src/burn/engine/elevation.cpp index 8488b649..504ddaea 100644 --- a/src/burn/engine/elevation.cpp +++ b/src/burn/engine/elevation.cpp @@ -20,6 +20,7 @@ typedef enum _BURN_ELEVATION_MESSAGE_TYPE BURN_ELEVATION_MESSAGE_TYPE_CACHE_CLEANUP, BURN_ELEVATION_MESSAGE_TYPE_PROCESS_DEPENDENT_REGISTRATION, BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_RELATED_BUNDLE, + BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_BUNDLE_PACKAGE, BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_EXE_PACKAGE, BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_MSI_PACKAGE, BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_MSP_PACKAGE, @@ -250,6 +251,14 @@ static HRESULT OnExecuteRelatedBundle( __in BYTE* pbData, __in SIZE_T cbData ); +static HRESULT OnExecuteBundlePackage( + __in HANDLE hPipe, + __in BURN_CACHE* pCache, + __in BURN_PACKAGES* pPackages, + __in BURN_VARIABLES* pVariables, + __in BYTE* pbData, + __in SIZE_T cbData + ); static HRESULT OnExecuteExePackage( __in HANDLE hPipe, __in BURN_CACHE* pCache, @@ -910,6 +919,63 @@ LExit: return hr; } +/******************************************************************* + ElevationExecuteBundlePackage - + +*******************************************************************/ +extern "C" HRESULT ElevationExecuteBundlePackage( + __in HANDLE hPipe, + __in BURN_EXECUTE_ACTION* pExecuteAction, + __in BURN_VARIABLES* pVariables, + __in BOOL fRollback, + __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, + __in LPVOID pvContext, + __out BOOTSTRAPPER_APPLY_RESTART* pRestart + ) +{ + HRESULT hr = S_OK; + BYTE* pbData = NULL; + SIZE_T cbData = 0; + BURN_ELEVATION_GENERIC_MESSAGE_CONTEXT context = { }; + DWORD dwResult = 0; + + // serialize message data + hr = BuffWriteString(&pbData, &cbData, pExecuteAction->bundlePackage.pPackage->sczId); + ExitOnFailure(hr, "Failed to write package id to message buffer."); + + hr = BuffWriteNumber(&pbData, &cbData, (DWORD)pExecuteAction->bundlePackage.action); + ExitOnFailure(hr, "Failed to write action to message buffer."); + + hr = BuffWriteNumber(&pbData, &cbData, fRollback); + ExitOnFailure(hr, "Failed to write rollback."); + + hr = BuffWriteString(&pbData, &cbData, pExecuteAction->bundlePackage.sczIgnoreDependencies); + ExitOnFailure(hr, "Failed to write the list of dependencies to ignore to the message buffer."); + + hr = BuffWriteString(&pbData, &cbData, pExecuteAction->bundlePackage.sczAncestors); + ExitOnFailure(hr, "Failed to write the list of ancestors to the message buffer."); + + hr = BuffWriteString(&pbData, &cbData, pExecuteAction->bundlePackage.sczEngineWorkingDirectory); + ExitOnFailure(hr, "Failed to write the custom working directory to the message buffer."); + + hr = VariableSerialize(pVariables, FALSE, &pbData, &cbData); + ExitOnFailure(hr, "Failed to write variables."); + + // send message + context.pfnGenericMessageHandler = pfnGenericMessageHandler; + context.pvContext = pvContext; + + hr = PipeSendMessage(hPipe, BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_BUNDLE_PACKAGE, pbData, cbData, ProcessGenericExecuteMessages, &context, &dwResult); + ExitOnFailure(hr, "Failed to send BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_BUNDLE_PACKAGE message to per-machine process."); + + hr = ProcessResult(dwResult, pRestart); + +LExit: + ReleaseBuffer(pbData); + + return hr; +} + /******************************************************************* ElevationExecuteExePackage - @@ -940,9 +1006,6 @@ extern "C" HRESULT ElevationExecuteExePackage( hr = BuffWriteNumber(&pbData, &cbData, fRollback); ExitOnFailure(hr, "Failed to write rollback."); - hr = BuffWriteString(&pbData, &cbData, pExecuteAction->exePackage.sczIgnoreDependencies); - ExitOnFailure(hr, "Failed to write the list of dependencies to ignore to the message buffer."); - hr = BuffWriteString(&pbData, &cbData, pExecuteAction->exePackage.sczAncestors); ExitOnFailure(hr, "Failed to write the list of ancestors to the message buffer."); @@ -2124,6 +2187,10 @@ static HRESULT ProcessElevatedChildMessage( hrResult = OnExecuteRelatedBundle(pContext->hPipe, pContext->pCache, &pContext->pRegistration->relatedBundles, pContext->pVariables, (BYTE*)pMsg->pvData, pMsg->cbData); break; + case BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_BUNDLE_PACKAGE: + hrResult = OnExecuteBundlePackage(pContext->hPipe, pContext->pCache, pContext->pPackages, pContext->pVariables, (BYTE*)pMsg->pvData, pMsg->cbData); + break; + case BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_EXE_PACKAGE: hrResult = OnExecuteExePackage(pContext->hPipe, pContext->pCache, pContext->pPackages, pContext->pVariables, (BYTE*)pMsg->pvData, pMsg->cbData); break; @@ -2839,7 +2906,7 @@ LExit: return hr; } -static HRESULT OnExecuteExePackage( +static HRESULT OnExecuteBundlePackage( __in HANDLE hPipe, __in BURN_CACHE* pCache, __in BURN_PACKAGES* pPackages, @@ -2856,15 +2923,15 @@ static HRESULT OnExecuteExePackage( LPWSTR sczIgnoreDependencies = NULL; LPWSTR sczAncestors = NULL; LPWSTR sczEngineWorkingDirectory = NULL; - BOOTSTRAPPER_APPLY_RESTART exeRestart = BOOTSTRAPPER_APPLY_RESTART_NONE; + BOOTSTRAPPER_APPLY_RESTART bundleRestart = BOOTSTRAPPER_APPLY_RESTART_NONE; - executeAction.type = BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE; + executeAction.type = BURN_EXECUTE_ACTION_TYPE_BUNDLE_PACKAGE; // Deserialize message data. hr = BuffReadString(pbData, cbData, &iData, &sczPackage); ExitOnFailure(hr, "Failed to read EXE package id."); - hr = BuffReadNumber(pbData, cbData, &iData, (DWORD*)&executeAction.exePackage.action); + hr = BuffReadNumber(pbData, cbData, &iData, (DWORD*)&executeAction.bundlePackage.action); ExitOnFailure(hr, "Failed to read action."); hr = BuffReadNumber(pbData, cbData, &iData, &dwRollback); @@ -2882,21 +2949,107 @@ static HRESULT OnExecuteExePackage( hr = VariableDeserialize(pVariables, FALSE, pbData, cbData, &iData); ExitOnFailure(hr, "Failed to read variables."); - hr = PackageFindById(pPackages, sczPackage, &executeAction.exePackage.pPackage); + hr = PackageFindById(pPackages, sczPackage, &executeAction.bundlePackage.pPackage); ExitOnFailure(hr, "Failed to find package: %ls", sczPackage); - if (BURN_PACKAGE_TYPE_EXE != executeAction.exePackage.pPackage->type) + if (BURN_PACKAGE_TYPE_BUNDLE != executeAction.bundlePackage.pPackage->type) { - ExitWithRootFailure(hr, E_INVALIDARG, "Package is not an EXE package: %ls", sczPackage); + ExitWithRootFailure(hr, E_INVALIDARG, "Package is not a BUNDLE package: %ls", sczPackage); } // Pass the list of dependencies to ignore, if any, to the related bundle. if (sczIgnoreDependencies && *sczIgnoreDependencies) { - hr = StrAllocString(&executeAction.exePackage.sczIgnoreDependencies, sczIgnoreDependencies, 0); + hr = StrAllocString(&executeAction.bundlePackage.sczIgnoreDependencies, sczIgnoreDependencies, 0); ExitOnFailure(hr, "Failed to allocate the list of dependencies to ignore."); } + // Pass the list of ancestors, if any, to the related bundle. + if (sczAncestors && *sczAncestors) + { + hr = StrAllocString(&executeAction.bundlePackage.sczAncestors, sczAncestors, 0); + ExitOnFailure(hr, "Failed to allocate the list of ancestors."); + } + + if (sczEngineWorkingDirectory && *sczEngineWorkingDirectory) + { + hr = StrAllocString(&executeAction.bundlePackage.sczEngineWorkingDirectory, sczEngineWorkingDirectory, 0); + ExitOnFailure(hr, "Failed to allocate the custom working directory."); + } + + // Execute BUNDLE package. + hr = BundlePackageEngineExecutePackage(&executeAction, pCache, pVariables, static_cast(dwRollback), GenericExecuteMessageHandler, hPipe, &bundleRestart); + ExitOnFailure(hr, "Failed to execute BUNDLE package."); + +LExit: + ReleaseStr(sczEngineWorkingDirectory); + ReleaseStr(sczAncestors); + ReleaseStr(sczIgnoreDependencies); + ReleaseStr(sczPackage); + PlanUninitializeExecuteAction(&executeAction); + + if (SUCCEEDED(hr)) + { + if (BOOTSTRAPPER_APPLY_RESTART_REQUIRED == bundleRestart) + { + hr = HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED); + } + else if (BOOTSTRAPPER_APPLY_RESTART_INITIATED == bundleRestart) + { + hr = HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_INITIATED); + } + } + + return hr; +} + +static HRESULT OnExecuteExePackage( + __in HANDLE hPipe, + __in BURN_CACHE* pCache, + __in BURN_PACKAGES* pPackages, + __in BURN_VARIABLES* pVariables, + __in BYTE* pbData, + __in SIZE_T cbData + ) +{ + HRESULT hr = S_OK; + SIZE_T iData = 0; + LPWSTR sczPackage = NULL; + DWORD dwRollback = 0; + BURN_EXECUTE_ACTION executeAction = { }; + LPWSTR sczAncestors = NULL; + LPWSTR sczEngineWorkingDirectory = NULL; + BOOTSTRAPPER_APPLY_RESTART exeRestart = BOOTSTRAPPER_APPLY_RESTART_NONE; + + executeAction.type = BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE; + + // Deserialize message data. + hr = BuffReadString(pbData, cbData, &iData, &sczPackage); + ExitOnFailure(hr, "Failed to read EXE package id."); + + hr = BuffReadNumber(pbData, cbData, &iData, (DWORD*)&executeAction.exePackage.action); + ExitOnFailure(hr, "Failed to read action."); + + hr = BuffReadNumber(pbData, cbData, &iData, &dwRollback); + ExitOnFailure(hr, "Failed to read rollback."); + + hr = BuffReadString(pbData, cbData, &iData, &sczAncestors); + ExitOnFailure(hr, "Failed to read the list of ancestors."); + + hr = BuffReadString(pbData, cbData, &iData, &sczEngineWorkingDirectory); + ExitOnFailure(hr, "Failed to read the custom working directory."); + + hr = VariableDeserialize(pVariables, FALSE, pbData, cbData, &iData); + ExitOnFailure(hr, "Failed to read variables."); + + hr = PackageFindById(pPackages, sczPackage, &executeAction.exePackage.pPackage); + ExitOnFailure(hr, "Failed to find package: %ls", sczPackage); + + if (BURN_PACKAGE_TYPE_EXE != executeAction.exePackage.pPackage->type) + { + ExitWithRootFailure(hr, E_INVALIDARG, "Package is not an EXE package: %ls", sczPackage); + } + // Pass the list of ancestors, if any, to the related bundle. if (sczAncestors && *sczAncestors) { @@ -2917,7 +3070,6 @@ static HRESULT OnExecuteExePackage( LExit: ReleaseStr(sczEngineWorkingDirectory); ReleaseStr(sczAncestors); - ReleaseStr(sczIgnoreDependencies); ReleaseStr(sczPackage); PlanUninitializeExecuteAction(&executeAction); diff --git a/src/burn/engine/elevation.h b/src/burn/engine/elevation.h index c2fa0627..3484057e 100644 --- a/src/burn/engine/elevation.h +++ b/src/burn/engine/elevation.h @@ -89,6 +89,15 @@ HRESULT ElevationExecuteRelatedBundle( __in LPVOID pvContext, __out BOOTSTRAPPER_APPLY_RESTART* pRestart ); +HRESULT ElevationExecuteBundlePackage( + __in HANDLE hPipe, + __in BURN_EXECUTE_ACTION* pExecuteAction, + __in BURN_VARIABLES* pVariables, + __in BOOL fRollback, + __in PFN_GENERICMESSAGEHANDLER pfnGenericExecuteProgress, + __in LPVOID pvContext, + __out BOOTSTRAPPER_APPLY_RESTART* pRestart + ); HRESULT ElevationExecuteExePackage( __in HANDLE hPipe, __in BURN_EXECUTE_ACTION* pExecuteAction, diff --git a/src/burn/engine/exeengine.cpp b/src/burn/engine/exeengine.cpp index 0a2084e5..a287d171 100644 --- a/src/burn/engine/exeengine.cpp +++ b/src/burn/engine/exeengine.cpp @@ -91,7 +91,6 @@ extern "C" void ExeEnginePackageUninitialize( ReleaseStr(pPackage->Exe.sczInstallArguments); ReleaseStr(pPackage->Exe.sczRepairArguments); ReleaseStr(pPackage->Exe.sczUninstallArguments); - ReleaseStr(pPackage->Exe.sczIgnoreDependencies); ReleaseMem(pPackage->Exe.rgExitCodes); // free command-line arguments @@ -291,12 +290,6 @@ extern "C" HRESULT ExeEnginePlanAddPackage( pAction->exePackage.pPackage = pPackage; pAction->exePackage.action = pPackage->rollback; - if (pPackage->Exe.sczIgnoreDependencies) - { - hr = StrAllocString(&pAction->exePackage.sczIgnoreDependencies, pPackage->Exe.sczIgnoreDependencies, 0); - ExitOnFailure(hr, "Failed to allocate the list of dependencies to ignore."); - } - if (pPackage->Exe.wzAncestors) { hr = StrAllocString(&pAction->exePackage.sczAncestors, pPackage->Exe.wzAncestors, 0); @@ -325,12 +318,6 @@ extern "C" HRESULT ExeEnginePlanAddPackage( pAction->exePackage.pPackage = pPackage; pAction->exePackage.action = pPackage->execute; - if (pPackage->Exe.sczIgnoreDependencies) - { - hr = StrAllocString(&pAction->exePackage.sczIgnoreDependencies, pPackage->Exe.sczIgnoreDependencies, 0); - ExitOnFailure(hr, "Failed to allocate the list of dependencies to ignore."); - } - if (pPackage->Exe.wzAncestors) { hr = StrAllocString(&pAction->exePackage.sczAncestors, pPackage->Exe.wzAncestors, 0); @@ -455,12 +442,11 @@ extern "C" HRESULT ExeEngineExecutePackage( hr = StrAllocConcat(&sczBaseCommand, L" -norestart", 0); ExitOnFailure(hr, "Failed to append norestart argument."); - // Add the list of dependencies to ignore, if any, to the burn command line. - if (pExecuteAction->exePackage.sczIgnoreDependencies) - { - hr = StrAllocConcatFormatted(&sczBaseCommand, L" -%ls=%ls", BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES, pExecuteAction->exePackage.sczIgnoreDependencies); - ExitOnFailure(hr, "Failed to append the list of dependencies to ignore to the command line."); - } + hr = StrAllocConcatFormatted(&sczBaseCommand, L" -%ls", BURN_COMMANDLINE_SWITCH_RELATED_CHAIN_PACKAGE); + ExitOnFailure(hr, "Failed to append the relation type to the command line."); + + hr = StrAllocConcatFormatted(&sczBaseCommand, L" -%ls=ALL", BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES); + ExitOnFailure(hr, "Failed to append the list of dependencies to ignore to the command line."); // Add the list of ancestors, if any, to the burn command line. if (pExecuteAction->exePackage.sczAncestors) diff --git a/src/burn/engine/logging.cpp b/src/burn/engine/logging.cpp index de332f84..a766b896 100644 --- a/src/burn/engine/logging.cpp +++ b/src/burn/engine/logging.cpp @@ -781,6 +781,8 @@ extern "C" LPCSTR LoggingRelationTypeToString( return "DependentPatch"; case BOOTSTRAPPER_RELATION_UPDATE: return "Update"; + case BOOTSTRAPPER_RELATION_CHAIN_PACKAGE: + return "ChainPackage"; default: return "Invalid"; } diff --git a/src/burn/engine/package.cpp b/src/burn/engine/package.cpp index 8a80194e..89203ada 100644 --- a/src/burn/engine/package.cpp +++ b/src/burn/engine/package.cpp @@ -87,7 +87,7 @@ extern "C" HRESULT PackagesParseFromXml( ReleaseNullObject(pixnNodes); // done with the RollbackBoundary elements. // select package nodes - hr = XmlSelectNodes(pixnBundle, L"Chain/ExePackage|Chain/MsiPackage|Chain/MspPackage|Chain/MsuPackage", &pixnNodes); + hr = XmlSelectNodes(pixnBundle, L"Chain/BundlePackage|Chain/ExePackage|Chain/MsiPackage|Chain/MspPackage|Chain/MsuPackage", &pixnNodes); ExitOnFailure(hr, "Failed to select package nodes."); // get package node count @@ -199,7 +199,14 @@ extern "C" HRESULT PackagesParseFromXml( } // read type specific attributes - if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"ExePackage", -1)) + if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"BundlePackage", -1)) + { + pPackage->type = BURN_PACKAGE_TYPE_BUNDLE; + + hr = BundlePackageEngineParsePackageFromXml(pixnNode, pPackage); // TODO: Modularization + ExitOnFailure(hr, "Failed to parse BUNDLE package."); + } + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"ExePackage", -1)) { pPackage->type = BURN_PACKAGE_TYPE_EXE; @@ -231,7 +238,7 @@ extern "C" HRESULT PackagesParseFromXml( } else { - // ignore other package types for now + ExitWithRootFailure(hr, E_UNEXPECTED, "Invalid package type: %ls", bstrNodeName); } if (!pPackage->fPermanent) @@ -371,7 +378,7 @@ extern "C" void PackageUninitialize( switch (pPackage->type) { case BURN_PACKAGE_TYPE_BUNDLE: - BundlePackageEnginePackageUninitialize(pPackage); + BundlePackageEnginePackageUninitialize(pPackage); // TODO: Modularization break; case BURN_PACKAGE_TYPE_EXE: ExeEnginePackageUninitialize(pPackage); // TODO: Modularization @@ -648,7 +655,6 @@ static HRESULT ParsePatchTargetCode( IXMLDOMNodeList* pixnNodes = NULL; IXMLDOMNode* pixnNode = NULL; DWORD cNodes = 0; - BSTR bstrNodeText = NULL; BOOL fProduct; hr = XmlSelectNodes(pixnBundle, L"PatchTargetCode", &pixnNodes); @@ -688,12 +694,10 @@ static HRESULT ParsePatchTargetCode( pTargetCode->type = fProduct ? BURN_PATCH_TARGETCODE_TYPE_PRODUCT : BURN_PATCH_TARGETCODE_TYPE_UPGRADE; // prepare next iteration - ReleaseNullBSTR(bstrNodeText); ReleaseNullObject(pixnNode); } LExit: - ReleaseBSTR(bstrNodeText); ReleaseObject(pixnNode); ReleaseObject(pixnNodes); diff --git a/src/burn/engine/package.h b/src/burn/engine/package.h index deab47b7..c13c651b 100644 --- a/src/burn/engine/package.h +++ b/src/burn/engine/package.h @@ -302,6 +302,8 @@ typedef struct _BURN_PACKAGE { struct { + LPWSTR sczBundleId; + LPWSTR sczRegistrationKey; LPWSTR sczInstallArguments; LPWSTR sczRepairArguments; LPWSTR sczUninstallArguments; @@ -310,6 +312,7 @@ typedef struct _BURN_PACKAGE LPCWSTR wzAncestors; // points directly into engine state. LPCWSTR wzEngineWorkingDirectory; // points directly into engine state. + BOOL fWin64; BOOL fSupportsBurnProtocol; BURN_EXE_EXIT_CODE* rgExitCodes; @@ -324,7 +327,6 @@ typedef struct _BURN_PACKAGE LPWSTR sczInstallArguments; LPWSTR sczRepairArguments; LPWSTR sczUninstallArguments; - LPWSTR sczIgnoreDependencies; LPCWSTR wzAncestors; // points directly into engine state. LPCWSTR wzEngineWorkingDirectory; // points directly into engine state. diff --git a/src/burn/engine/plan.cpp b/src/burn/engine/plan.cpp index cb50b0c9..1d008dba 100644 --- a/src/burn/engine/plan.cpp +++ b/src/burn/engine/plan.cpp @@ -292,7 +292,6 @@ extern "C" void PlanUninitializeExecuteAction( break; case BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE: - ReleaseStr(pExecuteAction->exePackage.sczIgnoreDependencies); ReleaseStr(pExecuteAction->exePackage.sczAncestors); ReleaseStr(pExecuteAction->exePackage.sczEngineWorkingDirectory); break; @@ -1181,6 +1180,10 @@ extern "C" HRESULT PlanExecutePackage( // Add execute actions. switch (pPackage->type) { + case BURN_PACKAGE_TYPE_BUNDLE: + hr = BundlePackageEnginePlanAddPackage(pPackage, pPlan, pLog, pVariables); + break; + case BURN_PACKAGE_TYPE_EXE: hr = ExeEnginePlanAddPackage(pPackage, pPlan, pLog, pVariables); break; @@ -1506,16 +1509,16 @@ extern "C" HRESULT PlanRelatedBundlesComplete( switch (pPlan->rgExecuteActions[i].type) { - case BURN_EXECUTE_ACTION_TYPE_RELATED_BUNDLE: - packageAction = pPlan->rgExecuteActions[i].relatedBundle.action; - pPackage = &pPlan->rgExecuteActions[i].relatedBundle.pRelatedBundle->package; + case BURN_EXECUTE_ACTION_TYPE_BUNDLE_PACKAGE: + packageAction = pPlan->rgExecuteActions[i].bundlePackage.action; + pPackage = pPlan->rgExecuteActions[i].bundlePackage.pPackage; fBundle = TRUE; break; case BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE: packageAction = pPlan->rgExecuteActions[i].exePackage.action; pPackage = pPlan->rgExecuteActions[i].exePackage.pPackage; - fBundle = TRUE; + fBundle = pPackage->Exe.fBundle; break; case BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE: @@ -2751,6 +2754,10 @@ static HRESULT CalculateExecuteActions( // Calculate execute actions. switch (pPackage->type) { + case BURN_PACKAGE_TYPE_BUNDLE: + hr = BundlePackageEnginePlanCalculatePackage(pPackage); + break; + case BURN_PACKAGE_TYPE_EXE: hr = ExeEnginePlanCalculatePackage(pPackage); break; @@ -2784,7 +2791,8 @@ static BOOL NeedsCache( ) { BOOTSTRAPPER_ACTION_STATE action = fExecute ? pPackage->execute : pPackage->rollback; - if (BURN_PACKAGE_TYPE_EXE == pPackage->type) // Exe packages require the package for all operations (even uninstall). + // TODO: bundles could theoretically use package cache + if (BURN_PACKAGE_TYPE_BUNDLE == pPackage->type || BURN_PACKAGE_TYPE_EXE == pPackage->type) // Bundle and Exe packages require the package for all operations (even uninstall). { return BOOTSTRAPPER_ACTION_STATE_NONE != action; } @@ -2918,6 +2926,10 @@ static void ExecuteActionLog( LogStringLine(PlanDumpLevel, "%ls action[%u]: RELATED_BUNDLE package id: %ls, action: %hs, ignore dependencies: %ls", wzBase, iAction, pAction->relatedBundle.pRelatedBundle->package.sczId, LoggingActionStateToString(pAction->relatedBundle.action), pAction->relatedBundle.sczIgnoreDependencies); break; + case BURN_EXECUTE_ACTION_TYPE_BUNDLE_PACKAGE: + LogStringLine(PlanDumpLevel, "%ls action[%u]: BUNDLE_PACKAGE package id: %ls, action: %hs", wzBase, iAction, pAction->bundlePackage.pPackage->sczId, LoggingActionStateToString(pAction->bundlePackage.action)); + break; + case BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE: LogStringLine(PlanDumpLevel, "%ls action[%u]: EXE_PACKAGE package id: %ls, action: %hs", wzBase, iAction, pAction->exePackage.pPackage->sczId, LoggingActionStateToString(pAction->exePackage.action)); break; diff --git a/src/burn/engine/plan.h b/src/burn/engine/plan.h index 6e9a1ff5..5b6ee0fb 100644 --- a/src/burn/engine/plan.h +++ b/src/burn/engine/plan.h @@ -43,6 +43,7 @@ enum BURN_EXECUTE_ACTION_TYPE BURN_EXECUTE_ACTION_TYPE_WAIT_CACHE_PACKAGE, BURN_EXECUTE_ACTION_TYPE_UNCACHE_PACKAGE, BURN_EXECUTE_ACTION_TYPE_RELATED_BUNDLE, + BURN_EXECUTE_ACTION_TYPE_BUNDLE_PACKAGE, BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE, BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE, BURN_EXECUTE_ACTION_TYPE_MSP_TARGET, @@ -167,6 +168,13 @@ typedef struct _BURN_EXECUTE_ACTION LPWSTR sczIgnoreDependencies; LPWSTR sczAncestors; LPWSTR sczEngineWorkingDirectory; + } bundlePackage; + struct + { + BURN_PACKAGE* pPackage; + BOOTSTRAPPER_ACTION_STATE action; + LPWSTR sczAncestors; + LPWSTR sczEngineWorkingDirectory; } exePackage; struct { diff --git a/src/burn/engine/registration.cpp b/src/burn/engine/registration.cpp index a65c30d3..78f8eeb1 100644 --- a/src/burn/engine/registration.cpp +++ b/src/burn/engine/registration.cpp @@ -7,7 +7,6 @@ const LPCWSTR REGISTRY_RUN_KEY = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"; const LPCWSTR REGISTRY_RUN_ONCE_KEY = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce"; -const LPCWSTR REGISTRY_BUNDLE_INSTALLED = L"Installed"; const LPCWSTR REGISTRY_BUNDLE_DISPLAY_ICON = L"DisplayIcon"; const LPCWSTR REGISTRY_BUNDLE_DISPLAY_VERSION = L"DisplayVersion"; const LPCWSTR REGISTRY_BUNDLE_ESTIMATED_SIZE = L"EstimatedSize"; @@ -1219,7 +1218,7 @@ static HRESULT SetPaths( pRegistration->hkRoot = pRegistration->fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; // build uninstall registry key path - hr = StrAllocFormatted(&pRegistration->sczRegistrationKey, L"%s\\%s", BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY, pRegistration->sczId); + hr = StrAllocFormatted(&pRegistration->sczRegistrationKey, L"%ls\\%ls", BURN_REGISTRATION_REGISTRY_UNINSTALL_KEY, pRegistration->sczId); ExitOnFailure(hr, "Failed to build uninstall registry key path."); // build cache directory @@ -1231,7 +1230,7 @@ static HRESULT SetPaths( ExitOnFailure(hr, "Failed to build cached executable path."); // build state file path - hr = StrAllocFormatted(&pRegistration->sczStateFile, L"%s\\state.rsm", sczCacheDirectory); + hr = StrAllocFormatted(&pRegistration->sczStateFile, L"%ls\\state.rsm", sczCacheDirectory); ExitOnFailure(hr, "Failed to build state file path."); LExit: diff --git a/src/burn/engine/registration.h b/src/burn/engine/registration.h index e4dd6f4a..58c883da 100644 --- a/src/burn/engine/registration.h +++ b/src/burn/engine/registration.h @@ -22,6 +22,8 @@ const LPCWSTR BURN_REGISTRATION_REGISTRY_ENGINE_PROTOCOL_VERSION = L"EngineProto const LPCWSTR BURN_REGISTRATION_REGISTRY_BUNDLE_PROVIDER_KEY = L"BundleProviderKey"; const LPCWSTR BURN_REGISTRATION_REGISTRY_BUNDLE_TAG = L"BundleTag"; +const LPCWSTR REGISTRY_BUNDLE_INSTALLED = L"Installed"; + enum BURN_RESUME_MODE { BURN_RESUME_MODE_NONE, diff --git a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj index 35415dc3..b0159840 100644 --- a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj +++ b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj @@ -80,6 +80,7 @@ + diff --git a/src/burn/test/BurnUnitTest/PlanTest.cpp b/src/burn/test/BurnUnitTest/PlanTest.cpp index 143ca7d7..536e5351 100644 --- a/src/burn/test/BurnUnitTest/PlanTest.cpp +++ b/src/burn/test/BurnUnitTest/PlanTest.cpp @@ -10,6 +10,7 @@ static HRESULT WINAPI PlanTestBAProc( ); static LPCWSTR wzMsiTransactionManifestFileName = L"MsiTransaction_BundleAv1_manifest.xml"; +static LPCWSTR wzMultipleBundlePackageManifestFileName = L"BundlePackage_Multiple_manifest.xml"; static LPCWSTR wzSingleExeManifestFileName = L"Failure_BundleD_manifest.xml"; static LPCWSTR wzSingleMsiManifestFileName = L"BasicFunctionality_BundleA_manifest.xml"; static LPCWSTR wzSingleMsuManifestFileName = L"MsuPackageFixture_manifest.xml"; @@ -339,6 +340,121 @@ namespace Bootstrapper ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[2], L"PackageC", BURN_PACKAGE_REGISTRATION_STATE_ABSENT, BURN_PACKAGE_REGISTRATION_STATE_ABSENT); } + [Fact] + void MultipleBundlePackageInstallTest() + { + HRESULT hr = S_OK; + BURN_ENGINE_STATE engineState = { }; + BURN_ENGINE_STATE* pEngineState = &engineState; + BURN_PLAN* pPlan = &engineState.plan; + + InitializeEngineStateForCorePlan(wzMultipleBundlePackageManifestFileName, pEngineState); + DetectAttachedContainerAsAttached(pEngineState); + DetectPermanentPackagesAsPresentAndCached(pEngineState); + + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL); + NativeAssert::Succeeded(hr, "CorePlan failed"); + + Assert::Equal(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); + NativeAssert::StringEqual(L"{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}", pPlan->wzBundleId); + NativeAssert::StringEqual(L"{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}", pPlan->wzBundleProviderKey); + Assert::Equal(FALSE, pPlan->fEnabledForwardCompatibleBundle); + Assert::Equal(TRUE, pPlan->fPerMachine); + Assert::Equal(TRUE, pPlan->fCanAffectMachineState); + Assert::Equal(FALSE, pPlan->fDisableRollback); + Assert::Equal(FALSE, pPlan->fDisallowRemoval); + Assert::Equal(FALSE, pPlan->fDowngrade); + + BOOL fRollback = FALSE; + DWORD dwIndex = 0; + ValidateDependentRegistrationAction(pPlan, fRollback, dwIndex++, TRUE, L"{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}", L"{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}"); + Assert::Equal(dwIndex, pPlan->cRegistrationActions); + + fRollback = TRUE; + dwIndex = 0; + ValidateDependentRegistrationAction(pPlan, fRollback, dwIndex++, FALSE, L"{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}", L"{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}"); + Assert::Equal(dwIndex, pPlan->cRollbackRegistrationActions); + + fRollback = FALSE; + dwIndex = 0; + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageA"); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 6); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageB"); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); + Assert::Equal(dwIndex, pPlan->cCacheActions); + + fRollback = TRUE; + dwIndex = 0; + Assert::Equal(dwIndex, pPlan->cRollbackCacheActions); + + Assert::Equal(18575450ull, pPlan->qwEstimatedSize); + Assert::Equal(78462280ull, pPlan->qwCacheSizeTotal); + + fRollback = FALSE; + dwIndex = 0; + DWORD dwExecuteCheckpointId = 2; + ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"PackageA"); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteBundlePackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_INSTALL); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}", registerActions1, 1); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + dwExecuteCheckpointId += 1; // cache checkpoints + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"PackageB"); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteBundlePackage(pPlan, fRollback, dwIndex++, L"PackageB", BOOTSTRAPPER_ACTION_STATE_INSTALL); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageB", L"{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}", registerActions1, 1); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++); + Assert::Equal(dwIndex, pPlan->cExecuteActions); + + fRollback = TRUE; + dwIndex = 0; + dwExecuteCheckpointId = 2; + ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteBundlePackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}", unregisterActions1, 1); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + dwExecuteCheckpointId += 1; // cache checkpoints + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteBundlePackage(pPlan, fRollback, dwIndex++, L"PackageB", BOOTSTRAPPER_ACTION_STATE_UNINSTALL); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageB", L"{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}", unregisterActions1, 1); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++); + Assert::Equal(dwIndex, pPlan->cRollbackActions); + + Assert::Equal(2ul, pPlan->cExecutePackagesTotal); + Assert::Equal(4ul, pPlan->cOverallProgressTicksTotal); + + dwIndex = 0; + Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions); + + dwIndex = 0; + ValidateCleanAction(pPlan, dwIndex++, L"NetFx48Web"); + Assert::Equal(dwIndex, pPlan->cCleanActions); + + UINT uIndex = 0; + ValidatePlannedProvider(pPlan, uIndex++, L"{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}", NULL); + Assert::Equal(uIndex, pPlan->cPlannedProviders); + + Assert::Equal(3ul, pEngineState->packages.cPackages); + ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[1], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT); + ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[2], L"PackageB", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT); + } + [Fact] void OrphanCompatiblePackageTest() { @@ -716,7 +832,7 @@ namespace Bootstrapper ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"ExeA"); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); - ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"ExeA", BOOTSTRAPPER_ACTION_STATE_INSTALL, NULL); + ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"ExeA", BOOTSTRAPPER_ACTION_STATE_INSTALL); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++); @@ -727,7 +843,7 @@ namespace Bootstrapper dwExecuteCheckpointId = 2; ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); - ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"ExeA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, NULL); + ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"ExeA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); @@ -2125,7 +2241,7 @@ namespace Bootstrapper ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"NetFx48Web"); - ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"NetFx48Web", BOOTSTRAPPER_ACTION_STATE_INSTALL, NULL); + ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"NetFx48Web", BOOTSTRAPPER_ACTION_STATE_INSTALL); ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); dwExecuteCheckpointId += 1; // cache checkpoints ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); @@ -2678,20 +2794,33 @@ namespace Bootstrapper Assert::Equal(FALSE, pAction->fDeleted); } + void ValidateExecuteBundlePackage( + __in BURN_PLAN* pPlan, + __in BOOL fRollback, + __in DWORD dwIndex, + __in LPCWSTR wzPackageId, + __in BOOTSTRAPPER_ACTION_STATE action + ) + { + BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex); + Assert::Equal(BURN_EXECUTE_ACTION_TYPE_BUNDLE_PACKAGE, pAction->type); + NativeAssert::StringEqual(wzPackageId, pAction->bundlePackage.pPackage->sczId); + Assert::Equal(action, pAction->bundlePackage.action); + Assert::Equal(FALSE, pAction->fDeleted); + } + void ValidateExecuteExePackage( __in BURN_PLAN* pPlan, __in BOOL fRollback, __in DWORD dwIndex, __in LPCWSTR wzPackageId, - __in BOOTSTRAPPER_ACTION_STATE action, - __in LPCWSTR wzIgnoreDependencies + __in BOOTSTRAPPER_ACTION_STATE action ) { BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex); Assert::Equal(BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE, pAction->type); NativeAssert::StringEqual(wzPackageId, pAction->exePackage.pPackage->sczId); Assert::Equal(action, pAction->exePackage.action); - NativeAssert::StringEqual(wzIgnoreDependencies, pAction->exePackage.sczIgnoreDependencies); Assert::Equal(FALSE, pAction->fDeleted); } diff --git a/src/burn/test/BurnUnitTest/TestData/PlanTest/BundlePackage_Multiple_manifest.xml b/src/burn/test/BurnUnitTest/TestData/PlanTest/BundlePackage_Multiple_manifest.xml new file mode 100644 index 00000000..6c60085f --- /dev/null +++ b/src/burn/test/BurnUnitTest/TestData/PlanTest/BundlePackage_Multiple_manifest.xml @@ -0,0 +1 @@ + \ No newline at end of file -- cgit v1.2.3-55-g6feb