aboutsummaryrefslogtreecommitdiff
path: root/src/burn/engine
diff options
context:
space:
mode:
Diffstat (limited to 'src/burn/engine')
-rw-r--r--src/burn/engine/apply.cpp8
-rw-r--r--src/burn/engine/apply.h5
-rw-r--r--src/burn/engine/bundlepackageengine.cpp28
-rw-r--r--src/burn/engine/elevation.cpp17
-rw-r--r--src/burn/engine/engine.mc7
-rw-r--r--src/burn/engine/exeengine.cpp132
-rw-r--r--src/burn/engine/exeengine.h9
-rw-r--r--src/burn/engine/msuengine.cpp32
-rw-r--r--src/burn/engine/userexperience.cpp30
-rw-r--r--src/burn/engine/userexperience.h6
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
18typedef struct _APPLY_AUTHENTICATION_REQUIRED_DATA 19typedef 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
933Could not create system restore point, error: 0x%1!x!. Continuing... 933Could not create system restore point, error: 0x%1!x!. Continuing...
934. 934.
935 935
936MessageId=364
937Severity=Success
938SymbolicName=MSG_EXECUTE_PROCESS_DELAYED_CANCEL_REQUESTED
939Language=English
940Bootstrapper application requested delayed cancel during package process progress, id: %1!ls!. Waiting...
941.
942
936MessageId=370 943MessageId=370
937Severity=Success 944Severity=Success
938SymbolicName=MSG_SESSION_BEGIN 945SymbolicName=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
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
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 );
45HRESULT 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 );
45void ExeEngineUpdateInstallRegistrationState( 54void 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
1704BAAPI 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
1728LExit:
1729 return hr;
1730}
1731
1704EXTERN_C BAAPI UserExperienceOnExecuteProgress( 1732EXTERN_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 );
401BAAPI UserExperienceOnExecuteProcessCancel(
402 __in BURN_USER_EXPERIENCE* pUserExperience,
403 __in_z LPCWSTR wzPackageId,
404 __in DWORD dwProcessId,
405 __inout BOOTSTRAPPER_EXECUTEPROCESSCANCEL_ACTION* pAction
406 );
401BAAPI UserExperienceOnExecuteProgress( 407BAAPI UserExperienceOnExecuteProgress(
402 __in BURN_USER_EXPERIENCE* pUserExperience, 408 __in BURN_USER_EXPERIENCE* pUserExperience,
403 __in_z LPCWSTR wzPackageId, 409 __in_z LPCWSTR wzPackageId,