aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2022-10-19 15:44:40 -0500
committerSean Hall <r.sean.hall@gmail.com>2022-10-25 15:13:06 -0500
commit98080672cdbbde00ea40a96c1ce38e8a52f24fee (patch)
tree9c0b859f147d55d5c4caadccfd764ca84ed7e648 /src
parent28e9c7c14d2a156b55476f6b8e39e13f17aa87b6 (diff)
downloadwix-98080672cdbbde00ea40a96c1ce38e8a52f24fee.tar.gz
wix-98080672cdbbde00ea40a96c1ce38e8a52f24fee.tar.bz2
wix-98080672cdbbde00ea40a96c1ce38e8a52f24fee.zip
Add queutil so Burn can manage its own queue of BA requested actions.
Fixes 6349
Diffstat (limited to 'src')
-rw-r--r--src/burn/engine/EngineForApplication.cpp12
-rw-r--r--src/burn/engine/EngineForApplication.h33
-rw-r--r--src/burn/engine/approvedexe.cpp1
-rw-r--r--src/burn/engine/core.cpp31
-rw-r--r--src/burn/engine/core.h9
-rw-r--r--src/burn/engine/elevation.cpp5
-rw-r--r--src/burn/engine/engine.cpp95
-rw-r--r--src/burn/engine/externalengine.cpp166
-rw-r--r--src/burn/engine/externalengine.h14
-rw-r--r--src/burn/engine/platform.h1
-rw-r--r--src/burn/engine/precomp.h1
-rw-r--r--src/libs/dutil/WixToolset.DUtil/dutil.vcxproj2
-rw-r--r--src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters6
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/dutilsources.h1
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/queutil.h52
-rw-r--r--src/libs/dutil/WixToolset.DUtil/precomp.h1
-rw-r--r--src/libs/dutil/WixToolset.DUtil/queutil.cpp144
-rw-r--r--src/test/burn/WixToolsetTest.BurnE2E/ElevationTests.cs2
18 files changed, 451 insertions, 125 deletions
diff --git a/src/burn/engine/EngineForApplication.cpp b/src/burn/engine/EngineForApplication.cpp
index 27f815c6..45bfaf83 100644
--- a/src/burn/engine/EngineForApplication.cpp
+++ b/src/burn/engine/EngineForApplication.cpp
@@ -325,7 +325,7 @@ static HRESULT BAEngineDetect(
325 ValidateMessageArgs(hr, pvArgs, BAENGINE_DETECT_ARGS, pArgs); 325 ValidateMessageArgs(hr, pvArgs, BAENGINE_DETECT_ARGS, pArgs);
326 ValidateMessageResults(hr, pvResults, BAENGINE_DETECT_RESULTS, pResults); 326 ValidateMessageResults(hr, pvResults, BAENGINE_DETECT_RESULTS, pResults);
327 327
328 hr = ExternalEngineDetect(pContext->dwThreadId, pArgs->hwndParent); 328 hr = ExternalEngineDetect(pContext, pArgs->hwndParent);
329 329
330LExit: 330LExit:
331 return hr; 331 return hr;
@@ -341,7 +341,7 @@ static HRESULT BAEnginePlan(
341 ValidateMessageArgs(hr, pvArgs, BAENGINE_PLAN_ARGS, pArgs); 341 ValidateMessageArgs(hr, pvArgs, BAENGINE_PLAN_ARGS, pArgs);
342 ValidateMessageResults(hr, pvResults, BAENGINE_PLAN_RESULTS, pResults); 342 ValidateMessageResults(hr, pvResults, BAENGINE_PLAN_RESULTS, pResults);
343 343
344 hr = ExternalEnginePlan(pContext->dwThreadId, pArgs->action); 344 hr = ExternalEnginePlan(pContext, pArgs->action);
345 345
346LExit: 346LExit:
347 return hr; 347 return hr;
@@ -357,7 +357,7 @@ static HRESULT BAEngineElevate(
357 ValidateMessageArgs(hr, pvArgs, BAENGINE_ELEVATE_ARGS, pArgs); 357 ValidateMessageArgs(hr, pvArgs, BAENGINE_ELEVATE_ARGS, pArgs);
358 ValidateMessageResults(hr, pvResults, BAENGINE_ELEVATE_RESULTS, pResults); 358 ValidateMessageResults(hr, pvResults, BAENGINE_ELEVATE_RESULTS, pResults);
359 359
360 hr = ExternalEngineElevate(pContext->pEngineState, pContext->dwThreadId, pArgs->hwndParent); 360 hr = ExternalEngineElevate(pContext, pArgs->hwndParent);
361 361
362LExit: 362LExit:
363 return hr; 363 return hr;
@@ -373,7 +373,7 @@ static HRESULT BAEngineApply(
373 ValidateMessageArgs(hr, pvArgs, BAENGINE_APPLY_ARGS, pArgs); 373 ValidateMessageArgs(hr, pvArgs, BAENGINE_APPLY_ARGS, pArgs);
374 ValidateMessageResults(hr, pvResults, BAENGINE_APPLY_RESULTS, pResults); 374 ValidateMessageResults(hr, pvResults, BAENGINE_APPLY_RESULTS, pResults);
375 375
376 hr = ExternalEngineApply(pContext->dwThreadId, pArgs->hwndParent); 376 hr = ExternalEngineApply(pContext, pArgs->hwndParent);
377 377
378LExit: 378LExit:
379 return hr; 379 return hr;
@@ -389,7 +389,7 @@ static HRESULT BAEngineQuit(
389 ValidateMessageArgs(hr, pvArgs, BAENGINE_QUIT_ARGS, pArgs); 389 ValidateMessageArgs(hr, pvArgs, BAENGINE_QUIT_ARGS, pArgs);
390 ValidateMessageResults(hr, pvResults, BAENGINE_QUIT_RESULTS, pResults); 390 ValidateMessageResults(hr, pvResults, BAENGINE_QUIT_RESULTS, pResults);
391 391
392 hr = ExternalEngineQuit(pContext->dwThreadId, pArgs->dwExitCode); 392 hr = ExternalEngineQuit(pContext, pArgs->dwExitCode);
393 393
394LExit: 394LExit:
395 return hr; 395 return hr;
@@ -405,7 +405,7 @@ static HRESULT BAEngineLaunchApprovedExe(
405 ValidateMessageArgs(hr, pvArgs, BAENGINE_LAUNCHAPPROVEDEXE_ARGS, pArgs); 405 ValidateMessageArgs(hr, pvArgs, BAENGINE_LAUNCHAPPROVEDEXE_ARGS, pArgs);
406 ValidateMessageResults(hr, pvResults, BAENGINE_LAUNCHAPPROVEDEXE_RESULTS, pResults); 406 ValidateMessageResults(hr, pvResults, BAENGINE_LAUNCHAPPROVEDEXE_RESULTS, pResults);
407 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 409
410LExit: 410LExit:
411 return hr; 411 return hr;
diff --git a/src/burn/engine/EngineForApplication.h b/src/burn/engine/EngineForApplication.h
index d25a7e51..bf86b7ee 100644
--- a/src/burn/engine/EngineForApplication.h
+++ b/src/burn/engine/EngineForApplication.h
@@ -11,9 +11,40 @@ extern "C" {
11typedef struct _BOOTSTRAPPER_ENGINE_CONTEXT 11typedef struct _BOOTSTRAPPER_ENGINE_CONTEXT
12{ 12{
13 BURN_ENGINE_STATE* pEngineState; 13 BURN_ENGINE_STATE* pEngineState;
14 DWORD dwThreadId; 14 QUEUTIL_QUEUE_HANDLE hQueue;
15 HANDLE hQueueSemaphore;
16 CRITICAL_SECTION csQueue;
15} BOOTSTRAPPER_ENGINE_CONTEXT; 17} BOOTSTRAPPER_ENGINE_CONTEXT;
16 18
19typedef 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
17// function declarations 48// function declarations
18 49
19HRESULT WINAPI EngineForApplicationProc( 50HRESULT WINAPI EngineForApplicationProc(
diff --git a/src/burn/engine/approvedexe.cpp b/src/burn/engine/approvedexe.cpp
index d8bd956b..28b26d6d 100644
--- a/src/burn/engine/approvedexe.cpp
+++ b/src/burn/engine/approvedexe.cpp
@@ -106,7 +106,6 @@ extern "C" void ApprovedExesUninitializeLaunch(
106 ReleaseStr(pLaunchApprovedExe->sczArguments); 106 ReleaseStr(pLaunchApprovedExe->sczArguments);
107 ReleaseStr(pLaunchApprovedExe->sczExecutablePath); 107 ReleaseStr(pLaunchApprovedExe->sczExecutablePath);
108 ReleaseStr(pLaunchApprovedExe->sczId); 108 ReleaseStr(pLaunchApprovedExe->sczId);
109 MemFree(pLaunchApprovedExe);
110 } 109 }
111} 110}
112 111
diff --git a/src/burn/engine/core.cpp b/src/burn/engine/core.cpp
index c443e0c8..8903b5b2 100644
--- a/src/burn/engine/core.cpp
+++ b/src/burn/engine/core.cpp
@@ -884,17 +884,16 @@ LExit:
884 884
885 LogId(REPORT_STANDARD, MSG_LAUNCH_APPROVED_EXE_COMPLETE, hr, dwProcessId); 885 LogId(REPORT_STANDARD, MSG_LAUNCH_APPROVED_EXE_COMPLETE, hr, dwProcessId);
886 886
887 ApprovedExesUninitializeLaunch(pLaunchApprovedExe);
888
889 return hr; 887 return hr;
890} 888}
891 889
892extern "C" HRESULT CoreQuit( 890extern "C" void CoreQuit(
893 __in BURN_ENGINE_STATE* pEngineState, 891 __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
894 __in int nExitCode 892 __in DWORD dwExitCode
895 ) 893 )
896{ 894{
897 HRESULT hr = S_OK; 895 HRESULT hr = S_OK;
896 BURN_ENGINE_STATE* pEngineState = pEngineContext->pEngineState;
898 897
899 // Save engine state if resume mode is unequal to "none". 898 // Save engine state if resume mode is unequal to "none".
900 if (BURN_RESUME_MODE_NONE != pEngineState->resumeMode) 899 if (BURN_RESUME_MODE_NONE != pEngineState->resumeMode)
@@ -907,13 +906,15 @@ extern "C" HRESULT CoreQuit(
907 } 906 }
908 } 907 }
909 908
910 LogId(REPORT_STANDARD, MSG_QUIT, nExitCode); 909 LogId(REPORT_STANDARD, MSG_QUIT, dwExitCode);
911 910
912 pEngineState->fQuit = TRUE; 911 pEngineState->userExperience.dwExitCode = dwExitCode;
913 912
914 ::PostQuitMessage(nExitCode); // go bye-bye. 913 ::EnterCriticalSection(&pEngineContext->csQueue);
915 914
916 return hr; 915 pEngineState->fQuit = TRUE;
916
917 ::LeaveCriticalSection(&pEngineContext->csQueue);
917} 918}
918 919
919extern "C" HRESULT CoreSaveEngineState( 920extern "C" HRESULT CoreSaveEngineState(
@@ -2071,6 +2072,18 @@ LExit:
2071 return hr; 2072 return hr;
2072} 2073}
2073 2074
2075extern "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
2074// internal helper functions 2087// internal helper functions
2075 2088
2076static HRESULT AppendEscapedArgumentToCommandLine( 2089static HRESULT AppendEscapedArgumentToCommandLine(
diff --git a/src/burn/engine/core.h b/src/burn/engine/core.h
index 3e636640..186b49ca 100644
--- a/src/burn/engine/core.h
+++ b/src/burn/engine/core.h
@@ -262,9 +262,9 @@ HRESULT CoreLaunchApprovedExe(
262 __in BURN_ENGINE_STATE* pEngineState, 262 __in BURN_ENGINE_STATE* pEngineState,
263 __in BURN_LAUNCH_APPROVED_EXE* pLaunchApprovedExe 263 __in BURN_LAUNCH_APPROVED_EXE* pLaunchApprovedExe
264 ); 264 );
265HRESULT CoreQuit( 265void CoreQuit(
266 __in BURN_ENGINE_STATE* pEngineState, 266 __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
267 __in int nExitCode 267 __in DWORD dwExitCode
268 ); 268 );
269HRESULT CoreSaveEngineState( 269HRESULT CoreSaveEngineState(
270 __in BURN_ENGINE_STATE* pEngineState 270 __in BURN_ENGINE_STATE* pEngineState
@@ -354,6 +354,9 @@ HRESULT DAPI CoreCloseElevatedLoggingThread(
354HRESULT DAPI CoreWaitForUnelevatedLoggingThread( 354HRESULT DAPI CoreWaitForUnelevatedLoggingThread(
355 __in HANDLE hUnelevatedLoggingThread 355 __in HANDLE hUnelevatedLoggingThread
356 ); 356 );
357void DAPI CoreBootstrapperEngineActionUninitialize(
358 __in BOOTSTRAPPER_ENGINE_ACTION* pAction
359 );
357 360
358#if defined(__cplusplus) 361#if defined(__cplusplus)
359} 362}
diff --git a/src/burn/engine/elevation.cpp b/src/burn/engine/elevation.cpp
index 7fd372b0..154c407d 100644
--- a/src/burn/engine/elevation.cpp
+++ b/src/burn/engine/elevation.cpp
@@ -3824,7 +3824,8 @@ static HRESULT OnLaunchApprovedExe(
3824{ 3824{
3825 HRESULT hr = S_OK; 3825 HRESULT hr = S_OK;
3826 SIZE_T iData = 0; 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;
3828 BURN_APPROVED_EXE* pApprovedExe = NULL; 3829 BURN_APPROVED_EXE* pApprovedExe = NULL;
3829 HKEY hKey = NULL; 3830 HKEY hKey = NULL;
3830 DWORD dwProcessId = 0; 3831 DWORD dwProcessId = 0;
@@ -3832,8 +3833,6 @@ static HRESULT OnLaunchApprovedExe(
3832 SIZE_T cbSendData = 0; 3833 SIZE_T cbSendData = 0;
3833 DWORD dwResult = 0; 3834 DWORD dwResult = 0;
3834 3835
3835 pLaunchApprovedExe = (BURN_LAUNCH_APPROVED_EXE*)MemAlloc(sizeof(BURN_LAUNCH_APPROVED_EXE), TRUE);
3836
3837 // Deserialize message data. 3836 // Deserialize message data.
3838 hr = BuffReadString(pbData, cbData, &iData, &pLaunchApprovedExe->sczId); 3837 hr = BuffReadString(pbData, cbData, &iData, &pLaunchApprovedExe->sczId);
3839 ExitOnFailure(hr, "Failed to read approved exe id."); 3838 ExitOnFailure(hr, "Failed to read approved exe id.");
diff --git a/src/burn/engine/engine.cpp b/src/burn/engine/engine.cpp
index 48196655..c9d2bdcd 100644
--- a/src/burn/engine/engine.cpp
+++ b/src/burn/engine/engine.cpp
@@ -42,8 +42,8 @@ static HRESULT RunApplication(
42 __out BOOL* pfSkipCleanup 42 __out BOOL* pfSkipCleanup
43 ); 43 );
44static HRESULT ProcessMessage( 44static HRESULT ProcessMessage(
45 __in BURN_ENGINE_STATE* pEngineState, 45 __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
46 __in const MSG* pmsg 46 __in BOOTSTRAPPER_ENGINE_ACTION* pAction
47 ); 47 );
48static HRESULT DAPI RedirectLoggingOverPipe( 48static HRESULT DAPI RedirectLoggingOverPipe(
49 __in_z LPCSTR szString, 49 __in_z LPCSTR szString,
@@ -790,6 +790,19 @@ LExit:
790 return hr; 790 return hr;
791} 791}
792 792
793static 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
793static HRESULT RunApplication( 806static HRESULT RunApplication(
794 __in BURN_ENGINE_STATE* pEngineState, 807 __in BURN_ENGINE_STATE* pEngineState,
795 __out BOOL* pfReloadApp, 808 __out BOOL* pfReloadApp,
@@ -799,16 +812,20 @@ static HRESULT RunApplication(
799 HRESULT hr = S_OK; 812 HRESULT hr = S_OK;
800 BOOTSTRAPPER_ENGINE_CONTEXT engineContext = { }; 813 BOOTSTRAPPER_ENGINE_CONTEXT engineContext = { };
801 BOOL fStartupCalled = FALSE; 814 BOOL fStartupCalled = FALSE;
802 BOOL fRet = FALSE;
803 MSG msg = { };
804 BOOTSTRAPPER_SHUTDOWN_ACTION shutdownAction = BOOTSTRAPPER_SHUTDOWN_ACTION_NONE; 815 BOOTSTRAPPER_SHUTDOWN_ACTION shutdownAction = BOOTSTRAPPER_SHUTDOWN_ACTION_NONE;
805 816 BOOTSTRAPPER_ENGINE_ACTION* pAction = NULL;
806 ::PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
807 817
808 // Setup the bootstrapper engine. 818 // Setup the bootstrapper engine.
809 engineContext.dwThreadId = ::GetCurrentThreadId();
810 engineContext.pEngineState = pEngineState; 819 engineContext.pEngineState = pEngineState;
811 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
812 // Load the bootstrapper application. 829 // Load the bootstrapper application.
813 hr = UserExperienceLoad(&pEngineState->userExperience, &engineContext, &pEngineState->command); 830 hr = UserExperienceLoad(&pEngineState->userExperience, &engineContext, &pEngineState->command);
814 ExitOnFailure(hr, "Failed to load BA."); 831 ExitOnFailure(hr, "Failed to load BA.");
@@ -817,28 +834,24 @@ static HRESULT RunApplication(
817 hr = UserExperienceOnStartup(&pEngineState->userExperience); 834 hr = UserExperienceOnStartup(&pEngineState->userExperience);
818 ExitOnFailure(hr, "Failed to start bootstrapper application."); 835 ExitOnFailure(hr, "Failed to start bootstrapper application.");
819 836
820 // Enter the message pump. 837 while (!pEngineState->fQuit)
821 while (0 != (fRet = ::GetMessageW(&msg, NULL, 0, 0)))
822 { 838 {
823 if (-1 == fRet) 839 hr = AppWaitForSingleObject(engineContext.hQueueSemaphore, INFINITE);
824 { 840 ExitOnFailure(hr, "Failed to wait on queue event.");
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);
835 841
836 ProcessMessage(pEngineState, &msg); 842 ::EnterCriticalSection(&engineContext.csQueue);
837 } 843
838 } 844 hr = QueDequeue(engineContext.hQueue, reinterpret_cast<void**>(&pAction));
845
846 ::LeaveCriticalSection(&engineContext.csQueue);
839 847
840 // Get exit code. 848 ExitOnFailure(hr, "Failed to dequeue action.");
841 pEngineState->userExperience.dwExitCode = (DWORD)msg.wParam; 849
850 ProcessMessage(&engineContext, pAction);
851
852 CoreBootstrapperEngineActionUninitialize(pAction);
853 MemFree(pAction);
854 }
842 855
843LExit: 856LExit:
844 if (fStartupCalled) 857 if (fStartupCalled)
@@ -864,52 +877,50 @@ LExit:
864 // Unload BA. 877 // Unload BA.
865 UserExperienceUnload(&pEngineState->userExperience, *pfReloadApp); 878 UserExperienceUnload(&pEngineState->userExperience, *pfReloadApp);
866 879
880 ::DeleteCriticalSection(&engineContext.csQueue);
881 ReleaseHandle(engineContext.hQueueSemaphore);
882 ReleaseQueue(engineContext.hQueue, FreeQueueItem, &engineContext);
883
867 return hr; 884 return hr;
868} 885}
869 886
870static HRESULT ProcessMessage( 887static HRESULT ProcessMessage(
871 __in BURN_ENGINE_STATE* pEngineState, 888 __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
872 __in const MSG* pmsg 889 __in BOOTSTRAPPER_ENGINE_ACTION* pAction
873 ) 890 )
874{ 891{
875 HRESULT hr = S_OK; 892 HRESULT hr = S_OK;
893 BURN_ENGINE_STATE* pEngineState = pEngineContext->pEngineState;
876 894
877 UserExperienceActivateEngine(&pEngineState->userExperience); 895 UserExperienceActivateEngine(&pEngineState->userExperience);
878 896
879 if (pEngineState->fQuit) 897 switch (pAction->dwMessage)
880 {
881 LogId(REPORT_WARNING, MSG_IGNORE_OPERATION_AFTER_QUIT, LoggingBurnMessageToString(pmsg->message));
882 ExitFunction1(hr = E_INVALIDSTATE);
883 }
884
885 switch (pmsg->message)
886 { 898 {
887 case WM_BURN_DETECT: 899 case WM_BURN_DETECT:
888 hr = CoreDetect(pEngineState, reinterpret_cast<HWND>(pmsg->lParam)); 900 hr = CoreDetect(pEngineState, pAction->detect.hwndParent);
889 break; 901 break;
890 902
891 case WM_BURN_PLAN: 903 case WM_BURN_PLAN:
892 hr = CorePlan(pEngineState, static_cast<BOOTSTRAPPER_ACTION>(pmsg->lParam)); 904 hr = CorePlan(pEngineState, pAction->plan.action);
893 break; 905 break;
894 906
895 case WM_BURN_ELEVATE: 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);
897 break; 909 break;
898 910
899 case WM_BURN_APPLY: 911 case WM_BURN_APPLY:
900 hr = CoreApply(pEngineState, reinterpret_cast<HWND>(pmsg->lParam)); 912 hr = CoreApply(pEngineState, pAction->apply.hwndParent);
901 break; 913 break;
902 914
903 case WM_BURN_LAUNCH_APPROVED_EXE: 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);
905 break; 917 break;
906 918
907 case WM_BURN_QUIT: 919 case WM_BURN_QUIT:
908 hr = CoreQuit(pEngineState, static_cast<int>(pmsg->wParam)); 920 CoreQuit(pEngineContext, pAction->quit.dwExitCode);
909 break; 921 break;
910 } 922 }
911 923
912LExit:
913 UserExperienceDeactivateEngine(&pEngineState->userExperience); 924 UserExperienceDeactivateEngine(&pEngineState->userExperience);
914 925
915 return hr; 926 return hr;
diff --git a/src/burn/engine/externalengine.cpp b/src/burn/engine/externalengine.cpp
index 5e540c2a..262bb1a9 100644
--- a/src/burn/engine/externalengine.cpp
+++ b/src/burn/engine/externalengine.cpp
@@ -13,6 +13,10 @@ static HRESULT ProcessUnknownEmbeddedMessages(
13 __in_opt LPVOID /*pvContext*/, 13 __in_opt LPVOID /*pvContext*/,
14 __out DWORD* pdwResult 14 __out DWORD* pdwResult
15 ); 15 );
16static HRESULT EnqueueAction(
17 __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
18 __inout BOOTSTRAPPER_ENGINE_ACTION** ppAction
19 );
16 20
17// function definitions 21// function definitions
18 22
@@ -582,69 +586,91 @@ HRESULT ExternalEngineCompareVersions(
582} 586}
583 587
584HRESULT ExternalEngineDetect( 588HRESULT ExternalEngineDetect(
585 __in const DWORD dwThreadId, 589 __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
586 __in_opt const HWND hwndParent 590 __in_opt const HWND hwndParent
587 ) 591 )
588{ 592{
589 HRESULT hr = S_OK; 593 HRESULT hr = S_OK;
594 BOOTSTRAPPER_ENGINE_ACTION* pAction = NULL;
590 595
591 if (!::PostThreadMessageW(dwThreadId, WM_BURN_DETECT, 0, reinterpret_cast<LPARAM>(hwndParent))) 596 pAction = (BOOTSTRAPPER_ENGINE_ACTION*)MemAlloc(sizeof(BOOTSTRAPPER_ENGINE_ACTION), TRUE);
592 { 597 ExitOnNull(pAction, hr, E_OUTOFMEMORY, "Failed to alloc BOOTSTRAPPER_ENGINE_ACTION");
593 ExitWithLastError(hr, "Failed to post detect message."); 598
594 } 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.");
595 604
596LExit: 605LExit:
606 ReleaseMem(pAction);
607
597 return hr; 608 return hr;
598} 609}
599 610
600HRESULT ExternalEnginePlan( 611HRESULT ExternalEnginePlan(
601 __in const DWORD dwThreadId, 612 __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
602 __in const BOOTSTRAPPER_ACTION action 613 __in const BOOTSTRAPPER_ACTION action
603 ) 614 )
604{ 615{
605 HRESULT hr = S_OK; 616 HRESULT hr = S_OK;
617 BOOTSTRAPPER_ENGINE_ACTION* pAction = NULL;
606 618
607 if (BOOTSTRAPPER_ACTION_LAYOUT > action || BOOTSTRAPPER_ACTION_UPDATE_REPLACE_EMBEDDED < action) 619 if (BOOTSTRAPPER_ACTION_LAYOUT > action || BOOTSTRAPPER_ACTION_UPDATE_REPLACE_EMBEDDED < action)
608 { 620 {
609 ExitOnRootFailure(hr = E_INVALIDARG, "BA passed invalid action to Plan: %u.", action); 621 ExitOnRootFailure(hr = E_INVALIDARG, "BA passed invalid action to Plan: %u.", action);
610 } 622 }
611 623
612 if (!::PostThreadMessageW(dwThreadId, WM_BURN_PLAN, 0, action)) 624 pAction = (BOOTSTRAPPER_ENGINE_ACTION*)MemAlloc(sizeof(BOOTSTRAPPER_ENGINE_ACTION), TRUE);
613 { 625 ExitOnNull(pAction, hr, E_OUTOFMEMORY, "Failed to alloc BOOTSTRAPPER_ENGINE_ACTION");
614 ExitWithLastError(hr, "Failed to post plan message."); 626
615 } 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.");
616 632
617LExit: 633LExit:
634 ReleaseMem(pAction);
635
618 return hr; 636 return hr;
619} 637}
620 638
621HRESULT ExternalEngineElevate( 639HRESULT ExternalEngineElevate(
622 __in BURN_ENGINE_STATE* pEngineState, 640 __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
623 __in const DWORD dwThreadId,
624 __in_opt const HWND hwndParent 641 __in_opt const HWND hwndParent
625 ) 642 )
626{ 643{
627 HRESULT hr = S_OK; 644 HRESULT hr = S_OK;
645 BOOTSTRAPPER_ENGINE_ACTION* pAction = NULL;
628 646
629 if (INVALID_HANDLE_VALUE != pEngineState->companionConnection.hPipe) 647 if (INVALID_HANDLE_VALUE != pEngineContext->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)))
634 { 648 {
635 ExitWithLastError(hr, "Failed to post elevate message."); 649 ExitFunction1(hr = HRESULT_FROM_WIN32(ERROR_ALREADY_INITIALIZED));
636 } 650 }
637 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
638LExit: 661LExit:
662 ReleaseMem(pAction);
663
639 return hr; 664 return hr;
640} 665}
641 666
642HRESULT ExternalEngineApply( 667HRESULT ExternalEngineApply(
643 __in const DWORD dwThreadId, 668 __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
644 __in_opt const HWND hwndParent 669 __in_opt const HWND hwndParent
645 ) 670 )
646{ 671{
647 HRESULT hr = S_OK; 672 HRESULT hr = S_OK;
673 BOOTSTRAPPER_ENGINE_ACTION* pAction = NULL;
648 674
649 ExitOnNull(hwndParent, hr, E_INVALIDARG, "BA passed NULL hwndParent to Apply."); 675 ExitOnNull(hwndParent, hr, E_INVALIDARG, "BA passed NULL hwndParent to Apply.");
650 if (!::IsWindow(hwndParent)) 676 if (!::IsWindow(hwndParent))
@@ -652,34 +678,46 @@ HRESULT ExternalEngineApply(
652 ExitOnRootFailure(hr = E_INVALIDARG, "BA passed invalid hwndParent to Apply."); 678 ExitOnRootFailure(hr = E_INVALIDARG, "BA passed invalid hwndParent to Apply.");
653 } 679 }
654 680
655 if (!::PostThreadMessageW(dwThreadId, WM_BURN_APPLY, 0, reinterpret_cast<LPARAM>(hwndParent))) 681 pAction = (BOOTSTRAPPER_ENGINE_ACTION*)MemAlloc(sizeof(BOOTSTRAPPER_ENGINE_ACTION), TRUE);
656 { 682 ExitOnNull(pAction, hr, E_OUTOFMEMORY, "Failed to alloc BOOTSTRAPPER_ENGINE_ACTION");
657 ExitWithLastError(hr, "Failed to post apply message."); 683
658 } 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.");
659 689
660LExit: 690LExit:
691 ReleaseMem(pAction);
692
661 return hr; 693 return hr;
662} 694}
663 695
664HRESULT ExternalEngineQuit( 696HRESULT ExternalEngineQuit(
665 __in const DWORD dwThreadId, 697 __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
666 __in const DWORD dwExitCode 698 __in const DWORD dwExitCode
667 ) 699 )
668{ 700{
669 HRESULT hr = S_OK; 701 HRESULT hr = S_OK;
702 BOOTSTRAPPER_ENGINE_ACTION* pAction = NULL;
670 703
671 if (!::PostThreadMessageW(dwThreadId, WM_BURN_QUIT, static_cast<WPARAM>(dwExitCode), 0)) 704 pAction = (BOOTSTRAPPER_ENGINE_ACTION*)MemAlloc(sizeof(BOOTSTRAPPER_ENGINE_ACTION), TRUE);
672 { 705 ExitOnNull(pAction, hr, E_OUTOFMEMORY, "Failed to alloc BOOTSTRAPPER_ENGINE_ACTION");
673 ExitWithLastError(hr, "Failed to post shutdown message."); 706
674 } 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.");
675 712
676LExit: 713LExit:
714 ReleaseMem(pAction);
715
677 return hr; 716 return hr;
678} 717}
679 718
680HRESULT ExternalEngineLaunchApprovedExe( 719HRESULT ExternalEngineLaunchApprovedExe(
681 __in BURN_ENGINE_STATE* pEngineState, 720 __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
682 __in const DWORD dwThreadId,
683 __in_opt const HWND hwndParent, 721 __in_opt const HWND hwndParent,
684 __in_z LPCWSTR wzApprovedExeForElevationId, 722 __in_z LPCWSTR wzApprovedExeForElevationId,
685 __in_z_opt LPCWSTR wzArguments, 723 __in_z_opt LPCWSTR wzArguments,
@@ -688,25 +726,23 @@ HRESULT ExternalEngineLaunchApprovedExe(
688{ 726{
689 HRESULT hr = S_OK; 727 HRESULT hr = S_OK;
690 BURN_APPROVED_EXE* pApprovedExe = NULL; 728 BURN_APPROVED_EXE* pApprovedExe = NULL;
691 BOOL fLeaveCriticalSection = FALSE;
692 BURN_LAUNCH_APPROVED_EXE* pLaunchApprovedExe = NULL; 729 BURN_LAUNCH_APPROVED_EXE* pLaunchApprovedExe = NULL;
693 730 BOOTSTRAPPER_ENGINE_ACTION* pAction = NULL;
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.");
701 731
702 if (!wzApprovedExeForElevationId || !*wzApprovedExeForElevationId) 732 if (!wzApprovedExeForElevationId || !*wzApprovedExeForElevationId)
703 { 733 {
704 ExitFunction1(hr = E_INVALIDARG); 734 ExitFunction1(hr = E_INVALIDARG);
705 } 735 }
706 736
707 hr = ApprovedExesFindById(&pEngineState->approvedExes, wzApprovedExeForElevationId, &pApprovedExe); 737 hr = ApprovedExesFindById(&pEngineContext->pEngineState->approvedExes, wzApprovedExeForElevationId, &pApprovedExe);
708 ExitOnFailure(hr, "BA requested unknown approved exe with id: %ls", wzApprovedExeForElevationId); 738 ExitOnFailure(hr, "BA requested unknown approved exe with id: %ls", wzApprovedExeForElevationId);
709 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
710 hr = StrAllocString(&pLaunchApprovedExe->sczId, wzApprovedExeForElevationId, NULL); 746 hr = StrAllocString(&pLaunchApprovedExe->sczId, wzApprovedExeForElevationId, NULL);
711 ExitOnFailure(hr, "Failed to copy the id."); 747 ExitOnFailure(hr, "Failed to copy the id.");
712 748
@@ -720,20 +756,14 @@ HRESULT ExternalEngineLaunchApprovedExe(
720 756
721 pLaunchApprovedExe->hwndParent = hwndParent; 757 pLaunchApprovedExe->hwndParent = hwndParent;
722 758
723 if (!::PostThreadMessageW(dwThreadId, WM_BURN_LAUNCH_APPROVED_EXE, 0, reinterpret_cast<LPARAM>(pLaunchApprovedExe))) 759 hr = EnqueueAction(pEngineContext, &pAction);
724 { 760 ExitOnFailure(hr, "Failed to enqueue launch approved exe action.");
725 ExitWithLastError(hr, "Failed to post launch approved exe message.");
726 }
727 761
728LExit: 762LExit:
729 if (fLeaveCriticalSection) 763 if (pAction)
730 { 764 {
731 ::LeaveCriticalSection(&pEngineState->userExperience.csEngineActive); 765 CoreBootstrapperEngineActionUninitialize(pAction);
732 } 766 MemFree(pAction);
733
734 if (FAILED(hr))
735 {
736 ApprovedExesUninitializeLaunch(pLaunchApprovedExe);
737 } 767 }
738 768
739 return hr; 769 return hr;
@@ -836,3 +866,37 @@ static HRESULT ProcessUnknownEmbeddedMessages(
836 866
837 return S_OK; 867 return S_OK;
838} 868}
869
870static 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
900LExit:
901 return hr;
902}
diff --git a/src/burn/engine/externalengine.h b/src/burn/engine/externalengine.h
index f28971cd..9322234a 100644
--- a/src/burn/engine/externalengine.h
+++ b/src/burn/engine/externalengine.h
@@ -130,34 +130,32 @@ HRESULT ExternalEngineCompareVersions(
130 ); 130 );
131 131
132HRESULT ExternalEngineDetect( 132HRESULT ExternalEngineDetect(
133 __in const DWORD dwThreadId, 133 __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
134 __in_opt const HWND hwndParent 134 __in_opt const HWND hwndParent
135 ); 135 );
136 136
137HRESULT ExternalEnginePlan( 137HRESULT ExternalEnginePlan(
138 __in const DWORD dwThreadId, 138 __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
139 __in const BOOTSTRAPPER_ACTION action 139 __in const BOOTSTRAPPER_ACTION action
140 ); 140 );
141 141
142HRESULT ExternalEngineElevate( 142HRESULT ExternalEngineElevate(
143 __in BURN_ENGINE_STATE* pEngineState, 143 __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
144 __in const DWORD dwThreadId,
145 __in_opt const HWND hwndParent 144 __in_opt const HWND hwndParent
146 ); 145 );
147 146
148HRESULT ExternalEngineApply( 147HRESULT ExternalEngineApply(
149 __in const DWORD dwThreadId, 148 __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
150 __in_opt const HWND hwndParent 149 __in_opt const HWND hwndParent
151 ); 150 );
152 151
153HRESULT ExternalEngineQuit( 152HRESULT ExternalEngineQuit(
154 __in const DWORD dwThreadId, 153 __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
155 __in const DWORD dwExitCode 154 __in const DWORD dwExitCode
156 ); 155 );
157 156
158HRESULT ExternalEngineLaunchApprovedExe( 157HRESULT ExternalEngineLaunchApprovedExe(
159 __in BURN_ENGINE_STATE* pEngineState, 158 __in BOOTSTRAPPER_ENGINE_CONTEXT* pEngineContext,
160 __in const DWORD dwThreadId,
161 __in_opt const HWND hwndParent, 159 __in_opt const HWND hwndParent,
162 __in_z LPCWSTR wzApprovedExeForElevationId, 160 __in_z LPCWSTR wzApprovedExeForElevationId,
163 __in_z_opt LPCWSTR wzArguments, 161 __in_z_opt LPCWSTR wzArguments,
diff --git a/src/burn/engine/platform.h b/src/burn/engine/platform.h
index 60184c23..5896a5ca 100644
--- a/src/burn/engine/platform.h
+++ b/src/burn/engine/platform.h
@@ -28,6 +28,7 @@ enum WM_BURN
28 28
29enum BURN_MODE; 29enum BURN_MODE;
30typedef struct _BOOTSTRAPPER_ENGINE_CONTEXT BOOTSTRAPPER_ENGINE_CONTEXT; 30typedef struct _BOOTSTRAPPER_ENGINE_CONTEXT BOOTSTRAPPER_ENGINE_CONTEXT;
31typedef struct _BOOTSTRAPPER_ENGINE_ACTION BOOTSTRAPPER_ENGINE_ACTION;
31typedef struct _BURN_CACHE BURN_CACHE; 32typedef struct _BURN_CACHE BURN_CACHE;
32typedef struct _BURN_DEPENDENCIES BURN_DEPENDENCIES; 33typedef struct _BURN_DEPENDENCIES BURN_DEPENDENCIES;
33typedef struct _BURN_ENGINE_COMMAND BURN_ENGINE_COMMAND; 34typedef struct _BURN_ENGINE_COMMAND BURN_ENGINE_COMMAND;
diff --git a/src/burn/engine/precomp.h b/src/burn/engine/precomp.h
index e2d1b5cd..a64ce474 100644
--- a/src/burn/engine/precomp.h
+++ b/src/burn/engine/precomp.h
@@ -40,6 +40,7 @@
40#include <pathutil.h> 40#include <pathutil.h>
41#include <polcutil.h> 41#include <polcutil.h>
42#include <procutil.h> 42#include <procutil.h>
43#include <queutil.h>
43#include <regutil.h> 44#include <regutil.h>
44#include <resrutil.h> 45#include <resrutil.h>
45#include <shelutil.h> 46#include <shelutil.h>
diff --git a/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj b/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj
index c84b98fe..dc6b913f 100644
--- a/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj
+++ b/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj
@@ -91,6 +91,7 @@
91 <ClCompile Include="proc2utl.cpp" /> 91 <ClCompile Include="proc2utl.cpp" />
92 <ClCompile Include="proc3utl.cpp" /> 92 <ClCompile Include="proc3utl.cpp" />
93 <ClCompile Include="procutil.cpp" /> 93 <ClCompile Include="procutil.cpp" />
94 <ClCompile Include="queutil.cpp" />
94 <ClCompile Include="regutil.cpp" /> 95 <ClCompile Include="regutil.cpp" />
95 <ClCompile Include="resrutil.cpp" /> 96 <ClCompile Include="resrutil.cpp" />
96 <ClCompile Include="reswutil.cpp" /> 97 <ClCompile Include="reswutil.cpp" />
@@ -153,6 +154,7 @@
153 <ClInclude Include="inc\perfutil.h" /> 154 <ClInclude Include="inc\perfutil.h" />
154 <ClInclude Include="inc\polcutil.h" /> 155 <ClInclude Include="inc\polcutil.h" />
155 <ClInclude Include="inc\procutil.h" /> 156 <ClInclude Include="inc\procutil.h" />
157 <ClInclude Include="inc\queutil.h" />
156 <ClInclude Include="inc\regutil.h" /> 158 <ClInclude Include="inc\regutil.h" />
157 <ClInclude Include="inc\resrutil.h" /> 159 <ClInclude Include="inc\resrutil.h" />
158 <ClInclude Include="inc\reswutil.h" /> 160 <ClInclude Include="inc\reswutil.h" />
diff --git a/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters b/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters
index efadef6f..c1095651 100644
--- a/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters
+++ b/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters
@@ -135,6 +135,9 @@
135 <ClCompile Include="procutil.cpp"> 135 <ClCompile Include="procutil.cpp">
136 <Filter>Source Files</Filter> 136 <Filter>Source Files</Filter>
137 </ClCompile> 137 </ClCompile>
138 <ClCompile Include="queutil.cpp">
139 <Filter>Source Files</Filter>
140 </ClCompile>
138 <ClCompile Include="resrutil.cpp"> 141 <ClCompile Include="resrutil.cpp">
139 <Filter>Source Files</Filter> 142 <Filter>Source Files</Filter>
140 </ClCompile> 143 </ClCompile>
@@ -314,6 +317,9 @@
314 <ClInclude Include="inc\procutil.h"> 317 <ClInclude Include="inc\procutil.h">
315 <Filter>Header Files</Filter> 318 <Filter>Header Files</Filter>
316 </ClInclude> 319 </ClInclude>
320 <ClInclude Include="inc\queutil.h">
321 <Filter>Header Files</Filter>
322 </ClInclude>
317 <ClInclude Include="inc\regutil.h"> 323 <ClInclude Include="inc\regutil.h">
318 <Filter>Header Files</Filter> 324 <Filter>Header Files</Filter>
319 </ClInclude> 325 </ClInclude>
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/dutilsources.h b/src/libs/dutil/WixToolset.DUtil/inc/dutilsources.h
index 664c21e5..cf10f910 100644
--- a/src/libs/dutil/WixToolset.DUtil/inc/dutilsources.h
+++ b/src/libs/dutil/WixToolset.DUtil/inc/dutilsources.h
@@ -64,6 +64,7 @@ typedef enum DUTIL_SOURCE
64 DUTIL_SOURCE_WNDUTIL, 64 DUTIL_SOURCE_WNDUTIL,
65 DUTIL_SOURCE_ENVUTIL, 65 DUTIL_SOURCE_ENVUTIL,
66 DUTIL_SOURCE_THRDUTIL, 66 DUTIL_SOURCE_THRDUTIL,
67 DUTIL_SOURCE_QUEUTIL,
67 68
68 DUTIL_SOURCE_EXTERNAL = 256, 69 DUTIL_SOURCE_EXTERNAL = 256,
69} DUTIL_SOURCE; 70} DUTIL_SOURCE;
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/queutil.h b/src/libs/dutil/WixToolset.DUtil/inc/queutil.h
new file mode 100644
index 00000000..3b88825e
--- /dev/null
+++ b/src/libs/dutil/WixToolset.DUtil/inc/queutil.h
@@ -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
6extern "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
12typedef void* QUEUTIL_QUEUE_HANDLE;
13
14typedef void(CALLBACK* PFNQUEUTIL_QUEUE_RELEASE_VALUE)(
15 __in void* pvValue,
16 __in void* pvContext
17 );
18
19extern const int QUEUTIL_QUEUE_HANDLE_BYTES;
20
21/********************************************************************
22QueCreate - Creates a simple queue. It is not thread safe.
23
24********************************************************************/
25HRESULT DAPI QueCreate(
26 __out_bcount(QUEUTIL_QUEUE_HANDLE_BYTES) QUEUTIL_QUEUE_HANDLE* phQueue
27 );
28
29HRESULT DAPI QueEnqueue(
30 __in_bcount(QUEUTIL_QUEUE_HANDLE_BYTES) QUEUTIL_QUEUE_HANDLE hQueue,
31 __in void* pvValue
32 );
33
34/********************************************************************
35QueDequeue - Returns the value from the beginning of the queue,
36 or E_NOMOREITEMS if the queue is empty.
37
38********************************************************************/
39HRESULT DAPI QueDequeue(
40 __in_bcount(QUEUTIL_QUEUE_HANDLE_BYTES) QUEUTIL_QUEUE_HANDLE hQueue,
41 __out void** ppvValue
42 );
43
44void 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
diff --git a/src/libs/dutil/WixToolset.DUtil/precomp.h b/src/libs/dutil/WixToolset.DUtil/precomp.h
index b628d271..607f7ce6 100644
--- a/src/libs/dutil/WixToolset.DUtil/precomp.h
+++ b/src/libs/dutil/WixToolset.DUtil/precomp.h
@@ -75,6 +75,7 @@
75#include "perfutil.h" 75#include "perfutil.h"
76#include "polcutil.h" 76#include "polcutil.h"
77#include "procutil.h" 77#include "procutil.h"
78#include "queutil.h"
78#include "regutil.h" 79#include "regutil.h"
79#include "butil.h" // NOTE: Butil must come after Regutil. 80#include "butil.h" // NOTE: Butil must come after Regutil.
80#include "resrutil.h" 81#include "resrutil.h"
diff --git a/src/libs/dutil/WixToolset.DUtil/queutil.cpp b/src/libs/dutil/WixToolset.DUtil/queutil.cpp
new file mode 100644
index 00000000..c5d2d736
--- /dev/null
+++ b/src/libs/dutil/WixToolset.DUtil/queutil.cpp
@@ -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
21struct QUEUTIL_QUEUE_ITEM
22{
23 QUEUTIL_QUEUE_ITEM* pNext;
24 void* pvValue;
25};
26
27struct QUEUTIL_QUEUE_STRUCT
28{
29 QUEUTIL_QUEUE_ITEM* pFirst;
30 QUEUTIL_QUEUE_ITEM* pLast;
31};
32
33const int QUEUTIL_QUEUE_HANDLE_BYTES = sizeof(QUEUTIL_QUEUE_STRUCT);
34
35extern "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
46LExit:
47 return hr;
48}
49
50extern "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
79LExit:
80 ReleaseMem(pItem);
81
82 return hr;
83}
84
85extern "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
116LExit:
117 ReleaseMem(pItem);
118
119 return hr;
120}
121
122extern "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}
diff --git a/src/test/burn/WixToolsetTest.BurnE2E/ElevationTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/ElevationTests.cs
index 8f141e5d..f040905d 100644
--- a/src/test/burn/WixToolsetTest.BurnE2E/ElevationTests.cs
+++ b/src/test/burn/WixToolsetTest.BurnE2E/ElevationTests.cs
@@ -13,7 +13,7 @@ namespace WixToolsetTest.BurnE2E
13 /// This test calls Elevate after Detect, and then calls Plan in OnElevateBegin. 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. 14 /// After calling Plan, it pumps some messages to simulate UI like the UAC callback.
15 /// </summary> 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() 17 public void CanExplicitlyElevateAndPlanFromOnElevateBegin()
18 { 18 {
19 var packageA = this.CreatePackageInstaller("PackageA"); 19 var packageA = this.CreatePackageInstaller("PackageA");