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 |