diff options
-rw-r--r-- | src/burn/engine/core.cpp | 42 | ||||
-rw-r--r-- | src/burn/engine/core.h | 17 | ||||
-rw-r--r-- | src/burn/engine/engine.cpp | 152 | ||||
-rw-r--r-- | src/burn/engine/uithread.cpp | 10 | ||||
-rw-r--r-- | src/test/burn/TestData/Manual/BafThmutilTesting/BafThmUtilTesting.cpp | 33 | ||||
-rw-r--r-- | src/test/burn/TestData/Manual/BundleA/BundleA.wixproj | 4 | ||||
-rw-r--r-- | src/test/burn/TestData/Manual/BundleA/BundleA.wxs | 5 | ||||
-rw-r--r-- | src/test/burn/TestData/Manual/BundleA/ManualTests.txt | 110 |
8 files changed, 240 insertions, 133 deletions
diff --git a/src/burn/engine/core.cpp b/src/burn/engine/core.cpp index 3c1ed117..c8dce17b 100644 --- a/src/burn/engine/core.cpp +++ b/src/burn/engine/core.cpp | |||
@@ -2028,6 +2028,48 @@ extern "C" HRESULT DAPI CoreWaitForProcCompletion( | |||
2028 | return vpfnProcWaitForCompletion(hProcess, dwTimeout, pdwReturnCode); | 2028 | return vpfnProcWaitForCompletion(hProcess, dwTimeout, pdwReturnCode); |
2029 | } | 2029 | } |
2030 | 2030 | ||
2031 | extern "C" HRESULT DAPI CoreCloseElevatedLoggingThread( | ||
2032 | __in BURN_ENGINE_STATE* pEngineState | ||
2033 | ) | ||
2034 | { | ||
2035 | HRESULT hr = S_OK; | ||
2036 | |||
2037 | if (INVALID_HANDLE_VALUE == pEngineState->elevatedLoggingContext.hThread) | ||
2038 | { | ||
2039 | ExitFunction(); | ||
2040 | } | ||
2041 | |||
2042 | if (!::SetEvent(pEngineState->elevatedLoggingContext.hFinishedEvent)) | ||
2043 | { | ||
2044 | ExitWithLastError(hr, "Failed to set log finished event."); | ||
2045 | } | ||
2046 | |||
2047 | hr = AppWaitForSingleObject(pEngineState->elevatedLoggingContext.hThread, 5 * 60 * 1000); // TODO: is 5 minutes good? | ||
2048 | ExitOnFailure(hr, "Failed to wait for elevated logging thread."); | ||
2049 | |||
2050 | LExit: | ||
2051 | return hr; | ||
2052 | } | ||
2053 | |||
2054 | extern "C" HRESULT DAPI CoreWaitForUnelevatedLoggingThread( | ||
2055 | __in HANDLE hUnelevatedLoggingThread | ||
2056 | ) | ||
2057 | { | ||
2058 | HRESULT hr = S_OK; | ||
2059 | |||
2060 | if (INVALID_HANDLE_VALUE == hUnelevatedLoggingThread) | ||
2061 | { | ||
2062 | ExitFunction(); | ||
2063 | } | ||
2064 | |||
2065 | // Give the thread 15 seconds to exit. | ||
2066 | hr = AppWaitForSingleObject(hUnelevatedLoggingThread, 15 * 1000); | ||
2067 | ExitOnFailure(hr, "Failed to wait for unelevated logging thread."); | ||
2068 | |||
2069 | LExit: | ||
2070 | return hr; | ||
2071 | } | ||
2072 | |||
2031 | // internal helper functions | 2073 | // internal helper functions |
2032 | 2074 | ||
2033 | static HRESULT AppendEscapedArgumentToCommandLine( | 2075 | static HRESULT AppendEscapedArgumentToCommandLine( |
diff --git a/src/burn/engine/core.h b/src/burn/engine/core.h index 28b5ba5d..812b40b1 100644 --- a/src/burn/engine/core.h +++ b/src/burn/engine/core.h | |||
@@ -123,6 +123,16 @@ typedef struct _BURN_ENGINE_COMMAND | |||
123 | LPWSTR sczLogFile; | 123 | LPWSTR sczLogFile; |
124 | } BURN_ENGINE_COMMAND; | 124 | } BURN_ENGINE_COMMAND; |
125 | 125 | ||
126 | typedef struct _BURN_REDIRECTED_LOGGING_CONTEXT | ||
127 | { | ||
128 | CRITICAL_SECTION csBuffer; | ||
129 | LPSTR sczBuffer; | ||
130 | HANDLE hPipe; | ||
131 | HANDLE hLogEvent; | ||
132 | HANDLE hFinishedEvent; | ||
133 | HANDLE hThread; | ||
134 | } BURN_REDIRECTED_LOGGING_CONTEXT; | ||
135 | |||
126 | typedef struct _BURN_ENGINE_STATE | 136 | typedef struct _BURN_ENGINE_STATE |
127 | { | 137 | { |
128 | // UX flow control | 138 | // UX flow control |
@@ -164,6 +174,7 @@ typedef struct _BURN_ENGINE_STATE | |||
164 | 174 | ||
165 | BURN_PLAN plan; | 175 | BURN_PLAN plan; |
166 | 176 | ||
177 | BURN_REDIRECTED_LOGGING_CONTEXT elevatedLoggingContext; | ||
167 | HANDLE hUnelevatedLoggingThread; | 178 | HANDLE hUnelevatedLoggingThread; |
168 | 179 | ||
169 | LPWSTR sczBundleEngineWorkingPath; | 180 | LPWSTR sczBundleEngineWorkingPath; |
@@ -336,6 +347,12 @@ HRESULT DAPI CoreWaitForProcCompletion( | |||
336 | __in DWORD dwTimeout, | 347 | __in DWORD dwTimeout, |
337 | __out_opt DWORD* pdwReturnCode | 348 | __out_opt DWORD* pdwReturnCode |
338 | ); | 349 | ); |
350 | HRESULT DAPI CoreCloseElevatedLoggingThread( | ||
351 | __in BURN_ENGINE_STATE* pEngineState | ||
352 | ); | ||
353 | HRESULT DAPI CoreWaitForUnelevatedLoggingThread( | ||
354 | __in HANDLE hUnelevatedLoggingThread | ||
355 | ); | ||
339 | 356 | ||
340 | #if defined(__cplusplus) | 357 | #if defined(__cplusplus) |
341 | } | 358 | } |
diff --git a/src/burn/engine/engine.cpp b/src/burn/engine/engine.cpp index 9c8b6c1d..89082a88 100644 --- a/src/burn/engine/engine.cpp +++ b/src/burn/engine/engine.cpp | |||
@@ -3,15 +3,6 @@ | |||
3 | #include "precomp.h" | 3 | #include "precomp.h" |
4 | 4 | ||
5 | 5 | ||
6 | typedef struct _REDIRECTED_LOGGING_CONTEXT | ||
7 | { | ||
8 | CRITICAL_SECTION csBuffer; | ||
9 | LPSTR sczBuffer; | ||
10 | HANDLE hPipe; | ||
11 | HANDLE hLogEvent; | ||
12 | HANDLE hFinishedEvent; | ||
13 | } REDIRECTED_LOGGING_CONTEXT; | ||
14 | |||
15 | // constants | 6 | // constants |
16 | 7 | ||
17 | const DWORD RESTART_RETRIES = 10; | 8 | const DWORD RESTART_RETRIES = 10; |
@@ -65,13 +56,6 @@ static HRESULT LogStringOverPipe( | |||
65 | static DWORD WINAPI ElevatedLoggingThreadProc( | 56 | static DWORD WINAPI ElevatedLoggingThreadProc( |
66 | __in LPVOID lpThreadParameter | 57 | __in LPVOID lpThreadParameter |
67 | ); | 58 | ); |
68 | static HRESULT WaitForElevatedLoggingThread( | ||
69 | __in REDIRECTED_LOGGING_CONTEXT* pContext, | ||
70 | __in HANDLE hLoggingThread | ||
71 | ); | ||
72 | static HRESULT WaitForUnelevatedLoggingThread( | ||
73 | __in HANDLE hUnelevatedLoggingThread | ||
74 | ); | ||
75 | static HRESULT Restart( | 59 | static HRESULT Restart( |
76 | __in BURN_ENGINE_STATE* pEngineState | 60 | __in BURN_ENGINE_STATE* pEngineState |
77 | ); | 61 | ); |
@@ -308,10 +292,6 @@ LExit: | |||
308 | { | 292 | { |
309 | LogId(REPORT_STANDARD, MSG_EXITING_RUN_ONCE, FAILED(hr) ? (int)hr : *pdwExitCode); | 293 | LogId(REPORT_STANDARD, MSG_EXITING_RUN_ONCE, FAILED(hr) ? (int)hr : *pdwExitCode); |
310 | } | 294 | } |
311 | else if (fRunElevated) | ||
312 | { | ||
313 | LogId(REPORT_STANDARD, MSG_EXITING_ELEVATED, FAILED(hr) ? (int)hr : *pdwExitCode); | ||
314 | } | ||
315 | 295 | ||
316 | if (fLogInitialized) | 296 | if (fLogInitialized) |
317 | { | 297 | { |
@@ -320,7 +300,12 @@ LExit: | |||
320 | LogFlush(); | 300 | LogFlush(); |
321 | } | 301 | } |
322 | 302 | ||
323 | if (engineState.fRestart) | 303 | // end per-machine process if running |
304 | if (!fRunElevated && INVALID_HANDLE_VALUE != engineState.companionConnection.hPipe) | ||
305 | { | ||
306 | PipeTerminateChildProcess(&engineState.companionConnection, *pdwExitCode, engineState.fRestart); | ||
307 | } | ||
308 | else if (engineState.fRestart) | ||
324 | { | 309 | { |
325 | LogId(REPORT_STANDARD, MSG_RESTARTING); | 310 | LogId(REPORT_STANDARD, MSG_RESTARTING); |
326 | 311 | ||
@@ -334,6 +319,30 @@ LExit: | |||
334 | // If the message window is still around, close it. | 319 | // If the message window is still around, close it. |
335 | UiCloseMessageWindow(&engineState); | 320 | UiCloseMessageWindow(&engineState); |
336 | 321 | ||
322 | // If the logging thread is still around, close it. | ||
323 | if (!fRunElevated) | ||
324 | { | ||
325 | CoreWaitForUnelevatedLoggingThread(engineState.hUnelevatedLoggingThread); | ||
326 | } | ||
327 | else if (fRunElevated) | ||
328 | { | ||
329 | CoreCloseElevatedLoggingThread(&engineState); | ||
330 | |||
331 | // We're done talking to the child so always reset logging now. | ||
332 | LogRedirect(NULL, NULL); | ||
333 | |||
334 | // If there was a log message left, try to log it locally. | ||
335 | if (engineState.elevatedLoggingContext.sczBuffer) | ||
336 | { | ||
337 | LogStringWorkRaw(engineState.elevatedLoggingContext.sczBuffer); | ||
338 | |||
339 | ReleaseStr(engineState.elevatedLoggingContext.sczBuffer); | ||
340 | } | ||
341 | |||
342 | // Log the exit code here to make sure it gets in the elevated log. | ||
343 | LogId(REPORT_STANDARD, MSG_EXITING_ELEVATED, FAILED(hr) ? (int)hr : *pdwExitCode); | ||
344 | } | ||
345 | |||
337 | UninitializeEngineState(&engineState); | 346 | UninitializeEngineState(&engineState); |
338 | 347 | ||
339 | if (fXmlInitialized) | 348 | if (fXmlInitialized) |
@@ -387,7 +396,12 @@ static HRESULT InitializeEngineState( | |||
387 | HANDLE hSectionFile = hEngineFile; | 396 | HANDLE hSectionFile = hEngineFile; |
388 | HANDLE hSourceEngineFile = INVALID_HANDLE_VALUE; | 397 | HANDLE hSourceEngineFile = INVALID_HANDLE_VALUE; |
389 | 398 | ||
399 | pEngineState->hUnelevatedLoggingThread = INVALID_HANDLE_VALUE; | ||
400 | pEngineState->elevatedLoggingContext.hPipe = INVALID_HANDLE_VALUE; | ||
401 | pEngineState->elevatedLoggingContext.hThread = INVALID_HANDLE_VALUE; | ||
402 | |||
390 | ::InitializeCriticalSection(&pEngineState->csRestartState); | 403 | ::InitializeCriticalSection(&pEngineState->csRestartState); |
404 | ::InitializeCriticalSection(&pEngineState->elevatedLoggingContext.csBuffer); | ||
391 | 405 | ||
392 | pEngineState->internalCommand.automaticUpdates = BURN_AU_PAUSE_ACTION_IFELEVATED; | 406 | pEngineState->internalCommand.automaticUpdates = BURN_AU_PAUSE_ACTION_IFELEVATED; |
393 | ::InitializeCriticalSection(&pEngineState->userExperience.csEngineActive); | 407 | ::InitializeCriticalSection(&pEngineState->userExperience.csEngineActive); |
@@ -423,6 +437,12 @@ static void UninitializeEngineState( | |||
423 | ReleaseMem(pEngineState->internalCommand.rgSecretArgs); | 437 | ReleaseMem(pEngineState->internalCommand.rgSecretArgs); |
424 | ReleaseMem(pEngineState->internalCommand.rgUnknownArgs); | 438 | ReleaseMem(pEngineState->internalCommand.rgUnknownArgs); |
425 | 439 | ||
440 | ReleaseFileHandle(pEngineState->hUnelevatedLoggingThread); | ||
441 | ReleaseFileHandle(pEngineState->elevatedLoggingContext.hThread); | ||
442 | ::DeleteCriticalSection(&pEngineState->elevatedLoggingContext.csBuffer); | ||
443 | ReleaseHandle(pEngineState->elevatedLoggingContext.hLogEvent); | ||
444 | ReleaseHandle(pEngineState->elevatedLoggingContext.hFinishedEvent); | ||
445 | |||
426 | PipeConnectionUninitialize(&pEngineState->embeddedConnection); | 446 | PipeConnectionUninitialize(&pEngineState->embeddedConnection); |
427 | PipeConnectionUninitialize(&pEngineState->companionConnection); | 447 | PipeConnectionUninitialize(&pEngineState->companionConnection); |
428 | ReleaseStr(pEngineState->sczBundleEngineWorkingPath) | 448 | ReleaseStr(pEngineState->sczBundleEngineWorkingPath) |
@@ -643,14 +663,6 @@ LExit: | |||
643 | 663 | ||
644 | VariablesDump(&pEngineState->variables); | 664 | VariablesDump(&pEngineState->variables); |
645 | 665 | ||
646 | // end per-machine process if running | ||
647 | if (INVALID_HANDLE_VALUE != pEngineState->companionConnection.hPipe) | ||
648 | { | ||
649 | PipeTerminateChildProcess(&pEngineState->companionConnection, pEngineState->userExperience.dwExitCode, FALSE); | ||
650 | |||
651 | WaitForUnelevatedLoggingThread(pEngineState->hUnelevatedLoggingThread); | ||
652 | } | ||
653 | |||
654 | // If the splash screen is still around, close it. | 666 | // If the splash screen is still around, close it. |
655 | if (::IsWindow(pEngineState->command.hwndSplashScreen)) | 667 | if (::IsWindow(pEngineState->command.hwndSplashScreen)) |
656 | { | 668 | { |
@@ -671,9 +683,7 @@ static HRESULT RunElevated( | |||
671 | { | 683 | { |
672 | HRESULT hr = S_OK; | 684 | HRESULT hr = S_OK; |
673 | HANDLE hLock = NULL; | 685 | HANDLE hLock = NULL; |
674 | HANDLE hLoggingThread = NULL; | 686 | BURN_REDIRECTED_LOGGING_CONTEXT* pLoggingContext = &pEngineState->elevatedLoggingContext; |
675 | REDIRECTED_LOGGING_CONTEXT loggingContext = { }; | ||
676 | BOOL fDeleteLoggingCs = FALSE; | ||
677 | 687 | ||
678 | // Initialize logging. | 688 | // Initialize logging. |
679 | hr = LoggingOpen(&pEngineState->log, &pEngineState->internalCommand, &pEngineState->command, &pEngineState->variables, pEngineState->registration.sczDisplayName); | 689 | hr = LoggingOpen(&pEngineState->log, &pEngineState->internalCommand, &pEngineState->command, &pEngineState->variables, pEngineState->registration.sczDisplayName); |
@@ -685,21 +695,18 @@ static HRESULT RunElevated( | |||
685 | 695 | ||
686 | // Set up the context for the logging thread then | 696 | // Set up the context for the logging thread then |
687 | // override logging to write over the pipe. | 697 | // override logging to write over the pipe. |
688 | ::InitializeCriticalSection(&loggingContext.csBuffer); | 698 | pLoggingContext->hLogEvent = ::CreateEventW(NULL, TRUE, FALSE, NULL); |
689 | fDeleteLoggingCs = TRUE; | 699 | ExitOnNullWithLastError(pLoggingContext->hLogEvent, hr, "Failed to create log event for logging thread."); |
690 | |||
691 | loggingContext.hLogEvent = ::CreateEventW(NULL, TRUE, FALSE, NULL); | ||
692 | ExitOnNullWithLastError(loggingContext.hLogEvent, hr, "Failed to create log event for logging thread."); | ||
693 | 700 | ||
694 | loggingContext.hFinishedEvent = ::CreateEventW(NULL, TRUE, FALSE, NULL); | 701 | pLoggingContext->hFinishedEvent = ::CreateEventW(NULL, TRUE, FALSE, NULL); |
695 | ExitOnNullWithLastError(loggingContext.hFinishedEvent, hr, "Failed to create finished event for logging thread."); | 702 | ExitOnNullWithLastError(pLoggingContext->hFinishedEvent, hr, "Failed to create finished event for logging thread."); |
696 | 703 | ||
697 | loggingContext.hPipe = pEngineState->companionConnection.hLoggingPipe; | 704 | pLoggingContext->hPipe = pEngineState->companionConnection.hLoggingPipe; |
698 | 705 | ||
699 | hLoggingThread = ::CreateThread(NULL, 0, ElevatedLoggingThreadProc, &loggingContext, 0, NULL); | 706 | pLoggingContext->hThread = ::CreateThread(NULL, 0, ElevatedLoggingThreadProc, pLoggingContext, 0, NULL); |
700 | ExitOnNullWithLastError(hLoggingThread, hr, "Failed to create elevated logging thread."); | 707 | ExitOnNullWithLastError(pLoggingContext->hThread, hr, "Failed to create elevated logging thread."); |
701 | 708 | ||
702 | LogRedirect(RedirectLoggingOverPipe, &loggingContext); | 709 | LogRedirect(RedirectLoggingOverPipe, pLoggingContext); |
703 | 710 | ||
704 | if (!pEngineState->internalCommand.fInitiallyElevated) | 711 | if (!pEngineState->internalCommand.fInitiallyElevated) |
705 | { | 712 | { |
@@ -716,29 +723,7 @@ static HRESULT RunElevated( | |||
716 | hr = ElevationChildPumpMessages(pEngineState->companionConnection.hPipe, pEngineState->companionConnection.hCachePipe, &pEngineState->approvedExes, &pEngineState->cache, &pEngineState->containers, &pEngineState->packages, &pEngineState->payloads, &pEngineState->variables, &pEngineState->registration, &pEngineState->userExperience, &hLock, &pEngineState->userExperience.dwExitCode, &pEngineState->fRestart, &pEngineState->plan.fApplying); | 723 | hr = ElevationChildPumpMessages(pEngineState->companionConnection.hPipe, pEngineState->companionConnection.hCachePipe, &pEngineState->approvedExes, &pEngineState->cache, &pEngineState->containers, &pEngineState->packages, &pEngineState->payloads, &pEngineState->variables, &pEngineState->registration, &pEngineState->userExperience, &hLock, &pEngineState->userExperience.dwExitCode, &pEngineState->fRestart, &pEngineState->plan.fApplying); |
717 | ExitOnFailure(hr, "Failed to pump messages from parent process."); | 724 | ExitOnFailure(hr, "Failed to pump messages from parent process."); |
718 | 725 | ||
719 | WaitForElevatedLoggingThread(&loggingContext, hLoggingThread); | ||
720 | |||
721 | LExit: | 726 | LExit: |
722 | ReleaseHandle(hLoggingThread); | ||
723 | |||
724 | LogRedirect(NULL, NULL); // we're done talking to the child so always reset logging now. | ||
725 | |||
726 | if (fDeleteLoggingCs) | ||
727 | { | ||
728 | ::DeleteCriticalSection(&loggingContext.csBuffer); | ||
729 | } | ||
730 | |||
731 | ReleaseHandle(loggingContext.hLogEvent); | ||
732 | ReleaseHandle(loggingContext.hFinishedEvent); | ||
733 | |||
734 | // If there was a log message left, try to log it locally. | ||
735 | if (loggingContext.sczBuffer) | ||
736 | { | ||
737 | LogStringWorkRaw(loggingContext.sczBuffer); | ||
738 | |||
739 | ReleaseStr(loggingContext.sczBuffer); | ||
740 | } | ||
741 | |||
742 | if (hLock) | 727 | if (hLock) |
743 | { | 728 | { |
744 | ::ReleaseMutex(hLock); | 729 | ::ReleaseMutex(hLock); |
@@ -936,7 +921,7 @@ static HRESULT DAPI RedirectLoggingOverPipe( | |||
936 | ) | 921 | ) |
937 | { | 922 | { |
938 | HRESULT hr = S_OK; | 923 | HRESULT hr = S_OK; |
939 | REDIRECTED_LOGGING_CONTEXT* pContext = static_cast<REDIRECTED_LOGGING_CONTEXT*>(pvContext); | 924 | BURN_REDIRECTED_LOGGING_CONTEXT* pContext = static_cast<BURN_REDIRECTED_LOGGING_CONTEXT*>(pvContext); |
940 | 925 | ||
941 | ::EnterCriticalSection(&pContext->csBuffer); | 926 | ::EnterCriticalSection(&pContext->csBuffer); |
942 | 927 | ||
@@ -986,7 +971,7 @@ static DWORD WINAPI ElevatedLoggingThreadProc( | |||
986 | { | 971 | { |
987 | HRESULT hr = S_OK; | 972 | HRESULT hr = S_OK; |
988 | DWORD dwLastError = ERROR_SUCCESS; | 973 | DWORD dwLastError = ERROR_SUCCESS; |
989 | REDIRECTED_LOGGING_CONTEXT* pContext = static_cast<REDIRECTED_LOGGING_CONTEXT*>(lpThreadParameter); | 974 | BURN_REDIRECTED_LOGGING_CONTEXT* pContext = static_cast<BURN_REDIRECTED_LOGGING_CONTEXT*>(lpThreadParameter); |
990 | DWORD dwSignaledIndex = 0; | 975 | DWORD dwSignaledIndex = 0; |
991 | LPSTR sczBuffer = NULL; | 976 | LPSTR sczBuffer = NULL; |
992 | BURN_PIPE_RESULT result = { }; | 977 | BURN_PIPE_RESULT result = { }; |
@@ -1079,39 +1064,6 @@ LExit: | |||
1079 | return (DWORD)hr; | 1064 | return (DWORD)hr; |
1080 | } | 1065 | } |
1081 | 1066 | ||
1082 | static HRESULT WaitForElevatedLoggingThread( | ||
1083 | __in REDIRECTED_LOGGING_CONTEXT* pContext, | ||
1084 | __in HANDLE hLoggingThread | ||
1085 | ) | ||
1086 | { | ||
1087 | HRESULT hr = S_OK; | ||
1088 | |||
1089 | if (!::SetEvent(pContext->hFinishedEvent)) | ||
1090 | { | ||
1091 | ExitWithLastError(hr, "Failed to set log finished event."); | ||
1092 | } | ||
1093 | |||
1094 | hr = AppWaitForSingleObject(hLoggingThread, 5 * 60 * 1000); // TODO: is 5 minutes good? | ||
1095 | ExitOnFailure(hr, "Failed to wait for elevated logging thread."); | ||
1096 | |||
1097 | LExit: | ||
1098 | return hr; | ||
1099 | } | ||
1100 | |||
1101 | static HRESULT WaitForUnelevatedLoggingThread( | ||
1102 | __in HANDLE hUnelevatedLoggingThread | ||
1103 | ) | ||
1104 | { | ||
1105 | HRESULT hr = S_OK; | ||
1106 | |||
1107 | // Give the thread 15 seconds to exit. | ||
1108 | hr = AppWaitForSingleObject(hUnelevatedLoggingThread, 15 * 1000); | ||
1109 | ExitOnFailure(hr, "Failed to wait for unelevated logging thread."); | ||
1110 | |||
1111 | LExit: | ||
1112 | return hr; | ||
1113 | } | ||
1114 | |||
1115 | static HRESULT Restart( | 1067 | static HRESULT Restart( |
1116 | __in BURN_ENGINE_STATE* pEngineState | 1068 | __in BURN_ENGINE_STATE* pEngineState |
1117 | ) | 1069 | ) |
diff --git a/src/burn/engine/uithread.cpp b/src/burn/engine/uithread.cpp index 673111f8..8ddd51bd 100644 --- a/src/burn/engine/uithread.cpp +++ b/src/burn/engine/uithread.cpp | |||
@@ -222,6 +222,16 @@ static LRESULT CALLBACK WndProc( | |||
222 | ::Sleep(250); | 222 | ::Sleep(250); |
223 | } | 223 | } |
224 | 224 | ||
225 | // If this is the per-machine process then close the logging pipe with the parent process. | ||
226 | if (pInfo->fElevatedEngine) | ||
227 | { | ||
228 | CoreCloseElevatedLoggingThread(pInfo->pEngineState); | ||
229 | } | ||
230 | else | ||
231 | { | ||
232 | CoreWaitForUnelevatedLoggingThread(pInfo->pEngineState->hUnelevatedLoggingThread); | ||
233 | } | ||
234 | |||
225 | LogStringWorkRaw("=======================================\r\n"); | 235 | LogStringWorkRaw("=======================================\r\n"); |
226 | 236 | ||
227 | // Close the log to try to make sure everything is flushed to disk. | 237 | // Close the log to try to make sure everything is flushed to disk. |
diff --git a/src/test/burn/TestData/Manual/BafThmutilTesting/BafThmUtilTesting.cpp b/src/test/burn/TestData/Manual/BafThmutilTesting/BafThmUtilTesting.cpp index ce74534d..c619dbd6 100644 --- a/src/test/burn/TestData/Manual/BafThmutilTesting/BafThmUtilTesting.cpp +++ b/src/test/burn/TestData/Manual/BafThmutilTesting/BafThmUtilTesting.cpp | |||
@@ -89,39 +89,6 @@ public: // IBAFunctions | |||
89 | return hr; | 89 | return hr; |
90 | } | 90 | } |
91 | 91 | ||
92 | virtual STDMETHODIMP WndProc( | ||
93 | __in HWND hWnd, | ||
94 | __in UINT uMsg, | ||
95 | __in WPARAM /*wParam*/, | ||
96 | __in LPARAM lParam, | ||
97 | __inout BOOL* pfProcessed, | ||
98 | __inout LRESULT* plResult | ||
99 | ) | ||
100 | { | ||
101 | switch (uMsg) | ||
102 | { | ||
103 | case WM_QUERYENDSESSION: | ||
104 | if (BOOTSTRAPPER_DISPLAY_FULL <= m_command.display) | ||
105 | { | ||
106 | DWORD dwEndSession = static_cast<DWORD>(lParam); | ||
107 | if (ENDSESSION_CRITICAL & dwEndSession) | ||
108 | { | ||
109 | // Return false to get the WM_ENDSESSION message so that critical shutdowns can be delayed. | ||
110 | *plResult = FALSE; | ||
111 | *pfProcessed = TRUE; | ||
112 | } | ||
113 | } | ||
114 | break; | ||
115 | case WM_ENDSESSION: | ||
116 | if (BOOTSTRAPPER_DISPLAY_FULL <= m_command.display) | ||
117 | { | ||
118 | ::MessageBoxW(hWnd, L"WM_ENDSESSION", L"BAFunctions WndProc", MB_OK); | ||
119 | } | ||
120 | break; | ||
121 | } | ||
122 | return S_OK; | ||
123 | } | ||
124 | |||
125 | public: //IBootstrapperApplication | 92 | public: //IBootstrapperApplication |
126 | virtual STDMETHODIMP OnExecuteBegin( | 93 | virtual STDMETHODIMP OnExecuteBegin( |
127 | __in DWORD /*cExecutingPackages*/, | 94 | __in DWORD /*cExecutingPackages*/, |
diff --git a/src/test/burn/TestData/Manual/BundleA/BundleA.wixproj b/src/test/burn/TestData/Manual/BundleA/BundleA.wixproj index 907b85c9..225664b9 100644 --- a/src/test/burn/TestData/Manual/BundleA/BundleA.wixproj +++ b/src/test/burn/TestData/Manual/BundleA/BundleA.wixproj | |||
@@ -11,8 +11,12 @@ | |||
11 | <ItemGroup> | 11 | <ItemGroup> |
12 | <ProjectReference Include="..\BafThmUtilTesting\BafThmUtilTesting.vcxproj" Properties="Platform=x86" ReferenceOutputAssembly="false" /> | 12 | <ProjectReference Include="..\BafThmUtilTesting\BafThmUtilTesting.vcxproj" Properties="Platform=x86" ReferenceOutputAssembly="false" /> |
13 | <ProjectReference Include="..\PackageA\PackageA.wixproj" /> | 13 | <ProjectReference Include="..\PackageA\PackageA.wixproj" /> |
14 | <ProjectReference Include="..\..\TestBA\TestBAWixlib\testbawixlib.wixproj" /> | ||
14 | </ItemGroup> | 15 | </ItemGroup> |
15 | <ItemGroup> | 16 | <ItemGroup> |
16 | <PackageReference Include="WixToolset.Bal.wixext" /> | 17 | <PackageReference Include="WixToolset.Bal.wixext" /> |
17 | </ItemGroup> | 18 | </ItemGroup> |
19 | <Target Name="CopyManualInstructions" AfterTargets="AfterBuild"> | ||
20 | <Copy SourceFiles="ManualTests.txt" DestinationFiles="$(OutputPath)ManualTests.txt" /> | ||
21 | </Target> | ||
18 | </Project> \ No newline at end of file | 22 | </Project> \ No newline at end of file |
diff --git a/src/test/burn/TestData/Manual/BundleA/BundleA.wxs b/src/test/burn/TestData/Manual/BundleA/BundleA.wxs index 44abc645..20b68a91 100644 --- a/src/test/burn/TestData/Manual/BundleA/BundleA.wxs +++ b/src/test/burn/TestData/Manual/BundleA/BundleA.wxs | |||
@@ -11,7 +11,12 @@ | |||
11 | <MsiPackage Id="PackageA" SourceFile="$(var.PackageA.TargetPath)"> | 11 | <MsiPackage Id="PackageA" SourceFile="$(var.PackageA.TargetPath)"> |
12 | <MsiProperty Name="FORCERESTARTCA" Value="[FORCERESTARTCA]" /> | 12 | <MsiProperty Name="FORCERESTARTCA" Value="[FORCERESTARTCA]" /> |
13 | </MsiPackage> | 13 | </MsiPackage> |
14 | <ExePackage Id="ExeA" Cache="remove" PerMachine="yes" | ||
15 | DetectCondition="" Permanent="yes" InstallArguments="/ec [EXEEXITCODE]"> | ||
16 | <PayloadGroupRef Id="TestExePayloads" /> | ||
17 | </ExePackage> | ||
14 | </PackageGroup> | 18 | </PackageGroup> |
19 | <Variable Name="EXEEXITCODE" bal:Overridable="yes" Value="0" /> | ||
15 | <Variable Name="FORCERESTARTCA" bal:Overridable="yes" /> | 20 | <Variable Name="FORCERESTARTCA" bal:Overridable="yes" /> |
16 | </Fragment> | 21 | </Fragment> |
17 | </Wix> | 22 | </Wix> |
diff --git a/src/test/burn/TestData/Manual/BundleA/ManualTests.txt b/src/test/burn/TestData/Manual/BundleA/ManualTests.txt new file mode 100644 index 00000000..d432f94a --- /dev/null +++ b/src/test/burn/TestData/Manual/BundleA/ManualTests.txt | |||
@@ -0,0 +1,110 @@ | |||
1 | VariousWixstdbaAndBAFunctionsAndThmutilFunctionality | ||
2 | 1. Run BundleA.exe unelevated. | ||
3 | 2. Click Test. | ||
4 | 3. Verify that the BafThmUtilTestingTheme window comes up and click Start. | ||
5 | 4. There are several pages. Follow the instructions on each page before clicking Next. | ||
6 | 5. Click ThemeClose to close the BafThmUtilTestingTheme window. | ||
7 | 6. Click the Options button. | ||
8 | 7. Click the Browse button. | ||
9 | 8. Type in "C:\Program Files (x86)\mytest". | ||
10 | 9. Click the Select Folder button. | ||
11 | 10. Verify the Install location textbox was populated with "C:\Program Files (x86)\mytest". | ||
12 | 11. Click OK. | ||
13 | 12. Verify the caption of the window is "~Manual - BundleA Setup" and the text is "~Manual - BundleA". | ||
14 | 13. Verify the Install button has the UAC shield and then click it (accept elevation). | ||
15 | 14. Click OK on the OnExecuteBegin message box. | ||
16 | 15. After it finishes, verify the window text is "Installation Successfully Completed". | ||
17 | 16. Click Close. | ||
18 | 17. Verify in the bundle log that the variable InstallFolder was set to "C:\Program Files (x86)\mytest". | ||
19 | 18. Run BundleA.exe again. | ||
20 | 19. Click Uninstall (accept elevation). | ||
21 | 20. Click OK on the OnExecuteBegin message box. | ||
22 | 21. After it finishes, verify the window text is "Uninstallation Successfully Completed". | ||
23 | 22. Click Close. | ||
24 | |||
25 | CanBlockShutdownDuringApply | ||
26 | 1. Run BundleA.exe unelevated. | ||
27 | 2. Click Install (accept elevation). | ||
28 | 3. Verify the OnExecuteBegin message box comes up with the message "Shutdown requests should be denied right now." and leave it up. | ||
29 | 4. Use the Windows UI to try to restart the machine. | ||
30 | 5. On current versions of Windows, full screen UI will display that the bundle is blocking restart. Click Cancel to stop the restart. | ||
31 | 6. Click OK on the message box from step 3 to allow installation to continue. | ||
32 | 7. Verify that the installation was successful and then close the bundle. | ||
33 | 8. Look in the bundle log and verify that the restart request didn't cause any errors, and that it logged messages that look like: | ||
34 | |||
35 | i400: Received system request to shut down the process: allowed: No, elevated: No, critical: No, logoff: No, close app: No | ||
36 | i400: Received system request to shut down the process: allowed: No, elevated: Yes, critical: No, logoff: No, close app: No | ||
37 | i401: Received result of system request to shut down the process: closing: No, elevated: No, critical: No, logoff: No, close app: No | ||
38 | i401: Received result of system request to shut down the process: closing: No, elevated: Yes, critical: No, logoff: No, close app: No | ||
39 | |||
40 | (9. Uninstall the bundle) | ||
41 | |||
42 | CanLogRestartFailure | ||
43 | |||
44 | Note: this test requires special setup. Change the User Rights Assignment such that no one has the shutdown privilege. Logout and log back in after making changes to make them take effect. | ||
45 | (mmc.exe -> Group Policy Object Editor -> Local Computer Policy -> Computer Configuration -> Windows Settings -> Security Settings -> Local Policies -> User Rights Assignment -> Shut down the system) | ||
46 | |||
47 | 1. Run BundleA.exe elevated with the command line EXEEXITCODE=3010. | ||
48 | 2. Click Install. | ||
49 | 3. Click OK on the OnExecuteBegin message box. | ||
50 | 4. Click Restart. | ||
51 | 5. Look in the bundle log and verify that the restart request failure was logged with messages that look like: | ||
52 | |||
53 | w005: Restarting computer... | ||
54 | e000: Error 0x80070005: Failed to schedule restart. | ||
55 | e023: The restart request failed, error: 0x80070005. The machine will need to be manually restarted. | ||
56 | |||
57 | (5. Uninstall the bundle) | ||
58 | |||
59 | CanGracefullyCutApplyShortInResponseToCriticalShutdown | ||
60 | |||
61 | Note: Requires different User Rights Assignment settings from CanLogRestartFailure - Administrators need to have the shutdown privilege. | ||
62 | |||
63 | 1. Run BundleA.exe FORCERESTARTCA=1. | ||
64 | 2. Click Install (accept elevation). | ||
65 | 3. Click OK on the OnExecuteBegin message box. | ||
66 | 4. Verify the machine automatically restarts with no chance to cancel it (because the MSI forces a restart). | ||
67 | 5. Login to the machine. | ||
68 | 6. Verify that the bundle automatically started running again. | ||
69 | 7. Click OK on the OnExecuteBegin message box. | ||
70 | 8. Verify that the installation was successful and then close the bundle. | ||
71 | 9. Look in the bundle log and verify that the restart request didn't cause any errors, and that it logged messages that look like: | ||
72 | |||
73 | i301: Applying execute package: PackageA, action: Install, path: C:\ProgramData\Package Cache\{1C6F49C0-B4BA-438D-871D-2B5E91C0EED5}v1.0.0.0\PackageA.msi, arguments: ' FORCERESTARTCA="1" ARPSYSTEMCOMPONENT="1" MSIFASTINSTALL="7" BURNMSIINSTALL=1 REINSTALLMODE="muso" REBOOT=ReallySuppress' | ||
74 | ... | ||
75 | i400: Received system request to shut down the process: allowed: No, elevated: No, critical: Yes, logoff: No, close app: No | ||
76 | i400: Received system request to shut down the process: allowed: No, elevated: Yes, critical: Yes, logoff: No, close app: No | ||
77 | i401: Received result of system request to shut down the process: closing: Yes, elevated: No, critical: Yes, logoff: No, close app: No | ||
78 | i401: Received result of system request to shut down the process: closing: Yes, elevated: Yes, critical: Yes, logoff: No, close app: No | ||
79 | ... | ||
80 | i319: Applied execute package: PackageA, result: 0x0, restart: Initiated | ||
81 | ... | ||
82 | i420: Resuming automatic updates. | ||
83 | i421: Resumed automatic updates. | ||
84 | ======================================= | ||
85 | i001: Burn x86 v4.0.0.525, Windows v10.0 x64 (Build 19041: Service Pack 0), path: C:\ProgramData\Package Cache\{30D63455-CD23-4AC3-81CC-4695434F848A}\BundleA.exe | ||
86 | |||
87 | (10. Uninstall the bundle) | ||
88 | |||
89 | CanRestartFromUnelevatedPerMachineBundleWithoutShutdownPrivilege | ||
90 | |||
91 | Note: Requires different User Rights Assignment settings from CanLogRestartFailure - Only Administrators should have the shutdown privilege. Users should not have it. | ||
92 | |||
93 | 1. Run BundleA.exe unelevated with the command line EXEEXITCODE=3010. | ||
94 | 2. Click Install. | ||
95 | 3. Verify that the UAC prompt came up and accept elevation. | ||
96 | 4. Click OK on the OnExecuteBegin message box. | ||
97 | 5. Click Restart. | ||
98 | 6. The machine should restart. | ||
99 | 7. Login to the machine. | ||
100 | 8. Verify that the bundle did not automatically start running. | ||
101 | 9. Look in the bundle log and verify that the restart request didn't cause any errors, and that it logged messages that look like (the process id for w005 must match the elevated i400 and i401): | ||
102 | |||
103 | [0DDC:0448]w005: Restarting computer... | ||
104 | [1228:18CC]i400: Received system request to shut down the process: allowed: Yes, elevated: No, critical: No, logoff: No, close app: No | ||
105 | [1228:18CC]i401: Received result of system request to shut down the process: closing: Yes, elevated: No, critical: No, logoff: No, close app: No | ||
106 | [0DDC:0954]i400: Received system request to shut down the process: allowed: Yes, elevated: Yes, critical: No, logoff: No, close app: No | ||
107 | [0DDC:0954]i401: Received result of system request to shut down the process: closing: Yes, elevated: Yes, critical: No, logoff: No, close app: No | ||
108 | ======================================= | ||
109 | |||
110 | (10. Uninstall the bundle) | ||