summaryrefslogtreecommitdiff
path: root/src/burn/engine/exeengine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/burn/engine/exeengine.cpp')
-rw-r--r--src/burn/engine/exeengine.cpp132
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
468extern "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
554LExit:
555 ReleaseHandle(pi.hThread);
556 ReleaseHandle(pi.hProcess);
557
558 return hr;
559}
560
501extern "C" void ExeEngineUpdateInstallRegistrationState( 561extern "C" void ExeEngineUpdateInstallRegistrationState(
502 __in BURN_EXECUTE_ACTION* pAction, 562 __in BURN_EXECUTE_ACTION* pAction,
503 __in HRESULT hrExecute 563 __in HRESULT hrExecute