aboutsummaryrefslogtreecommitdiff
path: root/src/burn
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2022-09-02 16:11:35 -0500
committerSean Hall <r.sean.hall@gmail.com>2022-09-03 15:29:26 -0500
commiteea6121f388197435529922b3cb13d3631afb9a8 (patch)
tree5740f0ff69f7e4aa9a7e8a92ff1f6fde0c1ae8d7 /src/burn
parente263e6bca03d783ece2f2dc86345dcdfc4b9776d (diff)
downloadwix-eea6121f388197435529922b3cb13d3631afb9a8.tar.gz
wix-eea6121f388197435529922b3cb13d3631afb9a8.tar.bz2
wix-eea6121f388197435529922b3cb13d3631afb9a8.zip
Delay closing Burn's UI thread so that it can log the bundle's restart.
Diffstat (limited to 'src/burn')
-rw-r--r--src/burn/engine/core.cpp15
-rw-r--r--src/burn/engine/core.h18
-rw-r--r--src/burn/engine/engine.cpp85
-rw-r--r--src/burn/engine/engine.mc19
-rw-r--r--src/burn/engine/uithread.cpp62
5 files changed, 159 insertions, 40 deletions
diff --git a/src/burn/engine/core.cpp b/src/burn/engine/core.cpp
index 25124c8a..3c1ed117 100644
--- a/src/burn/engine/core.cpp
+++ b/src/burn/engine/core.cpp
@@ -1963,6 +1963,21 @@ LExit:
1963 return hr; 1963 return hr;
1964} 1964}
1965 1965
1966extern "C" void CoreUpdateRestartState(
1967 __in BURN_ENGINE_STATE* pEngineState,
1968 __in BURN_RESTART_STATE restartState
1969 )
1970{
1971 ::EnterCriticalSection(&pEngineState->csRestartState);
1972
1973 if (pEngineState->fRestarting && restartState > pEngineState->restartState)
1974 {
1975 pEngineState->restartState = restartState;
1976 }
1977
1978 ::LeaveCriticalSection(&pEngineState->csRestartState);
1979}
1980
1966extern "C" void CoreFunctionOverride( 1981extern "C" void CoreFunctionOverride(
1967 __in_opt PFN_CREATEPROCESSW pfnCreateProcessW, 1982 __in_opt PFN_CREATEPROCESSW pfnCreateProcessW,
1968 __in_opt PFN_PROCWAITFORCOMPLETION pfnProcWaitForCompletion 1983 __in_opt PFN_PROCWAITFORCOMPLETION pfnProcWaitForCompletion
diff --git a/src/burn/engine/core.h b/src/burn/engine/core.h
index 7e594b52..28b5ba5d 100644
--- a/src/burn/engine/core.h
+++ b/src/burn/engine/core.h
@@ -82,6 +82,16 @@ enum BURN_AU_PAUSE_ACTION
82 BURN_AU_PAUSE_ACTION_IFELEVATED_NORESUME, 82 BURN_AU_PAUSE_ACTION_IFELEVATED_NORESUME,
83}; 83};
84 84
85enum BURN_RESTART_STATE
86{
87 BURN_RESTART_STATE_NONE,
88 BURN_RESTART_STATE_REQUESTING,
89 BURN_RESTART_STATE_REQUESTED,
90 BURN_RESTART_STATE_INITIATING,
91 BURN_RESTART_STATE_INITIATED,
92 BURN_RESTART_STATE_BLOCKED,
93};
94
85 95
86// structs 96// structs
87 97
@@ -160,6 +170,10 @@ typedef struct _BURN_ENGINE_STATE
160 BURN_PIPE_CONNECTION companionConnection; 170 BURN_PIPE_CONNECTION companionConnection;
161 BURN_PIPE_CONNECTION embeddedConnection; 171 BURN_PIPE_CONNECTION embeddedConnection;
162 172
173 CRITICAL_SECTION csRestartState;
174 BOOL fRestarting;
175 BURN_RESTART_STATE restartState;
176
163 BOOL fCriticalShutdownInitiated; 177 BOOL fCriticalShutdownInitiated;
164 BURN_RESUME_MODE resumeMode; 178 BURN_RESUME_MODE resumeMode;
165 LPCWSTR wzRestartInitiatedPackageId; 179 LPCWSTR wzRestartInitiatedPackageId;
@@ -300,6 +314,10 @@ HRESULT CoreParseCommandLine(
300 __inout HANDLE* phSectionFile, 314 __inout HANDLE* phSectionFile,
301 __inout HANDLE* phSourceEngineFile 315 __inout HANDLE* phSourceEngineFile
302 ); 316 );
317void CoreUpdateRestartState(
318 __in BURN_ENGINE_STATE* pEngineState,
319 __in BURN_RESTART_STATE restartState
320 );
303void CoreFunctionOverride( 321void CoreFunctionOverride(
304 __in_opt PFN_CREATEPROCESSW pfnCreateProcessW, 322 __in_opt PFN_CREATEPROCESSW pfnCreateProcessW,
305 __in_opt PFN_PROCWAITFORCOMPLETION pfnProcWaitForCompletion 323 __in_opt PFN_PROCWAITFORCOMPLETION pfnProcWaitForCompletion
diff --git a/src/burn/engine/engine.cpp b/src/burn/engine/engine.cpp
index 13d23ecd..9c8b6c1d 100644
--- a/src/burn/engine/engine.cpp
+++ b/src/burn/engine/engine.cpp
@@ -72,7 +72,9 @@ static HRESULT WaitForElevatedLoggingThread(
72static HRESULT WaitForUnelevatedLoggingThread( 72static HRESULT WaitForUnelevatedLoggingThread(
73 __in HANDLE hUnelevatedLoggingThread 73 __in HANDLE hUnelevatedLoggingThread
74 ); 74 );
75static HRESULT Restart(); 75static HRESULT Restart(
76 __in BURN_ENGINE_STATE* pEngineState
77 );
76static void CALLBACK BurnTraceError( 78static void CALLBACK BurnTraceError(
77 __in_z LPCSTR szFile, 79 __in_z LPCSTR szFile,
78 __in int iLine, 80 __in int iLine,
@@ -131,7 +133,6 @@ extern "C" HRESULT EngineRun(
131 BOOL fRunNormal = FALSE; 133 BOOL fRunNormal = FALSE;
132 BOOL fRunElevated = FALSE; 134 BOOL fRunElevated = FALSE;
133 BOOL fRunRunOnce = FALSE; 135 BOOL fRunRunOnce = FALSE;
134 BOOL fRestart = FALSE;
135 136
136 BURN_ENGINE_STATE engineState = { }; 137 BURN_ENGINE_STATE engineState = { };
137 engineState.command.cbSize = sizeof(BOOTSTRAPPER_COMMAND); 138 engineState.command.cbSize = sizeof(BOOTSTRAPPER_COMMAND);
@@ -269,9 +270,7 @@ extern "C" HRESULT EngineRun(
269 ExitOnFailure(hr, "Invalid run mode."); 270 ExitOnFailure(hr, "Invalid run mode.");
270 } 271 }
271 272
272 // set exit code and remember if we are supposed to restart.
273 *pdwExitCode = engineState.userExperience.dwExitCode; 273 *pdwExitCode = engineState.userExperience.dwExitCode;
274 fRestart = engineState.fRestart;
275 274
276LExit: 275LExit:
277 ReleaseStr(sczExePath); 276 ReleaseStr(sczExePath);
@@ -289,17 +288,17 @@ LExit:
289 CacheUninitialize(&engineState.cache); 288 CacheUninitialize(&engineState.cache);
290 289
291 // If this is a related bundle (but not an update) suppress restart and return the standard restart error code. 290 // If this is a related bundle (but not an update) suppress restart and return the standard restart error code.
292 if (fRestart && BOOTSTRAPPER_RELATION_NONE != engineState.command.relationType && BOOTSTRAPPER_RELATION_UPDATE != engineState.command.relationType) 291 if (engineState.fRestart && BOOTSTRAPPER_RELATION_NONE != engineState.command.relationType && BOOTSTRAPPER_RELATION_UPDATE != engineState.command.relationType)
293 { 292 {
294 LogId(REPORT_STANDARD, MSG_RESTART_ABORTED, LoggingRelationTypeToString(engineState.command.relationType)); 293 LogId(REPORT_STANDARD, MSG_RESTART_ABORTED, LoggingRelationTypeToString(engineState.command.relationType));
295 294
296 fRestart = FALSE; 295 engineState.fRestart = FALSE;
297 hr = SUCCEEDED(hr) ? HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED) : HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_REQUIRED); 296 hr = SUCCEEDED(hr) ? HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED) : HRESULT_FROM_WIN32(ERROR_FAIL_REBOOT_REQUIRED);
298 } 297 }
299 298
300 if (fRunNormal) 299 if (fRunNormal)
301 { 300 {
302 LogId(REPORT_STANDARD, MSG_EXITING, FAILED(hr) ? (int)hr : *pdwExitCode, LoggingBoolToString(fRestart)); 301 LogId(REPORT_STANDARD, MSG_EXITING, FAILED(hr) ? (int)hr : *pdwExitCode, LoggingBoolToString(engineState.fRestart));
303 } 302 }
304 else if (fRunUntrusted) 303 else if (fRunUntrusted)
305 { 304 {
@@ -321,17 +320,20 @@ LExit:
321 LogFlush(); 320 LogFlush();
322 } 321 }
323 322
324 if (fRestart) 323 if (engineState.fRestart)
325 { 324 {
326 LogId(REPORT_STANDARD, MSG_RESTARTING); 325 LogId(REPORT_STANDARD, MSG_RESTARTING);
327 326
328 HRESULT hrRestart = Restart(); 327 HRESULT hrRestart = Restart(&engineState);
329 if (FAILED(hrRestart)) 328 if (FAILED(hrRestart))
330 { 329 {
331 LogErrorId(hrRestart, MSG_RESTART_FAILED); 330 LogErrorId(hrRestart, MSG_RESTART_FAILED);
332 } 331 }
333 } 332 }
334 333
334 // If the message window is still around, close it.
335 UiCloseMessageWindow(&engineState);
336
335 UninitializeEngineState(&engineState); 337 UninitializeEngineState(&engineState);
336 338
337 if (fXmlInitialized) 339 if (fXmlInitialized)
@@ -385,6 +387,8 @@ static HRESULT InitializeEngineState(
385 HANDLE hSectionFile = hEngineFile; 387 HANDLE hSectionFile = hEngineFile;
386 HANDLE hSourceEngineFile = INVALID_HANDLE_VALUE; 388 HANDLE hSourceEngineFile = INVALID_HANDLE_VALUE;
387 389
390 ::InitializeCriticalSection(&pEngineState->csRestartState);
391
388 pEngineState->internalCommand.automaticUpdates = BURN_AU_PAUSE_ACTION_IFELEVATED; 392 pEngineState->internalCommand.automaticUpdates = BURN_AU_PAUSE_ACTION_IFELEVATED;
389 ::InitializeCriticalSection(&pEngineState->userExperience.csEngineActive); 393 ::InitializeCriticalSection(&pEngineState->userExperience.csEngineActive);
390 PipeConnectionInitialize(&pEngineState->companionConnection); 394 PipeConnectionInitialize(&pEngineState->companionConnection);
@@ -459,6 +463,8 @@ static void UninitializeEngineState(
459 ReleaseStr(pEngineState->log.sczPath); 463 ReleaseStr(pEngineState->log.sczPath);
460 ReleaseStr(pEngineState->log.sczPathVariable); 464 ReleaseStr(pEngineState->log.sczPathVariable);
461 465
466 ::DeleteCriticalSection(&pEngineState->csRestartState);
467
462 // clear struct 468 // clear struct
463 memset(pEngineState, 0, sizeof(BURN_ENGINE_STATE)); 469 memset(pEngineState, 0, sizeof(BURN_ENGINE_STATE));
464} 470}
@@ -635,9 +641,6 @@ LExit:
635 641
636 BurnExtensionUnload(&pEngineState->extensions); 642 BurnExtensionUnload(&pEngineState->extensions);
637 643
638 // If the message window is still around, close it.
639 UiCloseMessageWindow(pEngineState);
640
641 VariablesDump(&pEngineState->variables); 644 VariablesDump(&pEngineState->variables);
642 645
643 // end per-machine process if running 646 // end per-machine process if running
@@ -720,9 +723,6 @@ LExit:
720 723
721 LogRedirect(NULL, NULL); // we're done talking to the child so always reset logging now. 724 LogRedirect(NULL, NULL); // we're done talking to the child so always reset logging now.
722 725
723 // If the message window is still around, close it.
724 UiCloseMessageWindow(pEngineState);
725
726 if (fDeleteLoggingCs) 726 if (fDeleteLoggingCs)
727 { 727 {
728 ::DeleteCriticalSection(&loggingContext.csBuffer); 728 ::DeleteCriticalSection(&loggingContext.csBuffer);
@@ -1112,7 +1112,9 @@ LExit:
1112 return hr; 1112 return hr;
1113} 1113}
1114 1114
1115static HRESULT Restart() 1115static HRESULT Restart(
1116 __in BURN_ENGINE_STATE* pEngineState
1117 )
1116{ 1118{
1117 HRESULT hr = S_OK; 1119 HRESULT hr = S_OK;
1118 HANDLE hProcessToken = NULL; 1120 HANDLE hProcessToken = NULL;
@@ -1136,17 +1138,19 @@ static HRESULT Restart()
1136 ExitWithLastError(hr, "Failed to adjust token to add shutdown privileges."); 1138 ExitWithLastError(hr, "Failed to adjust token to add shutdown privileges.");
1137 } 1139 }
1138 1140
1141 pEngineState->fRestarting = TRUE;
1142 CoreUpdateRestartState(pEngineState, BURN_RESTART_STATE_REQUESTING);
1143
1139 do 1144 do
1140 { 1145 {
1141 hr = S_OK; 1146 hr = S_OK;
1142 1147
1143 // Wait a second to let the companion process (assuming we did an elevated install) to get to the 1148 if (dwRetries)
1144 // point where it too is thinking about restarting the computer. Only one will schedule the restart 1149 {
1145 // but both will have their log files closed and otherwise be ready to exit. 1150 // On retry, wait a second to let the OS try to get to a place where the restart can
1146 // 1151 // be initiated.
1147 // On retry, we'll also wait a second to let the OS try to get to a place where the restart can 1152 ::Sleep(1000);
1148 // be initiated. 1153 }
1149 ::Sleep(1000);
1150 1154
1151 if (!vpfnInitiateSystemShutdownExW(NULL, NULL, 0, FALSE, TRUE, SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_MINOR_INSTALLATION | SHTDN_REASON_FLAG_PLANNED)) 1155 if (!vpfnInitiateSystemShutdownExW(NULL, NULL, 0, FALSE, TRUE, SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_MINOR_INSTALLATION | SHTDN_REASON_FLAG_PLANNED))
1152 { 1156 {
@@ -1155,6 +1159,41 @@ static HRESULT Restart()
1155 } while (dwRetries++ < RESTART_RETRIES && (HRESULT_FROM_WIN32(ERROR_MACHINE_LOCKED) == hr || HRESULT_FROM_WIN32(ERROR_NOT_READY) == hr)); 1159 } while (dwRetries++ < RESTART_RETRIES && (HRESULT_FROM_WIN32(ERROR_MACHINE_LOCKED) == hr || HRESULT_FROM_WIN32(ERROR_NOT_READY) == hr));
1156 ExitOnRootFailure(hr, "Failed to schedule restart."); 1160 ExitOnRootFailure(hr, "Failed to schedule restart.");
1157 1161
1162 CoreUpdateRestartState(pEngineState, BURN_RESTART_STATE_REQUESTED);
1163
1164 // Give the UI thread approximately 15 seconds to get the WM_QUERYENDSESSION message.
1165 for (DWORD i = 0; i < 60; ++i)
1166 {
1167 if (!::IsWindow(pEngineState->hMessageWindow))
1168 {
1169 ExitFunction();
1170 }
1171
1172 if (BURN_RESTART_STATE_REQUESTED < pEngineState->restartState)
1173 {
1174 break;
1175 }
1176
1177 ::Sleep(250);
1178 }
1179
1180 if (BURN_RESTART_STATE_INITIATING > pEngineState->restartState)
1181 {
1182 LogId(REPORT_WARNING, MSG_RESTART_BLOCKED);
1183 ExitFunction();
1184 }
1185
1186 // Give the UI thread the chance to process the WM_ENDSESSION message.
1187 for (;;)
1188 {
1189 if (!::IsWindow(pEngineState->hMessageWindow) || BURN_RESTART_STATE_INITIATING < pEngineState->restartState)
1190 {
1191 break;
1192 }
1193
1194 ::Sleep(250);
1195 }
1196
1158LExit: 1197LExit:
1159 ReleaseHandle(hProcessToken); 1198 ReleaseHandle(hProcessToken);
1160 return hr; 1199 return hr;
diff --git a/src/burn/engine/engine.mc b/src/burn/engine/engine.mc
index dab1a504..d965d4ad 100644
--- a/src/burn/engine/engine.mc
+++ b/src/burn/engine/engine.mc
@@ -62,7 +62,6 @@ Severity=Warning
62SymbolicName=MSG_RESTARTING 62SymbolicName=MSG_RESTARTING
63Language=English 63Language=English
64Restarting computer... 64Restarting computer...
65=======================================
66. 65.
67 66
68MessageId=6 67MessageId=6
@@ -191,6 +190,13 @@ Language=English
191The restart request failed, error: %1!ls!. The machine will need to be manually restarted. 190The restart request failed, error: %1!ls!. The machine will need to be manually restarted.
192. 191.
193 192
193MessageId=24
194Severity=Error
195SymbolicName=MSG_RESTART_BLOCKED
196Language=English
197The restart request was successful, but no system restart messages have been received. This may be caused by another application blocking the restart or taking too long to respond. The machine might need to be manually restarted.
198.
199
194MessageId=51 200MessageId=51
195Severity=Error 201Severity=Error
196SymbolicName=MSG_FAILED_PARSE_CONDITION 202SymbolicName=MSG_FAILED_PARSE_CONDITION
@@ -1138,9 +1144,16 @@ Apply complete, result: 0x%1!x!, restart: %2!hs!, ba requested restart: %3!hs!
1138 1144
1139MessageId=400 1145MessageId=400
1140Severity=Success 1146Severity=Success
1141SymbolicName=MSG_SYSTEM_SHUTDOWN 1147SymbolicName=MSG_SYSTEM_SHUTDOWN_REQUEST
1148Language=English
1149Received system request to shut down the process: allowed: %1!hs!, elevated: %2!hs!, critical: %3!hs!, logoff: %4!hs!, close app: %5!hs!
1150.
1151
1152MessageId=401
1153Severity=Success
1154SymbolicName=MSG_SYSTEM_SHUTDOWN_RESULT
1142Language=English 1155Language=English
1143Received system request to shut down the process: critical: %1!hs!, elevated: %2!hs!, allowed: %3!hs! 1156Received result of system request to shut down the process: closing: %1!hs!, elevated: %2!hs!, critical: %3!hs!, logoff: %4!hs!, close app: %5!hs!
1144. 1157.
1145 1158
1146MessageId=410 1159MessageId=410
diff --git a/src/burn/engine/uithread.cpp b/src/burn/engine/uithread.cpp
index 26a9b723..673111f8 100644
--- a/src/burn/engine/uithread.cpp
+++ b/src/burn/engine/uithread.cpp
@@ -46,6 +46,11 @@ HRESULT UiCreateMessageWindow(
46 HANDLE rgWaitHandles[2] = { }; 46 HANDLE rgWaitHandles[2] = { };
47 UITHREAD_CONTEXT context = { }; 47 UITHREAD_CONTEXT context = { };
48 48
49 // Try to make this process the first one to receive WM_QUERYENDSESSION.
50 // When blocking shutdown during Apply, this prevents other applications from being closed even though the restart will be blocked.
51 // When initiating a restart, this makes it reasonable to assume WM_QUERYENDSESSION will be received quickly because otherwise other applications could delay indefinitely.
52 ::SetProcessShutdownParameters(0x3FF, 0);
53
49 // Create event to signal after the UI thread / window is initialized. 54 // Create event to signal after the UI thread / window is initialized.
50 rgWaitHandles[0] = ::CreateEventW(NULL, TRUE, FALSE, NULL); 55 rgWaitHandles[0] = ::CreateEventW(NULL, TRUE, FALSE, NULL);
51 ExitOnNullWithLastError(rgWaitHandles[0], hr, "Failed to create initialization event."); 56 ExitOnNullWithLastError(rgWaitHandles[0], hr, "Failed to create initialization event.");
@@ -79,10 +84,6 @@ void UiCloseMessageWindow(
79 if (::IsWindow(pEngineState->hMessageWindow)) 84 if (::IsWindow(pEngineState->hMessageWindow))
80 { 85 {
81 ::PostMessageW(pEngineState->hMessageWindow, WM_CLOSE, 0, 0); 86 ::PostMessageW(pEngineState->hMessageWindow, WM_CLOSE, 0, 0);
82
83 // Give the window 15 seconds to close because if it stays open it can prevent
84 // the engine from starting a reboot (should a reboot actually be necessary).
85 ::WaitForSingleObject(pEngineState->hMessageWindowThread, 15 * 1000);
86 } 87 }
87} 88}
88 89
@@ -180,23 +181,56 @@ static LRESULT CALLBACK WndProc(
180 181
181 case WM_QUERYENDSESSION: 182 case WM_QUERYENDSESSION:
182 { 183 {
183 DWORD dwEndSession = static_cast<DWORD>(lParam); 184 BOOL fCritical = ENDSESSION_CRITICAL & lParam;
184 BOOL fCritical = ENDSESSION_CRITICAL & dwEndSession; 185 BOOL fAllowed = FALSE;
185 BOOL fCancel = FALSE;
186 BOOL fRet = FALSE;
187 186
188 // Always block shutdown during apply.
189 UITHREAD_INFO* pInfo = reinterpret_cast<UITHREAD_INFO*>(::GetWindowLongPtrW(hWnd, GWLP_USERDATA)); 187 UITHREAD_INFO* pInfo = reinterpret_cast<UITHREAD_INFO*>(::GetWindowLongPtrW(hWnd, GWLP_USERDATA));
190 if (pInfo->pEngineState->plan.fApplying) 188 if (!pInfo->pEngineState->plan.fApplying && // always block shutdown during apply.
189 !fCritical) // always block critical shutdowns to receive the WM_ENDSESSION message.
191 { 190 {
192 fCancel = TRUE; 191 fAllowed = TRUE;
193 } 192 }
194 193
194 CoreUpdateRestartState(pInfo->pEngineState, BURN_RESTART_STATE_INITIATING);
195 pInfo->pEngineState->fCriticalShutdownInitiated |= fCritical; 195 pInfo->pEngineState->fCriticalShutdownInitiated |= fCritical;
196 196
197 fRet = !fCancel; 197 LogId(REPORT_STANDARD, MSG_SYSTEM_SHUTDOWN_REQUEST, LoggingBoolToString(fAllowed), LoggingBoolToString(pInfo->fElevatedEngine), LoggingBoolToString(fCritical), LoggingBoolToString(lParam & ENDSESSION_LOGOFF), LoggingBoolToString(lParam & ENDSESSION_CLOSEAPP));
198 LogId(REPORT_STANDARD, MSG_SYSTEM_SHUTDOWN, LoggingBoolToString(fCritical), LoggingBoolToString(pInfo->fElevatedEngine), LoggingBoolToString(fRet)); 198 LogFlush();
199 return fRet; 199 return fAllowed;
200 }
201
202 case WM_ENDSESSION:
203 {
204 UITHREAD_INFO* pInfo = reinterpret_cast<UITHREAD_INFO*>(::GetWindowLongPtrW(hWnd, GWLP_USERDATA));
205 BOOL fAllowed = 0 != wParam;
206
207 LogId(REPORT_STANDARD, MSG_SYSTEM_SHUTDOWN_RESULT, LoggingBoolToString(fAllowed), LoggingBoolToString(pInfo->fElevatedEngine), LoggingBoolToString(lParam & ENDSESSION_CRITICAL), LoggingBoolToString(lParam & ENDSESSION_LOGOFF), LoggingBoolToString(lParam & ENDSESSION_CLOSEAPP));
208
209 if (fAllowed)
210 {
211 // Windows will shutdown the process as soon as we return from this message.
212 // https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ms700677(v=vs.85)
213
214 // Give Apply approximately 20 seconds to complete.
215 for (DWORD i = 0; i < 80; ++i)
216 {
217 if (!pInfo->pEngineState->plan.fApplying)
218 {
219 break;
220 }
221
222 ::Sleep(250);
223 }
224
225 LogStringWorkRaw("=======================================\r\n");
226
227 // Close the log to try to make sure everything is flushed to disk.
228 LogClose(FALSE);
229 }
230
231 CoreUpdateRestartState(pInfo->pEngineState, fAllowed ? BURN_RESTART_STATE_INITIATED : BURN_RESTART_STATE_BLOCKED);
232
233 return 0;
200 } 234 }
201 235
202 case WM_DESTROY: 236 case WM_DESTROY: