From 4f5de06073ad664f60ac775da5de8c0fa1de4923 Mon Sep 17 00:00:00 2001
From: Sean Hall <r.sean.hall@gmail.com>
Date: Thu, 25 Aug 2022 15:08:34 -0500
Subject: Process and return the failed version of reboot exit codes in Burn.

(ERROR_FAIL_REBOOT_REQUIRED and ERROR_FAIL_REBOOT_INITIATED)

Fixes 6762
---
 .../Symbols/WixBundlePackageExitCodeSymbol.cs      |  2 ++
 src/burn/engine/engine.cpp                         |  2 +-
 src/burn/engine/exeengine.cpp                      | 28 ++++++++++++++++++++++
 src/burn/engine/logging.cpp                        |  4 ++++
 src/burn/engine/package.h                          |  2 ++
 src/burn/test/BurnUnitTest/ExitCodeTest.cpp        | 20 ++++++++++++++++
 .../WixInternalUIBootstrapperApplication.cpp       |  4 ++--
 .../WixStandardBootstrapperApplication.cpp         |  4 ++--
 src/libs/dutil/WixToolset.DUtil/wiutil.cpp         |  8 +++++++
 src/wix/WixToolset.Core/Compiler_Bundle.cs         |  8 ++++++-
 .../ExePackageFixture.cs                           |  8 +++++++
 .../TestData/ExePackage/CustomExitCodes.wxs        |  8 +++++++
 12 files changed, 92 insertions(+), 6 deletions(-)

diff --git a/src/api/wix/WixToolset.Data/Symbols/WixBundlePackageExitCodeSymbol.cs b/src/api/wix/WixToolset.Data/Symbols/WixBundlePackageExitCodeSymbol.cs
index f025a493..4d50b01c 100644
--- a/src/api/wix/WixToolset.Data/Symbols/WixBundlePackageExitCodeSymbol.cs
+++ b/src/api/wix/WixToolset.Data/Symbols/WixBundlePackageExitCodeSymbol.cs
@@ -36,6 +36,8 @@ namespace WixToolset.Data.Symbols
         Error,
         ScheduleReboot,
         ForceReboot,
+        ErrorScheduleReboot,
+        ErrorForceReboot,
     }
 
     public class WixBundlePackageExitCodeSymbol : IntermediateSymbol
diff --git a/src/burn/engine/engine.cpp b/src/burn/engine/engine.cpp
index daaf51dc..aefba98b 100644
--- a/src/burn/engine/engine.cpp
+++ b/src/burn/engine/engine.cpp
@@ -294,7 +294,7 @@ LExit:
         LogId(REPORT_STANDARD, MSG_RESTART_ABORTED, LoggingRelationTypeToString(engineState.command.relationType));
 
         fRestart = FALSE;
-        hr = HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED);
+        hr = SUCCEEDED(hr) ? HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED) : HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_REQUIRED);
     }
 
     UninitializeEngineState(&engineState);
diff --git a/src/burn/engine/exeengine.cpp b/src/burn/engine/exeengine.cpp
index 3cb9c72a..6d326a5a 100644
--- a/src/burn/engine/exeengine.cpp
+++ b/src/burn/engine/exeengine.cpp
@@ -992,6 +992,16 @@ extern "C" HRESULT ExeEngineHandleExitCode(
         {
             typeCode = BURN_EXE_EXIT_CODE_TYPE_FORCE_REBOOT;
         }
+        else if (ERROR_FAIL_REBOOT_REQUIRED == dwExitCode ||
+                 HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_REQUIRED) == static_cast<HRESULT>(dwExitCode))
+        {
+            typeCode = BURN_EXE_EXIT_CODE_TYPE_ERROR_SCHEDULE_REBOOT;
+        }
+        else if (ERROR_FAIL_REBOOT_INITIATED == dwExitCode ||
+                 HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_INITIATED) == static_cast<HRESULT>(dwExitCode))
+        {
+            typeCode = BURN_EXE_EXIT_CODE_TYPE_ERROR_FORCE_REBOOT;
+        }
         else
         {
             typeCode = BURN_EXE_EXIT_CODE_TYPE_ERROR;
@@ -1024,6 +1034,24 @@ extern "C" HRESULT ExeEngineHandleExitCode(
         hr = S_OK;
         break;
 
+    case BURN_EXE_EXIT_CODE_TYPE_ERROR_SCHEDULE_REBOOT:
+        *pRestart = BOOTSTRAPPER_APPLY_RESTART_REQUIRED;
+        hr = HRESULT_FROM_WIN32(dwExitCode);
+        if (SUCCEEDED(hr))
+        {
+            hr = HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_REQUIRED);
+        }
+        break;
+
+    case BURN_EXE_EXIT_CODE_TYPE_ERROR_FORCE_REBOOT:
+        *pRestart = BOOTSTRAPPER_APPLY_RESTART_INITIATED;
+        hr = HRESULT_FROM_WIN32(dwExitCode);
+        if (SUCCEEDED(hr))
+        {
+            hr = HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_INITIATED);
+        }
+        break;
+
     default:
         hr = E_UNEXPECTED;
         break;
diff --git a/src/burn/engine/logging.cpp b/src/burn/engine/logging.cpp
index 38c9d2d5..a16e82b0 100644
--- a/src/burn/engine/logging.cpp
+++ b/src/burn/engine/logging.cpp
@@ -545,6 +545,10 @@ extern "C" LPCSTR LoggingExitCodeTypeToString(
         return "ScheduleReboot";
     case BURN_EXE_EXIT_CODE_TYPE_FORCE_REBOOT:
         return "ForceReboot";
+    case BURN_EXE_EXIT_CODE_TYPE_ERROR_SCHEDULE_REBOOT:
+        return "ErrorScheduleReboot";
+    case BURN_EXE_EXIT_CODE_TYPE_ERROR_FORCE_REBOOT:
+        return "ErrorForceReboot";
     default:
         return "Invalid";
     }
diff --git a/src/burn/engine/package.h b/src/burn/engine/package.h
index e45c775d..bdebd5b6 100644
--- a/src/burn/engine/package.h
+++ b/src/burn/engine/package.h
@@ -37,6 +37,8 @@ enum BURN_EXE_EXIT_CODE_TYPE
     BURN_EXE_EXIT_CODE_TYPE_ERROR,
     BURN_EXE_EXIT_CODE_TYPE_SCHEDULE_REBOOT,
     BURN_EXE_EXIT_CODE_TYPE_FORCE_REBOOT,
+    BURN_EXE_EXIT_CODE_TYPE_ERROR_SCHEDULE_REBOOT,
+    BURN_EXE_EXIT_CODE_TYPE_ERROR_FORCE_REBOOT,
 };
 
 enum BURN_EXE_PROTOCOL_TYPE
diff --git a/src/burn/test/BurnUnitTest/ExitCodeTest.cpp b/src/burn/test/BurnUnitTest/ExitCodeTest.cpp
index 2c32c6ab..d7d91d06 100644
--- a/src/burn/test/BurnUnitTest/ExitCodeTest.cpp
+++ b/src/burn/test/BurnUnitTest/ExitCodeTest.cpp
@@ -82,16 +82,28 @@ static void LoadEngineState(
                 { (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" },
+                { ERROR_FAIL_REBOOT_REQUIRED, HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_REQUIRED), BOOTSTRAPPER_APPLY_RESTART_REQUIRED, L"Standard" },
+                { (DWORD)HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_REQUIRED), HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_REQUIRED), BOOTSTRAPPER_APPLY_RESTART_REQUIRED, L"Standard" },
+                { ERROR_FAIL_REBOOT_INITIATED, HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_INITIATED), BOOTSTRAPPER_APPLY_RESTART_INITIATED, L"Standard" },
+                { (DWORD)HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_INITIATED), HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_INITIATED), 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" },
+                { 5, HRESULT_FROM_WIN32(5), BOOTSTRAPPER_APPLY_RESTART_REQUIRED, L"Custom" },
+                { (DWORD)HRESULT_FROM_WIN32(5), HRESULT_FROM_WIN32(5), BOOTSTRAPPER_APPLY_RESTART_REQUIRED, L"Custom" },
+                { 6, HRESULT_FROM_WIN32(6), BOOTSTRAPPER_APPLY_RESTART_INITIATED, L"Custom" },
+                { (DWORD)HRESULT_FROM_WIN32(6), HRESULT_FROM_WIN32(6), 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" },
+                { ERROR_FAIL_REBOOT_REQUIRED, HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_REQUIRED), BOOTSTRAPPER_APPLY_RESTART_NONE, L"Custom" },
+                { (DWORD)HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_REQUIRED), HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_REQUIRED), BOOTSTRAPPER_APPLY_RESTART_NONE, L"Custom" },
+                { ERROR_FAIL_REBOOT_INITIATED, HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_INITIATED), BOOTSTRAPPER_APPLY_RESTART_NONE, L"Custom" },
+                { (DWORD)HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_INITIATED), HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_INITIATED), BOOTSTRAPPER_APPLY_RESTART_NONE, L"Custom" },
             };
 
             engineState.sczBundleEngineWorkingPath = L"tests\\ignore\\this\\path\\to\\burn.exe";
@@ -321,12 +333,20 @@ static void LoadEngineState(
         L"            <ExitCode Code='0' Type='2' />"
         L"            <ExitCode Code='3' Type='3' />"
         L"            <ExitCode Code='4' Type='4' />"
+        L"            <ExitCode Code='5' Type='5' />"
+        L"            <ExitCode Code='-2147024891' Type='5' />"
+        L"            <ExitCode Code='6' Type='6' />"
+        L"            <ExitCode Code='-2147024890' Type='6' />"
         L"            <ExitCode Code='3010' Type='2' />"
         L"            <ExitCode Code='-2147021886' Type='2' />"
         L"            <ExitCode Code='3011' Type='2' />"
         L"            <ExitCode Code='-2147021885' Type='2' />"
         L"            <ExitCode Code='1641' Type='2' />"
         L"            <ExitCode Code='-2147023255' Type='2' />"
+        L"            <ExitCode Code='3017' Type='2' />"
+        L"            <ExitCode Code='-2147021879' Type='2' />"
+        L"            <ExitCode Code='3018' Type='2' />"
+        L"            <ExitCode Code='-2147021878' Type='2' />"
         L"            <ExitCode Code='*' Type='1' />"
         L"            <PayloadRef Id='test.exe' />"
         L"        </ExePackage>"
diff --git a/src/ext/Bal/wixiuiba/WixInternalUIBootstrapperApplication.cpp b/src/ext/Bal/wixiuiba/WixInternalUIBootstrapperApplication.cpp
index dbb97366..91469489 100644
--- a/src/ext/Bal/wixiuiba/WixInternalUIBootstrapperApplication.cpp
+++ b/src/ext/Bal/wixiuiba/WixInternalUIBootstrapperApplication.cpp
@@ -391,11 +391,11 @@ private:
 
         if (BOOTSTRAPPER_APPLY_RESTART_INITIATED == pThis->m_restartResult)
         {
-            dwQuit = ERROR_SUCCESS_REBOOT_INITIATED;
+            dwQuit = SUCCEEDED(hr) ? ERROR_SUCCESS_REBOOT_INITIATED : ERROR_FAIL_REBOOT_INITIATED;
         }
         else if (BOOTSTRAPPER_APPLY_RESTART_REQUIRED == pThis->m_restartResult)
         {
-            dwQuit = ERROR_SUCCESS_REBOOT_REQUIRED;
+            dwQuit = SUCCEEDED(hr) ? ERROR_SUCCESS_REBOOT_REQUIRED : ERROR_FAIL_REBOOT_REQUIRED;
         }
         else if (SEVERITY_ERROR == HRESULT_SEVERITY(hr) && FACILITY_WIN32 == HRESULT_FACILITY(hr))
         {
diff --git a/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp b/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp
index d57d78a6..8c4b0b35 100644
--- a/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp
+++ b/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp
@@ -2684,11 +2684,11 @@ private:
 
         if (BOOTSTRAPPER_APPLY_RESTART_INITIATED == pThis->m_restartResult)
         {
-            dwQuit = ERROR_SUCCESS_REBOOT_INITIATED;
+            dwQuit = SUCCEEDED(hr) ? ERROR_SUCCESS_REBOOT_INITIATED : ERROR_FAIL_REBOOT_INITIATED;
         }
         else if (BOOTSTRAPPER_APPLY_RESTART_REQUIRED == pThis->m_restartResult)
         {
-            dwQuit = ERROR_SUCCESS_REBOOT_REQUIRED;
+            dwQuit = SUCCEEDED(hr) ? ERROR_SUCCESS_REBOOT_REQUIRED : ERROR_FAIL_REBOOT_REQUIRED;
         }
         else if (SEVERITY_ERROR == HRESULT_SEVERITY(hr) && FACILITY_WIN32 == HRESULT_FACILITY(hr))
         {
diff --git a/src/libs/dutil/WixToolset.DUtil/wiutil.cpp b/src/libs/dutil/WixToolset.DUtil/wiutil.cpp
index 5f81cf3a..4ed0e2c5 100644
--- a/src/libs/dutil/WixToolset.DUtil/wiutil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/wiutil.cpp
@@ -1034,6 +1034,14 @@ static DWORD CheckForRestartErrorCode(
         *pRestart = WIU_RESTART_INITIATED;
         dwErrorCode = ERROR_SUCCESS;
         break;
+
+    case ERROR_FAIL_REBOOT_REQUIRED:
+        *pRestart = WIU_RESTART_REQUIRED;
+        break;
+
+    case ERROR_FAIL_REBOOT_INITIATED:
+        *pRestart = WIU_RESTART_INITIATED;
+        break;
     }
 
     return dwErrorCode;
diff --git a/src/wix/WixToolset.Core/Compiler_Bundle.cs b/src/wix/WixToolset.Core/Compiler_Bundle.cs
index 0a1e416f..467b8fa9 100644
--- a/src/wix/WixToolset.Core/Compiler_Bundle.cs
+++ b/src/wix/WixToolset.Core/Compiler_Bundle.cs
@@ -1628,6 +1628,12 @@ namespace WixToolset.Core
                                 case "error":
                                     behavior = ExitCodeBehaviorType.Error;
                                     break;
+                                case "errorForceReboot":
+                                    behavior = ExitCodeBehaviorType.ErrorForceReboot;
+                                    break;
+                                case "errorScheduleReboot":
+                                    behavior = ExitCodeBehaviorType.ErrorScheduleReboot;
+                                    break;
                                 case "forceReboot":
                                     behavior = ExitCodeBehaviorType.ForceReboot;
                                     break;
@@ -1638,7 +1644,7 @@ namespace WixToolset.Core
                                     behavior = ExitCodeBehaviorType.Success;
                                     break;
                                 default:
-                                    this.Core.Write(ErrorMessages.IllegalAttributeValueWithLegalList(sourceLineNumbers, node.Name.LocalName, "Behavior", behaviorString, "success, error, scheduleReboot, forceReboot"));
+                                    this.Core.Write(ErrorMessages.IllegalAttributeValueWithLegalList(sourceLineNumbers, node.Name.LocalName, "Behavior", behaviorString, "success, error, scheduleReboot, forceReboot, errorScheduleReboot, errorForceReboot"));
                                     behavior = ExitCodeBehaviorType.Success; // set value to avoid ExpectedAttribute below.
                                     break;
                             }
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/ExePackageFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/ExePackageFixture.cs
index a3ca2917..2a4ac51b 100644
--- a/src/wix/test/WixToolsetTest.CoreIntegration/ExePackageFixture.cs
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/ExePackageFixture.cs
@@ -93,12 +93,20 @@ namespace WixToolsetTest.CoreIntegration
                       "<ExitCode Code='0' Type='2' />" +
                       "<ExitCode Code='3' Type='3' />" +
                       "<ExitCode Code='4' Type='4' />" +
+                      "<ExitCode Code='5' Type='5' />" +
+                      "<ExitCode Code='-2147024891' Type='5' />" +
+                      "<ExitCode Code='6' Type='6' />" +
+                      "<ExitCode Code='-2147024890' Type='6' />" +
                       "<ExitCode Code='3010' Type='2' />" +
                       "<ExitCode Code='-2147021886' Type='2' />" +
                       "<ExitCode Code='3011' Type='2' />" +
                       "<ExitCode Code='-2147021885' Type='2' />" +
                       "<ExitCode Code='1641' Type='2' />" +
                       "<ExitCode Code='-2147023255' Type='2' />" +
+                      "<ExitCode Code='3017' Type='2' />" +
+                      "<ExitCode Code='-2147021879' Type='2' />" +
+                      "<ExitCode Code='3018' Type='2' />" +
+                      "<ExitCode Code='-2147021878' Type='2' />" +
                       "<ExitCode Code='-2147483647' Type='2' />" +
                       "<ExitCode Code='-2147483648' Type='2' />" +
                       "<ExitCode Code='*' Type='1' />" +
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/CustomExitCodes.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/CustomExitCodes.wxs
index 9cbc9919..4536eaf8 100644
--- a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/CustomExitCodes.wxs
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/ExePackage/CustomExitCodes.wxs
@@ -10,12 +10,20 @@
                 <ExitCode Value="0" Behavior="error" />
                 <ExitCode Value="3" Behavior="scheduleReboot" />
                 <ExitCode Value="4" Behavior="forceReboot" />
+                <ExitCode Value="5" Behavior="errorScheduleReboot" />
+                <ExitCode Value="-2147024891" Behavior="errorScheduleReboot" />
+                <ExitCode Value="6" Behavior="errorForceReboot" />
+                <ExitCode Value="-2147024890" Behavior="errorForceReboot" />
                 <ExitCode Value="3010" Behavior="error" />
                 <ExitCode Value="-2147021886" Behavior="error" />
                 <ExitCode Value="3011" Behavior="error" />
                 <ExitCode Value="-2147021885" Behavior="error" />
                 <ExitCode Value="1641" Behavior="error" />
                 <ExitCode Value="-2147023255" Behavior="error" />
+                <ExitCode Value="3017" Behavior="error" />
+                <ExitCode Value="-2147021879" Behavior="error" />
+                <ExitCode Value="3018" Behavior="error" />
+                <ExitCode Value="-2147021878" Behavior="error" />
                 <ExitCode Value="-2147483647" Behavior="error" />
                 <ExitCode Value="-2147483648" Behavior="error" />
                 <ExitCode Behavior="success" />
-- 
cgit v1.2.3-55-g6feb