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/exeengine.cpp | |
| 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/exeengine.cpp')
| -rw-r--r-- | src/burn/engine/exeengine.cpp | 132 |
1 files changed, 96 insertions, 36 deletions
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 |
