| 1 | // 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. |
| 2 | |
| 3 | #include "precomp.h" |
| 4 | |
| 5 | namespace Microsoft |
| 6 | { |
| 7 | namespace Tools |
| 8 | { |
| 9 | namespace WindowsInstallerXml |
| 10 | { |
| 11 | namespace Test |
| 12 | { |
| 13 | namespace Bootstrapper |
| 14 | { |
| 15 | using namespace System; |
| 16 | using namespace System::IO; |
| 17 | using namespace System::Threading; |
| 18 | using namespace Xunit; |
| 19 | |
| 20 | struct EXIT_CODE_ITEM |
| 21 | { |
| 22 | DWORD dwExitCode; |
| 23 | HRESULT hrExpectedResult; |
| 24 | BOOTSTRAPPER_APPLY_RESTART expectedRestart; |
| 25 | LPCWSTR wzPackageId; |
| 26 | HRESULT hrResultPerUser; |
| 27 | BOOTSTRAPPER_APPLY_RESTART restartPerUser; |
| 28 | HRESULT hrResultPerMachine; |
| 29 | BOOTSTRAPPER_APPLY_RESTART restartPerMachine; |
| 30 | }; |
| 31 | |
| 32 | static BOOL STDAPICALLTYPE ExitCodeTest_ShellExecuteExW( |
| 33 | __inout LPSHELLEXECUTEINFOW lpExecInfo |
| 34 | ); |
| 35 | static DWORD CALLBACK ExitCodeTest_ElevationThreadProc( |
| 36 | __in LPVOID lpThreadParameter |
| 37 | ); |
| 38 | static BOOL STDAPICALLTYPE ExitCodeTest_CreateProcessW( |
| 39 | __in_opt LPCWSTR lpApplicationName, |
| 40 | __inout_opt LPWSTR lpCommandLine, |
| 41 | __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, |
| 42 | __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, |
| 43 | __in BOOL bInheritHandles, |
| 44 | __in DWORD dwCreationFlags, |
| 45 | __in_opt LPVOID lpEnvironment, |
| 46 | __in_opt LPCWSTR lpCurrentDirectory, |
| 47 | __in LPSTARTUPINFOW lpStartupInfo, |
| 48 | __out LPPROCESS_INFORMATION lpProcessInformation |
| 49 | ); |
| 50 | static DWORD CALLBACK ExitCodeTest_PackageThreadProc( |
| 51 | __in LPVOID lpThreadParameter |
| 52 | ); |
| 53 | static int ExitCodeTest_GenericMessageHandler( |
| 54 | __in GENERIC_EXECUTE_MESSAGE* pMessage, |
| 55 | __in LPVOID pvContext |
| 56 | ); |
| 57 | static void LoadEngineState( |
| 58 | __in BURN_ENGINE_STATE* pEngineState |
| 59 | ); |
| 60 | |
| 61 | public ref class ExitCodeTest : BurnUnitTest |
| 62 | { |
| 63 | public: |
| 64 | ExitCodeTest(BurnTestFixture^ fixture) : BurnUnitTest(fixture) |
| 65 | { |
| 66 | } |
| 67 | |
| 68 | [Fact] |
| 69 | void ExitCodeHandlingTest() |
| 70 | { |
| 71 | HRESULT hr = S_OK; |
| 72 | BURN_ENGINE_STATE engineState = { }; |
| 73 | BURN_PIPE_CONNECTION* pConnection = &engineState.companionConnection; |
| 74 | EXIT_CODE_ITEM rgExitCodeItems[] = |
| 75 | { |
| 76 | { 0, S_OK, BOOTSTRAPPER_APPLY_RESTART_NONE, L"Standard" }, |
| 77 | { 1, HRESULT_FROM_WIN32(1), BOOTSTRAPPER_APPLY_RESTART_NONE, L"Standard" }, |
| 78 | { ERROR_SUCCESS_REBOOT_REQUIRED, S_OK, BOOTSTRAPPER_APPLY_RESTART_REQUIRED, L"Standard" }, |
| 79 | { (DWORD)HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED), S_OK, BOOTSTRAPPER_APPLY_RESTART_REQUIRED, L"Standard" }, |
| 80 | { ERROR_SUCCESS_RESTART_REQUIRED, S_OK, BOOTSTRAPPER_APPLY_RESTART_REQUIRED, L"Standard" }, |
| 81 | { (DWORD)HRESULT_FROM_WIN32(ERROR_SUCCESS_RESTART_REQUIRED), S_OK, BOOTSTRAPPER_APPLY_RESTART_REQUIRED, L"Standard" }, |
| 82 | { ERROR_SUCCESS_REBOOT_INITIATED, S_OK, BOOTSTRAPPER_APPLY_RESTART_INITIATED, L"Standard" }, |
| 83 | { (DWORD)HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_INITIATED), S_OK, BOOTSTRAPPER_APPLY_RESTART_INITIATED, L"Standard" }, |
| 84 | { ERROR_FAIL_REBOOT_REQUIRED, HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_REQUIRED), BOOTSTRAPPER_APPLY_RESTART_REQUIRED, L"Standard" }, |
| 85 | { (DWORD)HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_REQUIRED), HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_REQUIRED), BOOTSTRAPPER_APPLY_RESTART_REQUIRED, L"Standard" }, |
| 86 | { ERROR_FAIL_REBOOT_INITIATED, HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_INITIATED), BOOTSTRAPPER_APPLY_RESTART_INITIATED, L"Standard" }, |
| 87 | { (DWORD)HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_INITIATED), HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_INITIATED), BOOTSTRAPPER_APPLY_RESTART_INITIATED, L"Standard" }, |
| 88 | { 0, E_FAIL, BOOTSTRAPPER_APPLY_RESTART_NONE, L"Custom" }, |
| 89 | { 1, S_OK, BOOTSTRAPPER_APPLY_RESTART_NONE, L"Custom" }, |
| 90 | { 3, S_OK, BOOTSTRAPPER_APPLY_RESTART_REQUIRED, L"Custom" }, |
| 91 | { 4, S_OK, BOOTSTRAPPER_APPLY_RESTART_INITIATED, L"Custom" }, |
| 92 | { 5, HRESULT_FROM_WIN32(5), BOOTSTRAPPER_APPLY_RESTART_REQUIRED, L"Custom" }, |
| 93 | { (DWORD)HRESULT_FROM_WIN32(5), HRESULT_FROM_WIN32(5), BOOTSTRAPPER_APPLY_RESTART_REQUIRED, L"Custom" }, |
| 94 | { 6, HRESULT_FROM_WIN32(6), BOOTSTRAPPER_APPLY_RESTART_INITIATED, L"Custom" }, |
| 95 | { (DWORD)HRESULT_FROM_WIN32(6), HRESULT_FROM_WIN32(6), BOOTSTRAPPER_APPLY_RESTART_INITIATED, L"Custom" }, |
| 96 | { ERROR_SUCCESS_REBOOT_REQUIRED, HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED), BOOTSTRAPPER_APPLY_RESTART_NONE, L"Custom" }, |
| 97 | { (DWORD)HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED), HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED), BOOTSTRAPPER_APPLY_RESTART_NONE, L"Custom" }, |
| 98 | { ERROR_SUCCESS_RESTART_REQUIRED, HRESULT_FROM_WIN32(ERROR_SUCCESS_RESTART_REQUIRED), BOOTSTRAPPER_APPLY_RESTART_NONE, L"Custom" }, |
| 99 | { (DWORD)HRESULT_FROM_WIN32(ERROR_SUCCESS_RESTART_REQUIRED), HRESULT_FROM_WIN32(ERROR_SUCCESS_RESTART_REQUIRED), BOOTSTRAPPER_APPLY_RESTART_NONE, L"Custom" }, |
| 100 | { ERROR_SUCCESS_REBOOT_INITIATED, HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_INITIATED), BOOTSTRAPPER_APPLY_RESTART_NONE, L"Custom" }, |
| 101 | { (DWORD)HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_INITIATED), HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_INITIATED), BOOTSTRAPPER_APPLY_RESTART_NONE, L"Custom" }, |
| 102 | { ERROR_FAIL_REBOOT_REQUIRED, HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_REQUIRED), BOOTSTRAPPER_APPLY_RESTART_NONE, L"Custom" }, |
| 103 | { (DWORD)HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_REQUIRED), HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_REQUIRED), BOOTSTRAPPER_APPLY_RESTART_NONE, L"Custom" }, |
| 104 | { ERROR_FAIL_REBOOT_INITIATED, HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_INITIATED), BOOTSTRAPPER_APPLY_RESTART_NONE, L"Custom" }, |
| 105 | { (DWORD)HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_INITIATED), HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_INITIATED), BOOTSTRAPPER_APPLY_RESTART_NONE, L"Custom" }, |
| 106 | }; |
| 107 | |
| 108 | engineState.sczBundleEngineWorkingPath = L"tests\\ignore\\this\\path\\to\\burn.exe"; |
| 109 | |
| 110 | try |
| 111 | { |
| 112 | ShelFunctionOverride(ExitCodeTest_ShellExecuteExW); |
| 113 | CoreFunctionOverride(ExitCodeTest_CreateProcessW, ThrdWaitForCompletion); |
| 114 | |
| 115 | // |
| 116 | // per-user side setup |
| 117 | // |
| 118 | LoadEngineState(&engineState); |
| 119 | |
| 120 | hr = ElevationElevate(&engineState, WM_BURN_ELEVATE, NULL); |
| 121 | TestThrowOnFailure(hr, L"Failed to elevate."); |
| 122 | |
| 123 | for (DWORD i = 0; i < countof(rgExitCodeItems); ++i) |
| 124 | { |
| 125 | // "run" the package both per-user and per-machine |
| 126 | ExecuteExePackage(&engineState, rgExitCodeItems + i); |
| 127 | } |
| 128 | |
| 129 | // |
| 130 | // initiate termination |
| 131 | // |
| 132 | hr = BurnPipeTerminateChildProcess(pConnection, 0, FALSE); |
| 133 | TestThrowOnFailure(hr, L"Failed to terminate elevated process."); |
| 134 | |
| 135 | // check results |
| 136 | for (DWORD i = 0; i < countof(rgExitCodeItems); ++i) |
| 137 | { |
| 138 | EXIT_CODE_ITEM* pExitCode = rgExitCodeItems + i; |
| 139 | String^ packageId = gcnew String(pExitCode->wzPackageId); |
| 140 | String^ exitCodeString = ((UInt32)pExitCode->dwExitCode).ToString(); |
| 141 | |
| 142 | NativeAssert::SpecificReturnCode(pExitCode->hrExpectedResult, pExitCode->hrResultPerMachine, L"Per-machine package: {0}, exit code: {1}", packageId, exitCodeString); |
| 143 | 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)))); |
| 144 | |
| 145 | NativeAssert::SpecificReturnCode(pExitCode->hrExpectedResult, pExitCode->hrResultPerUser, L"Per-user package: {0}, exit code: {1}", packageId, exitCodeString); |
| 146 | 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)))); |
| 147 | } |
| 148 | } |
| 149 | finally |
| 150 | { |
| 151 | VariablesUninitialize(&engineState.variables); |
| 152 | BurnPipeConnectionUninitialize(pConnection); |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | private: |
| 157 | void ExecuteExePackage( |
| 158 | __in BURN_ENGINE_STATE* pEngineState, |
| 159 | __in EXIT_CODE_ITEM* pExitCode |
| 160 | ) |
| 161 | { |
| 162 | HRESULT hr = S_OK; |
| 163 | LPWSTR sczExitCode = NULL; |
| 164 | BURN_PACKAGE* pPackage = NULL; |
| 165 | BURN_EXECUTE_ACTION executeAction = { }; |
| 166 | BURN_PIPE_CONNECTION* pConnection = &pEngineState->companionConnection; |
| 167 | BOOL fRollback = FALSE; |
| 168 | |
| 169 | hr = PackageFindById(&pEngineState->packages, pExitCode->wzPackageId, &pPackage); |
| 170 | TestThrowOnFailure(hr, L"Failed to find package."); |
| 171 | |
| 172 | executeAction.type = BURN_EXECUTE_ACTION_TYPE_EXE_PACKAGE; |
| 173 | executeAction.exePackage.action = BOOTSTRAPPER_ACTION_STATE_INSTALL; |
| 174 | executeAction.exePackage.pPackage = pPackage; |
| 175 | |
| 176 | try |
| 177 | { |
| 178 | hr = StrAllocFormatted(&sczExitCode, L"%u", pExitCode->dwExitCode); |
| 179 | TestThrowOnFailure(hr, L"Failed to convert exit code to string."); |
| 180 | |
| 181 | hr = VariableSetString(&pEngineState->variables, L"ExeExitCode", sczExitCode, FALSE, FALSE); |
| 182 | TestThrowOnFailure(hr, L"Failed to set variable."); |
| 183 | |
| 184 | pExitCode->hrResultPerMachine = ElevationExecuteExePackage(pConnection->hPipe, &executeAction, &pEngineState->variables, fRollback, ExitCodeTest_GenericMessageHandler, NULL, &pExitCode->restartPerMachine); |
| 185 | |
| 186 | pExitCode->hrResultPerUser = ExeEngineExecutePackage(&executeAction, &pEngineState->cache, &pEngineState->variables, fRollback, ExitCodeTest_GenericMessageHandler, NULL, &pExitCode->restartPerUser); |
| 187 | } |
| 188 | finally |
| 189 | { |
| 190 | ReleaseStr(sczExitCode); |
| 191 | } |
| 192 | } |
| 193 | }; |
| 194 | |
| 195 | |
| 196 | static BOOL STDAPICALLTYPE ExitCodeTest_ShellExecuteExW( |
| 197 | __inout LPSHELLEXECUTEINFOW lpExecInfo |
| 198 | ) |
| 199 | { |
| 200 | HRESULT hr = S_OK; |
| 201 | LPWSTR scz = NULL; |
| 202 | |
| 203 | hr = StrAllocString(&scz, lpExecInfo->lpParameters, 0); |
| 204 | ExitOnFailure(hr, "Failed to copy arguments."); |
| 205 | |
| 206 | // Pretend this thread is the elevated process. |
| 207 | lpExecInfo->hProcess = ::CreateThread(NULL, 0, ExitCodeTest_ElevationThreadProc, scz, 0, NULL); |
| 208 | ExitOnNullWithLastError(lpExecInfo->hProcess, hr, "Failed to create thread."); |
| 209 | scz = NULL; |
| 210 | |
| 211 | LExit: |
| 212 | ReleaseStr(scz); |
| 213 | |
| 214 | return SUCCEEDED(hr); |
| 215 | } |
| 216 | |
| 217 | static DWORD CALLBACK ExitCodeTest_ElevationThreadProc( |
| 218 | __in LPVOID lpThreadParameter |
| 219 | ) |
| 220 | { |
| 221 | HRESULT hr = S_OK; |
| 222 | LPWSTR sczArguments = (LPWSTR)lpThreadParameter; |
| 223 | BURN_ENGINE_STATE engineState = { }; |
| 224 | BURN_PIPE_CONNECTION* pConnection = &engineState.companionConnection; |
| 225 | HANDLE hLock = NULL; |
| 226 | DWORD dwChildExitCode = 0; |
| 227 | BOOL fRestart = FALSE; |
| 228 | BOOL fApplying = FALSE; |
| 229 | |
| 230 | LoadEngineState(&engineState); |
| 231 | |
| 232 | StrAlloc(&pConnection->sczName, MAX_PATH); |
| 233 | StrAlloc(&pConnection->sczSecret, MAX_PATH); |
| 234 | |
| 235 | // parse command line arguments |
| 236 | if (3 != swscanf_s(sczArguments, L"-q -burn.elevated %s %s %u", pConnection->sczName, MAX_PATH, pConnection->sczSecret, MAX_PATH, &pConnection->dwProcessId)) |
| 237 | { |
| 238 | hr = E_INVALIDARG; |
| 239 | ExitOnFailure(hr, "Failed to parse argument string."); |
| 240 | } |
| 241 | |
| 242 | // set up connection with per-user process |
| 243 | hr = BurnPipeChildConnect(pConnection, TRUE); |
| 244 | ExitOnFailure(hr, "Failed to connect to per-user process."); |
| 245 | |
| 246 | 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); |
| 247 | ExitOnFailure(hr, "Failed while pumping messages in child 'process'."); |
| 248 | |
| 249 | LExit: |
| 250 | BurnPipeConnectionUninitialize(pConnection); |
| 251 | VariablesUninitialize(&engineState.variables); |
| 252 | ReleaseStr(sczArguments); |
| 253 | |
| 254 | return FAILED(hr) ? (DWORD)hr : dwChildExitCode; |
| 255 | } |
| 256 | |
| 257 | static BOOL STDAPICALLTYPE ExitCodeTest_CreateProcessW( |
| 258 | __in_opt LPCWSTR /*lpApplicationName*/, |
| 259 | __inout_opt LPWSTR lpCommandLine, |
| 260 | __in_opt LPSECURITY_ATTRIBUTES /*lpProcessAttributes*/, |
| 261 | __in_opt LPSECURITY_ATTRIBUTES /*lpThreadAttributes*/, |
| 262 | __in BOOL /*bInheritHandles*/, |
| 263 | __in DWORD /*dwCreationFlags*/, |
| 264 | __in_opt LPVOID /*lpEnvironment*/, |
| 265 | __in_opt LPCWSTR /*lpCurrentDirectory*/, |
| 266 | __in LPSTARTUPINFOW /*lpStartupInfo*/, |
| 267 | __out LPPROCESS_INFORMATION lpProcessInformation |
| 268 | ) |
| 269 | { |
| 270 | HRESULT hr = S_OK; |
| 271 | LPWSTR scz = NULL; |
| 272 | LPCWSTR wzArgs = lpCommandLine; |
| 273 | |
| 274 | hr = StrAllocString(&scz, wzArgs, 0); |
| 275 | ExitOnFailure(hr, "Failed to copy arguments."); |
| 276 | |
| 277 | // Pretend this thread is the package process. |
| 278 | lpProcessInformation->hProcess = ::CreateThread(NULL, 0, ExitCodeTest_PackageThreadProc, scz, 0, NULL); |
| 279 | ExitOnNullWithLastError(lpProcessInformation->hProcess, hr, "Failed to create thread."); |
| 280 | |
| 281 | scz = NULL; |
| 282 | |
| 283 | LExit: |
| 284 | ReleaseStr(scz); |
| 285 | |
| 286 | return SUCCEEDED(hr); |
| 287 | } |
| 288 | |
| 289 | static DWORD CALLBACK ExitCodeTest_PackageThreadProc( |
| 290 | __in LPVOID lpThreadParameter |
| 291 | ) |
| 292 | { |
| 293 | HRESULT hr = S_OK; |
| 294 | LPWSTR sczArguments = (LPWSTR)lpThreadParameter; |
| 295 | int argc = 0; |
| 296 | LPWSTR* argv = NULL; |
| 297 | DWORD dwResult = 0; |
| 298 | |
| 299 | hr = AppParseCommandLine(sczArguments, &argc, &argv); |
| 300 | ExitOnFailure(hr, "Failed to parse command line: %ls", sczArguments); |
| 301 | |
| 302 | hr = StrStringToUInt32(argv[1], 0, reinterpret_cast<UINT*>(&dwResult)); |
| 303 | ExitOnFailure(hr, "Failed to convert %ls to DWORD.", argv[1]); |
| 304 | |
| 305 | LExit: |
| 306 | AppFreeCommandLineArgs(argv); |
| 307 | ReleaseStr(sczArguments); |
| 308 | |
| 309 | return FAILED(hr) ? (DWORD)hr : dwResult; |
| 310 | } |
| 311 | |
| 312 | static int ExitCodeTest_GenericMessageHandler( |
| 313 | __in GENERIC_EXECUTE_MESSAGE* /*pMessage*/, |
| 314 | __in LPVOID /*pvContext*/ |
| 315 | ) |
| 316 | { |
| 317 | return IDNOACTION; |
| 318 | } |
| 319 | |
| 320 | static void LoadEngineState( |
| 321 | __in BURN_ENGINE_STATE* pEngineState |
| 322 | ) |
| 323 | { |
| 324 | HRESULT hr = S_OK; |
| 325 | IXMLDOMElement* pixeBundle = NULL; |
| 326 | |
| 327 | LPCWSTR wzDocument = |
| 328 | L"<BurnManifest>" |
| 329 | L" <Payload Id='test.exe' FilePath='test.exe' Packaging='external' SourcePath='test.exe' Hash='000000000000' FileSize='1' />" |
| 330 | L" <Chain>" |
| 331 | L" <ExePackage Id='Custom' Cache='remove' CacheId='test.exe' InstallSize='1' Size='1' PerMachine='no' Permanent='yes' Vital='yes' DetectCondition='' InstallArguments='[ExeExitCode]' UninstallArguments='' Uninstallable='no' RepairArguments='' Repairable='no' Protocol='none' DetectionType='condition'>" |
| 332 | L" <ExitCode Code='0' Type='2' />" |
| 333 | L" <ExitCode Code='3' Type='3' />" |
| 334 | L" <ExitCode Code='4' Type='4' />" |
| 335 | L" <ExitCode Code='5' Type='5' />" |
| 336 | L" <ExitCode Code='-2147024891' Type='5' />" |
| 337 | L" <ExitCode Code='6' Type='6' />" |
| 338 | L" <ExitCode Code='-2147024890' Type='6' />" |
| 339 | L" <ExitCode Code='3010' Type='2' />" |
| 340 | L" <ExitCode Code='-2147021886' Type='2' />" |
| 341 | L" <ExitCode Code='3011' Type='2' />" |
| 342 | L" <ExitCode Code='-2147021885' Type='2' />" |
| 343 | L" <ExitCode Code='1641' Type='2' />" |
| 344 | L" <ExitCode Code='-2147023255' Type='2' />" |
| 345 | L" <ExitCode Code='3017' Type='2' />" |
| 346 | L" <ExitCode Code='-2147021879' Type='2' />" |
| 347 | L" <ExitCode Code='3018' Type='2' />" |
| 348 | L" <ExitCode Code='-2147021878' Type='2' />" |
| 349 | L" <ExitCode Code='*' Type='1' />" |
| 350 | L" <PayloadRef Id='test.exe' />" |
| 351 | L" </ExePackage>" |
| 352 | L" <ExePackage Id='Standard' Cache='remove' CacheId='test.exe' InstallSize='1' Size='1' PerMachine='no' Permanent='yes' Vital='yes' DetectCondition='' InstallArguments='[ExeExitCode]' UninstallArguments='' Uninstallable='no' RepairArguments='' Repairable='no' Protocol='none' DetectionType='condition'>" |
| 353 | L" <PayloadRef Id='test.exe' />" |
| 354 | L" </ExePackage>" |
| 355 | L" </Chain>" |
| 356 | L"</BurnManifest>"; |
| 357 | |
| 358 | VariableInitialize(&pEngineState->variables); |
| 359 | |
| 360 | BurnPipeConnectionInitialize(&pEngineState->companionConnection); |
| 361 | |
| 362 | hr = CacheInitialize(&pEngineState->cache, &pEngineState->internalCommand); |
| 363 | TestThrowOnFailure(hr, "CacheInitialize failed."); |
| 364 | |
| 365 | // load XML document |
| 366 | LoadBundleXmlHelper(wzDocument, &pixeBundle); |
| 367 | |
| 368 | hr = PayloadsParseFromXml(&pEngineState->payloads, &pEngineState->containers, &pEngineState->layoutPayloads, pixeBundle); |
| 369 | TestThrowOnFailure(hr, "Failed to parse payloads from manifest."); |
| 370 | |
| 371 | hr = PackagesParseFromXml(&pEngineState->packages, &pEngineState->payloads, pixeBundle); |
| 372 | TestThrowOnFailure(hr, "Failed to parse packages from manifest."); |
| 373 | |
| 374 | ReleaseObject(pixeBundle); |
| 375 | } |
| 376 | } |
| 377 | } |
| 378 | } |
| 379 | } |
| 380 | } |