[pypy-commit] pypy windowsinstaller: Got to the point where bootstrap is being built.

andr...@siemens.com pypy.commits at gmail.com
Tue Feb 5 05:57:59 EST 2019


Author: andrew.lawrence at siemens.com
Branch: windowsinstaller
Changeset: r95801:fb576872b8ca
Date: 2018-12-24 19:53 +0000
http://bitbucket.org/pypy/pypy/changeset/fb576872b8ca/

Log:	Got to the point where bootstrap is being built.

diff too long, truncating to 2000 out of 3893 lines

diff --git a/pypy/tool/release/windowsinstaller/bundle/bootstrap/LICENSE.txt b/pypy/tool/release/windowsinstaller/bundle/bootstrap/LICENSE.txt
new file mode 100644
--- /dev/null
+++ b/pypy/tool/release/windowsinstaller/bundle/bootstrap/LICENSE.txt
@@ -0,0 +1,25 @@
+This license applies to the bootstrapper application that is embedded within the installer. It has no impact on the licensing for the rest of the installer or Python itself, as no code covered by this license exists in any other part of the product.
+
+---
+
+Microsoft Reciprocal License (MS-RL)
+
+This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software.
+
+1. Definitions
+ The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law.
+ A "contribution" is the original software, or any additions or changes to the software.
+ A "contributor" is any person that distributes its contribution under this license.
+ "Licensed patents" are a contributor's patent claims that read directly on its contribution.
+
+2. Grant of Rights
+ (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
+ (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
+
+3. Conditions and Limitations
+ (A) Reciprocal Grants- For any file you distribute that contains code from the software (in source code or binary format), you must provide recipients the source code to that file along with a copy of this license, which license will govern that file. You may license other files that are entirely your own work and do not contain code from the software under any terms you choose.
+ (B) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
+ (C) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.
+ (D) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.
+ (E) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.
+ (F) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.
diff --git a/pypy/tool/release/windowsinstaller/bundle/bootstrap/PythonBootstrapperApplication.cpp b/pypy/tool/release/windowsinstaller/bundle/bootstrap/PythonBootstrapperApplication.cpp
new file mode 100644
--- /dev/null
+++ b/pypy/tool/release/windowsinstaller/bundle/bootstrap/PythonBootstrapperApplication.cpp
@@ -0,0 +1,3233 @@
+//-------------------------------------------------------------------------------------------------
+// <copyright file="WixStandardBootstrapperApplication.cpp" company="Outercurve Foundation">
+//   Copyright (c) 2004, Outercurve Foundation.
+//   This software is released under Microsoft Reciprocal License (MS-RL).
+//   The license and further copyright text can be found in the file
+//   LICENSE.TXT at the root directory of the distribution.
+// </copyright>
+//-------------------------------------------------------------------------------------------------
+
+
+#include "pch.h"
+
+static const LPCWSTR PYBA_WINDOW_CLASS = L"PythonBA";
+static const DWORD PYBA_ACQUIRE_PERCENTAGE = 30;
+static const LPCWSTR PYBA_VARIABLE_BUNDLE_FILE_VERSION = L"WixBundleFileVersion";
+
+enum PYBA_STATE {
+    PYBA_STATE_INITIALIZING,
+    PYBA_STATE_INITIALIZED,
+    PYBA_STATE_HELP,
+    PYBA_STATE_DETECTING,
+    PYBA_STATE_DETECTED,
+    PYBA_STATE_PLANNING,
+    PYBA_STATE_PLANNED,
+    PYBA_STATE_APPLYING,
+    PYBA_STATE_CACHING,
+    PYBA_STATE_CACHED,
+    PYBA_STATE_EXECUTING,
+    PYBA_STATE_EXECUTED,
+    PYBA_STATE_APPLIED,
+    PYBA_STATE_FAILED,
+};
+
+static const int WM_PYBA_SHOW_HELP = WM_APP + 100;
+static const int WM_PYBA_DETECT_PACKAGES = WM_APP + 101;
+static const int WM_PYBA_PLAN_PACKAGES = WM_APP + 102;
+static const int WM_PYBA_APPLY_PACKAGES = WM_APP + 103;
+static const int WM_PYBA_CHANGE_STATE = WM_APP + 104;
+static const int WM_PYBA_SHOW_FAILURE = WM_APP + 105;
+
+// This enum must be kept in the same order as the PAGE_NAMES array.
+enum PAGE {
+    PAGE_LOADING,
+    PAGE_HELP,
+    PAGE_INSTALL,
+    PAGE_UPGRADE,
+    PAGE_SIMPLE_INSTALL,
+    PAGE_CUSTOM1,
+    PAGE_CUSTOM2,
+    PAGE_MODIFY,
+    PAGE_PROGRESS,
+    PAGE_PROGRESS_PASSIVE,
+    PAGE_SUCCESS,
+    PAGE_FAILURE,
+    COUNT_PAGE,
+};
+
+// This array must be kept in the same order as the PAGE enum.
+static LPCWSTR PAGE_NAMES[] = {
+    L"Loading",
+    L"Help",
+    L"Install",
+    L"Upgrade",
+    L"SimpleInstall",
+    L"Custom1",
+    L"Custom2",
+    L"Modify",
+    L"Progress",
+    L"ProgressPassive",
+    L"Success",
+    L"Failure",
+};
+
+enum CONTROL_ID {
+    // Non-paged controls
+    ID_CLOSE_BUTTON = THEME_FIRST_ASSIGN_CONTROL_ID,
+    ID_MINIMIZE_BUTTON,
+
+    // Welcome page
+    ID_INSTALL_BUTTON,
+    ID_INSTALL_CUSTOM_BUTTON,
+    ID_INSTALL_SIMPLE_BUTTON,
+    ID_INSTALL_UPGRADE_BUTTON,
+    ID_INSTALL_UPGRADE_CUSTOM_BUTTON,
+    ID_INSTALL_CANCEL_BUTTON,
+    ID_INSTALL_LAUNCHER_ALL_USERS_CHECKBOX,
+
+    // Customize Page
+    ID_TARGETDIR_EDITBOX,
+    ID_CUSTOM_ASSOCIATE_FILES_CHECKBOX,
+    ID_CUSTOM_INSTALL_ALL_USERS_CHECKBOX,
+    ID_CUSTOM_INSTALL_LAUNCHER_ALL_USERS_CHECKBOX,
+    ID_CUSTOM_INCLUDE_LAUNCHER_HELP_LABEL,
+    ID_CUSTOM_COMPILE_ALL_CHECKBOX,
+    ID_CUSTOM_BROWSE_BUTTON,
+    ID_CUSTOM_BROWSE_BUTTON_LABEL,
+    ID_CUSTOM_INSTALL_BUTTON,
+    ID_CUSTOM_NEXT_BUTTON,
+    ID_CUSTOM1_BACK_BUTTON,
+    ID_CUSTOM2_BACK_BUTTON,
+    ID_CUSTOM1_CANCEL_BUTTON,
+    ID_CUSTOM2_CANCEL_BUTTON,
+
+    // Modify page
+    ID_MODIFY_BUTTON,
+    ID_REPAIR_BUTTON,
+    ID_UNINSTALL_BUTTON,
+    ID_MODIFY_CANCEL_BUTTON,
+
+    // Progress page
+    ID_CACHE_PROGRESS_PACKAGE_TEXT,
+    ID_CACHE_PROGRESS_BAR,
+    ID_CACHE_PROGRESS_TEXT,
+
+    ID_EXECUTE_PROGRESS_PACKAGE_TEXT,
+    ID_EXECUTE_PROGRESS_BAR,
+    ID_EXECUTE_PROGRESS_TEXT,
+    ID_EXECUTE_PROGRESS_ACTIONDATA_TEXT,
+
+    ID_OVERALL_PROGRESS_PACKAGE_TEXT,
+    ID_OVERALL_PROGRESS_BAR,
+    ID_OVERALL_CALCULATED_PROGRESS_BAR,
+    ID_OVERALL_PROGRESS_TEXT,
+
+    ID_PROGRESS_CANCEL_BUTTON,
+
+    // Success page
+    ID_SUCCESS_TEXT,
+    ID_SUCCESS_RESTART_TEXT,
+    ID_SUCCESS_RESTART_BUTTON,
+    ID_SUCCESS_CANCEL_BUTTON,
+    ID_SUCCESS_MAX_PATH_BUTTON,
+
+    // Failure page
+    ID_FAILURE_LOGFILE_LINK,
+    ID_FAILURE_MESSAGE_TEXT,
+    ID_FAILURE_RESTART_TEXT,
+    ID_FAILURE_RESTART_BUTTON,
+    ID_FAILURE_CANCEL_BUTTON
+};
+
+static THEME_ASSIGN_CONTROL_ID CONTROL_ID_NAMES[] = {
+    { ID_CLOSE_BUTTON, L"CloseButton" },
+    { ID_MINIMIZE_BUTTON, L"MinimizeButton" },
+
+    { ID_INSTALL_BUTTON, L"InstallButton" },
+    { ID_INSTALL_CUSTOM_BUTTON, L"InstallCustomButton" },
+    { ID_INSTALL_SIMPLE_BUTTON, L"InstallSimpleButton" },
+    { ID_INSTALL_UPGRADE_BUTTON, L"InstallUpgradeButton" },
+    { ID_INSTALL_UPGRADE_CUSTOM_BUTTON, L"InstallUpgradeCustomButton" },
+    { ID_INSTALL_CANCEL_BUTTON, L"InstallCancelButton" },
+    { ID_INSTALL_LAUNCHER_ALL_USERS_CHECKBOX, L"InstallLauncherAllUsers" },
+
+    { ID_TARGETDIR_EDITBOX, L"TargetDir" },
+    { ID_CUSTOM_ASSOCIATE_FILES_CHECKBOX, L"AssociateFiles" },
+    { ID_CUSTOM_INSTALL_ALL_USERS_CHECKBOX, L"InstallAllUsers" },
+    { ID_CUSTOM_INSTALL_LAUNCHER_ALL_USERS_CHECKBOX, L"CustomInstallLauncherAllUsers" },
+    { ID_CUSTOM_INCLUDE_LAUNCHER_HELP_LABEL, L"Include_launcherHelp" },
+    { ID_CUSTOM_COMPILE_ALL_CHECKBOX, L"CompileAll" },
+    { ID_CUSTOM_BROWSE_BUTTON, L"CustomBrowseButton" },
+    { ID_CUSTOM_BROWSE_BUTTON_LABEL, L"CustomBrowseButtonLabel" },
+    { ID_CUSTOM_INSTALL_BUTTON, L"CustomInstallButton" },
+    { ID_CUSTOM_NEXT_BUTTON, L"CustomNextButton" },
+    { ID_CUSTOM1_BACK_BUTTON, L"Custom1BackButton" },
+    { ID_CUSTOM2_BACK_BUTTON, L"Custom2BackButton" },
+    { ID_CUSTOM1_CANCEL_BUTTON, L"Custom1CancelButton" },
+    { ID_CUSTOM2_CANCEL_BUTTON, L"Custom2CancelButton" },
+
+    { ID_MODIFY_BUTTON, L"ModifyButton" },
+    { ID_REPAIR_BUTTON, L"RepairButton" },
+    { ID_UNINSTALL_BUTTON, L"UninstallButton" },
+    { ID_MODIFY_CANCEL_BUTTON, L"ModifyCancelButton" },
+
+    { ID_CACHE_PROGRESS_PACKAGE_TEXT, L"CacheProgressPackageText" },
+    { ID_CACHE_PROGRESS_BAR, L"CacheProgressbar" },
+    { ID_CACHE_PROGRESS_TEXT, L"CacheProgressText" },
+    { ID_EXECUTE_PROGRESS_PACKAGE_TEXT, L"ExecuteProgressPackageText" },
+    { ID_EXECUTE_PROGRESS_BAR, L"ExecuteProgressbar" },
+    { ID_EXECUTE_PROGRESS_TEXT, L"ExecuteProgressText" },
+    { ID_EXECUTE_PROGRESS_ACTIONDATA_TEXT, L"ExecuteProgressActionDataText" },
+    { ID_OVERALL_PROGRESS_PACKAGE_TEXT, L"OverallProgressPackageText" },
+    { ID_OVERALL_PROGRESS_BAR, L"OverallProgressbar" },
+    { ID_OVERALL_CALCULATED_PROGRESS_BAR, L"OverallCalculatedProgressbar" },
+    { ID_OVERALL_PROGRESS_TEXT, L"OverallProgressText" },
+    { ID_PROGRESS_CANCEL_BUTTON, L"ProgressCancelButton" },
+
+    { ID_SUCCESS_TEXT, L"SuccessText" },
+    { ID_SUCCESS_RESTART_TEXT, L"SuccessRestartText" },
+    { ID_SUCCESS_RESTART_BUTTON, L"SuccessRestartButton" },
+    { ID_SUCCESS_CANCEL_BUTTON, L"SuccessCancelButton" },
+    { ID_SUCCESS_MAX_PATH_BUTTON, L"SuccessMaxPathButton" },
+
+    { ID_FAILURE_LOGFILE_LINK, L"FailureLogFileLink" },
+    { ID_FAILURE_MESSAGE_TEXT, L"FailureMessageText" },
+    { ID_FAILURE_RESTART_TEXT, L"FailureRestartText" },
+    { ID_FAILURE_RESTART_BUTTON, L"FailureRestartButton" },
+    { ID_FAILURE_CANCEL_BUTTON, L"FailureCancelButton" },
+};
+
+static struct { LPCWSTR regName; LPCWSTR variableName; } OPTIONAL_FEATURES[] = {
+    { L"core_d", L"Include_debug" },
+    { L"core_pdb", L"Include_symbols" },
+    { L"dev", L"Include_dev" },
+    { L"doc", L"Include_doc" },
+    { L"exe", L"Include_exe" },
+    { L"lib", L"Include_lib" },
+    { L"path", L"PrependPath" },
+    { L"pip", L"Include_pip" },
+    { L"tcltk", L"Include_tcltk" },
+    { L"test", L"Include_test" },
+    { L"tools", L"Include_tools" },
+    { L"Shortcuts", L"Shortcuts" },
+    // Include_launcher and AssociateFiles are handled separately and so do
+    // not need to be included in this list.
+    { nullptr, nullptr }
+};
+
+
+
+class PythonBootstrapperApplication : public CBalBaseBootstrapperApplication {
+    void ShowPage(DWORD newPageId) {
+        // Process each control for special handling in the new page.
+        ProcessPageControls(ThemeGetPage(_theme, newPageId));
+
+        // Enable disable controls per-page.
+        if (_pageIds[PAGE_INSTALL] == newPageId ||
+            _pageIds[PAGE_SIMPLE_INSTALL] == newPageId ||
+            _pageIds[PAGE_UPGRADE] == newPageId) {
+            InstallPage_Show();
+        } else if (_pageIds[PAGE_CUSTOM1] == newPageId) {
+            Custom1Page_Show();
+        } else if (_pageIds[PAGE_CUSTOM2] == newPageId) {
+            Custom2Page_Show();
+        } else if (_pageIds[PAGE_MODIFY] == newPageId) {
+            ModifyPage_Show();
+        } else if (_pageIds[PAGE_SUCCESS] == newPageId) {
+            SuccessPage_Show();
+        } else if (_pageIds[PAGE_FAILURE] == newPageId) {
+            FailurePage_Show();
+        }
+
+        // Prevent repainting while switching page to avoid ugly flickering
+        _suppressPaint = TRUE;
+        ThemeShowPage(_theme, newPageId, SW_SHOW);
+        ThemeShowPage(_theme, _visiblePageId, SW_HIDE);
+        _suppressPaint = FALSE;
+        InvalidateRect(_theme->hwndParent, nullptr, TRUE);
+        _visiblePageId = newPageId;
+
+        // On the install page set the focus to the install button or
+        // the next enabled control if install is disabled
+        if (_pageIds[PAGE_INSTALL] == newPageId) {
+            ThemeSetFocus(_theme, ID_INSTALL_BUTTON);
+        } else if (_pageIds[PAGE_SIMPLE_INSTALL] == newPageId) {
+            ThemeSetFocus(_theme, ID_INSTALL_SIMPLE_BUTTON);
+        }
+    }
+
+    //
+    // Handles control clicks
+    //
+    void OnCommand(CONTROL_ID id) {
+        LPWSTR defaultDir = nullptr;
+        LPWSTR targetDir = nullptr;
+        LONGLONG elevated, crtInstalled, installAllUsers;
+        BOOL checked, launcherChecked;
+        WCHAR wzPath[MAX_PATH] = { };
+        BROWSEINFOW browseInfo = { };
+        PIDLIST_ABSOLUTE pidl = nullptr;
+        DWORD pageId;
+        HRESULT hr = S_OK;
+
+        switch(id) {
+        case ID_CLOSE_BUTTON:
+            OnClickCloseButton();
+            break;
+
+        // Install commands
+        case ID_INSTALL_SIMPLE_BUTTON: __fallthrough;
+        case ID_INSTALL_UPGRADE_BUTTON: __fallthrough;
+        case ID_INSTALL_BUTTON:
+            SavePageSettings();
+
+            hr = BalGetNumericVariable(L"InstallAllUsers", &installAllUsers);
+            ExitOnFailure(hr, L"Failed to get install scope");
+
+            hr = _engine->SetVariableNumeric(L"CompileAll", installAllUsers);
+            ExitOnFailure(hr, L"Failed to update CompileAll");
+
+            hr = EnsureTargetDir();
+            ExitOnFailure(hr, L"Failed to set TargetDir");
+
+            OnPlan(BOOTSTRAPPER_ACTION_INSTALL);
+            break;
+
+        case ID_CUSTOM1_BACK_BUTTON:
+            SavePageSettings();
+            if (_modifying) {
+                GoToPage(PAGE_MODIFY);
+            } else if (_upgrading) {
+                GoToPage(PAGE_UPGRADE);
+            } else {
+                GoToPage(PAGE_INSTALL);
+            }
+            break;
+
+        case ID_INSTALL_CUSTOM_BUTTON: __fallthrough;
+        case ID_INSTALL_UPGRADE_CUSTOM_BUTTON: __fallthrough;
+        case ID_CUSTOM2_BACK_BUTTON:
+            SavePageSettings();
+            GoToPage(PAGE_CUSTOM1);
+            break;
+
+        case ID_CUSTOM_NEXT_BUTTON:
+            SavePageSettings();
+            GoToPage(PAGE_CUSTOM2);
+            break;
+
+        case ID_CUSTOM_INSTALL_BUTTON:
+            SavePageSettings();
+
+            hr = EnsureTargetDir();
+            ExitOnFailure(hr, L"Failed to set TargetDir");
+
+            hr = BalGetStringVariable(L"TargetDir", &targetDir);
+            if (SUCCEEDED(hr)) {
+                // TODO: Check whether directory exists and contains another installation
+                ReleaseStr(targetDir);
+            }
+
+            OnPlan(_command.action);
+            break;
+
+        case ID_INSTALL_LAUNCHER_ALL_USERS_CHECKBOX:
+            checked = ThemeIsControlChecked(_theme, ID_INSTALL_LAUNCHER_ALL_USERS_CHECKBOX);
+            _engine->SetVariableNumeric(L"InstallLauncherAllUsers", checked);
+
+            ThemeControlElevates(_theme, ID_INSTALL_BUTTON, WillElevate());
+            break;
+
+        case ID_CUSTOM_INSTALL_LAUNCHER_ALL_USERS_CHECKBOX:
+            checked = ThemeIsControlChecked(_theme, ID_CUSTOM_INSTALL_LAUNCHER_ALL_USERS_CHECKBOX);
+            _engine->SetVariableNumeric(L"InstallLauncherAllUsers", checked);
+
+            ThemeControlElevates(_theme, ID_CUSTOM_INSTALL_BUTTON, WillElevate());
+            break;
+
+        case ID_CUSTOM_INSTALL_ALL_USERS_CHECKBOX:
+            checked = ThemeIsControlChecked(_theme, ID_CUSTOM_INSTALL_ALL_USERS_CHECKBOX);
+            _engine->SetVariableNumeric(L"InstallAllUsers", checked);
+
+            ThemeControlElevates(_theme, ID_CUSTOM_INSTALL_BUTTON, WillElevate());
+            ThemeControlEnable(_theme, ID_CUSTOM_BROWSE_BUTTON_LABEL, !checked);
+            if (checked) {
+                _engine->SetVariableNumeric(L"CompileAll", 1);
+                ThemeSendControlMessage(_theme, ID_CUSTOM_COMPILE_ALL_CHECKBOX, BM_SETCHECK, BST_CHECKED, 0);
+            }
+            ThemeGetTextControl(_theme, ID_TARGETDIR_EDITBOX, &targetDir);
+            if (targetDir) {
+                // Check the current value against the default to see
+                // if we should switch it automatically.
+                hr = BalGetStringVariable(
+                    checked ? L"DefaultJustForMeTargetDir" : L"DefaultAllUsersTargetDir",
+                    &defaultDir
+                );
+                
+                if (SUCCEEDED(hr) && defaultDir) {
+                    LPWSTR formatted = nullptr;
+                    if (defaultDir[0] && SUCCEEDED(BalFormatString(defaultDir, &formatted))) {
+                        if (wcscmp(formatted, targetDir) == 0) {
+                            ReleaseStr(defaultDir);
+                            defaultDir = nullptr;
+                            ReleaseStr(formatted);
+                            formatted = nullptr;
+                            
+                            hr = BalGetStringVariable(
+                                checked ? L"DefaultAllUsersTargetDir" : L"DefaultJustForMeTargetDir",
+                                &defaultDir
+                            );
+                            if (SUCCEEDED(hr) && defaultDir && defaultDir[0] && SUCCEEDED(BalFormatString(defaultDir, &formatted))) {
+                                ThemeSetTextControl(_theme, ID_TARGETDIR_EDITBOX, formatted);
+                                ReleaseStr(formatted);
+                            }
+                        } else {
+                            ReleaseStr(formatted);
+                        }
+                    }
+                    
+                    ReleaseStr(defaultDir);
+                }
+            }
+            break;
+
+        case ID_CUSTOM_BROWSE_BUTTON:
+            browseInfo.hwndOwner = _hWnd;
+            browseInfo.pszDisplayName = wzPath;
+            browseInfo.lpszTitle = _theme->sczCaption;
+            browseInfo.ulFlags = BIF_RETURNONLYFSDIRS | BIF_USENEWUI;
+            pidl = ::SHBrowseForFolderW(&browseInfo);
+            if (pidl && ::SHGetPathFromIDListW(pidl, wzPath)) {
+                ThemeSetTextControl(_theme, ID_TARGETDIR_EDITBOX, wzPath);
+            }
+
+            if (pidl) {
+                ::CoTaskMemFree(pidl);
+            }
+            break;
+
+        // Modify commands
+        case ID_MODIFY_BUTTON:
+            // Some variables cannot be modified
+            _engine->SetVariableString(L"InstallAllUsersState", L"disable");
+            _engine->SetVariableString(L"InstallLauncherAllUsersState", L"disable");
+            _engine->SetVariableString(L"TargetDirState", L"disable");
+            _engine->SetVariableString(L"CustomBrowseButtonState", L"disable");
+            _modifying = TRUE;
+            GoToPage(PAGE_CUSTOM1);
+            break;
+
+        case ID_REPAIR_BUTTON:
+            OnPlan(BOOTSTRAPPER_ACTION_REPAIR);
+            break;
+
+        case ID_UNINSTALL_BUTTON:
+            OnPlan(BOOTSTRAPPER_ACTION_UNINSTALL);
+            break;
+
+        case ID_SUCCESS_MAX_PATH_BUTTON:
+            EnableMaxPathSupport();
+            ThemeControlEnable(_theme, ID_SUCCESS_MAX_PATH_BUTTON, FALSE);
+            break;
+        }
+
+    LExit:
+        return;
+    }
+
+    void InstallPage_Show() {
+        // Ensure the All Users install button has a UAC shield
+        BOOL elevated = WillElevate();
+        ThemeControlElevates(_theme, ID_INSTALL_BUTTON, elevated);
+        ThemeControlElevates(_theme, ID_INSTALL_SIMPLE_BUTTON, elevated);
+        ThemeControlElevates(_theme, ID_INSTALL_UPGRADE_BUTTON, elevated);
+    }
+
+    void Custom1Page_Show() {
+        LONGLONG installLauncherAllUsers;
+
+        if (FAILED(BalGetNumericVariable(L"InstallLauncherAllUsers", &installLauncherAllUsers))) {
+            installLauncherAllUsers = 0;
+        }
+
+        ThemeSendControlMessage(_theme, ID_CUSTOM_INSTALL_LAUNCHER_ALL_USERS_CHECKBOX, BM_SETCHECK,
+            installLauncherAllUsers ? BST_CHECKED : BST_UNCHECKED, 0);
+
+        LOC_STRING *pLocString = nullptr;
+        LPCWSTR locKey = L"#(loc.Include_launcherHelp)";
+        LONGLONG detectedLauncher;
+
+        if (SUCCEEDED(BalGetNumericVariable(L"DetectedLauncher", &detectedLauncher)) && detectedLauncher) {
+            locKey = L"#(loc.Include_launcherRemove)";
+        } else if (SUCCEEDED(BalGetNumericVariable(L"DetectedOldLauncher", &detectedLauncher)) && detectedLauncher) {
+            locKey = L"#(loc.Include_launcherUpgrade)";
+        }
+
+        if (SUCCEEDED(LocGetString(_wixLoc, locKey, &pLocString)) && pLocString) {
+            ThemeSetTextControl(_theme, ID_CUSTOM_INCLUDE_LAUNCHER_HELP_LABEL, pLocString->wzText);
+        }
+    }
+
+    void Custom2Page_Show() {
+        HRESULT hr;
+        LONGLONG installAll, includeLauncher;
+        
+        if (FAILED(BalGetNumericVariable(L"InstallAllUsers", &installAll))) {
+            installAll = 0;
+        }
+
+        if (WillElevate()) {
+            ThemeControlElevates(_theme, ID_CUSTOM_INSTALL_BUTTON, TRUE);
+            ThemeShowControl(_theme, ID_CUSTOM_BROWSE_BUTTON_LABEL, SW_HIDE);
+        } else {
+            ThemeControlElevates(_theme, ID_CUSTOM_INSTALL_BUTTON, FALSE);
+            ThemeShowControl(_theme, ID_CUSTOM_BROWSE_BUTTON_LABEL, SW_SHOW);
+        }
+
+        if (SUCCEEDED(BalGetNumericVariable(L"Include_launcher", &includeLauncher)) && includeLauncher) {
+            ThemeControlEnable(_theme, ID_CUSTOM_ASSOCIATE_FILES_CHECKBOX, TRUE);
+        } else {
+            ThemeSendControlMessage(_theme, ID_CUSTOM_ASSOCIATE_FILES_CHECKBOX, BM_SETCHECK, BST_UNCHECKED, 0);
+            ThemeControlEnable(_theme, ID_CUSTOM_ASSOCIATE_FILES_CHECKBOX, FALSE);
+        }
+
+        LPWSTR targetDir = nullptr;
+        hr = BalGetStringVariable(L"TargetDir", &targetDir);
+        if (SUCCEEDED(hr) && targetDir && targetDir[0]) {
+            ThemeSetTextControl(_theme, ID_TARGETDIR_EDITBOX, targetDir);
+            StrFree(targetDir);
+        } else if (SUCCEEDED(hr)) {
+            StrFree(targetDir);
+            targetDir = nullptr;
+
+            LPWSTR defaultTargetDir = nullptr;
+            hr = BalGetStringVariable(L"DefaultCustomTargetDir", &defaultTargetDir);
+            if (SUCCEEDED(hr) && defaultTargetDir && !defaultTargetDir[0]) {
+                StrFree(defaultTargetDir);
+                defaultTargetDir = nullptr;
+                
+                hr = BalGetStringVariable(
+                    installAll ? L"DefaultAllUsersTargetDir" : L"DefaultJustForMeTargetDir",
+                    &defaultTargetDir
+                );
+            }
+            if (SUCCEEDED(hr) && defaultTargetDir) {
+                if (defaultTargetDir[0] && SUCCEEDED(BalFormatString(defaultTargetDir, &targetDir))) {
+                    ThemeSetTextControl(_theme, ID_TARGETDIR_EDITBOX, targetDir);
+                    StrFree(targetDir);
+                }
+                StrFree(defaultTargetDir);
+            }
+        }
+    }
+
+    void ModifyPage_Show() {
+        ThemeControlEnable(_theme, ID_REPAIR_BUTTON, !_suppressRepair);
+    }
+
+    void SuccessPage_Show() {
+        // on the "Success" page, check if the restart button should be enabled.
+        BOOL showRestartButton = FALSE;
+        LOC_STRING *successText = nullptr;
+        HRESULT hr = S_OK;
+        
+        if (_restartRequired) {
+            if (BOOTSTRAPPER_RESTART_PROMPT == _command.restart) {
+                showRestartButton = TRUE;
+            }
+        }
+
+        switch (_plannedAction) {
+        case BOOTSTRAPPER_ACTION_INSTALL:
+            hr = LocGetString(_wixLoc, L"#(loc.SuccessInstallMessage)", &successText);
+            break;
+        case BOOTSTRAPPER_ACTION_MODIFY:
+            hr = LocGetString(_wixLoc, L"#(loc.SuccessModifyMessage)", &successText);
+            break;
+        case BOOTSTRAPPER_ACTION_REPAIR:
+            hr = LocGetString(_wixLoc, L"#(loc.SuccessRepairMessage)", &successText);
+            break;
+        case BOOTSTRAPPER_ACTION_UNINSTALL:
+            hr = LocGetString(_wixLoc, L"#(loc.SuccessRemoveMessage)", &successText);
+            break;
+        }
+
+        if (successText) {
+            LPWSTR formattedString = nullptr;
+            BalFormatString(successText->wzText, &formattedString);
+            if (formattedString) {
+                ThemeSetTextControl(_theme, ID_SUCCESS_TEXT, formattedString);
+                StrFree(formattedString);
+            }
+        }
+
+        ThemeControlEnable(_theme, ID_SUCCESS_RESTART_TEXT, showRestartButton);
+        ThemeControlEnable(_theme, ID_SUCCESS_RESTART_BUTTON, showRestartButton);
+
+        if (_command.action != BOOTSTRAPPER_ACTION_INSTALL ||
+            !IsWindowsVersionOrGreater(10, 0, 0)) {
+            ThemeControlEnable(_theme, ID_SUCCESS_MAX_PATH_BUTTON, FALSE);
+        } else {
+            DWORD dataType = 0, buffer = 0, bufferLen = sizeof(buffer);
+            HKEY hKey;
+            LRESULT res = RegOpenKeyExW(
+                HKEY_LOCAL_MACHINE,
+                L"SYSTEM\\CurrentControlSet\\Control\\FileSystem",
+                0,
+                KEY_READ,
+                &hKey
+            );
+            if (res == ERROR_SUCCESS) {
+                res = RegQueryValueExW(hKey, L"LongPathsEnabled", nullptr, &dataType,
+                    (LPBYTE)&buffer, &bufferLen);
+                RegCloseKey(hKey);
+            }
+            else {
+                BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Failed to open SYSTEM\\CurrentControlSet\\Control\\FileSystem: error code %d", res);
+            }
+            if (res == ERROR_SUCCESS && dataType == REG_DWORD && buffer == 0) {
+                ThemeControlElevates(_theme, ID_SUCCESS_MAX_PATH_BUTTON, TRUE);
+            }
+            else {
+                if (res == ERROR_SUCCESS)
+                    BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Failed to read LongPathsEnabled value: error code %d", res);
+                else
+                    BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Hiding MAX_PATH button because it is already enabled");
+                ThemeControlEnable(_theme, ID_SUCCESS_MAX_PATH_BUTTON, FALSE);
+            }
+        }
+    }
+
+    void FailurePage_Show() {
+        // on the "Failure" page, show error message and check if the restart button should be enabled.
+
+        // if there is a log file variable then we'll assume the log file exists.
+        BOOL showLogLink = (_bundle.sczLogVariable && *_bundle.sczLogVariable);
+        BOOL showErrorMessage = FALSE;
+        BOOL showRestartButton = FALSE;
+
+        if (FAILED(_hrFinal)) {
+            LPWSTR unformattedText = nullptr;
+            LPWSTR text = nullptr;
+
+            // If we know the failure message, use that.
+            if (_failedMessage && *_failedMessage) {
+                StrAllocString(&unformattedText, _failedMessage, 0);
+            } else {
+                // try to get the error message from the error code.
+                StrAllocFromError(&unformattedText, _hrFinal, nullptr);
+                if (!unformattedText || !*unformattedText) {
+                    StrAllocFromError(&unformattedText, E_FAIL, nullptr);
+                }
+            }
+
+            if (E_WIXSTDBA_CONDITION_FAILED == _hrFinal) {
+                if (unformattedText) {
+                    StrAllocString(&text, unformattedText, 0);
+                }
+            } else {
+                StrAllocFormatted(&text, L"0x%08x - %ls", _hrFinal, unformattedText);
+            }
+
+            if (text) {
+                ThemeSetTextControl(_theme, ID_FAILURE_MESSAGE_TEXT, text);
+                showErrorMessage = TRUE;
+            }
+
+            ReleaseStr(text);
+            ReleaseStr(unformattedText);
+        }
+
+        if (_restartRequired && BOOTSTRAPPER_RESTART_PROMPT == _command.restart) {
+            showRestartButton = TRUE;
+        }
+
+        ThemeControlEnable(_theme, ID_FAILURE_LOGFILE_LINK, showLogLink);
+        ThemeControlEnable(_theme, ID_FAILURE_MESSAGE_TEXT, showErrorMessage);
+        ThemeControlEnable(_theme, ID_FAILURE_RESTART_TEXT, showRestartButton);
+        ThemeControlEnable(_theme, ID_FAILURE_RESTART_BUTTON, showRestartButton);
+    }
+
+    static void EnableMaxPathSupport() {
+        LPWSTR targetDir = nullptr, defaultDir = nullptr;
+        HRESULT hr = BalGetStringVariable(L"TargetDir", &targetDir);
+        if (FAILED(hr) || !targetDir || !targetDir[0]) {
+            BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "Failed to get TargetDir");
+            return;
+        }
+
+        LPWSTR pythonw = nullptr;
+        StrAllocFormatted(&pythonw, L"%ls\\pythonw.exe", targetDir);
+        if (!pythonw || !pythonw[0]) {
+            BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "Failed to construct pythonw.exe path");
+            return;
+        }
+
+        LPCWSTR arguments = L"-c \"import winreg; "
+            "winreg.SetValueEx("
+                "winreg.CreateKey(winreg.HKEY_LOCAL_MACHINE, "
+                    "r'SYSTEM\\CurrentControlSet\\Control\\FileSystem'), "
+                "'LongPathsEnabled', "
+                "None, "
+                "winreg.REG_DWORD, "
+                "1"
+            ")\"";
+        BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Executing %ls %ls", pythonw, arguments);
+        HINSTANCE res = ShellExecuteW(0, L"runas", pythonw, arguments, NULL, SW_HIDE);
+        BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "return code 0x%08x", res);
+    }
+
+public: // IBootstrapperApplication
+    virtual STDMETHODIMP OnStartup() {
+        HRESULT hr = S_OK;
+        DWORD dwUIThreadId = 0;
+
+        // create UI thread
+        _hUiThread = ::CreateThread(nullptr, 0, UiThreadProc, this, 0, &dwUIThreadId);
+        if (!_hUiThread) {
+            ExitWithLastError(hr, "Failed to create UI thread.");
+        }
+
+    LExit:
+        return hr;
+    }
+
+
+    virtual STDMETHODIMP_(int) OnShutdown() {
+        int nResult = IDNOACTION;
+
+        // wait for UI thread to terminate
+        if (_hUiThread) {
+            ::WaitForSingleObject(_hUiThread, INFINITE);
+            ReleaseHandle(_hUiThread);
+        }
+
+        // If a restart was required.
+        if (_restartRequired && _allowRestart) {
+            nResult = IDRESTART;
+        }
+
+        return nResult;
+    }
+
+    virtual STDMETHODIMP_(int) OnDetectRelatedMsiPackage(
+        __in_z LPCWSTR wzPackageId,
+        __in_z LPCWSTR /*wzProductCode*/,
+        __in BOOL fPerMachine,
+        __in DWORD64 /*dw64Version*/,
+        __in BOOTSTRAPPER_RELATED_OPERATION operation
+    ) {
+        if (BOOTSTRAPPER_RELATED_OPERATION_MAJOR_UPGRADE == operation && 
+            (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzPackageId, -1, L"launcher_AllUsers", -1) ||
+             CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzPackageId, -1, L"launcher_JustForMe", -1))) {
+            auto hr = LoadAssociateFilesStateFromKey(_engine, fPerMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER);
+            if (hr == S_OK) {
+                _engine->SetVariableNumeric(L"AssociateFiles", 1);
+            } else if (FAILED(hr)) {
+                BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "Failed to load AssociateFiles state: error code 0x%08X", hr);
+            }
+
+            _engine->SetVariableNumeric(L"Include_launcher", 1);
+            _engine->SetVariableNumeric(L"DetectedOldLauncher", 1);
+            _engine->SetVariableNumeric(L"InstallLauncherAllUsers", fPerMachine ? 1 : 0);
+        }
+        return CheckCanceled() ? IDCANCEL : IDNOACTION;
+    }
+
+    virtual STDMETHODIMP_(int) OnDetectRelatedBundle(
+        __in LPCWSTR wzBundleId,
+        __in BOOTSTRAPPER_RELATION_TYPE relationType,
+        __in LPCWSTR /*wzBundleTag*/,
+        __in BOOL fPerMachine,
+        __in DWORD64 /*dw64Version*/,
+        __in BOOTSTRAPPER_RELATED_OPERATION operation
+    ) {
+        BalInfoAddRelatedBundleAsPackage(&_bundle.packages, wzBundleId, relationType, fPerMachine);
+
+        // Remember when our bundle would cause a downgrade.
+        if (BOOTSTRAPPER_RELATED_OPERATION_DOWNGRADE == operation) {
+            _downgradingOtherVersion = TRUE;
+        } else if (BOOTSTRAPPER_RELATED_OPERATION_MAJOR_UPGRADE == operation) {
+            BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Detected previous version - planning upgrade");
+            _upgrading = TRUE;
+
+            LoadOptionalFeatureStates(_engine);
+        } else if (BOOTSTRAPPER_RELATED_OPERATION_NONE == operation) {
+            if (_command.action == BOOTSTRAPPER_ACTION_INSTALL) {
+                LOC_STRING *pLocString = nullptr;
+                if (SUCCEEDED(LocGetString(_wixLoc, L"#(loc.FailureExistingInstall)", &pLocString)) && pLocString) {
+                    BalFormatString(pLocString->wzText, &_failedMessage);
+                } else {
+                    BalFormatString(L"Cannot install [WixBundleName] because it is already installed.", &_failedMessage);
+                }
+                BalLog(
+                    BOOTSTRAPPER_LOG_LEVEL_ERROR,
+                    "Related bundle %ls is preventing install",
+                    wzBundleId
+                );
+                SetState(PYBA_STATE_FAILED, E_WIXSTDBA_CONDITION_FAILED);
+            }
+        }
+
+        return CheckCanceled() ? IDCANCEL : IDOK;
+    }
+
+
+    virtual STDMETHODIMP_(void) OnDetectPackageComplete(
+        __in LPCWSTR wzPackageId,
+        __in HRESULT hrStatus,
+        __in BOOTSTRAPPER_PACKAGE_STATE state
+    ) {
+        if (FAILED(hrStatus)) {
+            return;
+        }
+
+        BOOL detectedLauncher = FALSE;
+        HKEY hkey = HKEY_LOCAL_MACHINE;
+        if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzPackageId, -1, L"launcher_AllUsers", -1)) {
+            if (BOOTSTRAPPER_PACKAGE_STATE_PRESENT == state || BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE == state) {
+                detectedLauncher = TRUE;
+                _engine->SetVariableNumeric(L"InstallLauncherAllUsers", 1);
+            }
+        } else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzPackageId, -1, L"launcher_JustForMe", -1)) {
+            if (BOOTSTRAPPER_PACKAGE_STATE_PRESENT == state || BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE == state) {
+                detectedLauncher = TRUE;
+                _engine->SetVariableNumeric(L"InstallLauncherAllUsers", 0);
+            }
+        }
+
+        if (detectedLauncher) {
+            /* When we detect the current version of the launcher. */
+            _engine->SetVariableNumeric(L"Include_launcher", 1);
+            _engine->SetVariableNumeric(L"DetectedLauncher", 1);
+            _engine->SetVariableString(L"Include_launcherState", L"disable");
+            _engine->SetVariableString(L"InstallLauncherAllUsersState", L"disable");
+
+            auto hr = LoadAssociateFilesStateFromKey(_engine, hkey);
+            if (hr == S_OK) {
+                _engine->SetVariableNumeric(L"AssociateFiles", 1);
+            } else if (FAILED(hr)) {
+                BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "Failed to load AssociateFiles state: error code 0x%08X", hr);
+            }
+        }
+    }
+
+
+    virtual STDMETHODIMP_(void) OnDetectComplete(__in HRESULT hrStatus) {
+        if (SUCCEEDED(hrStatus) && _baFunction) {
+            BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Running detect complete BA function");
+            _baFunction->OnDetectComplete();
+        }
+
+        if (SUCCEEDED(hrStatus)) {
+            hrStatus = EvaluateConditions();
+        }
+
+        if (SUCCEEDED(hrStatus)) {
+            // Ensure the default path has been set
+            hrStatus = EnsureTargetDir();
+        }
+
+        SetState(PYBA_STATE_DETECTED, hrStatus);
+
+        // If we're not interacting with the user or we're doing a layout or we're just after a force restart
+        // then automatically start planning.
+        if (BOOTSTRAPPER_DISPLAY_FULL > _command.display ||
+            BOOTSTRAPPER_ACTION_LAYOUT == _command.action ||
+            BOOTSTRAPPER_ACTION_UNINSTALL == _command.action ||
+            BOOTSTRAPPER_RESUME_TYPE_REBOOT == _command.resumeType) {
+            if (SUCCEEDED(hrStatus)) {
+                ::PostMessageW(_hWnd, WM_PYBA_PLAN_PACKAGES, 0, _command.action);
+            }
+        }
+    }
+
+
+    virtual STDMETHODIMP_(int) OnPlanRelatedBundle(
+        __in_z LPCWSTR /*wzBundleId*/,
+        __inout_z BOOTSTRAPPER_REQUEST_STATE* pRequestedState
+    ) {
+        return CheckCanceled() ? IDCANCEL : IDOK;
+    }
+
+
+    virtual STDMETHODIMP_(int) OnPlanPackageBegin(
+        __in_z LPCWSTR wzPackageId,
+        __inout BOOTSTRAPPER_REQUEST_STATE *pRequestState
+    ) {
+        HRESULT hr = S_OK;
+        BAL_INFO_PACKAGE* pPackage = nullptr;
+
+        if (_nextPackageAfterRestart) {
+            // After restart we need to finish the dependency registration for our package so allow the package
+            // to go present.
+            if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzPackageId, -1, _nextPackageAfterRestart, -1)) {
+                // Do not allow a repair because that could put us in a perpetual restart loop.
+                if (BOOTSTRAPPER_REQUEST_STATE_REPAIR == *pRequestState) {
+                    *pRequestState = BOOTSTRAPPER_REQUEST_STATE_PRESENT;
+                }
+
+                ReleaseNullStr(_nextPackageAfterRestart); // no more skipping now.
+            } else {
+                // not the matching package, so skip it.
+                BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Skipping package: %ls, after restart because it was applied before the restart.", wzPackageId);
+
+                *pRequestState = BOOTSTRAPPER_REQUEST_STATE_NONE;
+            }
+        } else if ((_plannedAction == BOOTSTRAPPER_ACTION_INSTALL || _plannedAction == BOOTSTRAPPER_ACTION_MODIFY) &&
+                   SUCCEEDED(BalInfoFindPackageById(&_bundle.packages, wzPackageId, &pPackage))) {
+            BOOL f = FALSE;
+            if (SUCCEEDED(_engine->EvaluateCondition(pPackage->sczInstallCondition, &f)) && f) {
+                *pRequestState = BOOTSTRAPPER_REQUEST_STATE_PRESENT;
+            }
+        }
+
+        return CheckCanceled() ? IDCANCEL : IDOK;
+    }
+
+    virtual STDMETHODIMP_(int) OnPlanMsiFeature(
+        __in_z LPCWSTR wzPackageId,
+        __in_z LPCWSTR wzFeatureId,
+        __inout BOOTSTRAPPER_FEATURE_STATE* pRequestedState
+    ) {
+        LONGLONG install;
+        
+        if (wcscmp(wzFeatureId, L"AssociateFiles") == 0 || wcscmp(wzFeatureId, L"Shortcuts") == 0) {
+            if (SUCCEEDED(_engine->GetVariableNumeric(wzFeatureId, &install)) && install) {
+                *pRequestedState = BOOTSTRAPPER_FEATURE_STATE_LOCAL;
+            } else {
+                *pRequestedState = BOOTSTRAPPER_FEATURE_STATE_ABSENT;
+            }
+        } else {
+            *pRequestedState = BOOTSTRAPPER_FEATURE_STATE_LOCAL;
+        }
+        return CheckCanceled() ? IDCANCEL : IDNOACTION;
+    }
+
+    virtual STDMETHODIMP_(void) OnPlanComplete(__in HRESULT hrStatus) {
+        if (SUCCEEDED(hrStatus) && _baFunction) {
+            BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Running plan complete BA function");
+            _baFunction->OnPlanComplete();
+        }
+
+        SetState(PYBA_STATE_PLANNED, hrStatus);
+
+        if (SUCCEEDED(hrStatus)) {
+            ::PostMessageW(_hWnd, WM_PYBA_APPLY_PACKAGES, 0, 0);
+        }
+
+        _startedExecution = FALSE;
+        _calculatedCacheProgress = 0;
+        _calculatedExecuteProgress = 0;
+    }
+
+
+    virtual STDMETHODIMP_(int) OnCachePackageBegin(
+        __in_z LPCWSTR wzPackageId,
+        __in DWORD cCachePayloads,
+        __in DWORD64 dw64PackageCacheSize
+    ) {
+        if (wzPackageId && *wzPackageId) {
+            BAL_INFO_PACKAGE* pPackage = nullptr;
+            HRESULT hr = BalInfoFindPackageById(&_bundle.packages, wzPackageId, &pPackage);
+            LPCWSTR wz = (SUCCEEDED(hr) && pPackage->sczDisplayName) ? pPackage->sczDisplayName : wzPackageId;
+
+            ThemeSetTextControl(_theme, ID_CACHE_PROGRESS_PACKAGE_TEXT, wz);
+
+            // If something started executing, leave it in the overall progress text.
+            if (!_startedExecution) {
+                ThemeSetTextControl(_theme, ID_OVERALL_PROGRESS_PACKAGE_TEXT, wz);
+            }
+        }
+
+        return __super::OnCachePackageBegin(wzPackageId, cCachePayloads, dw64PackageCacheSize);
+    }
+
+
+    virtual STDMETHODIMP_(int) OnCacheAcquireProgress(
+        __in_z LPCWSTR wzPackageOrContainerId,
+        __in_z_opt LPCWSTR wzPayloadId,
+        __in DWORD64 dw64Progress,
+        __in DWORD64 dw64Total,
+        __in DWORD dwOverallPercentage
+    ) {
+        WCHAR wzProgress[5] = { };
+
+#ifdef DEBUG
+        BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "PYBA: OnCacheAcquireProgress() - container/package: %ls, payload: %ls, progress: %I64u, total: %I64u, overall progress: %u%%", wzPackageOrContainerId, wzPayloadId, dw64Progress, dw64Total, dwOverallPercentage);
+#endif
+
+        ::StringCchPrintfW(wzProgress, countof(wzProgress), L"%u%%", dwOverallPercentage);
+        ThemeSetTextControl(_theme, ID_CACHE_PROGRESS_TEXT, wzProgress);
+
+        ThemeSetProgressControl(_theme, ID_CACHE_PROGRESS_BAR, dwOverallPercentage);
+
+        _calculatedCacheProgress = dwOverallPercentage * PYBA_ACQUIRE_PERCENTAGE / 100;
+        ThemeSetProgressControl(_theme, ID_OVERALL_CALCULATED_PROGRESS_BAR, _calculatedCacheProgress + _calculatedExecuteProgress);
+
+        SetTaskbarButtonProgress(_calculatedCacheProgress + _calculatedExecuteProgress);
+
+        return __super::OnCacheAcquireProgress(wzPackageOrContainerId, wzPayloadId, dw64Progress, dw64Total, dwOverallPercentage);
+    }
+
+
+    virtual STDMETHODIMP_(int) OnCacheAcquireComplete(
+        __in_z LPCWSTR wzPackageOrContainerId,
+        __in_z_opt LPCWSTR wzPayloadId,
+        __in HRESULT hrStatus,
+        __in int nRecommendation
+    ) {
+        SetProgressState(hrStatus);
+        return __super::OnCacheAcquireComplete(wzPackageOrContainerId, wzPayloadId, hrStatus, nRecommendation);
+    }
+
+
+    virtual STDMETHODIMP_(int) OnCacheVerifyComplete(
+        __in_z LPCWSTR wzPackageId,
+        __in_z LPCWSTR wzPayloadId,
+        __in HRESULT hrStatus,
+        __in int nRecommendation
+    ) {
+        SetProgressState(hrStatus);
+        return __super::OnCacheVerifyComplete(wzPackageId, wzPayloadId, hrStatus, nRecommendation);
+    }
+
+
+    virtual STDMETHODIMP_(void) OnCacheComplete(__in HRESULT /*hrStatus*/) {
+        ThemeSetTextControl(_theme, ID_CACHE_PROGRESS_PACKAGE_TEXT, L"");
+        SetState(PYBA_STATE_CACHED, S_OK); // we always return success here and let OnApplyComplete() deal with the error.
+    }
+
+
+    virtual STDMETHODIMP_(int) OnError(
+        __in BOOTSTRAPPER_ERROR_TYPE errorType,
+        __in LPCWSTR wzPackageId,
+        __in DWORD dwCode,
+        __in_z LPCWSTR wzError,
+        __in DWORD dwUIHint,
+        __in DWORD /*cData*/,
+        __in_ecount_z_opt(cData) LPCWSTR* /*rgwzData*/,
+        __in int nRecommendation
+    ) {
+        int nResult = nRecommendation;
+        LPWSTR sczError = nullptr;
+
+        if (BOOTSTRAPPER_DISPLAY_EMBEDDED == _command.display) {
+            HRESULT hr = _engine->SendEmbeddedError(dwCode, wzError, dwUIHint, &nResult);
+            if (FAILED(hr)) {
+                nResult = IDERROR;
+            }
+        } else if (BOOTSTRAPPER_DISPLAY_FULL == _command.display) {
+            // If this is an authentication failure, let the engine try to handle it for us.
+            if (BOOTSTRAPPER_ERROR_TYPE_HTTP_AUTH_SERVER == errorType || BOOTSTRAPPER_ERROR_TYPE_HTTP_AUTH_PROXY == errorType) {
+                nResult = IDTRYAGAIN;
+            } else // show a generic error message box.
+            {
+                BalRetryErrorOccurred(wzPackageId, dwCode);
+
+                if (!_showingInternalUIThisPackage) {
+                    // If no error message was provided, use the error code to try and get an error message.
+                    if (!wzError || !*wzError || BOOTSTRAPPER_ERROR_TYPE_WINDOWS_INSTALLER != errorType) {
+                        HRESULT hr = StrAllocFromError(&sczError, dwCode, nullptr);
+                        if (FAILED(hr) || !sczError || !*sczError) {
+                            StrAllocFormatted(&sczError, L"0x%x", dwCode);
+                        }
+                    }
+
+                    nResult = ::MessageBoxW(_hWnd, sczError ? sczError : wzError, _theme->sczCaption, dwUIHint);
+                }
+            }
+
+            SetProgressState(HRESULT_FROM_WIN32(dwCode));
+        } else {
+            // just take note of the error code and let things continue.
+            BalRetryErrorOccurred(wzPackageId, dwCode);
+        }
+
+        ReleaseStr(sczError);
+        return nResult;
+    }
+
+
+    virtual STDMETHODIMP_(int) OnExecuteMsiMessage(
+        __in_z LPCWSTR wzPackageId,
+        __in INSTALLMESSAGE mt,
+        __in UINT uiFlags,
+        __in_z LPCWSTR wzMessage,
+        __in DWORD cData,
+        __in_ecount_z_opt(cData) LPCWSTR* rgwzData,
+        __in int nRecommendation
+    ) {
+#ifdef DEBUG
+        BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "PYBA: OnExecuteMsiMessage() - package: %ls, message: %ls", wzPackageId, wzMessage);
+#endif
+        if (BOOTSTRAPPER_DISPLAY_FULL == _command.display && (INSTALLMESSAGE_WARNING == mt || INSTALLMESSAGE_USER == mt)) {
+            int nResult = ::MessageBoxW(_hWnd, wzMessage, _theme->sczCaption, uiFlags);
+            return nResult;
+        }
+
+        if (INSTALLMESSAGE_ACTIONSTART == mt) {
+            ThemeSetTextControl(_theme, ID_EXECUTE_PROGRESS_ACTIONDATA_TEXT, wzMessage);
+        }
+
+        return __super::OnExecuteMsiMessage(wzPackageId, mt, uiFlags, wzMessage, cData, rgwzData, nRecommendation);
+    }
+
+
+    virtual STDMETHODIMP_(int) OnProgress(__in DWORD dwProgressPercentage, __in DWORD dwOverallProgressPercentage) {
+        WCHAR wzProgress[5] = { };
+
+#ifdef DEBUG
+        BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "PYBA: OnProgress() - progress: %u%%, overall progress: %u%%", dwProgressPercentage, dwOverallProgressPercentage);
+#endif
+
+        ::StringCchPrintfW(wzProgress, countof(wzProgress), L"%u%%", dwOverallProgressPercentage);
+        ThemeSetTextControl(_theme, ID_OVERALL_PROGRESS_TEXT, wzProgress);
+
+        ThemeSetProgressControl(_theme, ID_OVERALL_PROGRESS_BAR, dwOverallProgressPercentage);
+        SetTaskbarButtonProgress(dwOverallProgressPercentage);
+
+        return __super::OnProgress(dwProgressPercentage, dwOverallProgressPercentage);
+    }
+
+
+    virtual STDMETHODIMP_(int) OnExecutePackageBegin(__in_z LPCWSTR wzPackageId, __in BOOL fExecute) {
+        LPWSTR sczFormattedString = nullptr;
+
+        _startedExecution = TRUE;
+
+        if (wzPackageId && *wzPackageId) {
+            BAL_INFO_PACKAGE* pPackage = nullptr;
+            BalInfoFindPackageById(&_bundle.packages, wzPackageId, &pPackage);
+
+            LPCWSTR wz = wzPackageId;
+            if (pPackage) {
+                LOC_STRING* pLocString = nullptr;
+
+                switch (pPackage->type) {
+                case BAL_INFO_PACKAGE_TYPE_BUNDLE_ADDON:
+                    LocGetString(_wixLoc, L"#(loc.ExecuteAddonRelatedBundleMessage)", &pLocString);
+                    break;
+
+                case BAL_INFO_PACKAGE_TYPE_BUNDLE_PATCH:
+                    LocGetString(_wixLoc, L"#(loc.ExecutePatchRelatedBundleMessage)", &pLocString);
+                    break;
+
+                case BAL_INFO_PACKAGE_TYPE_BUNDLE_UPGRADE:
+                    LocGetString(_wixLoc, L"#(loc.ExecuteUpgradeRelatedBundleMessage)", &pLocString);
+                    break;
+                }
+
+                if (pLocString) {
+                    // If the wix developer is showing a hidden variable in the UI, then obviously they don't care about keeping it safe
+                    // so don't go down the rabbit hole of making sure that this is securely freed.
+                    BalFormatString(pLocString->wzText, &sczFormattedString);
+                }
+
+                wz = sczFormattedString ? sczFormattedString : pPackage->sczDisplayName ? pPackage->sczDisplayName : wzPackageId;
+            }
+
+            _showingInternalUIThisPackage = pPackage && pPackage->fDisplayInternalUI;
+
+            ThemeSetTextControl(_theme, ID_EXECUTE_PROGRESS_PACKAGE_TEXT, wz);
+            ThemeSetTextControl(_theme, ID_OVERALL_PROGRESS_PACKAGE_TEXT, wz);
+        } else {
+            _showingInternalUIThisPackage = FALSE;
+        }
+
+        ReleaseStr(sczFormattedString);
+        return __super::OnExecutePackageBegin(wzPackageId, fExecute);
+    }
+
+
+    virtual int __stdcall OnExecuteProgress(
+        __in_z LPCWSTR wzPackageId,
+        __in DWORD dwProgressPercentage,
+        __in DWORD dwOverallProgressPercentage
+    ) {
+        WCHAR wzProgress[8] = { };
+
+#ifdef DEBUG
+        BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "PYBA: OnExecuteProgress() - package: %ls, progress: %u%%, overall progress: %u%%", wzPackageId, dwProgressPercentage, dwOverallProgressPercentage);
+#endif
+
+        ::StringCchPrintfW(wzProgress, countof(wzProgress), L"%u%%", dwOverallProgressPercentage);
+        ThemeSetTextControl(_theme, ID_EXECUTE_PROGRESS_TEXT, wzProgress);
+
+        ThemeSetProgressControl(_theme, ID_EXECUTE_PROGRESS_BAR, dwOverallProgressPercentage);
+
+        _calculatedExecuteProgress = dwOverallProgressPercentage * (100 - PYBA_ACQUIRE_PERCENTAGE) / 100;
+        ThemeSetProgressControl(_theme, ID_OVERALL_CALCULATED_PROGRESS_BAR, _calculatedCacheProgress + _calculatedExecuteProgress);
+
+        SetTaskbarButtonProgress(_calculatedCacheProgress + _calculatedExecuteProgress);
+
+        return __super::OnExecuteProgress(wzPackageId, dwProgressPercentage, dwOverallProgressPercentage);
+    }
+
+
+    virtual STDMETHODIMP_(int) OnExecutePackageComplete(
+        __in_z LPCWSTR wzPackageId,
+        __in HRESULT hrExitCode,
+        __in BOOTSTRAPPER_APPLY_RESTART restart,
+        __in int nRecommendation
+    ) {
+        SetProgressState(hrExitCode);
+
+        if (_wcsnicmp(wzPackageId, L"path_", 5) == 0 && SUCCEEDED(hrExitCode)) {
+            SendMessageTimeoutW(
+                HWND_BROADCAST,
+                WM_SETTINGCHANGE,
+                0,
+                reinterpret_cast<LPARAM>(L"Environment"),
+                SMTO_ABORTIFHUNG,
+                1000,
+                nullptr
+            );
+        }
+
+        int nResult = __super::OnExecutePackageComplete(wzPackageId, hrExitCode, restart, nRecommendation);
+
+        return nResult;
+    }
+
+
+    virtual STDMETHODIMP_(void) OnExecuteComplete(__in HRESULT hrStatus) {
+        ThemeSetTextControl(_theme, ID_EXECUTE_PROGRESS_PACKAGE_TEXT, L"");
+        ThemeSetTextControl(_theme, ID_EXECUTE_PROGRESS_ACTIONDATA_TEXT, L"");
+        ThemeSetTextControl(_theme, ID_OVERALL_PROGRESS_PACKAGE_TEXT, L"");
+        ThemeControlEnable(_theme, ID_PROGRESS_CANCEL_BUTTON, FALSE); // no more cancel.
+
+        SetState(PYBA_STATE_EXECUTED, S_OK); // we always return success here and let OnApplyComplete() deal with the error.
+        SetProgressState(hrStatus);
+    }
+
+
+    virtual STDMETHODIMP_(int) OnResolveSource(
+        __in_z LPCWSTR wzPackageOrContainerId,
+        __in_z_opt LPCWSTR wzPayloadId,
+        __in_z LPCWSTR wzLocalSource,
+        __in_z_opt LPCWSTR wzDownloadSource
+    ) {
+        int nResult = IDERROR; // assume we won't resolve source and that is unexpected.
+
+        if (BOOTSTRAPPER_DISPLAY_FULL == _command.display) {
+            if (wzDownloadSource) {
+                nResult = IDDOWNLOAD;
+            } else {
+                // prompt to change the source location.
+                OPENFILENAMEW ofn = { };
+                WCHAR wzFile[MAX_PATH] = { };
+
+                ::StringCchCopyW(wzFile, countof(wzFile), wzLocalSource);
+
+                ofn.lStructSize = sizeof(ofn);
+                ofn.hwndOwner = _hWnd;
+                ofn.lpstrFile = wzFile;
+                ofn.nMaxFile = countof(wzFile);
+                ofn.lpstrFilter = L"All Files\0*.*\0";
+                ofn.nFilterIndex = 1;
+                ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
+                ofn.lpstrTitle = _theme->sczCaption;
+
+                if (::GetOpenFileNameW(&ofn)) {
+                    HRESULT hr = _engine->SetLocalSource(wzPackageOrContainerId, wzPayloadId, ofn.lpstrFile);
+                    nResult = SUCCEEDED(hr) ? IDRETRY : IDERROR;
+                } else {
+                    nResult = IDCANCEL;
+                }
+            }
+        } else if (wzDownloadSource) {
+            // If doing a non-interactive install and download source is available, let's try downloading the package silently
+            nResult = IDDOWNLOAD;
+        }
+        // else there's nothing more we can do in non-interactive mode
+
+        return CheckCanceled() ? IDCANCEL : nResult;
+    }
+
+
+    virtual STDMETHODIMP_(int) OnApplyComplete(__in HRESULT hrStatus, __in BOOTSTRAPPER_APPLY_RESTART restart) {
+        _restartResult = restart; // remember the restart result so we return the correct error code no matter what the user chooses to do in the UI.
+
+        // If a restart was encountered and we are not suppressing restarts, then restart is required.
+        _restartRequired = (BOOTSTRAPPER_APPLY_RESTART_NONE != restart && BOOTSTRAPPER_RESTART_NEVER < _command.restart);
+        // If a restart is required and we're not displaying a UI or we are not supposed to prompt for restart then allow the restart.
+        _allowRestart = _restartRequired && (BOOTSTRAPPER_DISPLAY_FULL > _command.display || BOOTSTRAPPER_RESTART_PROMPT < _command.restart);
+
+        // If we are showing UI, wait a beat before moving to the final screen.
+        if (BOOTSTRAPPER_DISPLAY_NONE < _command.display) {
+            ::Sleep(250);
+        }
+
+        SetState(PYBA_STATE_APPLIED, hrStatus);
+        SetTaskbarButtonProgress(100); // show full progress bar, green, yellow, or red
+
+        return IDNOACTION;
+    }
+
+    virtual STDMETHODIMP_(void) OnLaunchApprovedExeComplete(__in HRESULT hrStatus, __in DWORD /*processId*/) {
+    }
+
+
+private:
+    //
+    // UiThreadProc - entrypoint for UI thread.
+    //
+    static DWORD WINAPI UiThreadProc(__in LPVOID pvContext) {
+        HRESULT hr = S_OK;
+        PythonBootstrapperApplication* pThis = (PythonBootstrapperApplication*)pvContext;
+        BOOL comInitialized = FALSE;
+        BOOL ret = FALSE;
+        MSG msg = { };
+
+        // Initialize COM and theme.
+        hr = ::CoInitialize(nullptr);
+        BalExitOnFailure(hr, "Failed to initialize COM.");
+        comInitialized = TRUE;
+
+        hr = ThemeInitialize(pThis->_hModule);
+        BalExitOnFailure(hr, "Failed to initialize theme manager.");
+
+        hr = pThis->InitializeData();
+        BalExitOnFailure(hr, "Failed to initialize data in bootstrapper application.");
+
+        // Create main window.
+        pThis->InitializeTaskbarButton();
+        hr = pThis->CreateMainWindow();
+        BalExitOnFailure(hr, "Failed to create main window.");
+
+        pThis->ValidateOperatingSystem();
+
+        if (FAILED(pThis->_hrFinal)) {
+            pThis->SetState(PYBA_STATE_FAILED, hr);
+            ::PostMessageW(pThis->_hWnd, WM_PYBA_SHOW_FAILURE, 0, 0);
+        } else {
+            // Okay, we're ready for packages now.
+            pThis->SetState(PYBA_STATE_INITIALIZED, hr);
+            ::PostMessageW(pThis->_hWnd, BOOTSTRAPPER_ACTION_HELP == pThis->_command.action ? WM_PYBA_SHOW_HELP : WM_PYBA_DETECT_PACKAGES, 0, 0);
+        }
+
+        // message pump
+        while (0 != (ret = ::GetMessageW(&msg, nullptr, 0, 0))) {
+            if (-1 == ret) {
+                hr = E_UNEXPECTED;
+                BalExitOnFailure(hr, "Unexpected return value from message pump.");
+            } else if (!ThemeHandleKeyboardMessage(pThis->_theme, msg.hwnd, &msg)) {
+                ::TranslateMessage(&msg);
+                ::DispatchMessageW(&msg);
+            }
+        }
+
+        // Succeeded thus far, check to see if anything went wrong while actually
+        // executing changes.
+        if (FAILED(pThis->_hrFinal)) {
+            hr = pThis->_hrFinal;
+        } else if (pThis->CheckCanceled()) {
+            hr = HRESULT_FROM_WIN32(ERROR_INSTALL_USEREXIT);
+        }
+
+    LExit:
+        // destroy main window
+        pThis->DestroyMainWindow();
+
+        // initiate engine shutdown
+        DWORD dwQuit = HRESULT_CODE(hr);
+        if (BOOTSTRAPPER_APPLY_RESTART_INITIATED == pThis->_restartResult) {
+            dwQuit = ERROR_SUCCESS_REBOOT_INITIATED;
+        } else if (BOOTSTRAPPER_APPLY_RESTART_REQUIRED == pThis->_restartResult) {
+            dwQuit = ERROR_SUCCESS_REBOOT_REQUIRED;
+        }
+        pThis->_engine->Quit(dwQuit);
+
+        ReleaseTheme(pThis->_theme);
+        ThemeUninitialize();
+
+        // uninitialize COM
+        if (comInitialized) {
+            ::CoUninitialize();
+        }
+
+        return hr;
+    }
+
+    //
+    // ParseVariablesFromUnattendXml - reads options from unattend.xml if it
+    // exists
+    //
+    HRESULT ParseVariablesFromUnattendXml() {
+        HRESULT hr = S_OK;
+        LPWSTR sczUnattendXmlPath = nullptr;
+        IXMLDOMDocument *pixdUnattend = nullptr;
+        IXMLDOMNodeList *pNodes = nullptr;
+        IXMLDOMNode *pNode = nullptr;
+        long cNodes;
+        DWORD dwAttr;
+        LPWSTR scz = nullptr;
+        BOOL bValue;
+        int iValue;
+        BOOL tryConvert;
+        BSTR bstrValue = nullptr;
+
+        hr = BalFormatString(L"[WixBundleOriginalSourceFolder]unattend.xml", &sczUnattendXmlPath);
+        BalExitOnFailure(hr, "Failed to calculate path to unattend.xml");
+
+        if (!FileExistsEx(sczUnattendXmlPath, &dwAttr)) {
+            BalLog(BOOTSTRAPPER_LOG_LEVEL_VERBOSE, "Did not find %ls", sczUnattendXmlPath);
+            hr = S_FALSE;
+            goto LExit;
+        }
+
+        hr = XmlLoadDocumentFromFile(sczUnattendXmlPath, &pixdUnattend);
+        BalExitOnFailure1(hr, "Failed to read %ls", sczUnattendXmlPath);
+
+        // get the list of variables users have overridden
+        hr = XmlSelectNodes(pixdUnattend, L"/Options/Option", &pNodes);
+        if (S_FALSE == hr) {
+            ExitFunction1(hr = S_OK);
+        }
+        BalExitOnFailure(hr, "Failed to select option nodes.");
+
+        hr = pNodes->get_length((long*)&cNodes);
+        BalExitOnFailure(hr, "Failed to get option node count.");
+
+        BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Reading settings from %ls", sczUnattendXmlPath);
+
+        for (DWORD i = 0; i < cNodes; ++i) {
+            hr = XmlNextElement(pNodes, &pNode, nullptr);
+            BalExitOnFailure(hr, "Failed to get next node.");
+
+            // @Name
+            hr = XmlGetAttributeEx(pNode, L"Name", &scz);
+            BalExitOnFailure(hr, "Failed to get @Name.");
+
+            tryConvert = TRUE;
+            hr = XmlGetAttribute(pNode, L"Value", &bstrValue);
+            if (FAILED(hr) || !bstrValue || !*bstrValue) {
+                hr = XmlGetText(pNode, &bstrValue);
+                tryConvert = FALSE;
+            }
+            BalExitOnFailure(hr, "Failed to get @Value.");
+
+            if (tryConvert &&
+                CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, bstrValue, -1, L"yes", -1)) {
+                _engine->SetVariableNumeric(scz, 1);
+            } else if (tryConvert &&
+                       CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, bstrValue, -1, L"no", -1)) {
+                _engine->SetVariableNumeric(scz, 0);
+            } else if (tryConvert && ::StrToIntExW(bstrValue, STIF_DEFAULT, &iValue)) {
+                _engine->SetVariableNumeric(scz, iValue);
+            } else {
+                _engine->SetVariableString(scz, bstrValue);
+            }
+
+            ReleaseNullBSTR(bstrValue);
+            ReleaseNullStr(scz);
+            ReleaseNullObject(pNode);
+        }
+
+        BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Finished reading from %ls", sczUnattendXmlPath);
+
+    LExit:
+        ReleaseObject(pNode);
+        ReleaseObject(pNodes);
+        ReleaseObject(pixdUnattend);
+        ReleaseStr(sczUnattendXmlPath);
+
+        return hr;
+    }
+
+
+    //
+    // InitializeData - initializes all the package information.
+    //
+    HRESULT InitializeData() {
+        HRESULT hr = S_OK;
+        LPWSTR sczModulePath = nullptr;
+        IXMLDOMDocument *pixdManifest = nullptr;
+
+        hr = BalManifestLoad(_hModule, &pixdManifest);
+        BalExitOnFailure(hr, "Failed to load bootstrapper application manifest.");
+
+        hr = ParseOverridableVariablesFromXml(pixdManifest);
+        BalExitOnFailure(hr, "Failed to read overridable variables.");
+
+        hr = ParseVariablesFromUnattendXml();
+        ExitOnFailure(hr, "Failed to read unattend.ini file.");
+
+        hr = ProcessCommandLine(&_language);
+        ExitOnFailure(hr, "Unknown commandline parameters.");
+
+        hr = PathRelativeToModule(&sczModulePath, nullptr, _hModule);
+        BalExitOnFailure(hr, "Failed to get module path.");
+
+        hr = LoadLocalization(sczModulePath, _language);
+        ExitOnFailure(hr, "Failed to load localization.");
+
+        hr = LoadTheme(sczModulePath, _language);
+        ExitOnFailure(hr, "Failed to load theme.");
+
+        hr = BalInfoParseFromXml(&_bundle, pixdManifest);
+        BalExitOnFailure(hr, "Failed to load bundle information.");
+
+        hr = BalConditionsParseFromXml(&_conditions, pixdManifest, _wixLoc);
+        BalExitOnFailure(hr, "Failed to load conditions from XML.");
+
+        hr = LoadBootstrapperBAFunctions();
+        BalExitOnFailure(hr, "Failed to load bootstrapper functions.");
+
+        hr = UpdateUIStrings(_command.action);
+        BalExitOnFailure(hr, "Failed to load UI strings.");
+
+        if (_command.action == BOOTSTRAPPER_ACTION_MODIFY) {
+            LoadOptionalFeatureStates(_engine);
+        }
+
+        GetBundleFileVersion();
+        // don't fail if we couldn't get the version info; best-effort only
+    LExit:
+        ReleaseObject(pixdManifest);
+        ReleaseStr(sczModulePath);
+
+        return hr;
+    }
+
+
+    //
+    // ProcessCommandLine - process the provided command line arguments.
+    //
+    HRESULT ProcessCommandLine(__inout LPWSTR* psczLanguage) {
+        HRESULT hr = S_OK;
+        int argc = 0;
+        LPWSTR* argv = nullptr;
+        LPWSTR sczVariableName = nullptr;
+        LPWSTR sczVariableValue = nullptr;
+
+        if (_command.wzCommandLine && *_command.wzCommandLine) {
+            argv = ::CommandLineToArgvW(_command.wzCommandLine, &argc);
+            ExitOnNullWithLastError(argv, hr, "Failed to get command line.");
+
+            for (int i = 0; i < argc; ++i) {
+                if (argv[i][0] == L'-' || argv[i][0] == L'/') {
+                    if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"lang", -1)) {
+                        if (i + 1 >= argc) {
+                            hr = E_INVALIDARG;
+                            BalExitOnFailure(hr, "Must specify a language.");
+                        }
+
+                        ++i;
+
+                        hr = StrAllocString(psczLanguage, &argv[i][0], 0);
+                        BalExitOnFailure(hr, "Failed to copy language.");
+                    } else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], -1, L"simple", -1)) {
+                        _engine->SetVariableNumeric(L"SimpleInstall", 1);
+                    }
+                } else if (_overridableVariables) {
+                    int value;
+                    const wchar_t* pwc = wcschr(argv[i], L'=');
+                    if (pwc) {
+                        hr = StrAllocString(&sczVariableName, argv[i], pwc - argv[i]);
+                        BalExitOnFailure(hr, "Failed to copy variable name.");
+
+                        hr = DictKeyExists(_overridableVariables, sczVariableName);
+                        if (E_NOTFOUND == hr) {
+                            BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "Ignoring attempt to set non-overridable variable: '%ls'.", sczVariableName);
+                            hr = S_OK;
+                            continue;
+                        }
+                        ExitOnFailure(hr, "Failed to check the dictionary of overridable variables.");
+
+                        hr = StrAllocString(&sczVariableValue, ++pwc, 0);
+                        BalExitOnFailure(hr, "Failed to copy variable value.");
+
+                        if (::StrToIntEx(sczVariableValue, STIF_DEFAULT, &value)) {
+                            hr = _engine->SetVariableNumeric(sczVariableName, value);
+                        } else {
+                            hr = _engine->SetVariableString(sczVariableName, sczVariableValue);
+                        }
+                        BalExitOnFailure(hr, "Failed to set variable.");
+                    } else {
+                        BalLog(BOOTSTRAPPER_LOG_LEVEL_STANDARD, "Ignoring unknown argument: %ls", argv[i]);
+                    }
+                }
+            }
+        }
+
+    LExit:
+        if (argv) {
+            ::LocalFree(argv);
+        }
+
+        ReleaseStr(sczVariableName);
+        ReleaseStr(sczVariableValue);
+
+        return hr;
+    }
+
+    HRESULT LoadLocalization(__in_z LPCWSTR wzModulePath, __in_z_opt LPCWSTR wzLanguage) {
+        HRESULT hr = S_OK;
+        LPWSTR sczLocPath = nullptr;
+        LPCWSTR wzLocFileName = L"Default.wxl";
+
+        hr = LocProbeForFile(wzModulePath, wzLocFileName, wzLanguage, &sczLocPath);
+        BalExitOnFailure2(hr, "Failed to probe for loc file: %ls in path: %ls", wzLocFileName, wzModulePath);
+
+        hr = LocLoadFromFile(sczLocPath, &_wixLoc);
+        BalExitOnFailure1(hr, "Failed to load loc file from path: %ls", sczLocPath);
+
+        if (WIX_LOCALIZATION_LANGUAGE_NOT_SET != _wixLoc->dwLangId) {
+            ::SetThreadLocale(_wixLoc->dwLangId);
+        }
+
+        hr = StrAllocString(&_confirmCloseMessage, L"#(loc.ConfirmCancelMessage)", 0);
+        ExitOnFailure(hr, "Failed to initialize confirm message loc identifier.");
+
+        hr = LocLocalizeString(_wixLoc, &_confirmCloseMessage);
+        BalExitOnFailure1(hr, "Failed to localize confirm close message: %ls", _confirmCloseMessage);
+
+    LExit:
+        ReleaseStr(sczLocPath);
+
+        return hr;
+    }
+
+
+    HRESULT LoadTheme(__in_z LPCWSTR wzModulePath, __in_z_opt LPCWSTR wzLanguage) {
+        HRESULT hr = S_OK;
+        LPWSTR sczThemePath = nullptr;
+        LPCWSTR wzThemeFileName = L"Default.thm";
+        LPWSTR sczCaption = nullptr;
+
+        hr = LocProbeForFile(wzModulePath, wzThemeFileName, wzLanguage, &sczThemePath);
+        BalExitOnFailure2(hr, "Failed to probe for theme file: %ls in path: %ls", wzThemeFileName, wzModulePath);
+
+        hr = ThemeLoadFromFile(sczThemePath, &_theme);
+        BalExitOnFailure1(hr, "Failed to load theme from path: %ls", sczThemePath);
+
+        hr = ThemeLocalize(_theme, _wixLoc);
+        BalExitOnFailure1(hr, "Failed to localize theme: %ls", sczThemePath);
+
+        // Update the caption if there are any formatted strings in it.
+        // If the wix developer is showing a hidden variable in the UI, then
+        // obviously they don't care about keeping it safe so don't go down the
+        // rabbit hole of making sure that this is securely freed.
+        hr = BalFormatString(_theme->sczCaption, &sczCaption);
+        if (SUCCEEDED(hr)) {
+            ThemeUpdateCaption(_theme, sczCaption);
+        }
+
+    LExit:
+        ReleaseStr(sczCaption);
+        ReleaseStr(sczThemePath);
+
+        return hr;
+    }
+
+
+    HRESULT ParseOverridableVariablesFromXml(__in IXMLDOMDocument* pixdManifest) {
+        HRESULT hr = S_OK;
+        IXMLDOMNode* pNode = nullptr;
+        IXMLDOMNodeList* pNodes = nullptr;
+        DWORD cNodes = 0;
+        LPWSTR scz = nullptr;
+        BOOL hidden = FALSE;
+
+        // get the list of variables users can override on the command line
+        hr = XmlSelectNodes(pixdManifest, L"/BootstrapperApplicationData/WixStdbaOverridableVariable", &pNodes);
+        if (S_FALSE == hr) {
+            ExitFunction1(hr = S_OK);
+        }
+        ExitOnFailure(hr, "Failed to select overridable variable nodes.");
+
+        hr = pNodes->get_length((long*)&cNodes);
+        ExitOnFailure(hr, "Failed to get overridable variable node count.");
+
+        if (cNodes) {
+            hr = DictCreateStringList(&_overridableVariables, 32, DICT_FLAG_NONE);
+            ExitOnFailure(hr, "Failed to create the string dictionary.");
+
+            for (DWORD i = 0; i < cNodes; ++i) {
+                hr = XmlNextElement(pNodes, &pNode, nullptr);
+                ExitOnFailure(hr, "Failed to get next node.");
+
+                // @Name
+                hr = XmlGetAttributeEx(pNode, L"Name", &scz);
+                ExitOnFailure(hr, "Failed to get @Name.");
+
+                hr = XmlGetYesNoAttribute(pNode, L"Hidden", &hidden);
+
+                if (!hidden) {
+                    hr = DictAddKey(_overridableVariables, scz);
+                    ExitOnFailure1(hr, "Failed to add \"%ls\" to the string dictionary.", scz);
+                }
+
+                // prepare next iteration
+                ReleaseNullObject(pNode);
+            }
+        }
+
+    LExit:
+        ReleaseObject(pNode);
+        ReleaseObject(pNodes);
+        ReleaseStr(scz);
+        return hr;
+    }
+
+
+    //
+    // Get the file version of the bootstrapper and record in bootstrapper log file
+    //
+    HRESULT GetBundleFileVersion() {
+        HRESULT hr = S_OK;
+        ULARGE_INTEGER uliVersion = { };
+        LPWSTR sczCurrentPath = nullptr;
+
+        hr = PathForCurrentProcess(&sczCurrentPath, nullptr);
+        BalExitOnFailure(hr, "Failed to get bundle path.");
+
+        hr = FileVersion(sczCurrentPath, &uliVersion.HighPart, &uliVersion.LowPart);
+        BalExitOnFailure(hr, "Failed to get bundle file version.");
+
+        hr = _engine->SetVariableVersion(PYBA_VARIABLE_BUNDLE_FILE_VERSION, uliVersion.QuadPart);
+        BalExitOnFailure(hr, "Failed to set WixBundleFileVersion variable.");
+
+    LExit:
+        ReleaseStr(sczCurrentPath);
+
+        return hr;
+    }
+
+
+    //
+    // CreateMainWindow - creates the main install window.
+    //
+    HRESULT CreateMainWindow() {
+        HRESULT hr = S_OK;
+        HICON hIcon = reinterpret_cast<HICON>(_theme->hIcon);
+        WNDCLASSW wc = { };
+        DWORD dwWindowStyle = 0;
+        int x = CW_USEDEFAULT;
+        int y = CW_USEDEFAULT;
+        POINT ptCursor = { };
+        HMONITOR hMonitor = nullptr;
+        MONITORINFO mi = { };
+        COLORREF fg, bg;
+        HBRUSH bgBrush;
+
+        // If the theme did not provide an icon, try using the icon from the bundle engine.
+        if (!hIcon) {
+            HMODULE hBootstrapperEngine = ::GetModuleHandleW(nullptr);
+            if (hBootstrapperEngine) {
+                hIcon = ::LoadIconW(hBootstrapperEngine, MAKEINTRESOURCEW(1));
+            }
+        }
+
+        fg = RGB(0, 0, 0);
+        bg = RGB(255, 255, 255);
+        bgBrush = (HBRUSH)(COLOR_WINDOW+1);
+        if (_theme->dwFontId < _theme->cFonts) {
+            THEME_FONT *font = &_theme->rgFonts[_theme->dwFontId];
+            fg = font->crForeground;
+            bg = font->crBackground;
+            bgBrush = font->hBackground;
+            RemapColor(&fg, &bg, &bgBrush);
+        }
+
+        // Register the window class and create the window.
+        wc.lpfnWndProc = PythonBootstrapperApplication::WndProc;
+        wc.hInstance = _hModule;
+        wc.hIcon = hIcon;
+        wc.hCursor = ::LoadCursorW(nullptr, (LPCWSTR)IDC_ARROW);
+        wc.hbrBackground = bgBrush;
+        wc.lpszMenuName = nullptr;
+        wc.lpszClassName = PYBA_WINDOW_CLASS;
+        if (!::RegisterClassW(&wc)) {
+            ExitWithLastError(hr, "Failed to register window.");
+        }
+
+        _registered = TRUE;
+
+        // Calculate the window style based on the theme style and command display value.
+        dwWindowStyle = _theme->dwStyle;
+        if (BOOTSTRAPPER_DISPLAY_NONE >= _command.display) {
+            dwWindowStyle &= ~WS_VISIBLE;
+        }
+
+        // Don't show the window if there is a splash screen (it will be made visible when the splash screen is hidden)
+        if (::IsWindow(_command.hwndSplashScreen)) {
+            dwWindowStyle &= ~WS_VISIBLE;
+        }
+
+        // Center the window on the monitor with the mouse.
+        if (::GetCursorPos(&ptCursor)) {
+            hMonitor = ::MonitorFromPoint(ptCursor, MONITOR_DEFAULTTONEAREST);
+            if (hMonitor) {
+                mi.cbSize = sizeof(mi);
+                if (::GetMonitorInfoW(hMonitor, &mi)) {
+                    x = mi.rcWork.left + (mi.rcWork.right - mi.rcWork.left - _theme->nWidth) / 2;
+                    y = mi.rcWork.top + (mi.rcWork.bottom - mi.rcWork.top - _theme->nHeight) / 2;
+                }
+            }
+        }
+
+        _hWnd = ::CreateWindowExW(
+            0,
+            wc.lpszClassName,
+            _theme->sczCaption,
+            dwWindowStyle,
+            x,
+            y,
+            _theme->nWidth,
+            _theme->nHeight,
+            HWND_DESKTOP,
+            nullptr,
+            _hModule,
+            this
+        );
+        ExitOnNullWithLastError(_hWnd, hr, "Failed to create window.");
+
+        hr = S_OK;
+
+    LExit:
+        return hr;
+    }
+
+
+    //
+    // InitializeTaskbarButton - initializes taskbar button for progress.
+    //
+    void InitializeTaskbarButton() {
+        HRESULT hr = S_OK;
+
+        hr = ::CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_ALL, __uuidof(ITaskbarList3), reinterpret_cast<LPVOID*>(&_taskbarList));
+        if (REGDB_E_CLASSNOTREG == hr) {
+            // not supported before Windows 7
+            ExitFunction1(hr = S_OK);
+        }
+        BalExitOnFailure(hr, "Failed to create ITaskbarList3. Continuing.");
+
+        _taskbarButtonCreatedMessage = ::RegisterWindowMessageW(L"TaskbarButtonCreated");
+        BalExitOnNullWithLastError(_taskbarButtonCreatedMessage, hr, "Failed to get TaskbarButtonCreated message. Continuing.");
+
+    LExit:
+        return;
+    }
+
+    //
+    // DestroyMainWindow - clean up all the window registration.
+    //
+    void DestroyMainWindow() {
+        if (::IsWindow(_hWnd)) {
+            ::DestroyWindow(_hWnd);
+            _hWnd = nullptr;
+            _taskbarButtonOK = FALSE;
+        }
+
+        if (_registered) {
+            ::UnregisterClassW(PYBA_WINDOW_CLASS, _hModule);
+            _registered = FALSE;
+        }
+    }
+
+
+    //
+    // WndProc - standard windows message handler.
+    //
+    static LRESULT CALLBACK WndProc(
+        __in HWND hWnd,
+        __in UINT uMsg,
+        __in WPARAM wParam,
+        __in LPARAM lParam
+    ) {
+#pragma warning(suppress:4312)
+        auto pBA = reinterpret_cast<PythonBootstrapperApplication*>(::GetWindowLongPtrW(hWnd, GWLP_USERDATA));
+
+        switch (uMsg) {
+        case WM_NCCREATE: {
+            LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
+            pBA = reinterpret_cast<PythonBootstrapperApplication*>(lpcs->lpCreateParams);
+#pragma warning(suppress:4244)
+            ::SetWindowLongPtrW(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pBA));
+            break;
+        }
+
+        case WM_NCDESTROY: {
+            LRESULT lres = ThemeDefWindowProc(pBA ? pBA->_theme : nullptr, hWnd, uMsg, wParam, lParam);
+            ::SetWindowLongPtrW(hWnd, GWLP_USERDATA, 0);
+            return lres;
+        }
+
+        case WM_CREATE: 
+            if (!pBA->OnCreate(hWnd)) {
+                return -1;
+            }
+            break;
+
+        case WM_QUERYENDSESSION:
+            return IDCANCEL != pBA->OnSystemShutdown(static_cast<DWORD>(lParam), IDCANCEL);
+
+        case WM_CLOSE:
+            // If the user chose not to close, do *not* let the default window proc handle the message.
+            if (!pBA->OnClose()) {
+                return 0;
+            }
+            break;
+
+        case WM_DESTROY:
+            ::PostQuitMessage(0);
+            break;
+
+        case WM_PAINT: __fallthrough;
+        case WM_ERASEBKGND:
+            if (pBA && pBA->_suppressPaint) {
+                return TRUE;
+            }
+            break;
+
+        case WM_PYBA_SHOW_HELP:
+            pBA->OnShowHelp();
+            return 0;
+
+        case WM_PYBA_DETECT_PACKAGES:
+            pBA->OnDetect();
+            return 0;
+
+        case WM_PYBA_PLAN_PACKAGES:
+            pBA->OnPlan(static_cast<BOOTSTRAPPER_ACTION>(lParam));
+            return 0;
+
+        case WM_PYBA_APPLY_PACKAGES:
+            pBA->OnApply();
+            return 0;
+
+        case WM_PYBA_CHANGE_STATE:
+            pBA->OnChangeState(static_cast<PYBA_STATE>(lParam));
+            return 0;
+
+        case WM_PYBA_SHOW_FAILURE:
+            pBA->OnShowFailure();
+            return 0;
+
+        case WM_COMMAND:
+            switch (LOWORD(wParam)) {
+            // Customize commands
+            // Success/failure commands
+            case ID_SUCCESS_RESTART_BUTTON: __fallthrough;
+            case ID_FAILURE_RESTART_BUTTON:
+                pBA->OnClickRestartButton();
+                return 0;
+
+            case IDCANCEL: __fallthrough;
+            case ID_INSTALL_CANCEL_BUTTON: __fallthrough;
+            case ID_CUSTOM1_CANCEL_BUTTON: __fallthrough;
+            case ID_CUSTOM2_CANCEL_BUTTON: __fallthrough;
+            case ID_MODIFY_CANCEL_BUTTON: __fallthrough;
+            case ID_PROGRESS_CANCEL_BUTTON: __fallthrough;
+            case ID_SUCCESS_CANCEL_BUTTON: __fallthrough;
+            case ID_FAILURE_CANCEL_BUTTON: __fallthrough;
+            case ID_CLOSE_BUTTON:
+                pBA->OnCommand(ID_CLOSE_BUTTON);
+                return 0;
+
+            default:
+                pBA->OnCommand((CONTROL_ID)LOWORD(wParam));
+            }
+            break;
+
+        case WM_NOTIFY:
+            if (lParam) {
+                LPNMHDR pnmhdr = reinterpret_cast<LPNMHDR>(lParam);
+                switch (pnmhdr->code) {
+                case NM_CLICK: __fallthrough;
+                case NM_RETURN:
+                    switch (static_cast<DWORD>(pnmhdr->idFrom)) {
+                    case ID_FAILURE_LOGFILE_LINK:
+                        pBA->OnClickLogFileLink();
+                        return 1;
+                    }
+                }
+            }
+            break;
+
+        case WM_CTLCOLORSTATIC:
+        case WM_CTLCOLORBTN:
+            if (pBA) {
+                HBRUSH brush = nullptr;
+                if (pBA->SetControlColor((HWND)lParam, (HDC)wParam, &brush)) {
+                    return (LRESULT)brush;
+                }
+            }
+            break;
+        }
+
+        if (pBA && pBA->_taskbarList && uMsg == pBA->_taskbarButtonCreatedMessage) {
+            pBA->_taskbarButtonOK = TRUE;
+            return 0;
+        }


More information about the pypy-commit mailing list