diff options
author | Sean Hall <r.sean.hall@gmail.com> | 2022-03-18 20:15:33 -0500 |
---|---|---|
committer | Sean Hall <r.sean.hall@gmail.com> | 2022-03-19 12:07:32 -0500 |
commit | fb54576f1d05e82ba47cd718c4c4f8b3bad624c9 (patch) | |
tree | b7d6b30bd3c9294b74874c1a48b20a8da8869a69 /src/burn | |
parent | 581c320e04949300d6c3bee71fb5fc1a557f9263 (diff) | |
download | wix-fb54576f1d05e82ba47cd718c4c4f8b3bad624c9.tar.gz wix-fb54576f1d05e82ba47cd718c4c4f8b3bad624c9.tar.bz2 wix-fb54576f1d05e82ba47cd718c4c4f8b3bad624c9.zip |
Give BA process id and option to wait for cancelled process to exit.
Diffstat (limited to 'src/burn')
-rw-r--r-- | src/burn/engine/apply.cpp | 8 | ||||
-rw-r--r-- | src/burn/engine/apply.h | 5 | ||||
-rw-r--r-- | src/burn/engine/bundlepackageengine.cpp | 28 | ||||
-rw-r--r-- | src/burn/engine/elevation.cpp | 17 | ||||
-rw-r--r-- | src/burn/engine/engine.mc | 7 | ||||
-rw-r--r-- | src/burn/engine/exeengine.cpp | 132 | ||||
-rw-r--r-- | src/burn/engine/exeengine.h | 9 | ||||
-rw-r--r-- | src/burn/engine/msuengine.cpp | 32 | ||||
-rw-r--r-- | src/burn/engine/userexperience.cpp | 30 | ||||
-rw-r--r-- | src/burn/engine/userexperience.h | 6 | ||||
-rw-r--r-- | src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj | 2 | ||||
-rw-r--r-- | src/burn/test/BurnUnitTest/PlanTest.cpp | 200 | ||||
-rw-r--r-- | src/burn/test/BurnUnitTest/TestData/PlanTest/Failure_BundleD_manifest.xml | 1 | ||||
-rw-r--r-- | src/burn/test/BurnUnitTest/TestData/PlanTest/MsuPackageFixture_manifest.xml | 1 |
14 files changed, 385 insertions, 93 deletions
diff --git a/src/burn/engine/apply.cpp b/src/burn/engine/apply.cpp index 3ad22e9b..73b5b396 100644 --- a/src/burn/engine/apply.cpp +++ b/src/burn/engine/apply.cpp | |||
@@ -3326,6 +3326,14 @@ static int GenericExecuteMessageHandler( | |||
3326 | } | 3326 | } |
3327 | break; | 3327 | break; |
3328 | 3328 | ||
3329 | case GENERIC_EXECUTE_MESSAGE_PROCESS_CANCEL: | ||
3330 | { | ||
3331 | BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION action = BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION_ABANDON; | ||
3332 | UserExperienceOnExecuteProcessCancel(pContext->pUX, pContext->wzExecutingPackageId, pMessage->processCancel.dwProcessId, &action); // ignore return value. | ||
3333 | nResult = BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION_WAIT == action ? IDRETRY : IDIGNORE; | ||
3334 | } | ||
3335 | break; | ||
3336 | |||
3329 | case GENERIC_EXECUTE_MESSAGE_ERROR: | 3337 | case GENERIC_EXECUTE_MESSAGE_ERROR: |
3330 | UserExperienceOnError(pContext->pUX, BOOTSTRAPPER_ERROR_TYPE_EXE_PACKAGE, pContext->wzExecutingPackageId, pMessage->error.dwErrorCode, pMessage->error.wzMessage, pMessage->dwUIHint, 0, NULL, &nResult); // ignore return value. | 3338 | UserExperienceOnError(pContext->pUX, BOOTSTRAPPER_ERROR_TYPE_EXE_PACKAGE, pContext->wzExecutingPackageId, pMessage->error.dwErrorCode, pMessage->error.wzMessage, pMessage->dwUIHint, 0, NULL, &nResult); // ignore return value. |
3331 | break; | 3339 | break; |
diff --git a/src/burn/engine/apply.h b/src/burn/engine/apply.h index 1717a71a..47f0ece6 100644 --- a/src/burn/engine/apply.h +++ b/src/burn/engine/apply.h | |||
@@ -13,6 +13,7 @@ enum GENERIC_EXECUTE_MESSAGE_TYPE | |||
13 | GENERIC_EXECUTE_MESSAGE_ERROR, | 13 | GENERIC_EXECUTE_MESSAGE_ERROR, |
14 | GENERIC_EXECUTE_MESSAGE_PROGRESS, | 14 | GENERIC_EXECUTE_MESSAGE_PROGRESS, |
15 | GENERIC_EXECUTE_MESSAGE_NETFX_FILES_IN_USE, | 15 | GENERIC_EXECUTE_MESSAGE_NETFX_FILES_IN_USE, |
16 | GENERIC_EXECUTE_MESSAGE_PROCESS_CANCEL, | ||
16 | }; | 17 | }; |
17 | 18 | ||
18 | typedef struct _APPLY_AUTHENTICATION_REQUIRED_DATA | 19 | typedef struct _APPLY_AUTHENTICATION_REQUIRED_DATA |
@@ -43,6 +44,10 @@ typedef struct _GENERIC_EXECUTE_MESSAGE | |||
43 | DWORD cFiles; | 44 | DWORD cFiles; |
44 | LPCWSTR* rgwzFiles; | 45 | LPCWSTR* rgwzFiles; |
45 | } filesInUse; | 46 | } filesInUse; |
47 | struct | ||
48 | { | ||
49 | DWORD dwProcessId; | ||
50 | } processCancel; | ||
46 | }; | 51 | }; |
47 | } GENERIC_EXECUTE_MESSAGE; | 52 | } GENERIC_EXECUTE_MESSAGE; |
48 | 53 | ||
diff --git a/src/burn/engine/bundlepackageengine.cpp b/src/burn/engine/bundlepackageengine.cpp index 88a00f5e..0bee054f 100644 --- a/src/burn/engine/bundlepackageengine.cpp +++ b/src/burn/engine/bundlepackageengine.cpp | |||
@@ -251,7 +251,6 @@ extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle( | |||
251 | ) | 251 | ) |
252 | { | 252 | { |
253 | HRESULT hr = S_OK; | 253 | HRESULT hr = S_OK; |
254 | int nResult = IDNOACTION; | ||
255 | LPCWSTR wzArguments = NULL; | 254 | LPCWSTR wzArguments = NULL; |
256 | LPWSTR sczArguments = NULL; | 255 | LPWSTR sczArguments = NULL; |
257 | LPWSTR sczArgumentsFormatted = NULL; | 256 | LPWSTR sczArgumentsFormatted = NULL; |
@@ -420,31 +419,10 @@ extern "C" HRESULT BundlePackageEngineExecuteRelatedBundle( | |||
420 | hr = EmbeddedRunBundle(sczExecutablePath, sczCommand, pfnGenericMessageHandler, pvContext, &dwExitCode); | 419 | hr = EmbeddedRunBundle(sczExecutablePath, sczCommand, pfnGenericMessageHandler, pvContext, &dwExitCode); |
421 | ExitOnFailure(hr, "Failed to run bundle as embedded from path: %ls", sczExecutablePath); | 420 | ExitOnFailure(hr, "Failed to run bundle as embedded from path: %ls", sczExecutablePath); |
422 | } | 421 | } |
423 | else // create and wait for the executable process while sending fake progress to allow cancel. | 422 | else |
424 | { | 423 | { |
425 | // Make the cache location of the executable the current directory to help those executables | 424 | hr = ExeEngineRunProcess(pfnGenericMessageHandler, pvContext, pPackage, sczExecutablePath, sczCommand, sczCachedDirectory, &dwExitCode); |
426 | // that expect stuff to be relative to them. | 425 | ExitOnFailure(hr, "Failed to run BUNDLE process"); |
427 | si.cb = sizeof(si); | ||
428 | if (!::CreateProcessW(sczExecutablePath, sczCommand, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, sczCachedDirectory, &si, &pi)) | ||
429 | { | ||
430 | ExitWithLastError(hr, "Failed to CreateProcess on path: %ls", sczExecutablePath); | ||
431 | } | ||
432 | |||
433 | do | ||
434 | { | ||
435 | message.type = GENERIC_EXECUTE_MESSAGE_PROGRESS; | ||
436 | message.dwUIHint = MB_OKCANCEL; | ||
437 | message.progress.dwPercentage = 50; | ||
438 | nResult = pfnGenericMessageHandler(&message, pvContext); | ||
439 | hr = (IDOK == nResult || IDNOACTION == nResult) ? S_OK : IDCANCEL == nResult ? HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT) : HRESULT_FROM_WIN32(ERROR_INSTALL_FAILURE); | ||
440 | ExitOnRootFailure(hr, "Bootstrapper application aborted during BUNDLE progress."); | ||
441 | |||
442 | hr = ProcWaitForCompletion(pi.hProcess, 500, &dwExitCode); | ||
443 | if (HRESULT_FROM_WIN32(WAIT_TIMEOUT) != hr) | ||
444 | { | ||
445 | ExitOnFailure(hr, "Failed to wait for executable to complete: %ls", sczExecutablePath); | ||
446 | } | ||
447 | } while (HRESULT_FROM_WIN32(WAIT_TIMEOUT) == hr); | ||
448 | } | 426 | } |
449 | 427 | ||
450 | hr = ExeEngineHandleExitCode(pPackage->Bundle.rgExitCodes, pPackage->Bundle.cExitCodes, dwExitCode, pRestart); | 428 | hr = ExeEngineHandleExitCode(pPackage->Bundle.rgExitCodes, pPackage->Bundle.cExitCodes, dwExitCode, pRestart); |
diff --git a/src/burn/engine/elevation.cpp b/src/burn/engine/elevation.cpp index 636d67ce..3c2872f1 100644 --- a/src/burn/engine/elevation.cpp +++ b/src/burn/engine/elevation.cpp | |||
@@ -43,6 +43,7 @@ typedef enum _BURN_ELEVATION_MESSAGE_TYPE | |||
43 | BURN_ELEVATION_MESSAGE_TYPE_BURN_CACHE_COMPLETE, | 43 | BURN_ELEVATION_MESSAGE_TYPE_BURN_CACHE_COMPLETE, |
44 | BURN_ELEVATION_MESSAGE_TYPE_BURN_CACHE_SUCCESS, | 44 | BURN_ELEVATION_MESSAGE_TYPE_BURN_CACHE_SUCCESS, |
45 | BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PROGRESS, | 45 | BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PROGRESS, |
46 | BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PROCESS_CANCEL, | ||
46 | BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_ERROR, | 47 | BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_ERROR, |
47 | BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_MSI_MESSAGE, | 48 | BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_MSI_MESSAGE, |
48 | BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_MSI_FILES_IN_USE, | 49 | BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_MSI_FILES_IN_USE, |
@@ -1812,7 +1813,14 @@ static HRESULT ProcessGenericExecuteMessages( | |||
1812 | 1813 | ||
1813 | // read message parameters | 1814 | // read message parameters |
1814 | hr = BuffReadNumber((BYTE*)pMsg->pvData, pMsg->cbData, &iData, &message.progress.dwPercentage); | 1815 | hr = BuffReadNumber((BYTE*)pMsg->pvData, pMsg->cbData, &iData, &message.progress.dwPercentage); |
1815 | ExitOnFailure(hr, "Failed to progress."); | 1816 | ExitOnFailure(hr, "Failed to read progress."); |
1817 | break; | ||
1818 | |||
1819 | case BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PROCESS_CANCEL: | ||
1820 | message.type = GENERIC_EXECUTE_MESSAGE_PROCESS_CANCEL; | ||
1821 | |||
1822 | hr = BuffReadNumber((BYTE*)pMsg->pvData, pMsg->cbData, &iData, &message.processCancel.dwProcessId); | ||
1823 | ExitOnFailure(hr, "Failed to read processId."); | ||
1816 | break; | 1824 | break; |
1817 | 1825 | ||
1818 | case BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_ERROR: | 1826 | case BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_ERROR: |
@@ -3450,6 +3458,13 @@ static int GenericExecuteMessageHandler( | |||
3450 | dwMessage = BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PROGRESS; | 3458 | dwMessage = BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PROGRESS; |
3451 | break; | 3459 | break; |
3452 | 3460 | ||
3461 | case GENERIC_EXECUTE_MESSAGE_PROCESS_CANCEL: | ||
3462 | hr = BuffWriteNumber(&pbData, &cbData, pMessage->processCancel.dwProcessId); | ||
3463 | ExitOnFailure(hr, "Failed to write progress percentage to message buffer."); | ||
3464 | |||
3465 | dwMessage = BURN_ELEVATION_MESSAGE_TYPE_EXECUTE_PROCESS_CANCEL; | ||
3466 | break; | ||
3467 | |||
3453 | case GENERIC_EXECUTE_MESSAGE_ERROR: | 3468 | case GENERIC_EXECUTE_MESSAGE_ERROR: |
3454 | // serialize message data | 3469 | // serialize message data |
3455 | hr = BuffWriteNumber(&pbData, &cbData, pMessage->error.dwErrorCode); | 3470 | hr = BuffWriteNumber(&pbData, &cbData, pMessage->error.dwErrorCode); |
diff --git a/src/burn/engine/engine.mc b/src/burn/engine/engine.mc index 53e6b256..9e139661 100644 --- a/src/burn/engine/engine.mc +++ b/src/burn/engine/engine.mc | |||
@@ -933,6 +933,13 @@ Language=English | |||
933 | Could not create system restore point, error: 0x%1!x!. Continuing... | 933 | Could not create system restore point, error: 0x%1!x!. Continuing... |
934 | . | 934 | . |
935 | 935 | ||
936 | MessageId=364 | ||
937 | Severity=Success | ||
938 | SymbolicName=MSG_EXECUTE_PROCESS_DELAYED_CANCEL_REQUESTED | ||
939 | Language=English | ||
940 | Bootstrapper application requested delayed cancel during package process progress, id: %1!ls!. Waiting... | ||
941 | . | ||
942 | |||
936 | MessageId=370 | 943 | MessageId=370 |
937 | Severity=Success | 944 | Severity=Success |
938 | SymbolicName=MSG_SESSION_BEGIN | 945 | SymbolicName=MSG_SESSION_BEGIN |
diff --git a/src/burn/engine/exeengine.cpp b/src/burn/engine/exeengine.cpp index c984f5a7..4c3c6fb0 100644 --- a/src/burn/engine/exeengine.cpp +++ b/src/burn/engine/exeengine.cpp | |||
@@ -317,7 +317,6 @@ extern "C" HRESULT ExeEngineExecutePackage( | |||
317 | ) | 317 | ) |
318 | { | 318 | { |
319 | HRESULT hr = S_OK; | 319 | HRESULT hr = S_OK; |
320 | int nResult = IDNOACTION; | ||
321 | LPCWSTR wzArguments = NULL; | 320 | LPCWSTR wzArguments = NULL; |
322 | LPWSTR sczArguments = NULL; | 321 | LPWSTR sczArguments = NULL; |
323 | LPWSTR sczArgumentsFormatted = NULL; | 322 | LPWSTR sczArgumentsFormatted = NULL; |
@@ -327,10 +326,7 @@ extern "C" HRESULT ExeEngineExecutePackage( | |||
327 | LPWSTR sczCommand = NULL; | 326 | LPWSTR sczCommand = NULL; |
328 | LPWSTR sczCommandObfuscated = NULL; | 327 | LPWSTR sczCommandObfuscated = NULL; |
329 | HANDLE hExecutableFile = INVALID_HANDLE_VALUE; | 328 | HANDLE hExecutableFile = INVALID_HANDLE_VALUE; |
330 | STARTUPINFOW si = { }; | ||
331 | PROCESS_INFORMATION pi = { }; | ||
332 | DWORD dwExitCode = 0; | 329 | DWORD dwExitCode = 0; |
333 | GENERIC_EXECUTE_MESSAGE message = { }; | ||
334 | BURN_PACKAGE* pPackage = pExecuteAction->exePackage.pPackage; | 330 | BURN_PACKAGE* pPackage = pExecuteAction->exePackage.pPackage; |
335 | BURN_PAYLOAD* pPackagePayload = pPackage->payloads.rgItems[0].pPayload; | 331 | BURN_PAYLOAD* pPackagePayload = pPackage->payloads.rgItems[0].pPayload; |
336 | 332 | ||
@@ -442,37 +438,10 @@ extern "C" HRESULT ExeEngineExecutePackage( | |||
442 | hr = NetFxRunChainer(sczExecutablePath, sczCommand, pfnGenericMessageHandler, pvContext, &dwExitCode); | 438 | hr = NetFxRunChainer(sczExecutablePath, sczCommand, pfnGenericMessageHandler, pvContext, &dwExitCode); |
443 | ExitOnFailure(hr, "Failed to run netfx chainer: %ls", sczExecutablePath); | 439 | ExitOnFailure(hr, "Failed to run netfx chainer: %ls", sczExecutablePath); |
444 | } | 440 | } |
445 | else // create and wait for the executable process while sending fake progress to allow cancel. | 441 | else |
446 | { | 442 | { |
447 | // Make the cache location of the executable the current directory to help those executables | 443 | hr = ExeEngineRunProcess(pfnGenericMessageHandler, pvContext, pPackage, sczExecutablePath, sczCommand, sczCachedDirectory, &dwExitCode); |
448 | // that expect stuff to be relative to them. | 444 | ExitOnFailure(hr, "Failed to run EXE process"); |
449 | si.cb = sizeof(si); | ||
450 | if (!::CreateProcessW(sczExecutablePath, sczCommand, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, sczCachedDirectory, &si, &pi)) | ||
451 | { | ||
452 | ExitWithLastError(hr, "Failed to CreateProcess on path: %ls", sczExecutablePath); | ||
453 | } | ||
454 | |||
455 | if (pPackage->Exe.fFireAndForget) | ||
456 | { | ||
457 | ::WaitForInputIdle(pi.hProcess, 5000); | ||
458 | ExitFunction(); | ||
459 | } | ||
460 | |||
461 | do | ||
462 | { | ||
463 | message.type = GENERIC_EXECUTE_MESSAGE_PROGRESS; | ||
464 | message.dwUIHint = MB_OKCANCEL; | ||
465 | message.progress.dwPercentage = 50; | ||
466 | nResult = pfnGenericMessageHandler(&message, pvContext); | ||
467 | hr = (IDOK == nResult || IDNOACTION == nResult) ? S_OK : IDCANCEL == nResult ? HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT) : HRESULT_FROM_WIN32(ERROR_INSTALL_FAILURE); | ||
468 | ExitOnRootFailure(hr, "Bootstrapper application aborted during EXE progress."); | ||
469 | |||
470 | hr = ProcWaitForCompletion(pi.hProcess, 500, &dwExitCode); | ||
471 | if (HRESULT_FROM_WIN32(WAIT_TIMEOUT) != hr) | ||
472 | { | ||
473 | ExitOnFailure(hr, "Failed to wait for executable to complete: %ls", sczExecutablePath); | ||
474 | } | ||
475 | } while (HRESULT_FROM_WIN32(WAIT_TIMEOUT) == hr); | ||
476 | } | 445 | } |
477 | 446 | ||
478 | hr = ExeEngineHandleExitCode(pPackage->Exe.rgExitCodes, pPackage->Exe.cExitCodes, dwExitCode, pRestart); | 447 | hr = ExeEngineHandleExitCode(pPackage->Exe.rgExitCodes, pPackage->Exe.cExitCodes, dwExitCode, pRestart); |
@@ -487,8 +456,6 @@ LExit: | |||
487 | StrSecureZeroFreeString(sczCommand); | 456 | StrSecureZeroFreeString(sczCommand); |
488 | ReleaseStr(sczCommandObfuscated); | 457 | ReleaseStr(sczCommandObfuscated); |
489 | 458 | ||
490 | ReleaseHandle(pi.hThread); | ||
491 | ReleaseHandle(pi.hProcess); | ||
492 | ReleaseFileHandle(hExecutableFile); | 459 | ReleaseFileHandle(hExecutableFile); |
493 | 460 | ||
494 | // Best effort to clear the execute package cache folder and action variables. | 461 | // Best effort to clear the execute package cache folder and action variables. |
@@ -498,6 +465,99 @@ LExit: | |||
498 | return hr; | 465 | return hr; |
499 | } | 466 | } |
500 | 467 | ||
468 | extern "C" HRESULT ExeEngineRunProcess( | ||
469 | __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, | ||
470 | __in LPVOID pvContext, | ||
471 | __in BURN_PACKAGE* pPackage, | ||
472 | __in_z LPCWSTR wzExecutablePath, | ||
473 | __in_z LPWSTR wzCommand, | ||
474 | __in_z_opt LPCWSTR wzCachedDirectory, | ||
475 | __inout DWORD* pdwExitCode | ||
476 | ) | ||
477 | { | ||
478 | HRESULT hr = S_OK; | ||
479 | STARTUPINFOW si = { }; | ||
480 | PROCESS_INFORMATION pi = { }; | ||
481 | GENERIC_EXECUTE_MESSAGE message = { }; | ||
482 | int nResult = IDNOACTION; | ||
483 | DWORD dwProcessId = 0; | ||
484 | BOOL fDelayedCancel = FALSE; | ||
485 | BOOL fFireAndForget = BURN_PACKAGE_TYPE_EXE == pPackage->type && pPackage->Exe.fFireAndForget; | ||
486 | BOOL fInheritHandles = BURN_PACKAGE_TYPE_BUNDLE == pPackage->type; | ||
487 | |||
488 | // Make the cache location of the executable the current directory to help those executables | ||
489 | // that expect stuff to be relative to them. | ||
490 | si.cb = sizeof(si); | ||
491 | if (!::CreateProcessW(wzExecutablePath, wzCommand, NULL, NULL, fInheritHandles, CREATE_NO_WINDOW, NULL, wzCachedDirectory, &si, &pi)) | ||
492 | { | ||
493 | ExitWithLastError(hr, "Failed to CreateProcess on path: %ls", wzExecutablePath); | ||
494 | } | ||
495 | |||
496 | if (fFireAndForget) | ||
497 | { | ||
498 | ::WaitForInputIdle(pi.hProcess, 5000); | ||
499 | ExitFunction(); | ||
500 | } | ||
501 | |||
502 | dwProcessId = ::GetProcessId(pi.hProcess); | ||
503 | |||
504 | // Wait for the executable process while sending fake progress to allow cancel. | ||
505 | do | ||
506 | { | ||
507 | message.type = GENERIC_EXECUTE_MESSAGE_PROGRESS; | ||
508 | message.dwUIHint = MB_OKCANCEL; | ||
509 | message.progress.dwPercentage = 50; | ||
510 | nResult = pfnGenericMessageHandler(&message, pvContext); | ||
511 | |||
512 | if (IDCANCEL == nResult) | ||
513 | { | ||
514 | memset(&message, 0, sizeof(message)); | ||
515 | message.type = GENERIC_EXECUTE_MESSAGE_PROCESS_CANCEL; | ||
516 | message.dwUIHint = MB_ABORTRETRYIGNORE; | ||
517 | message.processCancel.dwProcessId = dwProcessId; | ||
518 | nResult = pfnGenericMessageHandler(&message, pvContext); | ||
519 | |||
520 | if (IDIGNORE == nResult) // abandon | ||
521 | { | ||
522 | nResult = IDCANCEL; | ||
523 | fDelayedCancel = FALSE; | ||
524 | } | ||
525 | //else if (IDABORT == nResult) // kill | ||
526 | else // wait | ||
527 | { | ||
528 | if (!fDelayedCancel) | ||
529 | { | ||
530 | fDelayedCancel = TRUE; | ||
531 | |||
532 | LogId(REPORT_STANDARD, MSG_EXECUTE_PROCESS_DELAYED_CANCEL_REQUESTED, pPackage->sczId); | ||
533 | } | ||
534 | |||
535 | nResult = IDNOACTION; | ||
536 | } | ||
537 | } | ||
538 | |||
539 | hr = (IDOK == nResult || IDNOACTION == nResult) ? S_OK : IDCANCEL == nResult ? HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT) : HRESULT_FROM_WIN32(ERROR_INSTALL_FAILURE); | ||
540 | ExitOnRootFailure(hr, "Bootstrapper application aborted during package process progress."); | ||
541 | |||
542 | hr = ProcWaitForCompletion(pi.hProcess, 500, pdwExitCode); | ||
543 | if (HRESULT_FROM_WIN32(WAIT_TIMEOUT) != hr) | ||
544 | { | ||
545 | ExitOnFailure(hr, "Failed to wait for executable to complete: %ls", wzExecutablePath); | ||
546 | } | ||
547 | } while (HRESULT_FROM_WIN32(WAIT_TIMEOUT) == hr); | ||
548 | |||
549 | if (fDelayedCancel) | ||
550 | { | ||
551 | ExitWithRootFailure(hr, HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT), "Bootstrapper application cancelled during package process progress, exit code: 0x%x", *pdwExitCode); | ||
552 | } | ||
553 | |||
554 | LExit: | ||
555 | ReleaseHandle(pi.hThread); | ||
556 | ReleaseHandle(pi.hProcess); | ||
557 | |||
558 | return hr; | ||
559 | } | ||
560 | |||
501 | extern "C" void ExeEngineUpdateInstallRegistrationState( | 561 | extern "C" void ExeEngineUpdateInstallRegistrationState( |
502 | __in BURN_EXECUTE_ACTION* pAction, | 562 | __in BURN_EXECUTE_ACTION* pAction, |
503 | __in HRESULT hrExecute | 563 | __in HRESULT hrExecute |
diff --git a/src/burn/engine/exeengine.h b/src/burn/engine/exeengine.h index 743621b7..636988f1 100644 --- a/src/burn/engine/exeengine.h +++ b/src/burn/engine/exeengine.h | |||
@@ -42,6 +42,15 @@ HRESULT ExeEngineExecutePackage( | |||
42 | __in LPVOID pvContext, | 42 | __in LPVOID pvContext, |
43 | __out BOOTSTRAPPER_APPLY_RESTART* pRestart | 43 | __out BOOTSTRAPPER_APPLY_RESTART* pRestart |
44 | ); | 44 | ); |
45 | HRESULT ExeEngineRunProcess( | ||
46 | __in PFN_GENERICMESSAGEHANDLER pfnGenericMessageHandler, | ||
47 | __in LPVOID pvContext, | ||
48 | __in BURN_PACKAGE* pPackage, | ||
49 | __in_z LPCWSTR wzExecutablePath, | ||
50 | __in_z LPWSTR wzCommand, | ||
51 | __in_z_opt LPCWSTR wzCachedDirectory, | ||
52 | __inout DWORD* pdwExitCode | ||
53 | ); | ||
45 | void ExeEngineUpdateInstallRegistrationState( | 54 | void ExeEngineUpdateInstallRegistrationState( |
46 | __in BURN_EXECUTE_ACTION* pAction, | 55 | __in BURN_EXECUTE_ACTION* pAction, |
47 | __in HRESULT hrExecute | 56 | __in HRESULT hrExecute |
diff --git a/src/burn/engine/msuengine.cpp b/src/burn/engine/msuengine.cpp index 091bbe62..2f1fb61c 100644 --- a/src/burn/engine/msuengine.cpp +++ b/src/burn/engine/msuengine.cpp | |||
@@ -264,7 +264,6 @@ extern "C" HRESULT MsuEngineExecutePackage( | |||
264 | ) | 264 | ) |
265 | { | 265 | { |
266 | HRESULT hr = S_OK; | 266 | HRESULT hr = S_OK; |
267 | int nResult = IDNOACTION; | ||
268 | LPWSTR sczCachedDirectory = NULL; | 267 | LPWSTR sczCachedDirectory = NULL; |
269 | LPWSTR sczMsuPath = NULL; | 268 | LPWSTR sczMsuPath = NULL; |
270 | LPWSTR sczWindowsPath = NULL; | 269 | LPWSTR sczWindowsPath = NULL; |
@@ -350,35 +349,8 @@ extern "C" HRESULT MsuEngineExecutePackage( | |||
350 | hr = EnsureWUServiceEnabled(fStopWusaService, &schWu, &fWuWasDisabled); | 349 | hr = EnsureWUServiceEnabled(fStopWusaService, &schWu, &fWuWasDisabled); |
351 | ExitOnFailure(hr, "Failed to ensure WU service was enabled to install MSU package."); | 350 | ExitOnFailure(hr, "Failed to ensure WU service was enabled to install MSU package."); |
352 | 351 | ||
353 | // create process | 352 | hr = ExeEngineRunProcess(pfnGenericMessageHandler, pvContext, pPackage, sczWusaPath, sczCommand, NULL, &dwExitCode); |
354 | si.cb = sizeof(si); | 353 | ExitOnFailure(hr, "Failed to run MSU process"); |
355 | if (!::CreateProcessW(sczWusaPath, sczCommand, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) | ||
356 | { | ||
357 | ExitWithLastError(hr, "Failed to CreateProcess on path: %ls", sczWusaPath); | ||
358 | } | ||
359 | |||
360 | do | ||
361 | { | ||
362 | message.type = GENERIC_EXECUTE_MESSAGE_PROGRESS; | ||
363 | message.dwUIHint = MB_OKCANCEL; | ||
364 | message.progress.dwPercentage = 50; | ||
365 | nResult = pfnGenericMessageHandler(&message, pvContext); | ||
366 | hr = (IDOK == nResult || IDNOACTION == nResult) ? S_OK : IDCANCEL == nResult ? HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT) : HRESULT_FROM_WIN32(ERROR_INSTALL_FAILURE); | ||
367 | ExitOnRootFailure(hr, "Bootstrapper application aborted during MSU progress."); | ||
368 | |||
369 | // wait for process to terminate | ||
370 | hr = ProcWaitForCompletion(pi.hProcess, 500, &dwExitCode); | ||
371 | if (HRESULT_FROM_WIN32(WAIT_TIMEOUT) != hr) | ||
372 | { | ||
373 | ExitOnFailure(hr, "Failed to wait for executable to complete: %ls", sczWusaPath); | ||
374 | } | ||
375 | } while (HRESULT_FROM_WIN32(WAIT_TIMEOUT) == hr); | ||
376 | |||
377 | // get process exit code | ||
378 | if (!::GetExitCodeProcess(pi.hProcess, &dwExitCode)) | ||
379 | { | ||
380 | ExitWithLastError(hr, "Failed to get process exit code."); | ||
381 | } | ||
382 | 354 | ||
383 | // We'll normalize the restart required error code from wusa.exe just in case. Most likely | 355 | // We'll normalize the restart required error code from wusa.exe just in case. Most likely |
384 | // that on reboot we'll actually get WU_S_REBOOT_REQUIRED. | 356 | // that on reboot we'll actually get WU_S_REBOOT_REQUIRED. |
diff --git a/src/burn/engine/userexperience.cpp b/src/burn/engine/userexperience.cpp index 81ce8bb9..06f87363 100644 --- a/src/burn/engine/userexperience.cpp +++ b/src/burn/engine/userexperience.cpp | |||
@@ -104,7 +104,7 @@ extern "C" HRESULT UserExperienceLoad( | |||
104 | args.pCommand = pCommand; | 104 | args.pCommand = pCommand; |
105 | args.pfnBootstrapperEngineProc = EngineForApplicationProc; | 105 | args.pfnBootstrapperEngineProc = EngineForApplicationProc; |
106 | args.pvBootstrapperEngineProcContext = pEngineContext; | 106 | args.pvBootstrapperEngineProcContext = pEngineContext; |
107 | args.qwEngineAPIVersion = MAKEQWORDVERSION(2022, 3, 14, 0); | 107 | args.qwEngineAPIVersion = MAKEQWORDVERSION(2022, 3, 17, 0); |
108 | 108 | ||
109 | results.cbSize = sizeof(BOOTSTRAPPER_CREATE_RESULTS); | 109 | results.cbSize = sizeof(BOOTSTRAPPER_CREATE_RESULTS); |
110 | 110 | ||
@@ -1701,6 +1701,34 @@ LExit: | |||
1701 | return hr; | 1701 | return hr; |
1702 | } | 1702 | } |
1703 | 1703 | ||
1704 | BAAPI UserExperienceOnExecuteProcessCancel( | ||
1705 | __in BURN_USER_EXPERIENCE* pUserExperience, | ||
1706 | __in_z LPCWSTR wzPackageId, | ||
1707 | __in DWORD dwProcessId, | ||
1708 | __inout BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION* pAction | ||
1709 | ) | ||
1710 | { | ||
1711 | HRESULT hr = S_OK; | ||
1712 | BA_ONEXECUTEPROCESSCANCEL_ARGS args = { }; | ||
1713 | BA_ONEXECUTEPROCESSCANCEL_RESULTS results = { }; | ||
1714 | |||
1715 | args.cbSize = sizeof(args); | ||
1716 | args.wzPackageId = wzPackageId; | ||
1717 | args.dwProcessId = dwProcessId; | ||
1718 | args.recommendation = *pAction; | ||
1719 | |||
1720 | results.cbSize = sizeof(results); | ||
1721 | results.action = *pAction; | ||
1722 | |||
1723 | hr = SendBAMessage(pUserExperience, BOOTSTRAPPER_APPLICATION_MESSAGE_ONEXECUTEPROCESSCANCEL, &args, &results); | ||
1724 | ExitOnFailure(hr, "BA OnExecuteProcessCancel failed."); | ||
1725 | |||
1726 | *pAction = results.action; | ||
1727 | |||
1728 | LExit: | ||
1729 | return hr; | ||
1730 | } | ||
1731 | |||
1704 | EXTERN_C BAAPI UserExperienceOnExecuteProgress( | 1732 | EXTERN_C BAAPI UserExperienceOnExecuteProgress( |
1705 | __in BURN_USER_EXPERIENCE* pUserExperience, | 1733 | __in BURN_USER_EXPERIENCE* pUserExperience, |
1706 | __in_z LPCWSTR wzPackageId, | 1734 | __in_z LPCWSTR wzPackageId, |
diff --git a/src/burn/engine/userexperience.h b/src/burn/engine/userexperience.h index 2f18acdd..de558ad5 100644 --- a/src/burn/engine/userexperience.h +++ b/src/burn/engine/userexperience.h | |||
@@ -398,6 +398,12 @@ BAAPI UserExperienceOnExecutePatchTarget( | |||
398 | __in_z LPCWSTR wzPackageId, | 398 | __in_z LPCWSTR wzPackageId, |
399 | __in_z LPCWSTR wzTargetProductCode | 399 | __in_z LPCWSTR wzTargetProductCode |
400 | ); | 400 | ); |
401 | BAAPI UserExperienceOnExecuteProcessCancel( | ||
402 | __in BURN_USER_EXPERIENCE* pUserExperience, | ||
403 | __in_z LPCWSTR wzPackageId, | ||
404 | __in DWORD dwProcessId, | ||
405 | __inout BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION* pAction | ||
406 | ); | ||
401 | BAAPI UserExperienceOnExecuteProgress( | 407 | BAAPI UserExperienceOnExecuteProgress( |
402 | __in BURN_USER_EXPERIENCE* pUserExperience, | 408 | __in BURN_USER_EXPERIENCE* pUserExperience, |
403 | __in_z LPCWSTR wzPackageId, | 409 | __in_z LPCWSTR wzPackageId, |
diff --git a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj index 7375af86..35415dc3 100644 --- a/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj +++ b/src/burn/test/BurnUnitTest/BurnUnitTest.vcxproj | |||
@@ -80,7 +80,9 @@ | |||
80 | <ItemGroup> | 80 | <ItemGroup> |
81 | <None Include="TestData\CacheTest\CacheSignatureTest.File" CopyToOutputDirectory="PreserveNewest" /> | 81 | <None Include="TestData\CacheTest\CacheSignatureTest.File" CopyToOutputDirectory="PreserveNewest" /> |
82 | <None Include="TestData\PlanTest\BasicFunctionality_BundleA_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> | 82 | <None Include="TestData\PlanTest\BasicFunctionality_BundleA_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> |
83 | <None Include="TestData\PlanTest\Failure_BundleD_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> | ||
83 | <None Include="TestData\PlanTest\MsiTransaction_BundleAv1_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> | 84 | <None Include="TestData\PlanTest\MsiTransaction_BundleAv1_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> |
85 | <None Include="TestData\PlanTest\MsuPackageFixture_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> | ||
84 | <None Include="TestData\PlanTest\Slipstream_BundleA_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> | 86 | <None Include="TestData\PlanTest\Slipstream_BundleA_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> |
85 | <None Include="TestData\PlanTest\Slipstream_BundleA_modified_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> | 87 | <None Include="TestData\PlanTest\Slipstream_BundleA_modified_manifest.xml" CopyToOutputDirectory="PreserveNewest" /> |
86 | </ItemGroup> | 88 | </ItemGroup> |
diff --git a/src/burn/test/BurnUnitTest/PlanTest.cpp b/src/burn/test/BurnUnitTest/PlanTest.cpp index 4d726fb4..770922b4 100644 --- a/src/burn/test/BurnUnitTest/PlanTest.cpp +++ b/src/burn/test/BurnUnitTest/PlanTest.cpp | |||
@@ -10,7 +10,9 @@ static HRESULT WINAPI PlanTestBAProc( | |||
10 | ); | 10 | ); |
11 | 11 | ||
12 | static LPCWSTR wzMsiTransactionManifestFileName = L"MsiTransaction_BundleAv1_manifest.xml"; | 12 | static LPCWSTR wzMsiTransactionManifestFileName = L"MsiTransaction_BundleAv1_manifest.xml"; |
13 | static LPCWSTR wzSingleExeManifestFileName = L"Failure_BundleD_manifest.xml"; | ||
13 | static LPCWSTR wzSingleMsiManifestFileName = L"BasicFunctionality_BundleA_manifest.xml"; | 14 | static LPCWSTR wzSingleMsiManifestFileName = L"BasicFunctionality_BundleA_manifest.xml"; |
15 | static LPCWSTR wzSingleMsuManifestFileName = L"MsuPackageFixture_manifest.xml"; | ||
14 | static LPCWSTR wzSlipstreamManifestFileName = L"Slipstream_BundleA_manifest.xml"; | 16 | static LPCWSTR wzSlipstreamManifestFileName = L"Slipstream_BundleA_manifest.xml"; |
15 | static LPCWSTR wzSlipstreamModifiedManifestFileName = L"Slipstream_BundleA_modified_manifest.xml"; | 17 | static LPCWSTR wzSlipstreamModifiedManifestFileName = L"Slipstream_BundleA_modified_manifest.xml"; |
16 | 18 | ||
@@ -659,6 +661,97 @@ namespace Bootstrapper | |||
659 | } | 661 | } |
660 | 662 | ||
661 | [Fact] | 663 | [Fact] |
664 | void SingleExeInstallTest() | ||
665 | { | ||
666 | HRESULT hr = S_OK; | ||
667 | BURN_ENGINE_STATE engineState = { }; | ||
668 | BURN_ENGINE_STATE* pEngineState = &engineState; | ||
669 | BURN_PLAN* pPlan = &engineState.plan; | ||
670 | |||
671 | InitializeEngineStateForCorePlan(wzSingleExeManifestFileName, pEngineState); | ||
672 | DetectAttachedContainerAsAttached(pEngineState); | ||
673 | DetectPermanentPackagesAsPresentAndCached(pEngineState); | ||
674 | |||
675 | hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL); | ||
676 | NativeAssert::Succeeded(hr, "CorePlan failed"); | ||
677 | |||
678 | Assert::Equal<DWORD>(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); | ||
679 | NativeAssert::StringEqual(L"{9C184683-04FB-49AD-9D79-65101BDC3EE3}", pPlan->wzBundleId); | ||
680 | NativeAssert::StringEqual(L"{9C184683-04FB-49AD-9D79-65101BDC3EE3}", pPlan->wzBundleProviderKey); | ||
681 | Assert::Equal<BOOL>(FALSE, pPlan->fEnabledForwardCompatibleBundle); | ||
682 | Assert::Equal<BOOL>(TRUE, pPlan->fPerMachine); | ||
683 | Assert::Equal<BOOL>(TRUE, pPlan->fCanAffectMachineState); | ||
684 | Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback); | ||
685 | Assert::Equal<BOOL>(FALSE, pPlan->fDisallowRemoval); | ||
686 | Assert::Equal<BOOL>(FALSE, pPlan->fDowngrade); | ||
687 | |||
688 | BOOL fRollback = FALSE; | ||
689 | DWORD dwIndex = 0; | ||
690 | ValidateDependentRegistrationAction(pPlan, fRollback, dwIndex++, TRUE, L"{9C184683-04FB-49AD-9D79-65101BDC3EE3}", L"{9C184683-04FB-49AD-9D79-65101BDC3EE3}"); | ||
691 | Assert::Equal(dwIndex, pPlan->cRegistrationActions); | ||
692 | |||
693 | fRollback = TRUE; | ||
694 | dwIndex = 0; | ||
695 | ValidateDependentRegistrationAction(pPlan, fRollback, dwIndex++, FALSE, L"{9C184683-04FB-49AD-9D79-65101BDC3EE3}", L"{9C184683-04FB-49AD-9D79-65101BDC3EE3}"); | ||
696 | Assert::Equal(dwIndex, pPlan->cRollbackRegistrationActions); | ||
697 | |||
698 | fRollback = FALSE; | ||
699 | dwIndex = 0; | ||
700 | ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); | ||
701 | ValidateCachePackage(pPlan, fRollback, dwIndex++, L"ExeA"); | ||
702 | ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); | ||
703 | Assert::Equal(dwIndex, pPlan->cCacheActions); | ||
704 | |||
705 | fRollback = TRUE; | ||
706 | dwIndex = 0; | ||
707 | Assert::Equal(dwIndex, pPlan->cRollbackCacheActions); | ||
708 | |||
709 | Assert::Equal(1463267ull, pPlan->qwEstimatedSize); | ||
710 | Assert::Equal(119695ull, pPlan->qwCacheSizeTotal); | ||
711 | |||
712 | fRollback = FALSE; | ||
713 | dwIndex = 0; | ||
714 | DWORD dwExecuteCheckpointId = 2; | ||
715 | ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); | ||
716 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
717 | ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"ExeA"); | ||
718 | ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"ExeA", BOOTSTRAPPER_ACTION_STATE_INSTALL); | ||
719 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
720 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
721 | ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++); | ||
722 | Assert::Equal(dwIndex, pPlan->cExecuteActions); | ||
723 | |||
724 | fRollback = TRUE; | ||
725 | dwIndex = 0; | ||
726 | dwExecuteCheckpointId = 2; | ||
727 | ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); | ||
728 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
729 | ValidateExecuteExePackage(pPlan, fRollback, dwIndex++, L"ExeA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL); | ||
730 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
731 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
732 | ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++); | ||
733 | Assert::Equal(dwIndex, pPlan->cRollbackActions); | ||
734 | |||
735 | Assert::Equal(1ul, pPlan->cExecutePackagesTotal); | ||
736 | Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal); | ||
737 | |||
738 | dwIndex = 0; | ||
739 | Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions); | ||
740 | |||
741 | dwIndex = 0; | ||
742 | ValidateCleanAction(pPlan, dwIndex++, L"NetFx48Web"); | ||
743 | ValidateCleanAction(pPlan, dwIndex++, L"ExeA"); | ||
744 | Assert::Equal(dwIndex, pPlan->cCleanActions); | ||
745 | |||
746 | UINT uIndex = 0; | ||
747 | ValidatePlannedProvider(pPlan, uIndex++, L"{9C184683-04FB-49AD-9D79-65101BDC3EE3}", NULL); | ||
748 | Assert::Equal(uIndex, pPlan->cPlannedProviders); | ||
749 | |||
750 | Assert::Equal(2ul, pEngineState->packages.cPackages); | ||
751 | ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[1], L"ExeA", BURN_PACKAGE_REGISTRATION_STATE_ABSENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT); | ||
752 | } | ||
753 | |||
754 | [Fact] | ||
662 | void SingleMsiCacheTest() | 755 | void SingleMsiCacheTest() |
663 | { | 756 | { |
664 | HRESULT hr = S_OK; | 757 | HRESULT hr = S_OK; |
@@ -1533,6 +1626,98 @@ namespace Bootstrapper | |||
1533 | } | 1626 | } |
1534 | 1627 | ||
1535 | [Fact] | 1628 | [Fact] |
1629 | void SingleMsuInstallTest() | ||
1630 | { | ||
1631 | HRESULT hr = S_OK; | ||
1632 | BURN_ENGINE_STATE engineState = { }; | ||
1633 | BURN_ENGINE_STATE* pEngineState = &engineState; | ||
1634 | BURN_PLAN* pPlan = &engineState.plan; | ||
1635 | |||
1636 | InitializeEngineStateForCorePlan(wzSingleMsuManifestFileName, pEngineState); | ||
1637 | DetectAttachedContainerAsAttached(pEngineState); | ||
1638 | DetectPackagesAsAbsent(pEngineState); | ||
1639 | |||
1640 | hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL); | ||
1641 | NativeAssert::Succeeded(hr, "CorePlan failed"); | ||
1642 | |||
1643 | Assert::Equal<DWORD>(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action); | ||
1644 | NativeAssert::StringEqual(L"{06077C60-DC46-4F4A-8D3C-05F869187191}", pPlan->wzBundleId); | ||
1645 | NativeAssert::StringEqual(L"{06077C60-DC46-4F4A-8D3C-05F869187191}", pPlan->wzBundleProviderKey); | ||
1646 | Assert::Equal<BOOL>(FALSE, pPlan->fEnabledForwardCompatibleBundle); | ||
1647 | Assert::Equal<BOOL>(TRUE, pPlan->fPerMachine); | ||
1648 | Assert::Equal<BOOL>(TRUE, pPlan->fCanAffectMachineState); | ||
1649 | Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback); | ||
1650 | Assert::Equal<BOOL>(FALSE, pPlan->fDisallowRemoval); | ||
1651 | Assert::Equal<BOOL>(FALSE, pPlan->fDowngrade); | ||
1652 | |||
1653 | BOOL fRollback = FALSE; | ||
1654 | DWORD dwIndex = 0; | ||
1655 | ValidateDependentRegistrationAction(pPlan, fRollback, dwIndex++, TRUE, L"{06077C60-DC46-4F4A-8D3C-05F869187191}", L"{06077C60-DC46-4F4A-8D3C-05F869187191}"); | ||
1656 | Assert::Equal(dwIndex, pPlan->cRegistrationActions); | ||
1657 | |||
1658 | fRollback = TRUE; | ||
1659 | dwIndex = 0; | ||
1660 | ValidateDependentRegistrationAction(pPlan, fRollback, dwIndex++, FALSE, L"{06077C60-DC46-4F4A-8D3C-05F869187191}", L"{06077C60-DC46-4F4A-8D3C-05F869187191}"); | ||
1661 | Assert::Equal(dwIndex, pPlan->cRollbackRegistrationActions); | ||
1662 | |||
1663 | fRollback = FALSE; | ||
1664 | dwIndex = 0; | ||
1665 | ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); | ||
1666 | ValidateCachePackage(pPlan, fRollback, dwIndex++, L"test.msu"); | ||
1667 | ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); | ||
1668 | Assert::Equal(dwIndex, pPlan->cCacheActions); | ||
1669 | |||
1670 | fRollback = TRUE; | ||
1671 | dwIndex = 0; | ||
1672 | ValidateCacheRollbackPackage(pPlan, fRollback, dwIndex++, L"test.msu"); | ||
1673 | ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1); | ||
1674 | Assert::Equal(dwIndex, pPlan->cRollbackCacheActions); | ||
1675 | |||
1676 | Assert::Equal(56ull, pPlan->qwEstimatedSize); | ||
1677 | Assert::Equal(140ull, pPlan->qwCacheSizeTotal); | ||
1678 | |||
1679 | fRollback = FALSE; | ||
1680 | dwIndex = 0; | ||
1681 | DWORD dwExecuteCheckpointId = 2; | ||
1682 | ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); | ||
1683 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
1684 | ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"test.msu"); | ||
1685 | ValidateExecuteMsuPackage(pPlan, fRollback, dwIndex++, L"test.msu", BOOTSTRAPPER_ACTION_STATE_INSTALL); | ||
1686 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
1687 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
1688 | ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++); | ||
1689 | Assert::Equal(dwIndex, pPlan->cExecuteActions); | ||
1690 | |||
1691 | fRollback = TRUE; | ||
1692 | dwIndex = 0; | ||
1693 | dwExecuteCheckpointId = 2; | ||
1694 | ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); | ||
1695 | ValidateExecuteUncachePackage(pPlan, fRollback, dwIndex++, L"test.msu"); | ||
1696 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
1697 | ValidateExecuteMsuPackage(pPlan, fRollback, dwIndex++, L"test.msu", BOOTSTRAPPER_ACTION_STATE_UNINSTALL); | ||
1698 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
1699 | ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); | ||
1700 | ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++); | ||
1701 | Assert::Equal(dwIndex, pPlan->cRollbackActions); | ||
1702 | |||
1703 | Assert::Equal(1ul, pPlan->cExecutePackagesTotal); | ||
1704 | Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal); | ||
1705 | |||
1706 | dwIndex = 0; | ||
1707 | Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions); | ||
1708 | |||
1709 | dwIndex = 0; | ||
1710 | Assert::Equal(dwIndex, pPlan->cCleanActions); | ||
1711 | |||
1712 | UINT uIndex = 0; | ||
1713 | ValidatePlannedProvider(pPlan, uIndex++, L"{06077C60-DC46-4F4A-8D3C-05F869187191}", NULL); | ||
1714 | Assert::Equal(uIndex, pPlan->cPlannedProviders); | ||
1715 | |||
1716 | Assert::Equal(1ul, pEngineState->packages.cPackages); | ||
1717 | ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"test.msu", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT); | ||
1718 | } | ||
1719 | |||
1720 | [Fact] | ||
1536 | void SlipstreamInstallTest() | 1721 | void SlipstreamInstallTest() |
1537 | { | 1722 | { |
1538 | HRESULT hr = S_OK; | 1723 | HRESULT hr = S_OK; |
@@ -2571,6 +2756,21 @@ namespace Bootstrapper | |||
2571 | NativeAssert::StringEqual(wzPackageId, pOrderedPatch->pPackage->sczId); | 2756 | NativeAssert::StringEqual(wzPackageId, pOrderedPatch->pPackage->sczId); |
2572 | } | 2757 | } |
2573 | 2758 | ||
2759 | void ValidateExecuteMsuPackage( | ||
2760 | __in BURN_PLAN* pPlan, | ||
2761 | __in BOOL fRollback, | ||
2762 | __in DWORD dwIndex, | ||
2763 | __in LPCWSTR wzPackageId, | ||
2764 | __in BOOTSTRAPPER_ACTION_STATE action | ||
2765 | ) | ||
2766 | { | ||
2767 | BURN_EXECUTE_ACTION* pAction = ValidateExecuteActionExists(pPlan, fRollback, dwIndex); | ||
2768 | Assert::Equal<DWORD>(BURN_EXECUTE_ACTION_TYPE_MSU_PACKAGE, pAction->type); | ||
2769 | NativeAssert::StringEqual(wzPackageId, pAction->msuPackage.pPackage->sczId); | ||
2770 | Assert::Equal<DWORD>(action, pAction->msuPackage.action); | ||
2771 | Assert::Equal<BOOL>(FALSE, pAction->fDeleted); | ||
2772 | } | ||
2773 | |||
2574 | void ValidateExecutePackageDependency( | 2774 | void ValidateExecutePackageDependency( |
2575 | __in BURN_PLAN* pPlan, | 2775 | __in BURN_PLAN* pPlan, |
2576 | __in BOOL fRollback, | 2776 | __in BOOL fRollback, |
diff --git a/src/burn/test/BurnUnitTest/TestData/PlanTest/Failure_BundleD_manifest.xml b/src/burn/test/BurnUnitTest/TestData/PlanTest/Failure_BundleD_manifest.xml new file mode 100644 index 00000000..6afb0108 --- /dev/null +++ b/src/burn/test/BurnUnitTest/TestData/PlanTest/Failure_BundleD_manifest.xml | |||
@@ -0,0 +1 @@ | |||
<?xml version="1.0" encoding="utf-8"?><BurnManifest xmlns="http://wixtoolset.org/schemas/v4/2008/Burn"><Log PathVariable="WixBundleLog" Prefix="~FailureTests_BundleD" Extension=".log" /><RelatedBundle Id="{3C1A4842-81AC-4C90-8B35-A5E18F034C8D}" Action="Upgrade" /><Variable Id="TestGroupName" Value="FailureTests" Type="string" Hidden="no" Persisted="no" /><Variable Id="WixBundleInProgressName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSource" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSourceFolder" Hidden="no" Persisted="yes" /><Variable Id="WixBundleLastUsedSource" Hidden="no" Persisted="yes" /><RegistrySearch Id="NETFRAMEWORK45" Variable="NETFRAMEWORK45" Root="HKLM" Key="SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" Value="Release" Type="value" VariableType="string" /><RegistrySearch Id="wrsQ7JTGqvaQuDYjfHJoyjxtkLlR6c" Variable="ExeA_Version" Root="HKLM" Key="Software\WiX\Tests\FailureTests\ExeA" Value="Version" Type="value" VariableType="string" /><UX><Payload Id="WixManagedBootstrapperApplicationHost" FilePath="mbahost.dll" SourcePath="u30" /><Payload Id="payO60IVK4ATGzPpMz3rwVbUWl6DyU" FilePath="WixToolset.Mba.Host.config" SourcePath="u0" /><Payload Id="payxj4zDAKL2NVlz4ohp0GvwFHepyI" FilePath="TestBA.dll" SourcePath="u1" /><Payload Id="pay1hOSAUC8_D633cD2TXpIXCL30OU" FilePath="mbanative.dll" SourcePath="u2" /><Payload Id="payujy6Izl_BlUNfHt2eI.ADfjYAv4" FilePath="WixToolset.Mba.Core.dll" SourcePath="u3" /><Payload Id="payR4EbR4OTDZpPEycWaSSM_gZRBWM" FilePath="mbapreq.thm" SourcePath="u4" /><Payload Id="paylVCy2Ecl8pHPdJTCQZryUG4T9us" FilePath="mbapreq.png" SourcePath="u5" /><Payload Id="payTaG4B_lob1aLcKFaOqSSG3MPMpU" FilePath="mbapreq.wxl" SourcePath="u6" /><Payload Id="payZwIGuiezVTitZOoZKxyh2DdRSGs" FilePath="1028\mbapreq.wxl" SourcePath="u7" /><Payload Id="pay.herBWX.LlOh8jLsx24aWdunV_0" FilePath="1029\mbapreq.wxl" SourcePath="u8" /><Payload Id="pay8DkMszYsoxxdgX14huLDMYXylQg" FilePath="1030\mbapreq.wxl" SourcePath="u9" /><Payload Id="payPaHpoTeOdkW.TK99IDwktNLhTAg" FilePath="1031\mbapreq.wxl" SourcePath="u10" /><Payload Id="pay45AtAzterLTMzZgdxxtuYvaiXwU" FilePath="1032\mbapreq.wxl" SourcePath="u11" /><Payload Id="payA2VEKIqhePyNIEmr14eyH3JoVLc" FilePath="1035\mbapreq.wxl" SourcePath="u12" /><Payload Id="payvre23ObscjzhcaFIifUAkXMdPa8" FilePath="1036\mbapreq.wxl" SourcePath="u13" /><Payload Id="paytxUV3vuBbG2c.a9c.d_sZX2x6wA" FilePath="1038\mbapreq.wxl" SourcePath="u14" /><Payload Id="payYvMWRK9xelo5.sQn7jRkJIaBp9A" FilePath="1040\mbapreq.wxl" SourcePath="u15" /><Payload Id="pay68KKSApyQimbA25t6kSbqhdeH10" FilePath="1041\mbapreq.wxl" SourcePath="u16" /><Payload Id="paypiqxaHpYZqx.9eDVjQrj1igLbRY" FilePath="1042\mbapreq.wxl" SourcePath="u17" /><Payload Id="payTO0YwZzxKpbqdrBVUcVRTu3BFe8" FilePath="1043\mbapreq.wxl" SourcePath="u18" /><Payload Id="payIXg2ldBJukRzhqWolJVOEbTmF34" FilePath="1044\mbapreq.wxl" SourcePath="u19" /><Payload Id="payOHIZbSkIvrpwKkkXI173tv3u3B4" FilePath="1045\mbapreq.wxl" SourcePath="u20" /><Payload Id="payQRQ_UZl_R2UtV0xDXB2yeH2bg3E" FilePath="1046\mbapreq.wxl" SourcePath="u21" /><Payload Id="payhrejLLBfc1i27iN._QPhQ4K337I" FilePath="1049\mbapreq.wxl" SourcePath="u22" /><Payload Id="payqEzaDNzxB68vGp29jgDcCos6dvg" FilePath="1051\mbapreq.wxl" SourcePath="u23" /><Payload Id="paydz8Vk8xSTyYohgGXTSIxWGXL5.Q" FilePath="1053\mbapreq.wxl" SourcePath="u24" /><Payload Id="pay0HRUZTlbC3taSOffJBsEj92Br8Y" FilePath="1055\mbapreq.wxl" SourcePath="u25" /><Payload Id="payIvUOkc_EMH7laMFehefNolV8hZo" FilePath="1060\mbapreq.wxl" SourcePath="u26" /><Payload Id="payLFhOb.rHuk4sW5CYAPMShG0NjGI" FilePath="2052\mbapreq.wxl" SourcePath="u27" /><Payload Id="payqIKCmERK7Nhxx_nNXvRxdKqKDbI" FilePath="2070\mbapreq.wxl" SourcePath="u28" /><Payload Id="payqeWUzIVaEqjuRXN0z8ECC3Y4tCc" FilePath="3082\mbapreq.wxl" SourcePath="u29" /><Payload Id="paylfeHEjJSSTnNzY9QMZM2Ye3Ipy4" FilePath="mbapreq.dll" SourcePath="u31" /><Payload Id="payDPxs6uy8nbky.R7zhir2RRAfc.c" FilePath="WixToolset.Mba.Host.dll" SourcePath="u32" /><Payload Id="uxTxMXPVMXwQrPTMIGa5WGt93w0Ns" FilePath="BootstrapperApplicationData.xml" SourcePath="u33" /><Payload Id="uxYRbgitOs0K878jn5L_z7LdJ21KI" FilePath="BundleExtensionData.xml" SourcePath="u34" /></UX><Container Id="WixAttachedContainer" FileSize="24029" Hash="03F9C95A2ADA5563D3D937C0161F22A76E12F2F0AF2AA6BE567292D0AB122E2C42990E97CA9C1EE9A5F43A571B01C4ED7A3EA5759A6836AC8BFD959D7FFDCB18" FilePath="BundleD.exe" AttachedIndex="1" Attached="yes" Primary="yes" /><Payload Id="NetFx48Web" FilePath="redist\ndp48-web.exe" FileSize="1439328" CertificateRootPublicKeyIdentifier="F49F9B33E25E33CCA0BFB15A62B7C29FFAB3880B" CertificateRootThumbprint="ABDCA79AF9DD48A0EA702AD45260B3C03093FB4B" DownloadUrl="https://go.microsoft.com/fwlink/?LinkId=2085155" Packaging="external" SourcePath="redist\ndp48-web.exe" /><Payload Id="TestExe.exe" FilePath="TestExe.exe" FileSize="23552" Hash="4344604ECBA4DFE5DE7C680CB1AA5BD6FAA29BF95CE07740F02878C2BB1EF6DE6432944A0DB79B034D1C6F68CF80842EEE442EA8A551816E52D3F68901C50AB9" Packaging="embedded" SourcePath="a0" Container="WixAttachedContainer" /><Payload Id="paygJp32KbpyjbVEQFNbl5_izmhdZw" FilePath="TestExe.exe.config" FileSize="387" Hash="8C819A9E835F3921FA80C5C783AB0C42DDAADF0C0F2BEF8630EA122ABCB9DC8EAF0B14E061C46B37C92F55114BB09A8D5B1B613947A76A648953F2C63C0ACA63" Packaging="embedded" SourcePath="a1" Container="WixAttachedContainer" /><RollbackBoundary Id="WixDefaultBoundary" Vital="yes" Transaction="no" /><Registration Id="{9C184683-04FB-49AD-9D79-65101BDC3EE3}" ExecutableName="BundleD.exe" PerMachine="yes" Tag="" Version="1.0.0.0" ProviderKey="{9C184683-04FB-49AD-9D79-65101BDC3EE3}"><Arp Register="yes" DisplayName="~FailureTests - BundleD" DisplayVersion="1.0.0.0" /></Registration><Chain><ExePackage Id="NetFx48Web" Cache="remove" CacheId="642721C60D52051C7F3434D8710FE3406A7CFE10B2B39E90EA847719ED1697D7C614F2DF44AD50412B1DF8C98DD78FDC57CA1D047D28C81AC158092E5FB18040" InstallSize="1439328" Size="1439328" PerMachine="yes" Permanent="yes" Vital="yes" RollbackBoundaryForward="WixDefaultBoundary" LogPathVariable="NetFx48WebLog" RollbackLogPathVariable="WixBundleRollbackLog_NetFx48Web" DetectCondition="NETFRAMEWORK45 >= 528040" InstallArguments="/q /norestart /log "[NetFx48WebLog].html"" UninstallArguments="" Uninstallable="no" RepairArguments="" Repairable="no" Protocol="netfx4"><PayloadRef Id="NetFx48Web" /></ExePackage><ExePackage Id="ExeA" Cache="remove" CacheId="4344604ECBA4DFE5DE7C680CB1AA5BD6FAA29BF95CE07740F02878C2BB1EF6DE6432944A0DB79B034D1C6F68CF80842EEE442EA8A551816E52D3F68901C50AB9" InstallSize="23939" Size="23939" PerMachine="yes" Permanent="no" Vital="yes" RollbackBoundaryBackward="WixDefaultBoundary" LogPathVariable="WixBundleLog_ExeA" RollbackLogPathVariable="WixBundleRollbackLog_ExeA" DetectCondition="ExeA_Version AND ExeA_Version >= v1.0.0.0" InstallArguments="/s 5000 /regw "HKLM\Software\WiX\Tests\FailureTests\ExeA,Version,String,1.0.0.0"" UninstallArguments="/regd "HKLM\Software\WiX\Tests\FailureTests\ExeA,Version"" Uninstallable="yes" RepairArguments="/regw "HKLM\Software\WiX\Tests\FailureTests\ExeA,Version,String,1.0.0.0"" Repairable="yes"><PayloadRef Id="TestExe.exe" /><PayloadRef Id="paygJp32KbpyjbVEQFNbl5_izmhdZw" /></ExePackage></Chain><CommandLine Variables="upperCase" /></BurnManifest> \ No newline at end of file | |||
diff --git a/src/burn/test/BurnUnitTest/TestData/PlanTest/MsuPackageFixture_manifest.xml b/src/burn/test/BurnUnitTest/TestData/PlanTest/MsuPackageFixture_manifest.xml new file mode 100644 index 00000000..fb6afa88 --- /dev/null +++ b/src/burn/test/BurnUnitTest/TestData/PlanTest/MsuPackageFixture_manifest.xml | |||
@@ -0,0 +1 @@ | |||
<?xml version="1.0" encoding="utf-8"?><BurnManifest xmlns="http://wixtoolset.org/schemas/v4/2008/Burn"><Log PathVariable="WixBundleLog" Prefix="BurnBundle" Extension="log" /><RelatedBundle Id="{B94478B1-E1F3-4700-9CE8-6AA090854AEC}" Action="Upgrade" /><Variable Id="WixBundleInProgressName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleName" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSource" Hidden="no" Persisted="yes" /><Variable Id="WixBundleOriginalSourceFolder" Hidden="no" Persisted="yes" /><Variable Id="WixBundleLastUsedSource" Hidden="no" Persisted="yes" /><UX><Payload Id="payaQenPi7_8hq6T._EXtBW0NvR7gA" FilePath="fakeba.dll" SourcePath="u0" /><Payload Id="uxTxMXPVMXwQrPTMIGa5WGt93w0Ns" FilePath="BootstrapperApplicationData.xml" SourcePath="u1" /><Payload Id="uxYRbgitOs0K878jn5L_z7LdJ21KI" FilePath="BundleExtensionData.xml" SourcePath="u2" /></UX><Container Id="WixAttachedContainer" FileSize="119" Hash="06D28293FD57CD231E125EF9C82418A488928A98832A6937A77A3283A17A5C37F8D619C51759319A57E8F8A948FA73E8C5814185A0114130F3213AB268073555" FilePath="test.exe" AttachedIndex="1" Attached="yes" Primary="yes" /><Payload Id="test.msu" FilePath="test.msu" FileSize="28" Hash="B040F02D2F90E04E9AFBDC91C00CEB5DF97D48E205D96DC0A44E10AF8870794DAE62CA70224F12BE9112AA730BBE470CA81FB5617AAC690E832F3F84510E92BA" Packaging="embedded" SourcePath="a0" Container="WixAttachedContainer" /><RollbackBoundary Id="WixDefaultBoundary" Vital="yes" Transaction="no" /><Registration Id="{06077C60-DC46-4F4A-8D3C-05F869187191}" ExecutableName="test.exe" PerMachine="yes" Tag="" Version="1.0.0.0" ProviderKey="{06077C60-DC46-4F4A-8D3C-05F869187191}"><Arp Register="yes" DisplayName="BurnBundle" DisplayVersion="1.0.0.0" Publisher="Example Corporation" /></Registration><Chain><MsuPackage Id="test.msu" Cache="keep" CacheId="B040F02D2F90E04E9AFBDC91C00CEB5DF97D48E205D96DC0A44E10AF8870794DAE62CA70224F12BE9112AA730BBE470CA81FB5617AAC690E832F3F84510E92BA" InstallSize="28" Size="28" PerMachine="yes" Permanent="no" Vital="yes" RollbackBoundaryForward="WixDefaultBoundary" RollbackBoundaryBackward="WixDefaultBoundary" DetectCondition="DetectedTheMsu" KB="xyz"><PayloadRef Id="test.msu" /></MsuPackage></Chain><CommandLine Variables="upperCase" /></BurnManifest> \ No newline at end of file | |||