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/engine | |
| 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/engine')
| -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 |
10 files changed, 181 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, |
