From a37208d9a26ec7886870cc17f0726676a285bf7f Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Thu, 25 Aug 2022 15:06:04 -0500 Subject: Make sure error codes are translated correctly for per-machine packages. --- src/burn/engine/bundlepackageengine.cpp | 2 +- src/burn/engine/elevation.cpp | 300 ++++++++--------- src/burn/engine/engine.mc | 7 + src/burn/engine/exeengine.cpp | 7 +- src/burn/engine/exeengine.h | 1 + src/burn/engine/logging.cpp | 19 ++ src/burn/engine/logging.h | 4 + src/burn/engine/pipe.cpp | 2 +- src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj | 1 + .../test/BurnUnitTest/BurnUnitTest.vcxproj.filters | 3 + src/burn/test/BurnUnitTest/ExitCodeTest.cpp | 361 +++++++++++++++++++++ src/burn/test/BurnUnitTest/precomp.h | 1 + .../XunitExtensions/SpecificReturnCodeException.cs | 9 +- .../XunitExtensions/WixAssert.cs | 2 +- 14 files changed, 554 insertions(+), 165 deletions(-) create mode 100644 src/burn/test/BurnUnitTest/ExitCodeTest.cpp (limited to 'src') diff --git a/src/burn/engine/bundlepackageengine.cpp b/src/burn/engine/bundlepackageengine.cpp index 8896fdd0..95f5acbc 100644 --- a/src/burn/engine/bundlepackageengine.cpp +++ b/src/burn/engine/bundlepackageengine.cpp @@ -1014,7 +1014,7 @@ static HRESULT ExecuteBundle( ExitOnFailure(hr, "Failed to run BUNDLE process"); } - hr = ExeEngineHandleExitCode(pPackage->Bundle.rgExitCodes, pPackage->Bundle.cExitCodes, dwExitCode, pRestart); + hr = ExeEngineHandleExitCode(pPackage->Bundle.rgExitCodes, pPackage->Bundle.cExitCodes, pPackage->sczId, dwExitCode, pRestart); ExitOnRootFailure(hr, "Process returned error: 0x%x", dwExitCode); LExit: diff --git a/src/burn/engine/elevation.cpp b/src/burn/engine/elevation.cpp index adc3aad9..c27289c5 100644 --- a/src/burn/engine/elevation.cpp +++ b/src/burn/engine/elevation.cpp @@ -53,6 +53,7 @@ typedef enum _BURN_ELEVATION_MESSAGE_TYPE BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_NETFX_FILES_IN_USE, BURN_ELEVATION_MESSAGE_TYPE_LAUNCH_APPROVED_EXE_PROCESSID, BURN_ELEVATION_MESSAGE_TYPE_PROGRESS_ROUTINE, + BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_ACTION_COMPLETE, } BURN_ELEVATION_MESSAGE_TYPE; @@ -76,12 +77,14 @@ typedef struct _BURN_ELEVATION_GENERIC_MESSAGE_CONTEXT { PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler; LPVOID pvContext; + BOOTSTRAPPER_APPLY_RESTART restart; } BURN_ELEVATION_GENERIC_MESSAGE_CONTEXT; typedef struct _BURN_ELEVATION_MSI_MESSAGE_CONTEXT { PFN_MSIEXECUTEMESSAGEHANDLER pfnMessageHandler; LPVOID pvContext; + BOOTSTRAPPER_APPLY_RESTART restart; } BURN_ELEVATION_MSI_MESSAGE_CONTEXT; typedef struct _BURN_ELEVATION_LAUNCH_APPROVED_EXE_MESSAGE_CONTEXT @@ -166,9 +169,11 @@ static HRESULT ProcessElevatedChildCacheMessage( __in_opt LPVOID pvContext, __out DWORD* pdwResult ); -static HRESULT ProcessResult( - __in DWORD dwResult, - __out BOOTSTRAPPER_APPLY_RESTART* pRestart +static HRESULT ProcessExecuteActionCompleteMessage( + __in BYTE* pbData, + __in DWORD cbData, + __out BOOTSTRAPPER_APPLY_RESTART* pRestart, + __out DWORD* pdwResult ); static HRESULT OnApplyInitialize( __in HANDLE hPipe, @@ -246,7 +251,8 @@ static HRESULT OnExecuteRelatedBundle( __in BURN_RELATED_BUNDLES* pRelatedBundles, __in BURN_VARIABLES* pVariables, __in BYTE* pbData, - __in SIZE_T cbData + __in SIZE_T cbData, + __out BOOTSTRAPPER_APPLY_RESTART* pRestart ); static HRESULT OnExecuteBundlePackage( __in HANDLE hPipe, @@ -254,7 +260,8 @@ static HRESULT OnExecuteBundlePackage( __in BURN_PACKAGES* pPackages, __in BURN_VARIABLES* pVariables, __in BYTE* pbData, - __in SIZE_T cbData + __in SIZE_T cbData, + __out BOOTSTRAPPER_APPLY_RESTART* pRestart ); static HRESULT OnExecuteExePackage( __in HANDLE hPipe, @@ -262,7 +269,8 @@ static HRESULT OnExecuteExePackage( __in BURN_PACKAGES* pPackages, __in BURN_VARIABLES* pVariables, __in BYTE* pbData, - __in SIZE_T cbData + __in SIZE_T cbData, + __out BOOTSTRAPPER_APPLY_RESTART* pRestart ); static HRESULT OnExecuteMsiPackage( __in HANDLE hPipe, @@ -270,7 +278,8 @@ static HRESULT OnExecuteMsiPackage( __in BURN_PACKAGES* pPackages, __in BURN_VARIABLES* pVariables, __in BYTE* pbData, - __in SIZE_T cbData + __in SIZE_T cbData, + __out BOOTSTRAPPER_APPLY_RESTART* pRestart ); static HRESULT OnExecuteMspPackage( __in HANDLE hPipe, @@ -278,7 +287,8 @@ static HRESULT OnExecuteMspPackage( __in BURN_PACKAGES* pPackages, __in BURN_VARIABLES* pVariables, __in BYTE* pbData, - __in SIZE_T cbData + __in SIZE_T cbData, + __out BOOTSTRAPPER_APPLY_RESTART* pRestart ); static HRESULT OnExecuteMsuPackage( __in HANDLE hPipe, @@ -286,7 +296,8 @@ static HRESULT OnExecuteMsuPackage( __in BURN_PACKAGES* pPackages, __in BURN_VARIABLES* pVariables, __in BYTE* pbData, - __in SIZE_T cbData + __in SIZE_T cbData, + __out BOOTSTRAPPER_APPLY_RESTART* pRestart ); static HRESULT OnUninstallMsiCompatiblePackage( __in HANDLE hPipe, @@ -294,7 +305,8 @@ static HRESULT OnUninstallMsiCompatiblePackage( __in BURN_PACKAGES* pPackages, __in BURN_VARIABLES* pVariables, __in BYTE* pbData, - __in SIZE_T cbData + __in SIZE_T cbData, + __out BOOTSTRAPPER_APPLY_RESTART* pRestart ); static HRESULT OnExecutePackageProviderAction( __in BURN_PACKAGES* pPackages, @@ -380,6 +392,10 @@ static HRESULT ElevatedOnSystemRestorePointComplete( __in HANDLE hPipe, __in HRESULT hrStatus ); +static HRESULT ElevatedOnExecuteActionComplete( + __in HANDLE hPipe, + __in BOOTSTRAPPER_APPLY_RESTART restart + ); // function definitions @@ -868,7 +884,8 @@ extern "C" HRESULT ElevationExecuteRelatedBundle( hr = PipeSendMessage(hPipe, BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_RELATED_BUNDLE, pbData, cbData, ProcessGenericExecuteMessages, &context, &dwResult); ExitOnFailure(hr, "Failed to send BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_RELATED_BUNDLE message to per-machine process."); - hr = ProcessResult(dwResult, pRestart); + hr = static_cast(dwResult); + *pRestart = context.restart; LExit: ReleaseBuffer(pbData); @@ -931,7 +948,8 @@ extern "C" HRESULT ElevationExecuteBundlePackage( 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); + hr = static_cast(dwResult); + *pRestart = context.restart; LExit: ReleaseBuffer(pbData); @@ -985,7 +1003,8 @@ extern "C" HRESULT ElevationExecuteExePackage( hr = PipeSendMessage(hPipe, BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_EXE_PACKAGE, pbData, cbData, ProcessGenericExecuteMessages, &context, &dwResult); ExitOnFailure(hr, "Failed to send BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_EXE_PACKAGE message to per-machine process."); - hr = ProcessResult(dwResult, pRestart); + hr = static_cast(dwResult); + *pRestart = context.restart; LExit: ReleaseBuffer(pbData); @@ -1155,7 +1174,8 @@ extern "C" HRESULT ElevationExecuteMsiPackage( hr = PipeSendMessage(hPipe, BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_MSI_PACKAGE, pbData, cbData, ProcessMsiPackageMessages, &context, &dwResult); ExitOnFailure(hr, "Failed to send BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_MSI_PACKAGE message to per-machine process."); - hr = ProcessResult(dwResult, pRestart); + hr = static_cast(dwResult); + *pRestart = context.restart; LExit: ReleaseBuffer(pbData); @@ -1234,7 +1254,8 @@ extern "C" HRESULT ElevationExecuteMspPackage( hr = PipeSendMessage(hPipe, BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_MSP_PACKAGE, pbData, cbData, ProcessMsiPackageMessages, &context, &dwResult); ExitOnFailure(hr, "Failed to send BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_MSP_PACKAGE message to per-machine process."); - hr = ProcessResult(dwResult, pRestart); + hr = static_cast(dwResult); + *pRestart = context.restart; LExit: ReleaseBuffer(pbData); @@ -1285,7 +1306,8 @@ extern "C" HRESULT ElevationExecuteMsuPackage( hr = PipeSendMessage(hPipe, BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_MSU_PACKAGE, pbData, cbData, ProcessGenericExecuteMessages, &context, &dwResult); ExitOnFailure(hr, "Failed to send BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_MSU_PACKAGE message to per-machine process."); - hr = ProcessResult(dwResult, pRestart); + hr = static_cast(dwResult); + *pRestart = context.restart; LExit: ReleaseBuffer(pbData); @@ -1337,7 +1359,8 @@ extern "C" HRESULT ElevationUninstallMsiCompatiblePackage( hr = PipeSendMessage(hPipe, BURN_ELEVATION_MESSAGE_TYPE_UNINSTALL_MSI_COMPATIBLE_PACKAGE, pbData, cbData, ProcessMsiPackageMessages, &context, &dwResult); ExitOnFailure(hr, "Failed to send BURN_ELEVATION_MESSAGE_TYPE_UNINSTALL_MSI_COMPATIBLE_PACKAGE message to per-machine process."); - hr = ProcessResult(dwResult, pRestart); + hr = static_cast(dwResult); + *pRestart = context.restart; LExit: ReleaseBuffer(pbData); @@ -1355,7 +1378,6 @@ extern "C" HRESULT ElevationExecutePackageProviderAction( BYTE* pbData = NULL; SIZE_T cbData = 0; DWORD dwResult = 0; - BOOTSTRAPPER_APPLY_RESTART restart = BOOTSTRAPPER_APPLY_RESTART_NONE; // Serialize the message data. hr = BuffWriteString(&pbData, &cbData, pExecuteAction->packageProvider.pPackage->sczId); @@ -1377,9 +1399,6 @@ extern "C" HRESULT ElevationExecutePackageProviderAction( hr = PipeSendMessage(hPipe, BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PACKAGE_PROVIDER, pbData, cbData, NULL, NULL, &dwResult); ExitOnFailure(hr, "Failed to send BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PACKAGE_PROVIDER message to per-machine process."); - // Ignore the restart since this action only results in registry writes. - hr = ProcessResult(dwResult, &restart); - LExit: ReleaseBuffer(pbData); @@ -1396,7 +1415,6 @@ extern "C" HRESULT ElevationExecutePackageDependencyAction( BYTE* pbData = NULL; SIZE_T cbData = 0; DWORD dwResult = 0; - BOOTSTRAPPER_APPLY_RESTART restart = BOOTSTRAPPER_APPLY_RESTART_NONE; // Serialize the message data. hr = BuffWriteString(&pbData, &cbData, pExecuteAction->packageDependency.pPackage->sczId); @@ -1421,9 +1439,6 @@ extern "C" HRESULT ElevationExecutePackageDependencyAction( hr = PipeSendMessage(hPipe, BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PACKAGE_DEPENDENCY, pbData, cbData, NULL, NULL, &dwResult); ExitOnFailure(hr, "Failed to send BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PACKAGE_DEPENDENCY message to per-machine process."); - // Ignore the restart since this action only results in registry writes. - hr = ProcessResult(dwResult, &restart); - LExit: ReleaseBuffer(pbData); @@ -1839,6 +1854,14 @@ static HRESULT ProcessGenericExecuteMessages( LPWSTR* rgwzFiles = NULL; GENERIC_EXECUTE_MESSAGE message = { }; + if (BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_ACTION_COMPLETE == pMsg->dwMessage) + { + hr = ProcessExecuteActionCompleteMessage((BYTE*)pMsg->pvData, pMsg->cbData, &pContext->restart, pdwResult); + ExitOnFailure(hr, "Failed to process BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_ACTION_COMPLETE message."); + + ExitFunction(); + } + hr = BuffReadNumber((BYTE*)pMsg->pvData, pMsg->cbData, &iData, &message.dwUIHint); ExitOnFailure(hr, "Failed to allowed results."); @@ -1939,6 +1962,14 @@ static HRESULT ProcessMsiPackageMessages( LPWSTR sczMessage = NULL; BOOL fRestartManager = FALSE; + if (BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_ACTION_COMPLETE == pMsg->dwMessage) + { + hr = ProcessExecuteActionCompleteMessage((BYTE*)pMsg->pvData, pMsg->cbData, &pContext->restart, pdwResult); + ExitOnFailure(hr, "Failed to process BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_ACTION_COMPLETE message."); + + ExitFunction(); + } + // Read MSI extended message data. hr = BuffReadNumber((BYTE*)pMsg->pvData, pMsg->cbData, &iData, &cMsiData); ExitOnFailure(hr, "Failed to read MSI data count."); @@ -2102,7 +2133,8 @@ static HRESULT ProcessElevatedChildMessage( HRESULT hr = S_OK; BURN_ELEVATION_CHILD_MESSAGE_CONTEXT* pContext = static_cast(pvContext); HRESULT hrResult = S_OK; - DWORD dwPid = 0; + BOOTSTRAPPER_APPLY_RESTART restart = BOOTSTRAPPER_APPLY_RESTART_NONE; + BOOL fSendRestart = FALSE; switch (pMsg->dwMessage) { @@ -2143,27 +2175,33 @@ static HRESULT ProcessElevatedChildMessage( break; case BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_RELATED_BUNDLE: - hrResult = OnExecuteRelatedBundle(pContext->hPipe, pContext->pCache, &pContext->pRegistration->relatedBundles, pContext->pVariables, (BYTE*)pMsg->pvData, pMsg->cbData); + hrResult = OnExecuteRelatedBundle(pContext->hPipe, pContext->pCache, &pContext->pRegistration->relatedBundles, pContext->pVariables, (BYTE*)pMsg->pvData, pMsg->cbData, &restart); + fSendRestart = TRUE; break; case BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_BUNDLE_PACKAGE: - hrResult = OnExecuteBundlePackage(pContext->hPipe, pContext->pCache, pContext->pPackages, pContext->pVariables, (BYTE*)pMsg->pvData, pMsg->cbData); + hrResult = OnExecuteBundlePackage(pContext->hPipe, pContext->pCache, pContext->pPackages, pContext->pVariables, (BYTE*)pMsg->pvData, pMsg->cbData, &restart); + fSendRestart = TRUE; break; case BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_EXE_PACKAGE: - hrResult = OnExecuteExePackage(pContext->hPipe, pContext->pCache, pContext->pPackages, pContext->pVariables, (BYTE*)pMsg->pvData, pMsg->cbData); + hrResult = OnExecuteExePackage(pContext->hPipe, pContext->pCache, pContext->pPackages, pContext->pVariables, (BYTE*)pMsg->pvData, pMsg->cbData, &restart); + fSendRestart = TRUE; break; case BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_MSI_PACKAGE: - hrResult = OnExecuteMsiPackage(pContext->hPipe, pContext->pCache, pContext->pPackages, pContext->pVariables, (BYTE*)pMsg->pvData, pMsg->cbData); + hrResult = OnExecuteMsiPackage(pContext->hPipe, pContext->pCache, pContext->pPackages, pContext->pVariables, (BYTE*)pMsg->pvData, pMsg->cbData, &restart); + fSendRestart = TRUE; break; case BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_MSP_PACKAGE: - hrResult = OnExecuteMspPackage(pContext->hPipe, pContext->pCache, pContext->pPackages, pContext->pVariables, (BYTE*)pMsg->pvData, pMsg->cbData); + hrResult = OnExecuteMspPackage(pContext->hPipe, pContext->pCache, pContext->pPackages, pContext->pVariables, (BYTE*)pMsg->pvData, pMsg->cbData, &restart); + fSendRestart = TRUE; break; case BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_MSU_PACKAGE: - hrResult = OnExecuteMsuPackage(pContext->hPipe, pContext->pCache, pContext->pPackages, pContext->pVariables, (BYTE*)pMsg->pvData, pMsg->cbData); + hrResult = OnExecuteMsuPackage(pContext->hPipe, pContext->pCache, pContext->pPackages, pContext->pVariables, (BYTE*)pMsg->pvData, pMsg->cbData, &restart); + fSendRestart = TRUE; break; case BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PACKAGE_PROVIDER: @@ -2183,7 +2221,8 @@ static HRESULT ProcessElevatedChildMessage( break; case BURN_ELEVATION_MESSAGE_TYPE_UNINSTALL_MSI_COMPATIBLE_PACKAGE: - hrResult = OnUninstallMsiCompatiblePackage(pContext->hPipe, pContext->pCache, pContext->pPackages, pContext->pVariables, (BYTE*)pMsg->pvData, pMsg->cbData); + hrResult = OnUninstallMsiCompatiblePackage(pContext->hPipe, pContext->pCache, pContext->pPackages, pContext->pVariables, (BYTE*)pMsg->pvData, pMsg->cbData, &restart); + fSendRestart = TRUE; break; case BURN_ELEVATION_MESSAGE_TYPE_CLEAN_COMPATIBLE_PACKAGE: @@ -2191,11 +2230,16 @@ static HRESULT ProcessElevatedChildMessage( break; default: - hr = E_INVALIDARG; - ExitOnRootFailure(hr, "Unexpected elevated message sent to child process, msg: %u", pMsg->dwMessage); + ExitWithRootFailure(hr, E_INVALIDARG, "Unexpected elevated message sent to child process, msg: %u", pMsg->dwMessage); } - *pdwResult = dwPid ? dwPid : (DWORD)hrResult; + if (fSendRestart) + { + hr = ElevatedOnExecuteActionComplete(pContext->hPipe, restart); + ExitOnFailure(hr, "ElevatedOnExecuteActionComplete failed."); + } + + *pdwResult = (DWORD)hrResult; LExit: return hr; @@ -2245,23 +2289,22 @@ LExit: return hr; } -static HRESULT ProcessResult( - __in DWORD dwResult, - __out BOOTSTRAPPER_APPLY_RESTART* pRestart +static HRESULT ProcessExecuteActionCompleteMessage( + __in BYTE* pbData, + __in DWORD cbData, + __out BOOTSTRAPPER_APPLY_RESTART* pRestart, + __out DWORD* pdwResult ) { - HRESULT hr = static_cast(dwResult); - if (HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED) == hr) - { - *pRestart = BOOTSTRAPPER_APPLY_RESTART_REQUIRED; - hr = S_OK; - } - else if (HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_INITIATED) == hr) - { - *pRestart = BOOTSTRAPPER_APPLY_RESTART_INITIATED; - hr = S_OK; - } + HRESULT hr = S_OK; + SIZE_T iData = 0; + + hr = BuffReadNumber(pbData, cbData, &iData, reinterpret_cast(pRestart)); + ExitOnFailure(hr, "Failed to read execute action restart result."); + + *pdwResult = (DWORD)hr; +LExit: return hr; } @@ -2759,7 +2802,8 @@ static HRESULT OnExecuteRelatedBundle( __in BURN_RELATED_BUNDLES* pRelatedBundles, __in BURN_VARIABLES* pVariables, __in BYTE* pbData, - __in SIZE_T cbData + __in SIZE_T cbData, + __out BOOTSTRAPPER_APPLY_RESTART* pRestart ) { HRESULT hr = S_OK; @@ -2771,7 +2815,7 @@ static HRESULT OnExecuteRelatedBundle( LPWSTR sczIgnoreDependencies = NULL; LPWSTR sczAncestors = NULL; LPWSTR sczEngineWorkingDirectory = NULL; - BOOTSTRAPPER_APPLY_RESTART bundleRestart = BOOTSTRAPPER_APPLY_RESTART_NONE; + *pRestart = BOOTSTRAPPER_APPLY_RESTART_NONE; executeAction.type = BURN_EXECUTE_ACTION_TYPE_RELATED_BUNDLE; @@ -2826,7 +2870,7 @@ static HRESULT OnExecuteRelatedBundle( } // Execute related bundle. - hr = BundlePackageEngineExecuteRelatedBundle(&executeAction, pCache, pVariables, static_cast(dwRollback), GenericExecuteMessageHandler, hPipe, &bundleRestart); + hr = BundlePackageEngineExecuteRelatedBundle(&executeAction, pCache, pVariables, static_cast(dwRollback), GenericExecuteMessageHandler, hPipe, pRestart); ExitOnFailure(hr, "Failed to execute related bundle."); LExit: @@ -2836,18 +2880,6 @@ LExit: 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; } @@ -2857,7 +2889,8 @@ static HRESULT OnExecuteBundlePackage( __in BURN_PACKAGES* pPackages, __in BURN_VARIABLES* pVariables, __in BYTE* pbData, - __in SIZE_T cbData + __in SIZE_T cbData, + __out BOOTSTRAPPER_APPLY_RESTART* pRestart ) { HRESULT hr = S_OK; @@ -2869,7 +2902,7 @@ static HRESULT OnExecuteBundlePackage( LPWSTR sczIgnoreDependencies = NULL; LPWSTR sczAncestors = NULL; LPWSTR sczEngineWorkingDirectory = NULL; - BOOTSTRAPPER_APPLY_RESTART bundleRestart = BOOTSTRAPPER_APPLY_RESTART_NONE; + *pRestart = BOOTSTRAPPER_APPLY_RESTART_NONE; executeAction.type = BURN_EXECUTE_ACTION_TYPE_BUNDLE_PACKAGE; @@ -2930,7 +2963,7 @@ static HRESULT OnExecuteBundlePackage( } // Execute BUNDLE package. - hr = BundlePackageEngineExecutePackage(&executeAction, pCache, pVariables, fRollback, fCacheAvailable, GenericExecuteMessageHandler, hPipe, &bundleRestart); + hr = BundlePackageEngineExecutePackage(&executeAction, pCache, pVariables, fRollback, fCacheAvailable, GenericExecuteMessageHandler, hPipe, pRestart); ExitOnFailure(hr, "Failed to execute BUNDLE package."); LExit: @@ -2940,18 +2973,6 @@ LExit: 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; } @@ -2961,7 +2982,8 @@ static HRESULT OnExecuteExePackage( __in BURN_PACKAGES* pPackages, __in BURN_VARIABLES* pVariables, __in BYTE* pbData, - __in SIZE_T cbData + __in SIZE_T cbData, + __out BOOTSTRAPPER_APPLY_RESTART* pRestart ) { HRESULT hr = S_OK; @@ -2971,7 +2993,7 @@ static HRESULT OnExecuteExePackage( BURN_EXECUTE_ACTION executeAction = { }; LPWSTR sczAncestors = NULL; LPWSTR sczEngineWorkingDirectory = NULL; - BOOTSTRAPPER_APPLY_RESTART exeRestart = BOOTSTRAPPER_APPLY_RESTART_NONE; + *pRestart = BOOTSTRAPPER_APPLY_RESTART_NONE; executeAction.type = BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE; @@ -3016,7 +3038,7 @@ static HRESULT OnExecuteExePackage( } // Execute EXE package. - hr = ExeEngineExecutePackage(&executeAction, pCache, pVariables, static_cast(dwRollback), GenericExecuteMessageHandler, hPipe, &exeRestart); + hr = ExeEngineExecutePackage(&executeAction, pCache, pVariables, static_cast(dwRollback), GenericExecuteMessageHandler, hPipe, pRestart); ExitOnFailure(hr, "Failed to execute EXE package."); LExit: @@ -3025,18 +3047,6 @@ LExit: ReleaseStr(sczPackage); PlanUninitializeExecuteAction(&executeAction); - if (SUCCEEDED(hr)) - { - if (BOOTSTRAPPER_APPLY_RESTART_REQUIRED == exeRestart) - { - hr = HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED); - } - else if (BOOTSTRAPPER_APPLY_RESTART_INITIATED == exeRestart) - { - hr = HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_INITIATED); - } - } - return hr; } @@ -3046,7 +3056,8 @@ static HRESULT OnExecuteMsiPackage( __in BURN_PACKAGES* pPackages, __in BURN_VARIABLES* pVariables, __in BYTE* pbData, - __in SIZE_T cbData + __in SIZE_T cbData, + __out BOOTSTRAPPER_APPLY_RESTART* pRestart ) { HRESULT hr = S_OK; @@ -3055,7 +3066,7 @@ static HRESULT OnExecuteMsiPackage( HWND hwndParent = NULL; BOOL fRollback = FALSE; BURN_EXECUTE_ACTION executeAction = { }; - BOOTSTRAPPER_APPLY_RESTART msiRestart = BOOTSTRAPPER_APPLY_RESTART_NONE; + *pRestart = BOOTSTRAPPER_APPLY_RESTART_NONE; executeAction.type = BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE; @@ -3124,25 +3135,13 @@ static HRESULT OnExecuteMsiPackage( } // Execute MSI package. - hr = MsiEngineExecutePackage(hwndParent, &executeAction, pCache, pVariables, fRollback, MsiExecuteMessageHandler, hPipe, &msiRestart); + hr = MsiEngineExecutePackage(hwndParent, &executeAction, pCache, pVariables, fRollback, MsiExecuteMessageHandler, hPipe, pRestart); ExitOnFailure(hr, "Failed to execute MSI package."); LExit: ReleaseStr(sczPackage); PlanUninitializeExecuteAction(&executeAction); - if (SUCCEEDED(hr)) - { - if (BOOTSTRAPPER_APPLY_RESTART_REQUIRED == msiRestart) - { - hr = HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED); - } - else if (BOOTSTRAPPER_APPLY_RESTART_INITIATED == msiRestart) - { - hr = HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_INITIATED); - } - } - return hr; } @@ -3152,7 +3151,8 @@ static HRESULT OnExecuteMspPackage( __in BURN_PACKAGES* pPackages, __in BURN_VARIABLES* pVariables, __in BYTE* pbData, - __in SIZE_T cbData + __in SIZE_T cbData, + __out BOOTSTRAPPER_APPLY_RESTART* pRestart ) { HRESULT hr = S_OK; @@ -3161,7 +3161,7 @@ static HRESULT OnExecuteMspPackage( HWND hwndParent = NULL; BOOL fRollback = FALSE; BURN_EXECUTE_ACTION executeAction = { }; - BOOTSTRAPPER_APPLY_RESTART restart = BOOTSTRAPPER_APPLY_RESTART_NONE; + *pRestart = BOOTSTRAPPER_APPLY_RESTART_NONE; executeAction.type = BURN_EXECUTE_ACTION_TYPE_MSP_TARGET; @@ -3228,25 +3228,13 @@ static HRESULT OnExecuteMspPackage( } // Execute MSP package. - hr = MspEngineExecutePackage(hwndParent, &executeAction, pCache, pVariables, fRollback, MsiExecuteMessageHandler, hPipe, &restart); + hr = MspEngineExecutePackage(hwndParent, &executeAction, pCache, pVariables, fRollback, MsiExecuteMessageHandler, hPipe, pRestart); ExitOnFailure(hr, "Failed to execute MSP package."); LExit: ReleaseStr(sczPackage); PlanUninitializeExecuteAction(&executeAction); - if (SUCCEEDED(hr)) - { - if (BOOTSTRAPPER_APPLY_RESTART_REQUIRED == restart) - { - hr = HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED); - } - else if (BOOTSTRAPPER_APPLY_RESTART_INITIATED == restart) - { - hr = HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_INITIATED); - } - } - return hr; } @@ -3256,7 +3244,8 @@ static HRESULT OnExecuteMsuPackage( __in BURN_PACKAGES* pPackages, __in BURN_VARIABLES* pVariables, __in BYTE* pbData, - __in SIZE_T cbData + __in SIZE_T cbData, + __out BOOTSTRAPPER_APPLY_RESTART* pRestart ) { HRESULT hr = S_OK; @@ -3265,7 +3254,7 @@ static HRESULT OnExecuteMsuPackage( DWORD dwRollback = 0; DWORD dwStopWusaService = 0; BURN_EXECUTE_ACTION executeAction = { }; - BOOTSTRAPPER_APPLY_RESTART restart = BOOTSTRAPPER_APPLY_RESTART_NONE; + *pRestart = BOOTSTRAPPER_APPLY_RESTART_NONE; executeAction.type = BURN_EXECUTE_ACTION_TYPE_MSU_PACKAGE; @@ -3294,25 +3283,13 @@ static HRESULT OnExecuteMsuPackage( } // execute MSU package - hr = MsuEngineExecutePackage(&executeAction, pCache, pVariables, static_cast(dwRollback), static_cast(dwStopWusaService), GenericExecuteMessageHandler, hPipe, &restart); + hr = MsuEngineExecutePackage(&executeAction, pCache, pVariables, static_cast(dwRollback), static_cast(dwStopWusaService), GenericExecuteMessageHandler, hPipe, pRestart); ExitOnFailure(hr, "Failed to execute MSU package."); LExit: ReleaseStr(sczPackage); PlanUninitializeExecuteAction(&executeAction); - if (SUCCEEDED(hr)) - { - if (BOOTSTRAPPER_APPLY_RESTART_REQUIRED == restart) - { - hr = HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED); - } - else if (BOOTSTRAPPER_APPLY_RESTART_INITIATED == restart) - { - hr = HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_INITIATED); - } - } - return hr; } @@ -3322,7 +3299,8 @@ static HRESULT OnUninstallMsiCompatiblePackage( __in BURN_PACKAGES* pPackages, __in BURN_VARIABLES* pVariables, __in BYTE* pbData, - __in SIZE_T cbData + __in SIZE_T cbData, + __out BOOTSTRAPPER_APPLY_RESTART* pRestart ) { HRESULT hr = S_OK; @@ -3334,7 +3312,7 @@ static HRESULT OnUninstallMsiCompatiblePackage( BURN_EXECUTE_ACTION executeAction = { }; BURN_PACKAGE* pPackage = NULL; BURN_COMPATIBLE_PACKAGE* pCompatiblePackage = NULL; - BOOTSTRAPPER_APPLY_RESTART msiRestart = BOOTSTRAPPER_APPLY_RESTART_NONE; + *pRestart = BOOTSTRAPPER_APPLY_RESTART_NONE; executeAction.type = BURN_EXECUTE_ACTION_TYPE_MSI_PACKAGE; @@ -3375,26 +3353,14 @@ static HRESULT OnUninstallMsiCompatiblePackage( } // Uninstall MSI compatible package. - hr = MsiEngineUninstallCompatiblePackage(hwndParent, &executeAction, pCache, pVariables, fRollback, MsiExecuteMessageHandler, hPipe, &msiRestart); - ExitOnFailure(hr, "Failed to execute MSI package."); + hr = MsiEngineUninstallCompatiblePackage(hwndParent, &executeAction, pCache, pVariables, fRollback, MsiExecuteMessageHandler, hPipe, pRestart); + ExitOnFailure(hr, "Failed to execute compatible MSI package."); LExit: ReleaseStr(sczPackageId); ReleaseStr(sczCompatiblePackageId); PlanUninitializeExecuteAction(&executeAction); - if (SUCCEEDED(hr)) - { - if (BOOTSTRAPPER_APPLY_RESTART_REQUIRED == msiRestart) - { - hr = HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED); - } - else if (BOOTSTRAPPER_APPLY_RESTART_INITIATED == msiRestart) - { - hr = HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_INITIATED); - } - } - return hr; } @@ -4096,3 +4062,25 @@ LExit: return hr; } + +static HRESULT ElevatedOnExecuteActionComplete( + __in HANDLE hPipe, + __in BOOTSTRAPPER_APPLY_RESTART restart + ) +{ + HRESULT hr = S_OK; + BYTE* pbSendData = NULL; + SIZE_T cbSendData = 0; + DWORD dwResult = 0; + + hr = BuffWriteNumber(&pbSendData, &cbSendData, restart); + ExitOnFailure(hr, "Failed to write the restart type to message buffer."); + + hr = PipeSendMessage(hPipe, BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_ACTION_COMPLETE, pbSendData, cbSendData, NULL, NULL, &dwResult); + ExitOnFailure(hr, "Failed to send BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_ACTION_COMPLETE message to per-user process."); + +LExit: + ReleaseBuffer(pbSendData); + + return hr; +} diff --git a/src/burn/engine/engine.mc b/src/burn/engine/engine.mc index 08269ea0..41c17270 100644 --- a/src/burn/engine/engine.mc +++ b/src/burn/engine/engine.mc @@ -982,6 +982,13 @@ Language=English Skipping rollback of package: %1!ls! due to abandoning its process. Continuing... . +MessageId=366 +Severity=Success +SymbolicName=MSG_EXECUTE_PACKAGE_PROCESS_EXITED +Language=English +The process for package: %1!ls! exited with code: %2!u!. The exit code has been translated to type: %3!hs! and restart: %4!hs!. +. + MessageId=370 Severity=Success SymbolicName=MSG_SESSION_BEGIN diff --git a/src/burn/engine/exeengine.cpp b/src/burn/engine/exeengine.cpp index b4898d42..3cb9c72a 100644 --- a/src/burn/engine/exeengine.cpp +++ b/src/burn/engine/exeengine.cpp @@ -648,7 +648,7 @@ extern "C" HRESULT ExeEngineExecutePackage( ExitOnFailure(hr, "Failed to run EXE process"); } - hr = ExeEngineHandleExitCode(pPackage->Exe.rgExitCodes, pPackage->Exe.cExitCodes, dwExitCode, pRestart); + hr = ExeEngineHandleExitCode(pPackage->Exe.rgExitCodes, pPackage->Exe.cExitCodes, pPackage->sczId, dwExitCode, pRestart); ExitOnRootFailure(hr, "Process returned error: 0x%x", dwExitCode); LExit: @@ -759,7 +759,7 @@ extern "C" HRESULT ExeEngineRunProcess( hr = (IDOK == nResult || IDNOACTION == nResult) ? S_OK : IDCANCEL == nResult ? HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT) : HRESULT_FROM_WIN32(ERROR_INSTALL_FAILURE); ExitOnRootFailure(hr, "Bootstrapper application aborted during package process progress."); - hr = ProcWaitForCompletion(pi.hProcess, 500, pdwExitCode); + hr = CoreWaitForProcCompletion(pi.hProcess, 500, pdwExitCode); if (HRESULT_FROM_WIN32(WAIT_TIMEOUT) != hr) { ExitOnFailure(hr, "Failed to wait for executable to complete: %ls", wzExecutablePath); @@ -948,6 +948,7 @@ LExit: extern "C" HRESULT ExeEngineHandleExitCode( __in BURN_EXE_EXIT_CODE* rgCustomExitCodes, __in DWORD cCustomExitCodes, + __in_z LPCWSTR wzId, __in DWORD dwExitCode, __out BOOTSTRAPPER_APPLY_RESTART* pRestart ) @@ -1029,6 +1030,8 @@ extern "C" HRESULT ExeEngineHandleExitCode( } //LExit: + LogId(REPORT_STANDARD, MSG_EXECUTE_PACKAGE_PROCESS_EXITED, wzId, dwExitCode, LoggingExitCodeTypeToString(typeCode), LoggingRestartToString(*pRestart)); + return hr; } diff --git a/src/burn/engine/exeengine.h b/src/burn/engine/exeengine.h index b74d5c9a..75eb9dc2 100644 --- a/src/burn/engine/exeengine.h +++ b/src/burn/engine/exeengine.h @@ -69,6 +69,7 @@ HRESULT ExeEngineParseCommandLineArgumentsFromXml( HRESULT ExeEngineHandleExitCode( __in BURN_EXE_EXIT_CODE* rgCustomExitCodes, __in DWORD cCustomExitCodes, + __in_z LPCWSTR wzId, __in DWORD dwExitCode, __out BOOTSTRAPPER_APPLY_RESTART* pRestart ); diff --git a/src/burn/engine/logging.cpp b/src/burn/engine/logging.cpp index 885e2c84..38c9d2d5 100644 --- a/src/burn/engine/logging.cpp +++ b/src/burn/engine/logging.cpp @@ -531,6 +531,25 @@ extern "C" LPCSTR LoggingTrueFalseToString( return "false"; } +extern "C" LPCSTR LoggingExitCodeTypeToString( + __in BURN_EXE_EXIT_CODE_TYPE exitCodeType + ) +{ + switch (exitCodeType) + { + case BURN_EXE_EXIT_CODE_TYPE_SUCCESS: + return "Success"; + case BURN_EXE_EXIT_CODE_TYPE_ERROR: + return "Error"; + case BURN_EXE_EXIT_CODE_TYPE_SCHEDULE_REBOOT: + return "ScheduleReboot"; + case BURN_EXE_EXIT_CODE_TYPE_FORCE_REBOOT: + return "ForceReboot"; + default: + return "Invalid"; + } +} + extern "C" LPCSTR LoggingPackageStateToString( __in BOOTSTRAPPER_PACKAGE_STATE packageState ) diff --git a/src/burn/engine/logging.h b/src/burn/engine/logging.h index 5597bb57..1b4a7b7f 100644 --- a/src/burn/engine/logging.h +++ b/src/burn/engine/logging.h @@ -112,6 +112,10 @@ LPCSTR LoggingTrueFalseToString( __in BOOL f ); +LPCSTR LoggingExitCodeTypeToString( + __in BURN_EXE_EXIT_CODE_TYPE exitCodeType + ); + LPCSTR LoggingPackageStateToString( __in BOOTSTRAPPER_PACKAGE_STATE packageState ); diff --git a/src/burn/engine/pipe.cpp b/src/burn/engine/pipe.cpp index 19bdcaa2..5003622c 100644 --- a/src/burn/engine/pipe.cpp +++ b/src/burn/engine/pipe.cpp @@ -495,7 +495,7 @@ extern "C" HRESULT PipeTerminateChildProcess( HRESULT hrDebug = S_OK; hrDebug = CoreWaitForProcCompletion(pConnection->hProcess, 0, &dwChildExitCode); - if (E_ACCESSDENIED != hrDebug) // if the other process is elevated and we are not, then we'll get ERROR_ACCESS_DENIED. + if (E_ACCESSDENIED != hrDebug && FAILED(hrDebug)) // if the other process is elevated and we are not, then we'll get ERROR_ACCESS_DENIED. { TraceError(hrDebug, "Failed to wait for child process completion."); } diff --git a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj index 04491608..fe86f042 100644 --- a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj +++ b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj @@ -48,6 +48,7 @@ + diff --git a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj.filters b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj.filters index 19061009..82725436 100644 --- a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj.filters +++ b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj.filters @@ -27,6 +27,9 @@ Source Files + + Source Files + Source Files diff --git a/src/burn/test/BurnUnitTest/ExitCodeTest.cpp b/src/burn/test/BurnUnitTest/ExitCodeTest.cpp new file mode 100644 index 00000000..2c32c6ab --- /dev/null +++ b/src/burn/test/BurnUnitTest/ExitCodeTest.cpp @@ -0,0 +1,361 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + + +namespace Microsoft +{ +namespace Tools +{ +namespace WindowsInstallerXml +{ +namespace Test +{ +namespace Bootstrapper +{ + using namespace System; + using namespace System::IO; + using namespace System::Threading; + using namespace Xunit; + +struct EXIT_CODE_ITEM +{ + DWORD dwExitCode; + HRESULT hrExpectedResult; + BOOTSTRAPPER_APPLY_RESTART expectedRestart; + LPCWSTR wzPackageId; + HRESULT hrResultPerUser; + BOOTSTRAPPER_APPLY_RESTART restartPerUser; + HRESULT hrResultPerMachine; + BOOTSTRAPPER_APPLY_RESTART restartPerMachine; +}; + +static BOOL STDAPICALLTYPE ExitCodeTest_ShellExecuteExW( + __inout LPSHELLEXECUTEINFOW lpExecInfo + ); +static DWORD CALLBACK ExitCodeTest_ElevationThreadProc( + __in LPVOID lpThreadParameter + ); +static BOOL STDAPICALLTYPE ExitCodeTest_CreateProcessW( + __in_opt LPCWSTR lpApplicationName, + __inout_opt LPWSTR lpCommandLine, + __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, + __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, + __in BOOL bInheritHandles, + __in DWORD dwCreationFlags, + __in_opt LPVOID lpEnvironment, + __in_opt LPCWSTR lpCurrentDirectory, + __in LPSTARTUPINFOW lpStartupInfo, + __out LPPROCESS_INFORMATION lpProcessInformation + ); +static DWORD CALLBACK ExitCodeTest_PackageThreadProc( + __in LPVOID lpThreadParameter + ); +static int ExitCodeTest_GenericMessageHandler( + __in GENERIC_EXECUTE_MESSAGE* pMessage, + __in LPVOID pvContext + ); +static void LoadEngineState( + __in BURN_ENGINE_STATE* pEngineState + ); + + public ref class ExitCodeTest : BurnUnitTest + { + public: + ExitCodeTest(BurnTestFixture^ fixture) : BurnUnitTest(fixture) + { + } + + [Fact] + void ExitCodeHandlingTest() + { + HRESULT hr = S_OK; + BURN_ENGINE_STATE engineState = { }; + BURN_PIPE_CONNECTION* pConnection = &engineState.companionConnection; + EXIT_CODE_ITEM rgExitCodeItems[] = + { + { 0, S_OK, BOOTSTRAPPER_APPLY_RESTART_NONE, L"Standard" }, + { 1, HRESULT_FROM_WIN32(1), BOOTSTRAPPER_APPLY_RESTART_NONE, L"Standard" }, + { ERROR_SUCCESS_REBOOT_REQUIRED, S_OK, BOOTSTRAPPER_APPLY_RESTART_REQUIRED, L"Standard" }, + { (DWORD)HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED), S_OK, BOOTSTRAPPER_APPLY_RESTART_REQUIRED, L"Standard" }, + { ERROR_SUCCESS_RESTART_REQUIRED, S_OK, BOOTSTRAPPER_APPLY_RESTART_REQUIRED, L"Standard" }, + { (DWORD)HRESULT_FROM_WIN32(ERROR_SUCCESS_RESTART_REQUIRED), S_OK, BOOTSTRAPPER_APPLY_RESTART_REQUIRED, L"Standard" }, + { ERROR_SUCCESS_REBOOT_INITIATED, S_OK, BOOTSTRAPPER_APPLY_RESTART_INITIATED, L"Standard" }, + { (DWORD)HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_INITIATED), S_OK, BOOTSTRAPPER_APPLY_RESTART_INITIATED, L"Standard" }, + { 0, E_FAIL, BOOTSTRAPPER_APPLY_RESTART_NONE, L"Custom" }, + { 1, S_OK, BOOTSTRAPPER_APPLY_RESTART_NONE, L"Custom" }, + { 3, S_OK, BOOTSTRAPPER_APPLY_RESTART_REQUIRED, L"Custom" }, + { 4, S_OK, BOOTSTRAPPER_APPLY_RESTART_INITIATED, L"Custom" }, + { ERROR_SUCCESS_REBOOT_REQUIRED, HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED), BOOTSTRAPPER_APPLY_RESTART_NONE, L"Custom" }, + { (DWORD)HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED), HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED), BOOTSTRAPPER_APPLY_RESTART_NONE, L"Custom" }, + { ERROR_SUCCESS_RESTART_REQUIRED, HRESULT_FROM_WIN32(ERROR_SUCCESS_RESTART_REQUIRED), BOOTSTRAPPER_APPLY_RESTART_NONE, L"Custom" }, + { (DWORD)HRESULT_FROM_WIN32(ERROR_SUCCESS_RESTART_REQUIRED), HRESULT_FROM_WIN32(ERROR_SUCCESS_RESTART_REQUIRED), BOOTSTRAPPER_APPLY_RESTART_NONE, L"Custom" }, + { ERROR_SUCCESS_REBOOT_INITIATED, HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_INITIATED), BOOTSTRAPPER_APPLY_RESTART_NONE, L"Custom" }, + { (DWORD)HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_INITIATED), HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_INITIATED), BOOTSTRAPPER_APPLY_RESTART_NONE, L"Custom" }, + }; + + engineState.sczBundleEngineWorkingPath = L"tests\\ignore\\this\\path\\to\\burn.exe"; + + try + { + ShelFunctionOverride(ExitCodeTest_ShellExecuteExW); + CoreFunctionOverride(ExitCodeTest_CreateProcessW, ThrdWaitForCompletion); + + // + // per-user side setup + // + LoadEngineState(&engineState); + + hr = ElevationElevate(&engineState, NULL); + TestThrowOnFailure(hr, L"Failed to elevate."); + + for (DWORD i = 0; i < countof(rgExitCodeItems); ++i) + { + // "run" the package both per-user and per-machine + ExecuteExePackage(&engineState, rgExitCodeItems + i); + } + + // + // initiate termination + // + hr = PipeTerminateChildProcess(pConnection, 0, FALSE); + TestThrowOnFailure(hr, L"Failed to terminate elevated process."); + + // check results + for (DWORD i = 0; i < countof(rgExitCodeItems); ++i) + { + EXIT_CODE_ITEM* pExitCode = rgExitCodeItems + i; + String^ packageId = gcnew String(pExitCode->wzPackageId); + String^ exitCodeString = ((UInt32)pExitCode->dwExitCode).ToString(); + + NativeAssert::SpecificReturnCode(pExitCode->hrExpectedResult, pExitCode->hrResultPerMachine, L"Per-machine package: {0}, exit code: {1}", packageId, exitCodeString); + Assert::True(pExitCode->expectedRestart == pExitCode->restartPerMachine, String::Format("Per-machine package: {0}, exit code: {1}, expected restart type '{2}' but got '{3}'", packageId, exitCodeString, gcnew String(LoggingRestartToString(pExitCode->expectedRestart)), gcnew String(LoggingRestartToString(pExitCode->restartPerMachine)))); + + NativeAssert::SpecificReturnCode(pExitCode->hrExpectedResult, pExitCode->hrResultPerUser, L"Per-user package: {0}, exit code: {1}", packageId, exitCodeString); + Assert::True(pExitCode->expectedRestart == pExitCode->restartPerUser, String::Format("Per-user package: {0}, exit code: {1}, expected restart type '{2}' but got '{3}'", packageId, exitCodeString, gcnew String(LoggingRestartToString(pExitCode->expectedRestart)), gcnew String(LoggingRestartToString(pExitCode->restartPerUser)))); + } + } + finally + { + VariablesUninitialize(&engineState.variables); + PipeConnectionUninitialize(pConnection); + } + } + + private: + void ExecuteExePackage( + __in BURN_ENGINE_STATE* pEngineState, + __in EXIT_CODE_ITEM* pExitCode + ) + { + HRESULT hr = S_OK; + LPWSTR sczExitCode = NULL; + BURN_PACKAGE* pPackage = NULL; + BURN_EXECUTE_ACTION executeAction = { }; + BURN_PIPE_CONNECTION* pConnection = &pEngineState->companionConnection; + BOOL fRollback = FALSE; + + hr = PackageFindById(&pEngineState->packages, pExitCode->wzPackageId, &pPackage); + TestThrowOnFailure(hr, L"Failed to find package."); + + executeAction.type = BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE; + executeAction.exePackage.action = BOOTSTRAPPER_ACTION_STATE_INSTALL; + executeAction.exePackage.pPackage = pPackage; + + try + { + hr = StrAllocFormatted(&sczExitCode, L"%u", pExitCode->dwExitCode); + TestThrowOnFailure(hr, L"Failed to convert exit code to string."); + + hr = VariableSetString(&pEngineState->variables, L"ExeExitCode", sczExitCode, FALSE, FALSE); + TestThrowOnFailure(hr, L"Failed to set variable."); + + pExitCode->hrResultPerMachine = ElevationExecuteExePackage(pConnection->hPipe, &executeAction, &pEngineState->variables, fRollback, ExitCodeTest_GenericMessageHandler, NULL, &pExitCode->restartPerMachine); + + pExitCode->hrResultPerUser = ExeEngineExecutePackage(&executeAction, &pEngineState->cache, &pEngineState->variables, fRollback, ExitCodeTest_GenericMessageHandler, NULL, &pExitCode->restartPerUser); + } + finally + { + ReleaseStr(sczExitCode); + } + } + }; + + +static BOOL STDAPICALLTYPE ExitCodeTest_ShellExecuteExW( + __inout LPSHELLEXECUTEINFOW lpExecInfo + ) +{ + HRESULT hr = S_OK; + LPWSTR scz = NULL; + + hr = StrAllocString(&scz, lpExecInfo->lpParameters, 0); + ExitOnFailure(hr, "Failed to copy arguments."); + + // Pretend this thread is the elevated process. + lpExecInfo->hProcess = ::CreateThread(NULL, 0, ExitCodeTest_ElevationThreadProc, scz, 0, NULL); + ExitOnNullWithLastError(lpExecInfo->hProcess, hr, "Failed to create thread."); + scz = NULL; + +LExit: + ReleaseStr(scz); + + return SUCCEEDED(hr); +} + +static DWORD CALLBACK ExitCodeTest_ElevationThreadProc( + __in LPVOID lpThreadParameter + ) +{ + HRESULT hr = S_OK; + LPWSTR sczArguments = (LPWSTR)lpThreadParameter; + BURN_ENGINE_STATE engineState = { }; + BURN_PIPE_CONNECTION* pConnection = &engineState.companionConnection; + HANDLE hLock = NULL; + DWORD dwChildExitCode = 0; + BOOL fRestart = FALSE; + BOOL fApplying = FALSE; + + LoadEngineState(&engineState); + + StrAlloc(&pConnection->sczName, MAX_PATH); + StrAlloc(&pConnection->sczSecret, MAX_PATH); + + // parse command line arguments + if (3 != swscanf_s(sczArguments, L"-q -burn.elevated %s %s %u", pConnection->sczName, MAX_PATH, pConnection->sczSecret, MAX_PATH, &pConnection->dwProcessId)) + { + hr = E_INVALIDARG; + ExitOnFailure(hr, "Failed to parse argument string."); + } + + // set up connection with per-user process + hr = PipeChildConnect(pConnection, TRUE); + ExitOnFailure(hr, "Failed to connect to per-user process."); + + hr = ElevationChildPumpMessages(pConnection->hPipe, pConnection->hCachePipe, &engineState.approvedExes, &engineState.cache, &engineState.containers, &engineState.packages, &engineState.payloads, &engineState.variables, &engineState.registration, &engineState.userExperience, &hLock, &dwChildExitCode, &fRestart, &fApplying); + ExitOnFailure(hr, "Failed while pumping messages in child 'process'."); + +LExit: + PipeConnectionUninitialize(pConnection); + VariablesUninitialize(&engineState.variables); + ReleaseStr(sczArguments); + + return FAILED(hr) ? (DWORD)hr : dwChildExitCode; +} + +static BOOL STDAPICALLTYPE ExitCodeTest_CreateProcessW( + __in_opt LPCWSTR /*lpApplicationName*/, + __inout_opt LPWSTR lpCommandLine, + __in_opt LPSECURITY_ATTRIBUTES /*lpProcessAttributes*/, + __in_opt LPSECURITY_ATTRIBUTES /*lpThreadAttributes*/, + __in BOOL /*bInheritHandles*/, + __in DWORD /*dwCreationFlags*/, + __in_opt LPVOID /*lpEnvironment*/, + __in_opt LPCWSTR /*lpCurrentDirectory*/, + __in LPSTARTUPINFOW /*lpStartupInfo*/, + __out LPPROCESS_INFORMATION lpProcessInformation + ) +{ + HRESULT hr = S_OK; + LPWSTR scz = NULL; + LPCWSTR wzArgs = lpCommandLine; + + hr = StrAllocString(&scz, wzArgs, 0); + ExitOnFailure(hr, "Failed to copy arguments."); + + // Pretend this thread is the package process. + lpProcessInformation->hProcess = ::CreateThread(NULL, 0, ExitCodeTest_PackageThreadProc, scz, 0, NULL); + ExitOnNullWithLastError(lpProcessInformation->hProcess, hr, "Failed to create thread."); + + scz = NULL; + +LExit: + ReleaseStr(scz); + + return SUCCEEDED(hr); +} + +static DWORD CALLBACK ExitCodeTest_PackageThreadProc( + __in LPVOID lpThreadParameter + ) +{ + HRESULT hr = S_OK; + LPWSTR sczArguments = (LPWSTR)lpThreadParameter; + int argc = 0; + LPWSTR* argv = NULL; + DWORD dwResult = 0; + + hr = AppParseCommandLine(sczArguments, &argc, &argv); + ExitOnFailure(hr, "Failed to parse command line: %ls", sczArguments); + + hr = StrStringToUInt32(argv[1], 0, reinterpret_cast(&dwResult)); + ExitOnFailure(hr, "Failed to convert %ls to DWORD.", argv[1]); + +LExit: + AppFreeCommandLineArgs(argv); + ReleaseStr(sczArguments); + + return FAILED(hr) ? (DWORD)hr : dwResult; +} + +static int ExitCodeTest_GenericMessageHandler( + __in GENERIC_EXECUTE_MESSAGE* /*pMessage*/, + __in LPVOID /*pvContext*/ + ) +{ + return IDNOACTION; +} + +static void LoadEngineState( + __in BURN_ENGINE_STATE* pEngineState + ) +{ + HRESULT hr = S_OK; + IXMLDOMElement* pixeBundle = NULL; + + LPCWSTR wzDocument = + L"" + L" " + L" " + L" " + L" " + L" " + L" " + L" " + L" " + L" " + L" " + L" " + L" " + L" " + L" " + L" " + L" " + L" " + L" " + L" " + L""; + + VariableInitialize(&pEngineState->variables); + + PipeConnectionInitialize(&pEngineState->companionConnection); + + hr = CacheInitialize(&pEngineState->cache, &pEngineState->internalCommand); + TestThrowOnFailure(hr, "CacheInitialize failed."); + + // load XML document + LoadBundleXmlHelper(wzDocument, &pixeBundle); + + hr = PayloadsParseFromXml(&pEngineState->payloads, &pEngineState->containers, &pEngineState->layoutPayloads, pixeBundle); + TestThrowOnFailure(hr, "Failed to parse payloads from manifest."); + + hr = PackagesParseFromXml(&pEngineState->packages, &pEngineState->payloads, pixeBundle); + TestThrowOnFailure(hr, "Failed to parse packages from manifest."); + + ReleaseObject(pixeBundle); +} +} +} +} +} +} diff --git a/src/burn/test/BurnUnitTest/precomp.h b/src/burn/test/BurnUnitTest/precomp.h index 84e989a4..2b90cb58 100644 --- a/src/burn/test/BurnUnitTest/precomp.h +++ b/src/burn/test/BurnUnitTest/precomp.h @@ -13,6 +13,7 @@ #include "wininet.h" #include +#include #include #include #include diff --git a/src/internal/WixBuildTools.TestSupport/XunitExtensions/SpecificReturnCodeException.cs b/src/internal/WixBuildTools.TestSupport/XunitExtensions/SpecificReturnCodeException.cs index c66890f8..c703e90a 100644 --- a/src/internal/WixBuildTools.TestSupport/XunitExtensions/SpecificReturnCodeException.cs +++ b/src/internal/WixBuildTools.TestSupport/XunitExtensions/SpecificReturnCodeException.cs @@ -7,11 +7,12 @@ namespace WixBuildTools.TestSupport public class SpecificReturnCodeException : XunitException { - public SpecificReturnCodeException(int hr, string userMessage) + public SpecificReturnCodeException(int hrExpected, int hr, string userMessage) : base(String.Format("WixAssert.SpecificReturnCode() Failure\r\n" + - "HRESULT: 0x{0:X8}\r\n" + - "Message: {1}", - hr, userMessage)) + "Expected HRESULT: 0x{0:X8}\r\n" + + "Actual HRESULT: 0x{1:X8}\r\n" + + "Message: {2}", + hrExpected, hr, userMessage)) { this.HResult = hr; } diff --git a/src/internal/WixBuildTools.TestSupport/XunitExtensions/WixAssert.cs b/src/internal/WixBuildTools.TestSupport/XunitExtensions/WixAssert.cs index d8d02746..a8513bfb 100644 --- a/src/internal/WixBuildTools.TestSupport/XunitExtensions/WixAssert.cs +++ b/src/internal/WixBuildTools.TestSupport/XunitExtensions/WixAssert.cs @@ -58,7 +58,7 @@ namespace WixBuildTools.TestSupport { if (hrExpected != hr) { - throw new SpecificReturnCodeException(hr, String.Format(format, formatArgs)); + throw new SpecificReturnCodeException(hrExpected, hr, String.Format(format, formatArgs)); } } -- cgit v1.2.3-55-g6feb