aboutsummaryrefslogtreecommitdiff
path: root/src/ext/Bal/wixiuiba/WixInternalUIBootstrapperApplication.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ext/Bal/wixiuiba/WixInternalUIBootstrapperApplication.cpp')
-rw-r--r--src/ext/Bal/wixiuiba/WixInternalUIBootstrapperApplication.cpp918
1 files changed, 918 insertions, 0 deletions
diff --git a/src/ext/Bal/wixiuiba/WixInternalUIBootstrapperApplication.cpp b/src/ext/Bal/wixiuiba/WixInternalUIBootstrapperApplication.cpp
new file mode 100644
index 00000000..dbb97366
--- /dev/null
+++ b/src/ext/Bal/wixiuiba/WixInternalUIBootstrapperApplication.cpp
@@ -0,0 +1,918 @@
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#include "BalBaseBootstrapperApplicationProc.h"
5#include "BalBaseBootstrapperApplication.h"
6
7static const LPCWSTR WIXIUIBA_WINDOW_CLASS = L"WixInternalUIBA";
8
9enum WM_WIXIUIBA
10{
11 WM_WIXIUIBA_DETECT_PACKAGES = WM_APP + 100,
12 WM_WIXIUIBA_PLAN_PACKAGES,
13 WM_WIXIUIBA_APPLY_PACKAGES,
14 WM_WIXIUIBA_DETECT_FOR_CLEANUP,
15 WM_WIXIUIBA_PLAN_PACKAGES_FOR_CLEANUP,
16};
17
18
19class CWixInternalUIBootstrapperApplication : public CBalBaseBootstrapperApplication
20{
21public: // IBootstrapperApplication
22 virtual STDMETHODIMP OnStartup()
23 {
24 HRESULT hr = S_OK;
25 DWORD dwUIThreadId = 0;
26
27 // create UI thread
28 m_hUiThread = ::CreateThread(NULL, 0, UiThreadProc, this, 0, &dwUIThreadId);
29 if (!m_hUiThread)
30 {
31 BalExitWithLastError(hr, "Failed to create UI thread.");
32 }
33
34 LExit:
35 return hr;
36 }
37
38
39 virtual STDMETHODIMP OnShutdown(
40 __inout BOOTSTRAPPER_SHUTDOWN_ACTION* pAction
41 )
42 {
43 // wait for UI thread to terminate
44 if (m_hUiThread)
45 {
46 ::WaitForSingleObject(m_hUiThread, INFINITE);
47 ReleaseHandle(m_hUiThread);
48 }
49
50 if (m_fFailedToLoadPackage)
51 {
52 Assert(FAILED(m_hrFinal));
53 m_pPrereqData->hrFatalError = m_hrFinal;
54 BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "Failed to load primary package as the BA. The bootstrapper application will be reloaded to show the error.");
55 *pAction = BOOTSTRAPPER_SHUTDOWN_ACTION_RELOAD_BOOTSTRAPPER;
56 }
57
58 return S_OK;
59 }
60
61
62 virtual STDMETHODIMP OnDetectPackageComplete(
63 __in_z LPCWSTR wzPackageId,
64 __in HRESULT hrStatus,
65 __in BOOTSTRAPPER_PACKAGE_STATE state,
66 __in BOOL fCached
67 )
68 {
69 BAL_INFO_PACKAGE* pPackage = NULL;
70
71 if (SUCCEEDED(hrStatus) && SUCCEEDED(BalInfoFindPackageById(&m_Bundle.packages, wzPackageId, &pPackage)) &&
72 BAL_INFO_PRIMARY_PACKAGE_TYPE_DEFAULT == pPackage->primaryPackageType)
73 {
74 BOOL fInstalled = BOOTSTRAPPER_PACKAGE_STATE_ABSENT < state;
75
76 // Maybe modify the action state if the primary package is or is not already installed.
77 if (fInstalled && BOOTSTRAPPER_ACTION_INSTALL == m_command.action)
78 {
79 m_command.action = BOOTSTRAPPER_ACTION_MODIFY;
80 }
81 else if (!fInstalled && (BOOTSTRAPPER_ACTION_MODIFY == m_command.action || BOOTSTRAPPER_ACTION_REPAIR == m_command.action))
82 {
83 m_command.action = BOOTSTRAPPER_ACTION_INSTALL;
84 }
85
86 if (m_fApplied && !fInstalled && fCached)
87 {
88 m_fAutomaticRemoval = TRUE;
89 }
90 }
91
92 return __super::OnDetectPackageComplete(wzPackageId, hrStatus, state, fCached);
93 }
94
95
96 virtual STDMETHODIMP OnDetectComplete(
97 __in HRESULT hrStatus,
98 __in BOOL fEligibleForCleanup
99 )
100 {
101 if (m_fAutomaticRemoval && SUCCEEDED(hrStatus))
102 {
103 ::PostMessageW(m_hWnd, WM_WIXIUIBA_PLAN_PACKAGES_FOR_CLEANUP, 0, BOOTSTRAPPER_ACTION_UNINSTALL);
104 ExitFunction();
105 }
106 else if (m_fApplied)
107 {
108 ::PostMessageW(m_hWnd, WM_CLOSE, 0, 0);
109 ExitFunction();
110 }
111
112 // If we're performing an action that modifies machine state then evaluate conditions.
113 BOOL fEvaluateConditions = SUCCEEDED(hrStatus) &&
114 (BOOTSTRAPPER_ACTION_LAYOUT < m_command.action && BOOTSTRAPPER_ACTION_UPDATE_REPLACE > m_command.action);
115
116 if (fEvaluateConditions)
117 {
118 hrStatus = EvaluateConditions();
119 }
120
121 if (SUCCEEDED(hrStatus))
122 {
123 ::PostMessageW(m_hWnd, WM_WIXIUIBA_PLAN_PACKAGES, 0, m_command.action);
124 }
125 else
126 {
127 SetLoadPackageFailure(hrStatus);
128 }
129
130 LExit:
131 return __super::OnDetectComplete(hrStatus, fEligibleForCleanup);
132 }
133
134
135 virtual STDMETHODIMP OnPlanPackageBegin(
136 __in_z LPCWSTR wzPackageId,
137 __in BOOTSTRAPPER_PACKAGE_STATE state,
138 __in BOOL fCached,
139 __in BOOTSTRAPPER_PACKAGE_CONDITION_RESULT installCondition,
140 __in BOOTSTRAPPER_PACKAGE_CONDITION_RESULT repairCondition,
141 __in BOOTSTRAPPER_REQUEST_STATE recommendedState,
142 __in BOOTSTRAPPER_CACHE_TYPE recommendedCacheType,
143 __inout BOOTSTRAPPER_REQUEST_STATE* pRequestState,
144 __inout BOOTSTRAPPER_CACHE_TYPE* pRequestedCacheType,
145 __inout BOOL* pfCancel
146 )
147 {
148 HRESULT hr = S_OK;
149 BAL_INFO_PACKAGE* pPackage = NULL;
150
151 hr = BalInfoFindPackageById(&m_Bundle.packages, wzPackageId, &pPackage);
152 if (FAILED(hr))
153 {
154 // Non-chain package, keep default.
155 }
156 else if (BAL_INFO_PRIMARY_PACKAGE_TYPE_DEFAULT != pPackage->primaryPackageType)
157 {
158 // Only the primary package should be cached or executed.
159 if (BOOTSTRAPPER_CACHE_TYPE_FORCE == *pRequestedCacheType)
160 {
161 *pRequestedCacheType = BOOTSTRAPPER_CACHE_TYPE_KEEP;
162 }
163
164 *pRequestState = BOOTSTRAPPER_REQUEST_STATE_NONE;
165 }
166 else if (BOOTSTRAPPER_DISPLAY_FULL == m_command.display && !m_fAutomaticRemoval)
167 {
168 // Make sure the MSI UI is shown regardless of the current state of the package.
169 *pRequestState = BOOTSTRAPPER_REQUEST_STATE_REPAIR;
170 }
171
172 return __super::OnPlanPackageBegin(wzPackageId, state, fCached, installCondition, repairCondition, recommendedState, recommendedCacheType, pRequestState, pRequestedCacheType, pfCancel);
173 }
174
175
176 virtual STDMETHODIMP OnPlanMsiPackage(
177 __in_z LPCWSTR wzPackageId,
178 __in BOOL fExecute,
179 __in BOOTSTRAPPER_ACTION_STATE action,
180 __in BOOTSTRAPPER_MSI_FILE_VERSIONING recommendedFileVersioning,
181 __inout BOOL* pfCancel,
182 __inout BURN_MSI_PROPERTY* pActionMsiProperty,
183 __inout INSTALLUILEVEL* pUiLevel,
184 __inout BOOL* pfDisableExternalUiHandler,
185 __inout BOOTSTRAPPER_MSI_FILE_VERSIONING* pFileVersioning
186 )
187 {
188 INSTALLUILEVEL uiLevel = INSTALLUILEVEL_NOCHANGE;
189
190 if (m_fAutomaticRemoval)
191 {
192 ExitFunction();
193 }
194
195 switch (m_command.display)
196 {
197 case BOOTSTRAPPER_DISPLAY_FULL:
198 uiLevel = INSTALLUILEVEL_FULL;
199 break;
200
201 case BOOTSTRAPPER_DISPLAY_PASSIVE:
202 uiLevel = INSTALLUILEVEL_REDUCED;
203 break;
204 }
205
206 if (INSTALLUILEVEL_NOCHANGE != uiLevel)
207 {
208 *pUiLevel = uiLevel;
209 }
210
211 *pActionMsiProperty = BURN_MSI_PROPERTY_NONE;
212 *pfDisableExternalUiHandler = TRUE;
213
214 LExit:
215 return __super::OnPlanMsiPackage(wzPackageId, fExecute, action, recommendedFileVersioning, pfCancel, pActionMsiProperty, pUiLevel, pfDisableExternalUiHandler, pFileVersioning);
216 }
217
218
219 virtual STDMETHODIMP OnPlanComplete(
220 __in HRESULT hrStatus
221 )
222 {
223 if (SUCCEEDED(hrStatus))
224 {
225 ::PostMessageW(m_hWnd, WM_WIXIUIBA_APPLY_PACKAGES, 0, 0);
226 }
227 else if (m_fAutomaticRemoval)
228 {
229 ::PostMessageW(m_hWnd, WM_CLOSE, 0, 0);
230 }
231 else
232 {
233 SetLoadPackageFailure(hrStatus);
234 }
235
236 return __super::OnPlanComplete(hrStatus);
237 }
238
239
240 virtual STDMETHODIMP OnApplyBegin(
241 __in DWORD dwPhaseCount,
242 __inout BOOL* pfCancel
243 )
244 {
245 m_fApplying = TRUE;
246 return __super::OnApplyBegin(dwPhaseCount, pfCancel);
247 }
248
249
250 virtual STDMETHODIMP OnCacheComplete(
251 __in HRESULT hrStatus
252 )
253 {
254 if (FAILED(hrStatus) && !m_fAutomaticRemoval)
255 {
256 SetLoadPackageFailure(hrStatus);
257 }
258
259 return __super::OnCacheComplete(hrStatus);
260 }
261
262
263 virtual STDMETHODIMP OnExecuteBegin(
264 __in DWORD cExecutingPackages,
265 __in BOOL* pfCancel
266 )
267 {
268 m_pEngine->CloseSplashScreen();
269
270 return __super::OnExecuteBegin(cExecutingPackages, pfCancel);
271 }
272
273
274 virtual STDMETHODIMP OnApplyComplete(
275 __in HRESULT hrStatus,
276 __in BOOTSTRAPPER_APPLY_RESTART restart,
277 __in BOOTSTRAPPER_APPLYCOMPLETE_ACTION recommendation,
278 __inout BOOTSTRAPPER_APPLYCOMPLETE_ACTION* pAction
279 )
280 {
281 HRESULT hr = __super::OnApplyComplete(hrStatus, restart, recommendation, pAction);
282
283 *pAction = BOOTSTRAPPER_APPLYCOMPLETE_ACTION_NONE;
284 m_fApplying = FALSE;
285
286 if (m_fAutomaticRemoval)
287 {
288 ::PostMessageW(m_hWnd, WM_CLOSE, 0, 0);
289 }
290 else
291 {
292 m_restartResult = restart; // remember the restart result so we return the correct error code.
293 m_fApplied = TRUE;
294
295 if (FAILED(hrStatus))
296 {
297 m_hrFinal = hrStatus;
298 }
299
300 ::PostMessageW(m_hWnd, WM_WIXIUIBA_DETECT_FOR_CLEANUP, 0, 0);
301 }
302
303 return hr;
304 }
305
306
307public: //CBalBaseBootstrapperApplication
308 virtual STDMETHODIMP Initialize(
309 __in const BOOTSTRAPPER_CREATE_ARGS* pCreateArgs
310 )
311 {
312 HRESULT hr = S_OK;
313
314 hr = __super::Initialize(pCreateArgs);
315 BalExitOnFailure(hr, "CBalBaseBootstrapperApplication initialization failed.");
316
317 memcpy_s(&m_command, sizeof(m_command), pCreateArgs->pCommand, sizeof(BOOTSTRAPPER_COMMAND));
318 memcpy_s(&m_createArgs, sizeof(m_createArgs), pCreateArgs, sizeof(BOOTSTRAPPER_CREATE_ARGS));
319 m_createArgs.pCommand = &m_command;
320
321 LExit:
322 return hr;
323 }
324
325 void Uninitialize(
326 __in const BOOTSTRAPPER_DESTROY_ARGS* /*pArgs*/,
327 __in BOOTSTRAPPER_DESTROY_RESULTS* /*pResults*/
328 )
329 {
330 }
331
332
333private:
334 //
335 // UiThreadProc - entrypoint for UI thread.
336 //
337 static DWORD WINAPI UiThreadProc(
338 __in LPVOID pvContext
339 )
340 {
341 HRESULT hr = S_OK;
342 CWixInternalUIBootstrapperApplication* pThis = (CWixInternalUIBootstrapperApplication*)pvContext;
343 BOOL fComInitialized = FALSE;
344 BOOL fRet = FALSE;
345 MSG msg = { };
346 DWORD dwQuit = 0;
347
348 // Initialize COM and theme.
349 hr = ::CoInitialize(NULL);
350 BalExitOnFailure(hr, "Failed to initialize COM.");
351 fComInitialized = TRUE;
352
353 hr = pThis->InitializeData();
354 BalExitOnFailure(hr, "Failed to initialize data in bootstrapper application.");
355
356 // Create main window.
357 hr = pThis->CreateMainWindow();
358 BalExitOnFailure(hr, "Failed to create main window.");
359
360 ::PostMessageW(pThis->m_hWnd, WM_WIXIUIBA_DETECT_PACKAGES, 0, 0);
361
362 // message pump
363 while (0 != (fRet = ::GetMessageW(&msg, NULL, 0, 0)))
364 {
365 if (-1 == fRet)
366 {
367 hr = E_UNEXPECTED;
368 BalExitOnFailure(hr, "Unexpected return value from message pump.");
369 }
370 else if (!::IsDialogMessageW(pThis->m_hWnd, &msg))
371 {
372 ::TranslateMessage(&msg);
373 ::DispatchMessageW(&msg);
374 }
375 }
376
377 // Succeeded thus far, check to see if anything went wrong while actually
378 // executing changes.
379 if (FAILED(pThis->m_hrFinal))
380 {
381 hr = pThis->m_hrFinal;
382 }
383 else if (pThis->CheckCanceled())
384 {
385 hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT);
386 }
387
388 LExit:
389 // destroy main window
390 pThis->DestroyMainWindow();
391
392 if (BOOTSTRAPPER_APPLY_RESTART_INITIATED == pThis->m_restartResult)
393 {
394 dwQuit = ERROR_SUCCESS_REBOOT_INITIATED;
395 }
396 else if (BOOTSTRAPPER_APPLY_RESTART_REQUIRED == pThis->m_restartResult)
397 {
398 dwQuit = ERROR_SUCCESS_REBOOT_REQUIRED;
399 }
400 else if (SEVERITY_ERROR == HRESULT_SEVERITY(hr) && FACILITY_WIN32 == HRESULT_FACILITY(hr))
401 {
402 // Convert Win32 HRESULTs back to the error code.
403 dwQuit = HRESULT_CODE(hr);
404 }
405 else
406 {
407 dwQuit = hr;
408 }
409
410 // initiate engine shutdown
411 pThis->m_pEngine->Quit(dwQuit);
412
413 // uninitialize COM
414 if (fComInitialized)
415 {
416 ::CoUninitialize();
417 }
418
419 return hr;
420 }
421
422
423 //
424 // InitializeData - initializes all the package and prerequisite information.
425 //
426 HRESULT InitializeData()
427 {
428 HRESULT hr = S_OK;
429 IXMLDOMDocument* pixdManifest = NULL;
430
431 hr = BalManifestLoad(m_hModule, &pixdManifest);
432 BalExitOnFailure(hr, "Failed to load bootstrapper application manifest.");
433
434 hr = BalInfoParseFromXml(&m_Bundle, pixdManifest);
435 BalExitOnFailure(hr, "Failed to load bundle information.");
436
437 hr = EnsureSinglePrimaryPackage();
438 BalExitOnFailure(hr, "Failed to ensure single primary package.");
439
440 hr = ProcessCommandLine();
441 ExitOnFailure(hr, "Unknown commandline parameters.");
442
443 hr = BalConditionsParseFromXml(&m_Conditions, pixdManifest, NULL);
444 BalExitOnFailure(hr, "Failed to load conditions from XML.");
445
446 LExit:
447 ReleaseObject(pixdManifest);
448
449 return hr;
450 }
451
452
453 //
454 // ProcessCommandLine - process the provided command line arguments.
455 //
456 HRESULT ProcessCommandLine()
457 {
458 HRESULT hr = S_OK;
459 int argc = 0;
460 LPWSTR* argv = NULL;
461
462 argc = m_BalInfoCommand.cUnknownArgs;
463 argv = m_BalInfoCommand.rgUnknownArgs;
464
465 for (int i = 0; i < argc; ++i)
466 {
467 BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Ignoring unknown argument: %ls", argv[i]);
468 }
469
470 hr = BalSetOverridableVariablesFromEngine(&m_Bundle.overridableVariables, &m_BalInfoCommand, m_pEngine);
471 BalExitOnFailure(hr, "Failed to set overridable variables from the command line.");
472
473 LExit:
474 return hr;
475 }
476
477 HRESULT EnsureSinglePrimaryPackage()
478 {
479 HRESULT hr = S_OK;
480 BAL_INFO_PACKAGE* pDefaultPackage = NULL;
481 BOOL fPrimaryArchSpecific = FALSE;
482 USHORT usNativeMachine = 0;
483 BAL_INFO_PRIMARY_PACKAGE_TYPE nativeType = BAL_INFO_PRIMARY_PACKAGE_TYPE_NONE;
484
485 hr = ProcNativeMachine(::GetCurrentProcess(), &usNativeMachine);
486 BalExitOnFailure(hr, "Failed to get native machine value.");
487
488 if (S_FALSE != hr)
489 {
490 switch (usNativeMachine)
491 {
492 case IMAGE_FILE_MACHINE_I386:
493 nativeType = BAL_INFO_PRIMARY_PACKAGE_TYPE_X86;
494 break;
495 case IMAGE_FILE_MACHINE_AMD64:
496 nativeType = BAL_INFO_PRIMARY_PACKAGE_TYPE_X64;
497 break;
498 case IMAGE_FILE_MACHINE_ARM64:
499 nativeType = BAL_INFO_PRIMARY_PACKAGE_TYPE_ARM64;
500 break;
501 }
502 }
503 else
504 {
505#if !defined(_WIN64)
506 BOOL fIsWow64 = FALSE;
507
508 ProcWow64(::GetCurrentProcess(), &fIsWow64);
509 if (!fIsWow64)
510 {
511 nativeType = BAL_INFO_PRIMARY_PACKAGE_TYPE_X86;
512 }
513 else
514#endif
515 {
516 nativeType = BAL_INFO_PRIMARY_PACKAGE_TYPE_X64;
517 }
518 }
519
520 for (DWORD i = 0; i < m_Bundle.packages.cPackages; ++i)
521 {
522 BAL_INFO_PACKAGE* pPackage = m_Bundle.packages.rgPackages + i;
523
524 if (BAL_INFO_PRIMARY_PACKAGE_TYPE_NONE == pPackage->primaryPackageType)
525 {
526 // Skip.
527 }
528 else if (nativeType == pPackage->primaryPackageType)
529 {
530 if (fPrimaryArchSpecific)
531 {
532 BalExitWithRootFailure(hr, E_INVALIDDATA, "Bundle contains multiple primary packages for same architecture: %u.", nativeType);
533 }
534
535 pPackage->primaryPackageType = BAL_INFO_PRIMARY_PACKAGE_TYPE_DEFAULT;
536 fPrimaryArchSpecific = TRUE;
537 }
538 else if (BAL_INFO_PRIMARY_PACKAGE_TYPE_DEFAULT == pPackage->primaryPackageType)
539 {
540 if (pDefaultPackage)
541 {
542 BalExitWithRootFailure(hr, E_INVALIDDATA, "Bundle contains multiple default primary packages.");
543 }
544
545 pDefaultPackage = pPackage;
546 }
547 }
548
549 BalExitOnNull(pDefaultPackage, hr, E_INVALIDSTATE, "Bundle did not contain default primary package.");
550
551 if (fPrimaryArchSpecific)
552 {
553 pDefaultPackage->primaryPackageType = BAL_INFO_PRIMARY_PACKAGE_TYPE_NONE;
554 }
555
556 LExit:
557 return hr;
558 }
559
560
561 //
562 // CreateMainWindow - creates the main install window.
563 //
564 HRESULT CreateMainWindow()
565 {
566 HRESULT hr = S_OK;
567 WNDCLASSW wc = { };
568 DWORD dwWindowStyle = WS_POPUP;
569
570 wc.lpfnWndProc = CWixInternalUIBootstrapperApplication::WndProc;
571 wc.hInstance = m_hModule;
572 wc.lpszClassName = WIXIUIBA_WINDOW_CLASS;
573
574 if (!::RegisterClassW(&wc))
575 {
576 ExitWithLastError(hr, "Failed to register window.");
577 }
578
579 m_fRegistered = TRUE;
580
581 // If the UI should be visible, allow it to be visible and activated so we are the foreground window.
582 // This allows the UAC prompt and MSI UI to automatically be activated.
583 if (BOOTSTRAPPER_DISPLAY_NONE < m_command.display)
584 {
585 dwWindowStyle |= WS_VISIBLE;
586 }
587
588 m_hWnd = ::CreateWindowExW(WS_EX_TOOLWINDOW, wc.lpszClassName, NULL, dwWindowStyle, 0, 0, 0, 0, HWND_DESKTOP, NULL, m_hModule, this);
589 ExitOnNullWithLastError(m_hWnd, hr, "Failed to create window.");
590
591 LExit:
592 return hr;
593 }
594
595 //
596 // DestroyMainWindow - clean up all the window registration.
597 //
598 void DestroyMainWindow()
599 {
600 if (::IsWindow(m_hWnd))
601 {
602 ::DestroyWindow(m_hWnd);
603 m_hWnd = NULL;
604 }
605
606 if (m_fRegistered)
607 {
608 ::UnregisterClassW(WIXIUIBA_WINDOW_CLASS, m_hModule);
609 m_fRegistered = FALSE;
610 }
611 }
612
613 //
614 // WndProc - standard windows message handler.
615 //
616 static LRESULT CALLBACK WndProc(
617 __in HWND hWnd,
618 __in UINT uMsg,
619 __in WPARAM wParam,
620 __in LPARAM lParam
621 )
622 {
623#pragma warning(suppress:4312)
624 CWixInternalUIBootstrapperApplication* pBA = reinterpret_cast<CWixInternalUIBootstrapperApplication*>(::GetWindowLongPtrW(hWnd, GWLP_USERDATA));
625
626 switch (uMsg)
627 {
628 case WM_NCCREATE:
629 {
630 LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
631 pBA = reinterpret_cast<CWixInternalUIBootstrapperApplication*>(lpcs->lpCreateParams);
632#pragma warning(suppress:4244)
633 ::SetWindowLongPtrW(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pBA));
634 }
635 break;
636
637 case WM_NCDESTROY:
638 {
639 LRESULT lres = ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
640 ::SetWindowLongPtrW(hWnd, GWLP_USERDATA, 0);
641 ::PostQuitMessage(0);
642 return lres;
643 }
644
645 case WM_CLOSE:
646 // If the user chose not to close, do *not* let the default window proc handle the message.
647 if (!pBA->OnClose())
648 {
649 return 0;
650 }
651 break;
652
653 case WM_WIXIUIBA_DETECT_PACKAGES: __fallthrough;
654 case WM_WIXIUIBA_DETECT_FOR_CLEANUP:
655 pBA->OnDetect();
656 return 0;
657
658 case WM_WIXIUIBA_PLAN_PACKAGES:
659 case WM_WIXIUIBA_PLAN_PACKAGES_FOR_CLEANUP:
660 pBA->OnPlan(static_cast<BOOTSTRAPPER_ACTION>(lParam));
661 return 0;
662
663 case WM_WIXIUIBA_APPLY_PACKAGES:
664 pBA->OnApply();
665 return 0;
666 }
667
668 return ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
669 }
670
671
672 //
673 // OnDetect - start the processing of packages.
674 //
675 void OnDetect()
676 {
677 HRESULT hr = S_OK;
678
679 hr = m_pEngine->Detect();
680 BalExitOnFailure(hr, "Failed to start detecting chain.");
681
682 LExit:
683 if (FAILED(hr))
684 {
685 SetLoadPackageFailure(hr);
686 }
687 }
688
689
690 //
691 // OnPlan - plan the detected changes.
692 //
693 void OnPlan(
694 __in BOOTSTRAPPER_ACTION action
695 )
696 {
697 HRESULT hr = S_OK;
698
699 m_plannedAction = action;
700
701 hr = m_pEngine->Plan(action);
702 BalExitOnFailure(hr, "Failed to start planning packages.");
703
704 LExit:
705 if (FAILED(hr))
706 {
707 SetLoadPackageFailure(hr);
708 }
709 }
710
711
712 //
713 // OnApply - apply the packages.
714 //
715 void OnApply()
716 {
717 HRESULT hr = S_OK;
718
719 hr = m_pEngine->Apply(m_hWnd);
720 BalExitOnFailure(hr, "Failed to start applying packages.");
721
722 LExit:
723 if (FAILED(hr))
724 {
725 SetLoadPackageFailure(hr);
726 }
727 }
728
729
730 //
731 // OnClose - called when the window is trying to be closed.
732 //
733 BOOL OnClose()
734 {
735 BOOL fClose = FALSE;
736
737 // If we've already applied, just close.
738 if (m_fApplied)
739 {
740 fClose = TRUE;
741 }
742 else
743 {
744 PromptCancel(m_hWnd, TRUE, NULL, NULL);
745
746 // If we're inside Apply then we never close, we just cancel to let rollback occur.
747 fClose = !m_fApplying;
748 }
749
750 return fClose;
751 }
752
753
754 HRESULT EvaluateConditions()
755 {
756 HRESULT hr = S_OK;
757 BOOL fResult = FALSE;
758
759 for (DWORD i = 0; i < m_Conditions.cConditions; ++i)
760 {
761 BAL_CONDITION* pCondition = m_Conditions.rgConditions + i;
762
763 hr = BalConditionEvaluate(pCondition, m_pEngine, &fResult, &m_sczFailedMessage);
764 BalExitOnFailure(hr, "Failed to evaluate condition.");
765
766 if (!fResult)
767 {
768 hr = E_WIXSTDBA_CONDITION_FAILED;
769 BalExitOnFailure(hr, "%ls", m_sczFailedMessage);
770 }
771 }
772
773 ReleaseNullStrSecure(m_sczFailedMessage);
774
775 LExit:
776 return hr;
777 }
778
779
780 void SetLoadPackageFailure(
781 __in HRESULT hrStatus
782 )
783 {
784 Assert(FAILED(hrStatus));
785
786 if (!m_fApplied)
787 {
788 m_hrFinal = hrStatus;
789 m_fFailedToLoadPackage = TRUE;
790 }
791
792 // Quietly exit.
793 ::PostMessageW(m_hWnd, WM_CLOSE, 0, 0);
794 }
795
796
797public:
798 //
799 // Constructor - initialize member variables.
800 //
801 CWixInternalUIBootstrapperApplication(
802 __in HMODULE hModule,
803 __in_opt PREQBA_DATA* pPrereqData,
804 __in IBootstrapperEngine* pEngine
805 ) : CBalBaseBootstrapperApplication(pEngine, 3, 3000)
806 {
807 m_hModule = hModule;
808 m_command = { };
809 m_createArgs = { };
810
811 m_plannedAction = BOOTSTRAPPER_ACTION_UNKNOWN;
812
813 m_Bundle = { };
814 m_Conditions = { };
815 m_sczConfirmCloseMessage = NULL;
816 m_sczFailedMessage = NULL;
817
818 m_hUiThread = NULL;
819 m_fRegistered = FALSE;
820 m_hWnd = NULL;
821
822 m_hrFinal = S_OK;
823
824 m_restartResult = BOOTSTRAPPER_APPLY_RESTART_NONE;
825
826 m_fApplying = FALSE;
827 m_fApplied = FALSE;
828 m_fAutomaticRemoval = FALSE;
829 m_fFailedToLoadPackage = FALSE;
830 m_pPrereqData = pPrereqData;
831
832 pEngine->AddRef();
833 m_pEngine = pEngine;
834 }
835
836
837 //
838 // Destructor - release member variables.
839 //
840 ~CWixInternalUIBootstrapperApplication()
841 {
842 ReleaseStr(m_sczFailedMessage);
843 ReleaseStr(m_sczConfirmCloseMessage);
844 BalConditionsUninitialize(&m_Conditions);
845 BalInfoUninitialize(&m_Bundle);
846
847 ReleaseNullObject(m_pEngine);
848 }
849
850private:
851 HMODULE m_hModule;
852 BOOTSTRAPPER_CREATE_ARGS m_createArgs;
853 BOOTSTRAPPER_COMMAND m_command;
854 IBootstrapperEngine* m_pEngine;
855 BOOTSTRAPPER_ACTION m_plannedAction;
856
857 BAL_INFO_BUNDLE m_Bundle;
858 BAL_CONDITIONS m_Conditions;
859 LPWSTR m_sczFailedMessage;
860 LPWSTR m_sczConfirmCloseMessage;
861
862 HANDLE m_hUiThread;
863 BOOL m_fRegistered;
864 HWND m_hWnd;
865
866 HRESULT m_hrFinal;
867
868 BOOTSTRAPPER_APPLY_RESTART m_restartResult;
869
870 BOOL m_fApplying;
871 BOOL m_fApplied;
872 BOOL m_fAutomaticRemoval;
873 BOOL m_fFailedToLoadPackage;
874 PREQBA_DATA* m_pPrereqData;
875};
876
877
878//
879// CreateBootstrapperApplication - creates a new IBootstrapperApplication object.
880//
881HRESULT CreateBootstrapperApplication(
882 __in HMODULE hModule,
883 __in_opt PREQBA_DATA* pPrereqData,
884 __in IBootstrapperEngine* pEngine,
885 __in const BOOTSTRAPPER_CREATE_ARGS* pArgs,
886 __inout BOOTSTRAPPER_CREATE_RESULTS* pResults,
887 __out IBootstrapperApplication** ppApplication
888 )
889{
890 HRESULT hr = S_OK;
891 CWixInternalUIBootstrapperApplication* pApplication = NULL;
892
893 pApplication = new CWixInternalUIBootstrapperApplication(hModule, pPrereqData, pEngine);
894 BalExitOnNull(pApplication, hr, E_OUTOFMEMORY, "Failed to create new InternalUI bootstrapper application object.");
895
896 hr = pApplication->Initialize(pArgs);
897 ExitOnFailure(hr, "CWixInternalUIBootstrapperApplication initialization failed.");
898
899 pResults->pfnBootstrapperApplicationProc = BalBaseBootstrapperApplicationProc;
900 pResults->pvBootstrapperApplicationProcContext = pApplication;
901 *ppApplication = pApplication;
902 pApplication = NULL;
903
904LExit:
905 ReleaseObject(pApplication);
906 return hr;
907}
908
909
910void DestroyBootstrapperApplication(
911 __in IBootstrapperApplication* pApplication,
912 __in const BOOTSTRAPPER_DESTROY_ARGS* pArgs,
913 __inout BOOTSTRAPPER_DESTROY_RESULTS* pResults
914 )
915{
916 CWixInternalUIBootstrapperApplication* pBA = (CWixInternalUIBootstrapperApplication*)pApplication;
917 pBA->Uninitialize(pArgs, pResults);
918}