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");