@joebigelow / wix / commits / 98080672

Add queutil so Burn can manage its own queue of BA requested actions.

Fixes 6349

Sean Hall committed Oct 19, 2022 at 15:44 UTC 98080672cdbbde00ea40a96c1ce38e8a52f24fee
18 files changed +451 -125
src/burn/engine/EngineForApplication.cpp
+6 -6
@@ -325,7 +325,7 @@ static HRESULT BAEngineDetect(
325 ValidateMessageArgs(hr, pvArgs, BAENGINE_DETECT_ARGS, pArgs);
326 ValidateMessageResults(hr, pvResults, BAENGINE_DETECT_RESULTS, pResults);
327
328 - hr = ExternalEngineDetect(pContext->dwThreadId, pArgs->hwndParent);
328 + hr = ExternalEngineDetect(pContext, pArgs->hwndParent);
329
330 LExit:
331 return hr;
@@ -341,7 +341,7 @@ static HRESULT BAEnginePlan(
341 ValidateMessageArgs(hr, pvArgs, BAENGINE_PLAN_ARGS, pArgs);
342 ValidateMessageResults(hr, pvResults, BAENGINE_PLAN_RESULTS, pResults);
343
344 - hr = ExternalEnginePlan(pContext->dwThreadId, pArgs->action);
344 + hr = ExternalEnginePlan(pContext, pArgs->action);
345
346 LExit:
347 return hr;
@@ -357,7 +357,7 @@ static HRESULT BAEngineElevate(
357 ValidateMessageArgs(hr, pvArgs, BAENGINE_ELEVATE_ARGS, pArgs);
358 ValidateMessageResults(hr, pvResults, BAENGINE_ELEVATE_RESULTS, pResults);
359
360 - hr = ExternalEngineElevate(pContext->pEngineState, pContext->dwThreadId, pArgs->hwndParent);
360 + hr = ExternalEngineElevate(pContext, pArgs->hwndParent);
361
362 LExit:
363 return hr;
@@ -373,7 +373,7 @@ static HRESULT BAEngineApply(
373 ValidateMessageArgs(hr, pvArgs, BAENGINE_APPLY_ARGS, pArgs);
374 ValidateMessageResults(hr, pvResults, BAENGINE_APPLY_RESULTS, pResults);
375
376 - hr = ExternalEngineApply(pContext->dwThreadId, pArgs->hwndParent);
376 + hr = ExternalEngineApply(pContext, pArgs->hwndParent);
377
378 LExit:
379 return hr;
@@ -389,7 +389,7 @@ static HRESULT BAEngineQuit(
389 ValidateMessageArgs(hr, pvArgs, BAENGINE_QUIT_ARGS, pArgs);
390 ValidateMessageResults(hr, pvResults, BAENGINE_QUIT_RESULTS, pResults);
391
392 - hr = ExternalEngineQuit(pContext->dwThreadId, pArgs->dwExitCode);
392 + hr = ExternalEngineQuit(pContext, pArgs->dwExitCode);
393
394 LExit:
395 return hr;
@@ -405,7 +405,7 @@ static HRESULT BAEngineLaunchApprovedExe(
405 ValidateMessageArgs(hr, pvArgs, BAENGINE_LAUNCHAPPROVEDEXE_ARGS, pArgs);
406 ValidateMessageResults(hr, pvResults, BAENGINE_LAUNCHAPPROVEDEXE_RESULTS, pResults);
407
408 - hr = ExternalEngineLaunchApprovedExe(pContext->pEngineState, pContext->dwThreadId, pArgs->hwndParent, pArgs->wzApprovedExeForElevationId, pArgs->wzArguments, pArgs->dwWaitForInputIdleTimeout);
408 + hr = ExternalEngineLaunchApprovedExe(pContext, pArgs->hwndParent, pArgs->wzApprovedExeForElevationId, pArgs->wzArguments, pArgs->dwWaitForInputIdleTimeout);
409
410 LExit:
411 return hr;
src/burn/engine/EngineForApplication.h
+32 -1
@@ -11,9 +11,40 @@ extern "C" {
11 typedef struct _BOOTSTRAPPER_ENGINE_CONTEXT
12 {
13 BURN_ENGINE_STATE* pEngineState;
14 - DWORD dwThreadId;
14 + QUEUTIL_QUEUE_HANDLE hQueue;
15 + HANDLE hQueueSemaphore;
16 + CRITICAL_SECTION csQueue;
17 } BOOTSTRAPPER_ENGINE_CONTEXT;
18
19 +typedef struct _BOOTSTRAPPER_ENGINE_ACTION
20 +{
21 + WM_BURN dwMessage;
22 + union
23 + {
24 + struct
25 + {
26 + HWND hwndParent;
27 + } detect;
28 + struct
29 + {
30 + BOOTSTRAPPER_ACTION action;
31 + } plan;
32 + struct
33 + {
34 + HWND hwndParent;
35 + } elevate;
36 + struct
37 + {
38 + HWND hwndParent;
39 + } apply;
40 + BURN_LAUNCH_APPROVED_EXE launchApprovedExe;
41 + struct
42 + {
43 + DWORD dwExitCode;
44 + } quit;
45 + };
46 +} BOOTSTRAPPER_ENGINE_ACTION;
47 +
48 // function declarations
49
50 HRESULT WINAPI EngineForApplicationProc(
src/burn/engine/approvedexe.cpp
-1
@@ -106,7 +106,6 @@ extern "C" void ApprovedExesUninitializeLaunch(
106 ReleaseStr(pLaunchApprovedExe->sczArguments);
107 ReleaseStr(pLaunchApprovedExe->sczExecutablePath);
108 ReleaseStr(pLaunchApprovedExe->sczId);
109 - MemFree(pLaunchApprovedExe);
109 }
110 }
111
src/burn/engine/core.cpp
+22 -9
@@ -884,17 +884,16 @@ LExit:
884
885 LogId(REPORT_STANDARD, MSG_LAUNCH_APPROVED_EXE_COMPLETE, hr, dwProcessId);
886
887 - ApprovedExesUninitializeLaunch(pLaunchApprovedExe);
888 -
887 return hr;
888 }
889
892 -extern "C" HRESULT CoreQuit(
893 - __in BURN_ENGINE_STATE* pEngineState,
894 - __in int nExitCode
890 +extern "C" void CoreQuit(
891 + __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
892 + __in DWORD dwExitCode
893 )
894 {
895 HRESULT hr = S_OK;
896 + BURN_ENGINE_STATE* pEngineState = pEngineContext->pEngineState;
897
898 // Save engine state if resume mode is unequal to "none".
899 if (BURN_RESUME_MODE_NONE != pEngineState->resumeMode)
@@ -907,13 +906,15 @@ extern "C" HRESULT CoreQuit(
906 }
907 }
908
910 - LogId(REPORT_STANDARD, MSG_QUIT, nExitCode);
909 + LogId(REPORT_STANDARD, MSG_QUIT, dwExitCode);
910
912 - pEngineState->fQuit = TRUE;
911 + pEngineState->userExperience.dwExitCode = dwExitCode;
912
914 - ::PostQuitMessage(nExitCode); // go bye-bye.
913 + ::EnterCriticalSection(&pEngineContext->csQueue);
914
916 - return hr;
915 + pEngineState->fQuit = TRUE;
916 +
917 + ::LeaveCriticalSection(&pEngineContext->csQueue);
918 }
919
920 extern "C" HRESULT CoreSaveEngineState(
@@ -2071,6 +2072,18 @@ LExit:
2072 return hr;
2073 }
2074
2075 +extern "C" void DAPI CoreBootstrapperEngineActionUninitialize(
2076 + __in BOOTSTRAPPER_ENGINE_ACTION* pAction
2077 + )
2078 +{
2079 + switch (pAction->dwMessage)
2080 + {
2081 + case WM_BURN_LAUNCH_APPROVED_EXE:
2082 + ApprovedExesUninitializeLaunch(&pAction->launchApprovedExe);
2083 + break;
2084 + }
2085 +}
2086 +
2087 // internal helper functions
2088
2089 static HRESULT AppendEscapedArgumentToCommandLine(
src/burn/engine/core.h
+6 -3
@@ -262,9 +262,9 @@ HRESULT CoreLaunchApprovedExe(
262 __in BURN_ENGINE_STATE* pEngineState,
263 __in BURN_LAUNCH_APPROVED_EXE* pLaunchApprovedExe
264 );
265 -HRESULT CoreQuit(
266 - __in BURN_ENGINE_STATE* pEngineState,
267 - __in int nExitCode
265 +void CoreQuit(
266 + __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
267 + __in DWORD dwExitCode
268 );
269 HRESULT CoreSaveEngineState(
270 __in BURN_ENGINE_STATE* pEngineState
@@ -354,6 +354,9 @@ HRESULT DAPI CoreCloseElevatedLoggingThread(
354 HRESULT DAPI CoreWaitForUnelevatedLoggingThread(
355 __in HANDLE hUnelevatedLoggingThread
356 );
357 +void DAPI CoreBootstrapperEngineActionUninitialize(
358 + __in BOOTSTRAPPER_ENGINE_ACTION* pAction
359 + );
360
361 #if defined(__cplusplus)
362 }
src/burn/engine/elevation.cpp
+2 -3
@@ -3824,7 +3824,8 @@ static HRESULT OnLaunchApprovedExe(
3824 {
3825 HRESULT hr = S_OK;
3826 SIZE_T iData = 0;
3827 - BURN_LAUNCH_APPROVED_EXE* pLaunchApprovedExe = NULL;
3827 + BURN_LAUNCH_APPROVED_EXE launchApprovedExe = { };
3828 + BURN_LAUNCH_APPROVED_EXE* pLaunchApprovedExe = &launchApprovedExe;
3829 BURN_APPROVED_EXE* pApprovedExe = NULL;
3830 HKEY hKey = NULL;
3831 DWORD dwProcessId = 0;
@@ -3832,8 +3833,6 @@ static HRESULT OnLaunchApprovedExe(
3833 SIZE_T cbSendData = 0;
3834 DWORD dwResult = 0;
3835
3835 - pLaunchApprovedExe = (BURN_LAUNCH_APPROVED_EXE*)MemAlloc(sizeof(BURN_LAUNCH_APPROVED_EXE), TRUE);
3836 -
3836 // Deserialize message data.
3837 hr = BuffReadString(pbData, cbData, &iData, &pLaunchApprovedExe->sczId);
3838 ExitOnFailure(hr, "Failed to read approved exe id.");
src/burn/engine/engine.cpp
+53 -42
@@ -42,8 +42,8 @@ static HRESULT RunApplication(
42 __out BOOL* pfSkipCleanup
43 );
44 static HRESULT ProcessMessage(
45 - __in BURN_ENGINE_STATE* pEngineState,
46 - __in const MSG* pmsg
45 + __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
46 + __in BOOTSTRAPPER_ENGINE_ACTION* pAction
47 );
48 static HRESULT DAPI RedirectLoggingOverPipe(
49 __in_z LPCSTR szString,
@@ -790,6 +790,19 @@ LExit:
790 return hr;
791 }
792
793 +static void CALLBACK FreeQueueItem(
794 + __in void* pvValue,
795 + __in void* /*pvContext*/
796 + )
797 +{
798 + BOOTSTRAPPER_ENGINE_ACTION* pAction = reinterpret_cast<BOOTSTRAPPER_ENGINE_ACTION*>(pvValue);
799 +
800 + LogId(REPORT_WARNING, MSG_IGNORE_OPERATION_AFTER_QUIT, LoggingBurnMessageToString(pAction->dwMessage));
801 +
802 + CoreBootstrapperEngineActionUninitialize(pAction);
803 + MemFree(pAction);
804 +}
805 +
806 static HRESULT RunApplication(
807 __in BURN_ENGINE_STATE* pEngineState,
808 __out BOOL* pfReloadApp,
@@ -799,16 +812,20 @@ static HRESULT RunApplication(
812 HRESULT hr = S_OK;
813 BOOTSTRAPPER_ENGINE_CONTEXT engineContext = { };
814 BOOL fStartupCalled = FALSE;
802 - BOOL fRet = FALSE;
803 - MSG msg = { };
815 BOOTSTRAPPER_SHUTDOWN_ACTION shutdownAction = BOOTSTRAPPER_SHUTDOWN_ACTION_NONE;
805 -
806 - ::PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
816 + BOOTSTRAPPER_ENGINE_ACTION* pAction = NULL;
817
818 // Setup the bootstrapper engine.
809 - engineContext.dwThreadId = ::GetCurrentThreadId();
819 engineContext.pEngineState = pEngineState;
820
821 + ::InitializeCriticalSection(&engineContext.csQueue);
822 +
823 + engineContext.hQueueSemaphore = ::CreateSemaphoreW(NULL, 0, LONG_MAX, NULL);
824 + ExitOnNullWithLastError(engineContext.hQueueSemaphore, hr, "Failed to create semaphore for queue.");
825 +
826 + hr = QueCreate(&engineContext.hQueue);
827 + ExitOnFailure(hr, "Failed to create queue for bootstrapper engine.");
828 +
829 // Load the bootstrapper application.
830 hr = UserExperienceLoad(&pEngineState->userExperience, &engineContext, &pEngineState->command);
831 ExitOnFailure(hr, "Failed to load BA.");
@@ -817,28 +834,24 @@ static HRESULT RunApplication(
834 hr = UserExperienceOnStartup(&pEngineState->userExperience);
835 ExitOnFailure(hr, "Failed to start bootstrapper application.");
836
820 - // Enter the message pump.
821 - while (0 != (fRet = ::GetMessageW(&msg, NULL, 0, 0)))
837 + while (!pEngineState->fQuit)
838 {
823 - if (-1 == fRet)
824 - {
825 - hr = E_UNEXPECTED;
826 - ExitOnRootFailure(hr, "Unexpected return value from message pump.");
827 - }
828 - else
829 - {
830 - // When the BA makes a request from its own thread, it's common for the PostThreadMessage in externalengine.cpp
831 - // to block until this thread waits on something. It's also common for Detect and Plan to never wait on something.
832 - // In the extreme case, the engine could be elevating in Apply before the Detect call returned to the BA.
833 - // This helps to avoid that situation, which could be blocking a UI thread.
834 - ::Sleep(0);
839 + hr = AppWaitForSingleObject(engineContext.hQueueSemaphore, INFINITE);
840 + ExitOnFailure(hr, "Failed to wait on queue event.");
841
836 - ProcessMessage(pEngineState, &msg);
837 - }
838 - }
842 + ::EnterCriticalSection(&engineContext.csQueue);
843 +
844 + hr = QueDequeue(engineContext.hQueue, reinterpret_cast<void**>(&pAction));
845 +
846 + ::LeaveCriticalSection(&engineContext.csQueue);
847
840 - // Get exit code.
841 - pEngineState->userExperience.dwExitCode = (DWORD)msg.wParam;
848 + ExitOnFailure(hr, "Failed to dequeue action.");
849 +
850 + ProcessMessage(&engineContext, pAction);
851 +
852 + CoreBootstrapperEngineActionUninitialize(pAction);
853 + MemFree(pAction);
854 + }
855
856 LExit:
857 if (fStartupCalled)
@@ -864,52 +877,50 @@ LExit:
877 // Unload BA.
878 UserExperienceUnload(&pEngineState->userExperience, *pfReloadApp);
879
880 + ::DeleteCriticalSection(&engineContext.csQueue);
881 + ReleaseHandle(engineContext.hQueueSemaphore);
882 + ReleaseQueue(engineContext.hQueue, FreeQueueItem, &engineContext);
883 +
884 return hr;
885 }
886
887 static HRESULT ProcessMessage(
871 - __in BURN_ENGINE_STATE* pEngineState,
872 - __in const MSG* pmsg
888 + __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
889 + __in BOOTSTRAPPER_ENGINE_ACTION* pAction
890 )
891 {
892 HRESULT hr = S_OK;
893 + BURN_ENGINE_STATE* pEngineState = pEngineContext->pEngineState;
894
895 UserExperienceActivateEngine(&pEngineState->userExperience);
896
879 - if (pEngineState->fQuit)
880 - {
881 - LogId(REPORT_WARNING, MSG_IGNORE_OPERATION_AFTER_QUIT, LoggingBurnMessageToString(pmsg->message));
882 - ExitFunction1(hr = E_INVALIDSTATE);
883 - }
884 -
885 - switch (pmsg->message)
897 + switch (pAction->dwMessage)
898 {
899 case WM_BURN_DETECT:
888 - hr = CoreDetect(pEngineState, reinterpret_cast<HWND>(pmsg->lParam));
900 + hr = CoreDetect(pEngineState, pAction->detect.hwndParent);
901 break;
902
903 case WM_BURN_PLAN:
892 - hr = CorePlan(pEngineState, static_cast<BOOTSTRAPPER_ACTION>(pmsg->lParam));
904 + hr = CorePlan(pEngineState, pAction->plan.action);
905 break;
906
907 case WM_BURN_ELEVATE:
896 - hr = CoreElevate(pEngineState, WM_BURN_ELEVATE, reinterpret_cast<HWND>(pmsg->lParam));
908 + hr = CoreElevate(pEngineState, WM_BURN_ELEVATE, pAction->elevate.hwndParent);
909 break;
910
911 case WM_BURN_APPLY:
900 - hr = CoreApply(pEngineState, reinterpret_cast<HWND>(pmsg->lParam));
912 + hr = CoreApply(pEngineState, pAction->apply.hwndParent);
913 break;
914
915 case WM_BURN_LAUNCH_APPROVED_EXE:
904 - hr = CoreLaunchApprovedExe(pEngineState, reinterpret_cast<BURN_LAUNCH_APPROVED_EXE*>(pmsg->lParam));
916 + hr = CoreLaunchApprovedExe(pEngineState, &pAction->launchApprovedExe);
917 break;
918
919 case WM_BURN_QUIT:
908 - hr = CoreQuit(pEngineState, static_cast<int>(pmsg->wParam));
920 + CoreQuit(pEngineContext, pAction->quit.dwExitCode);
921 break;
922 }
923
912 -LExit:
924 UserExperienceDeactivateEngine(&pEngineState->userExperience);
925
926 return hr;
src/burn/engine/externalengine.cpp
+115 -51
@@ -13,6 +13,10 @@ static HRESULT ProcessUnknownEmbeddedMessages(
13 __in_opt LPVOID /*pvContext*/,
14 __out DWORD* pdwResult
15 );
16 +static HRESULT EnqueueAction(
17 + __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
18 + __inout BOOTSTRAPPER_ENGINE_ACTION** ppAction
19 + );
20
21 // function definitions
22
@@ -582,69 +586,91 @@ HRESULT ExternalEngineCompareVersions(
586 }
587
588 HRESULT ExternalEngineDetect(
585 - __in const DWORD dwThreadId,
589 + __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
590 __in_opt const HWND hwndParent
591 )
592 {
593 HRESULT hr = S_OK;
594 + BOOTSTRAPPER_ENGINE_ACTION* pAction = NULL;
595
591 - if (!::PostThreadMessageW(dwThreadId, WM_BURN_DETECT, 0, reinterpret_cast<LPARAM>(hwndParent)))
592 - {
593 - ExitWithLastError(hr, "Failed to post detect message.");
594 - }
596 + pAction = (BOOTSTRAPPER_ENGINE_ACTION*)MemAlloc(sizeof(BOOTSTRAPPER_ENGINE_ACTION), TRUE);
597 + ExitOnNull(pAction, hr, E_OUTOFMEMORY, "Failed to alloc BOOTSTRAPPER_ENGINE_ACTION");
598 +
599 + pAction->dwMessage = WM_BURN_DETECT;
600 + pAction->detect.hwndParent = hwndParent;
601 +
602 + hr = EnqueueAction(pEngineContext, &pAction);
603 + ExitOnFailure(hr, "Failed to enqueue detect action.");
604
605 LExit:
606 + ReleaseMem(pAction);
607 +
608 return hr;
609 }
610
611 HRESULT ExternalEnginePlan(
601 - __in const DWORD dwThreadId,
612 + __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
613 __in const BOOTSTRAPPER_ACTION action
614 )
615 {
616 HRESULT hr = S_OK;
617 + BOOTSTRAPPER_ENGINE_ACTION* pAction = NULL;
618
619 if (BOOTSTRAPPER_ACTION_LAYOUT > action || BOOTSTRAPPER_ACTION_UPDATE_REPLACE_EMBEDDED < action)
620 {
621 ExitOnRootFailure(hr = E_INVALIDARG, "BA passed invalid action to Plan: %u.", action);
622 }
623
612 - if (!::PostThreadMessageW(dwThreadId, WM_BURN_PLAN, 0, action))
613 - {
614 - ExitWithLastError(hr, "Failed to post plan message.");
615 - }
624 + pAction = (BOOTSTRAPPER_ENGINE_ACTION*)MemAlloc(sizeof(BOOTSTRAPPER_ENGINE_ACTION), TRUE);
625 + ExitOnNull(pAction, hr, E_OUTOFMEMORY, "Failed to alloc BOOTSTRAPPER_ENGINE_ACTION");
626 +
627 + pAction->dwMessage = WM_BURN_PLAN;
628 + pAction->plan.action = action;
629 +
630 + hr = EnqueueAction(pEngineContext, &pAction);
631 + ExitOnFailure(hr, "Failed to enqueue plan action.");
632
633 LExit:
634 + ReleaseMem(pAction);
635 +
636 return hr;
637 }
638
639 HRESULT ExternalEngineElevate(
622 - __in BURN_ENGINE_STATE* pEngineState,
623 - __in const DWORD dwThreadId,
640 + __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
641 __in_opt const HWND hwndParent
642 )
643 {
644 HRESULT hr = S_OK;
645 + BOOTSTRAPPER_ENGINE_ACTION* pAction = NULL;
646
629 - if (INVALID_HANDLE_VALUE != pEngineState->companionConnection.hPipe)
630 - {
631 - hr = HRESULT_FROM_WIN32(ERROR_ALREADY_INITIALIZED);
632 - }
633 - else if (!::PostThreadMessageW(dwThreadId, WM_BURN_ELEVATE, 0, reinterpret_cast<LPARAM>(hwndParent)))
647 + if (INVALID_HANDLE_VALUE != pEngineContext->pEngineState->companionConnection.hPipe)
648 {
635 - ExitWithLastError(hr, "Failed to post elevate message.");
649 + ExitFunction1(hr = HRESULT_FROM_WIN32(ERROR_ALREADY_INITIALIZED));
650 }
651
652 + pAction = (BOOTSTRAPPER_ENGINE_ACTION*)MemAlloc(sizeof(BOOTSTRAPPER_ENGINE_ACTION), TRUE);
653 + ExitOnNull(pAction, hr, E_OUTOFMEMORY, "Failed to alloc BOOTSTRAPPER_ENGINE_ACTION");
654 +
655 + pAction->dwMessage = WM_BURN_ELEVATE;
656 + pAction->elevate.hwndParent = hwndParent;
657 +
658 + hr = EnqueueAction(pEngineContext, &pAction);
659 + ExitOnFailure(hr, "Failed to enqueue elevate action.");
660 +
661 LExit:
662 + ReleaseMem(pAction);
663 +
664 return hr;
665 }
666
667 HRESULT ExternalEngineApply(
643 - __in const DWORD dwThreadId,
668 + __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
669 __in_opt const HWND hwndParent
670 )
671 {
672 HRESULT hr = S_OK;
673 + BOOTSTRAPPER_ENGINE_ACTION* pAction = NULL;
674
675 ExitOnNull(hwndParent, hr, E_INVALIDARG, "BA passed NULL hwndParent to Apply.");
676 if (!::IsWindow(hwndParent))
@@ -652,34 +678,46 @@ HRESULT ExternalEngineApply(
678 ExitOnRootFailure(hr = E_INVALIDARG, "BA passed invalid hwndParent to Apply.");
679 }
680
655 - if (!::PostThreadMessageW(dwThreadId, WM_BURN_APPLY, 0, reinterpret_cast<LPARAM>(hwndParent)))
656 - {
657 - ExitWithLastError(hr, "Failed to post apply message.");
658 - }
681 + pAction = (BOOTSTRAPPER_ENGINE_ACTION*)MemAlloc(sizeof(BOOTSTRAPPER_ENGINE_ACTION), TRUE);
682 + ExitOnNull(pAction, hr, E_OUTOFMEMORY, "Failed to alloc BOOTSTRAPPER_ENGINE_ACTION");
683 +
684 + pAction->dwMessage = WM_BURN_APPLY;
685 + pAction->apply.hwndParent = hwndParent;
686 +
687 + hr = EnqueueAction(pEngineContext, &pAction);
688 + ExitOnFailure(hr, "Failed to enqueue apply action.");
689
690 LExit:
691 + ReleaseMem(pAction);
692 +
693 return hr;
694 }
695
696 HRESULT ExternalEngineQuit(
665 - __in const DWORD dwThreadId,
697 + __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
698 __in const DWORD dwExitCode
699 )
700 {
701 HRESULT hr = S_OK;
702 + BOOTSTRAPPER_ENGINE_ACTION* pAction = NULL;
703
671 - if (!::PostThreadMessageW(dwThreadId, WM_BURN_QUIT, static_cast<WPARAM>(dwExitCode), 0))
672 - {
673 - ExitWithLastError(hr, "Failed to post shutdown message.");
674 - }
704 + pAction = (BOOTSTRAPPER_ENGINE_ACTION*)MemAlloc(sizeof(BOOTSTRAPPER_ENGINE_ACTION), TRUE);
705 + ExitOnNull(pAction, hr, E_OUTOFMEMORY, "Failed to alloc BOOTSTRAPPER_ENGINE_ACTION");
706 +
707 + pAction->dwMessage = WM_BURN_QUIT;
708 + pAction->quit.dwExitCode = dwExitCode;
709 +
710 + hr = EnqueueAction(pEngineContext, &pAction);
711 + ExitOnFailure(hr, "Failed to enqueue shutdown action.");
712
713 LExit:
714 + ReleaseMem(pAction);
715 +
716 return hr;
717 }
718
719 HRESULT ExternalEngineLaunchApprovedExe(
681 - __in BURN_ENGINE_STATE* pEngineState,
682 - __in const DWORD dwThreadId,
720 + __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
721 __in_opt const HWND hwndParent,
722 __in_z LPCWSTR wzApprovedExeForElevationId,
723 __in_z_opt LPCWSTR wzArguments,
@@ -688,25 +726,23 @@ HRESULT ExternalEngineLaunchApprovedExe(
726 {
727 HRESULT hr = S_OK;
728 BURN_APPROVED_EXE* pApprovedExe = NULL;
691 - BOOL fLeaveCriticalSection = FALSE;
729 BURN_LAUNCH_APPROVED_EXE* pLaunchApprovedExe = NULL;
693 -
694 - pLaunchApprovedExe = (BURN_LAUNCH_APPROVED_EXE*)MemAlloc(sizeof(BURN_LAUNCH_APPROVED_EXE), TRUE);
695 - ExitOnNull(pLaunchApprovedExe, hr, E_OUTOFMEMORY, "Failed to alloc BURN_LAUNCH_APPROVED_EXE");
696 -
697 - ::EnterCriticalSection(&pEngineState->userExperience.csEngineActive);
698 - fLeaveCriticalSection = TRUE;
699 - hr = UserExperienceEnsureEngineInactive(&pEngineState->userExperience);
700 - ExitOnFailure(hr, "Engine is active, cannot change engine state.");
730 + BOOTSTRAPPER_ENGINE_ACTION* pAction = NULL;
731
732 if (!wzApprovedExeForElevationId || !*wzApprovedExeForElevationId)
733 {
734 ExitFunction1(hr = E_INVALIDARG);
735 }
736
707 - hr = ApprovedExesFindById(&pEngineState->approvedExes, wzApprovedExeForElevationId, &pApprovedExe);
737 + hr = ApprovedExesFindById(&pEngineContext->pEngineState->approvedExes, wzApprovedExeForElevationId, &pApprovedExe);
738 ExitOnFailure(hr, "BA requested unknown approved exe with id: %ls", wzApprovedExeForElevationId);
739
740 + pAction = (BOOTSTRAPPER_ENGINE_ACTION*)MemAlloc(sizeof(BOOTSTRAPPER_ENGINE_ACTION), TRUE);
741 + ExitOnNull(pAction, hr, E_OUTOFMEMORY, "Failed to alloc BOOTSTRAPPER_ENGINE_ACTION");
742 +
743 + pAction->dwMessage = WM_BURN_LAUNCH_APPROVED_EXE;
744 + pLaunchApprovedExe = &pAction->launchApprovedExe;
745 +
746 hr = StrAllocString(&pLaunchApprovedExe->sczId, wzApprovedExeForElevationId, NULL);
747 ExitOnFailure(hr, "Failed to copy the id.");
748
@@ -720,20 +756,14 @@ HRESULT ExternalEngineLaunchApprovedExe(
756
757 pLaunchApprovedExe->hwndParent = hwndParent;
758
723 - if (!::PostThreadMessageW(dwThreadId, WM_BURN_LAUNCH_APPROVED_EXE, 0, reinterpret_cast<LPARAM>(pLaunchApprovedExe)))
724 - {
725 - ExitWithLastError(hr, "Failed to post launch approved exe message.");
726 - }
759 + hr = EnqueueAction(pEngineContext, &pAction);
760 + ExitOnFailure(hr, "Failed to enqueue launch approved exe action.");
761
762 LExit:
729 - if (fLeaveCriticalSection)
763 + if (pAction)
764 {
731 - ::LeaveCriticalSection(&pEngineState->userExperience.csEngineActive);
732 - }
733 -
734 - if (FAILED(hr))
735 - {
736 - ApprovedExesUninitializeLaunch(pLaunchApprovedExe);
765 + CoreBootstrapperEngineActionUninitialize(pAction);
766 + MemFree(pAction);
767 }
768
769 return hr;
@@ -836,3 +866,37 @@ static HRESULT ProcessUnknownEmbeddedMessages(
866
867 return S_OK;
868 }
869 +
870 +static HRESULT EnqueueAction(
871 + __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
872 + __inout BOOTSTRAPPER_ENGINE_ACTION** ppAction
873 + )
874 +{
875 + HRESULT hr = S_OK;
876 +
877 + ::EnterCriticalSection(&pEngineContext->csQueue);
878 +
879 + if (pEngineContext->pEngineState->fQuit)
880 + {
881 + LogId(REPORT_WARNING, MSG_IGNORE_OPERATION_AFTER_QUIT, LoggingBurnMessageToString((*ppAction)->dwMessage));
882 + hr = E_INVALIDSTATE;
883 + }
884 + else
885 + {
886 + hr = QueEnqueue(pEngineContext->hQueue, *ppAction);
887 + }
888 +
889 + ::LeaveCriticalSection(&pEngineContext->csQueue);
890 +
891 + ExitOnFailure(hr, "Failed to enqueue action.");
892 +
893 + *ppAction = NULL;
894 +
895 + if (!::ReleaseSemaphore(pEngineContext->hQueueSemaphore, 1, NULL))
896 + {
897 + ExitWithLastError(hr, "Failed to signal queue semaphore.");
898 + }
899 +
900 +LExit:
901 + return hr;
902 +}
src/burn/engine/externalengine.h
+6 -8
@@ -130,34 +130,32 @@ HRESULT ExternalEngineCompareVersions(
130 );
131
132 HRESULT ExternalEngineDetect(
133 - __in const DWORD dwThreadId,
133 + __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
134 __in_opt const HWND hwndParent
135 );
136
137 HRESULT ExternalEnginePlan(
138 - __in const DWORD dwThreadId,
138 + __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
139 __in const BOOTSTRAPPER_ACTION action
140 );
141
142 HRESULT ExternalEngineElevate(
143 - __in BURN_ENGINE_STATE* pEngineState,
144 - __in const DWORD dwThreadId,
143 + __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
144 __in_opt const HWND hwndParent
145 );
146
147 HRESULT ExternalEngineApply(
149 - __in const DWORD dwThreadId,
148 + __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
149 __in_opt const HWND hwndParent
150 );
151
152 HRESULT ExternalEngineQuit(
154 - __in const DWORD dwThreadId,
153 + __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
154 __in const DWORD dwExitCode
155 );
156
157 HRESULT ExternalEngineLaunchApprovedExe(
159 - __in BURN_ENGINE_STATE* pEngineState,
160 - __in const DWORD dwThreadId,
158 + __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
159 __in_opt const HWND hwndParent,
160 __in_z LPCWSTR wzApprovedExeForElevationId,
161 __in_z_opt LPCWSTR wzArguments,
src/burn/engine/platform.h
+1
@@ -28,6 +28,7 @@ enum WM_BURN
28
29 enum BURN_MODE;
30 typedef struct _BOOTSTRAPPER_ENGINE_CONTEXT BOOTSTRAPPER_ENGINE_CONTEXT;
31 +typedef struct _BOOTSTRAPPER_ENGINE_ACTION BOOTSTRAPPER_ENGINE_ACTION;
32 typedef struct _BURN_CACHE BURN_CACHE;
33 typedef struct _BURN_DEPENDENCIES BURN_DEPENDENCIES;
34 typedef struct _BURN_ENGINE_COMMAND BURN_ENGINE_COMMAND;
src/burn/engine/precomp.h
+1
@@ -40,6 +40,7 @@
40 #include <pathutil.h>
41 #include <polcutil.h>
42 #include <procutil.h>
43 +#include <queutil.h>
44 #include <regutil.h>
45 #include <resrutil.h>
46 #include <shelutil.h>
src/libs/dutil/WixToolset.DUtil/dutil.vcxproj
+2
@@ -91,6 +91,7 @@
91 <ClCompile Include="proc2utl.cpp" />
92 <ClCompile Include="proc3utl.cpp" />
93 <ClCompile Include="procutil.cpp" />
94 + <ClCompile Include="queutil.cpp" />
95 <ClCompile Include="regutil.cpp" />
96 <ClCompile Include="resrutil.cpp" />
97 <ClCompile Include="reswutil.cpp" />
@@ -153,6 +154,7 @@
154 <ClInclude Include="inc\perfutil.h" />
155 <ClInclude Include="inc\polcutil.h" />
156 <ClInclude Include="inc\procutil.h" />
157 + <ClInclude Include="inc\queutil.h" />
158 <ClInclude Include="inc\regutil.h" />
159 <ClInclude Include="inc\resrutil.h" />
160 <ClInclude Include="inc\reswutil.h" />
src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters
+6
@@ -135,6 +135,9 @@
135 <ClCompile Include="procutil.cpp">
136 <Filter>Source Files</Filter>
137 </ClCompile>
138 + <ClCompile Include="queutil.cpp">
139 + <Filter>Source Files</Filter>
140 + </ClCompile>
141 <ClCompile Include="resrutil.cpp">
142 <Filter>Source Files</Filter>
143 </ClCompile>
@@ -314,6 +317,9 @@
317 <ClInclude Include="inc\procutil.h">
318 <Filter>Header Files</Filter>
319 </ClInclude>
320 + <ClInclude Include="inc\queutil.h">
321 + <Filter>Header Files</Filter>
322 + </ClInclude>
323 <ClInclude Include="inc\regutil.h">
324 <Filter>Header Files</Filter>
325 </ClInclude>
src/libs/dutil/WixToolset.DUtil/inc/dutilsources.h
+1
@@ -64,6 +64,7 @@ typedef enum DUTIL_SOURCE
64 DUTIL_SOURCE_WNDUTIL,
65 DUTIL_SOURCE_ENVUTIL,
66 DUTIL_SOURCE_THRDUTIL,
67 + DUTIL_SOURCE_QUEUTIL,
68
69 DUTIL_SOURCE_EXTERNAL = 256,
70 } DUTIL_SOURCE;
src/libs/dutil/WixToolset.DUtil/inc/queutil.h new
+52
@@ -0,0 +1,52 @@
1 +#pragma once
2 +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
3 +
4 +
5 +#ifdef __cplusplus
6 +extern "C" {
7 +#endif
8 +
9 +#define ReleaseQueue(qh, pfn, pv) if (qh) { QueDestroy(qh, pfn, pv); }
10 +#define ReleaseNullQue(qh, pfv, pv) if (qh) { QueDestroy(qh, pfn, pv); qh = NULL; }
11 +
12 +typedef void* QUEUTIL_QUEUE_HANDLE;
13 +
14 +typedef void(CALLBACK* PFNQUEUTIL_QUEUE_RELEASE_VALUE)(
15 + __in void* pvValue,
16 + __in void* pvContext
17 + );
18 +
19 +extern const int QUEUTIL_QUEUE_HANDLE_BYTES;
20 +
21 +/********************************************************************
22 +QueCreate - Creates a simple queue. It is not thread safe.
23 +
24 +********************************************************************/
25 +HRESULT DAPI QueCreate(
26 + __out_bcount(QUEUTIL_QUEUE_HANDLE_BYTES) QUEUTIL_QUEUE_HANDLE* phQueue
27 + );
28 +
29 +HRESULT DAPI QueEnqueue(
30 + __in_bcount(QUEUTIL_QUEUE_HANDLE_BYTES) QUEUTIL_QUEUE_HANDLE hQueue,
31 + __in void* pvValue
32 + );
33 +
34 +/********************************************************************
35 +QueDequeue - Returns the value from the beginning of the queue,
36 + or E_NOMOREITEMS if the queue is empty.
37 +
38 +********************************************************************/
39 +HRESULT DAPI QueDequeue(
40 + __in_bcount(QUEUTIL_QUEUE_HANDLE_BYTES) QUEUTIL_QUEUE_HANDLE hQueue,
41 + __out void** ppvValue
42 + );
43 +
44 +void DAPI QueDestroy(
45 + __in_bcount(QUEUTIL_QUEUE_HANDLE_BYTES) QUEUTIL_QUEUE_HANDLE hQueue,
46 + __in_opt PFNQUEUTIL_QUEUE_RELEASE_VALUE pfnReleaseValue,
47 + __in_opt void* pvContext
48 + );
49 +
50 +#ifdef __cplusplus
51 +}
52 +#endif
src/libs/dutil/WixToolset.DUtil/precomp.h
+1
@@ -75,6 +75,7 @@
75 #include "perfutil.h"
76 #include "polcutil.h"
77 #include "procutil.h"
78 +#include "queutil.h"
79 #include "regutil.h"
80 #include "butil.h" // NOTE: Butil must come after Regutil.
81 #include "resrutil.h"
src/libs/dutil/WixToolset.DUtil/queutil.cpp new
+144
@@ -0,0 +1,144 @@
1 +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2 +
3 +#include "precomp.h"
4 +
5 +
6 +// Exit macros
7 +#define QueExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_QUEUTIL, x, s, __VA_ARGS__)
8 +#define QueExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_QUEUTIL, x, s, __VA_ARGS__)
9 +#define QueExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_QUEUTIL, x, s, __VA_ARGS__)
10 +#define QueExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_QUEUTIL, x, s, __VA_ARGS__)
11 +#define QueExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_QUEUTIL, x, s, __VA_ARGS__)
12 +#define QueExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_QUEUTIL, x, s, __VA_ARGS__)
13 +#define QueExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_QUEUTIL, p, x, e, s, __VA_ARGS__)
14 +#define QueExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_QUEUTIL, p, x, s, __VA_ARGS__)
15 +#define QueExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_QUEUTIL, p, x, e, s, __VA_ARGS__)
16 +#define QueExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_QUEUTIL, p, x, s, __VA_ARGS__)
17 +#define QueExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_QUEUTIL, e, x, s, __VA_ARGS__)
18 +#define QueExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_QUEUTIL, g, x, s, __VA_ARGS__)
19 +
20 +
21 +struct QUEUTIL_QUEUE_ITEM
22 +{
23 + QUEUTIL_QUEUE_ITEM* pNext;
24 + void* pvValue;
25 +};
26 +
27 +struct QUEUTIL_QUEUE_STRUCT
28 +{
29 + QUEUTIL_QUEUE_ITEM* pFirst;
30 + QUEUTIL_QUEUE_ITEM* pLast;
31 +};
32 +
33 +const int QUEUTIL_QUEUE_HANDLE_BYTES = sizeof(QUEUTIL_QUEUE_STRUCT);
34 +
35 +extern "C" HRESULT DAPI QueCreate(
36 + __out_bcount(QUEUTIL_QUEUE_HANDLE_BYTES) QUEUTIL_QUEUE_HANDLE* phQueue
37 + )
38 +{
39 + HRESULT hr = S_OK;
40 +
41 + QueExitOnNull(phQueue, hr, E_INVALIDARG, "Handle not specified while creating queue.");
42 +
43 + *phQueue = reinterpret_cast<QUEUTIL_QUEUE_HANDLE>(MemAlloc(QUEUTIL_QUEUE_HANDLE_BYTES, TRUE));
44 + QueExitOnNull(*phQueue, hr, E_OUTOFMEMORY, "Failed to allocate queue object.");
45 +
46 +LExit:
47 + return hr;
48 +}
49 +
50 +extern "C" HRESULT DAPI QueEnqueue(
51 + __in_bcount(QUEUTIL_QUEUE_HANDLE_BYTES) QUEUTIL_QUEUE_HANDLE hQueue,
52 + __in void* pvValue
53 + )
54 +{
55 + HRESULT hr = S_OK;
56 + QUEUTIL_QUEUE_ITEM* pItem = NULL;
57 + QUEUTIL_QUEUE_STRUCT* pQueue = reinterpret_cast<QUEUTIL_QUEUE_STRUCT*>(hQueue);
58 +
59 + QueExitOnNull(pQueue, hr, E_INVALIDARG, "Handle not specified while enqueing value.");
60 +
61 + pItem = reinterpret_cast<QUEUTIL_QUEUE_ITEM*>(MemAlloc(sizeof(QUEUTIL_QUEUE_ITEM), TRUE));
62 + QueExitOnNull(pItem, hr, E_OUTOFMEMORY, "Failed to allocate queue item.");
63 +
64 + pItem->pvValue = pvValue;
65 +
66 + if (!pQueue->pLast)
67 + {
68 + pQueue->pFirst = pItem;
69 + }
70 + else
71 + {
72 + pQueue->pLast->pNext = pItem;
73 + }
74 +
75 + pQueue->pLast = pItem;
76 +
77 + pItem = NULL;
78 +
79 +LExit:
80 + ReleaseMem(pItem);
81 +
82 + return hr;
83 +}
84 +
85 +extern "C" HRESULT DAPI QueDequeue(
86 + __in_bcount(QUEUTIL_QUEUE_HANDLE_BYTES) QUEUTIL_QUEUE_HANDLE hQueue,
87 + __out void** ppvValue
88 + )
89 +{
90 + HRESULT hr = S_OK;
91 + QUEUTIL_QUEUE_ITEM* pItem = NULL;
92 + QUEUTIL_QUEUE_STRUCT* pQueue = reinterpret_cast<QUEUTIL_QUEUE_STRUCT*>(hQueue);
93 +
94 + QueExitOnNull(pQueue, hr, E_INVALIDARG, "Handle not specified while dequeing value.");
95 +
96 + if (!pQueue->pFirst)
97 + {
98 + *ppvValue = NULL;
99 + ExitFunction1(hr = E_NOMOREITEMS);
100 + }
101 +
102 + pItem = pQueue->pFirst;
103 +
104 + if (!pItem->pNext)
105 + {
106 + pQueue->pFirst = NULL;
107 + pQueue->pLast = NULL;
108 + }
109 + else
110 + {
111 + pQueue->pFirst = pItem->pNext;
112 + }
113 +
114 + *ppvValue = pItem->pvValue;
115 +
116 +LExit:
117 + ReleaseMem(pItem);
118 +
119 + return hr;
120 +}
121 +
122 +extern "C" void DAPI QueDestroy(
123 + __in_bcount(QUEUTIL_QUEUE_HANDLE_BYTES) QUEUTIL_QUEUE_HANDLE hQueue,
124 + __in_opt PFNQUEUTIL_QUEUE_RELEASE_VALUE pfnReleaseValue,
125 + __in_opt void* pvContext
126 + )
127 +{
128 + HRESULT hr = S_OK;
129 + void* pvValue = NULL;
130 +
131 + hr = hQueue ? QueDequeue(hQueue, &pvValue) : E_NOMOREITEMS;
132 +
133 + while (SUCCEEDED(hr))
134 + {
135 + if (pfnReleaseValue)
136 + {
137 + pfnReleaseValue(pvValue, pvContext);
138 + }
139 +
140 + hr = QueDequeue(hQueue, &pvValue);
141 + }
142 +
143 + ReleaseMem(hQueue);
144 +}
src/test/burn/WixToolsetTest.BurnE2E/ElevationTests.cs
+1 -1
@@ -13,7 +13,7 @@ namespace WixToolsetTest.BurnE2E
13 /// This test calls Elevate after Detect, and then calls Plan in OnElevateBegin.
14 /// After calling Plan, it pumps some messages to simulate UI like the UAC callback.
15 /// </summary>
16 - [RuntimeFact(Skip = "https://github.com/wixtoolset/issues/issues/6349")] // CAUTION: this test currently hangs because the Plan request gets dropped.
16 + [RuntimeFact]
17 public void CanExplicitlyElevateAndPlanFromOnElevateBegin()
18 {
19 var packageA = this.CreatePackageInstaller("PackageA");