2020-08-05 22:20:50 +08:00
|
|
|
#include "pch.h"
|
2020-09-10 21:57:16 +08:00
|
|
|
#include "Generated Files/resource.h"
|
2020-07-28 00:53:29 +08:00
|
|
|
|
2020-12-15 20:16:09 +08:00
|
|
|
#include "RcResource.h"
|
2020-07-28 00:53:29 +08:00
|
|
|
#include <common/updating/dotnet_installation.h>
|
2020-11-20 16:34:34 +08:00
|
|
|
#include <common/updating/installer.h>
|
2020-12-15 20:16:09 +08:00
|
|
|
#include <common/updating/notifications.h>
|
|
|
|
#include <common/version/version.h>
|
|
|
|
#include <common/utils/appMutex.h>
|
|
|
|
#include <common/utils/elevation.h>
|
|
|
|
#include <common/utils/processApi.h>
|
|
|
|
#include <common/utils/resources.h>
|
|
|
|
#include <common/utils/window.h>
|
|
|
|
#include <common/utils/winapi_error.h>
|
2021-03-25 22:28:29 +08:00
|
|
|
#include <common/SettingsAPI/settings_helpers.h>
|
2020-07-28 00:53:29 +08:00
|
|
|
|
|
|
|
#include <runner/action_runner_utils.h>
|
|
|
|
|
2020-11-27 05:31:00 +08:00
|
|
|
#include "progressbar_window.h"
|
|
|
|
|
2020-11-13 20:57:01 +08:00
|
|
|
auto Strings = create_notifications_strings();
|
2021-02-12 23:56:15 +08:00
|
|
|
static bool g_Silent = false;
|
2020-10-23 00:02:59 +08:00
|
|
|
|
2020-10-14 22:36:03 +08:00
|
|
|
#define STR_HELPER(x) #x
|
|
|
|
#define STR(x) STR_HELPER(x)
|
2020-11-18 18:15:14 +08:00
|
|
|
|
2020-10-23 00:02:59 +08:00
|
|
|
namespace // Strings in this namespace should not be localized
|
2020-07-28 00:53:29 +08:00
|
|
|
{
|
|
|
|
const wchar_t APPLICATION_ID[] = L"PowerToysInstaller";
|
2021-02-12 23:56:15 +08:00
|
|
|
const char EXE_LOG_FILENAME[] = "powertoys-bootstrapper-exe-" STR(VERSION_MAJOR) "." STR(VERSION_MINOR) "." STR(VERSION_REVISION) ".log";
|
2020-10-14 22:36:03 +08:00
|
|
|
const char MSI_LOG_FILENAME[] = "powertoys-bootstrapper-msi-" STR(VERSION_MAJOR) "." STR(VERSION_MINOR) "." STR(VERSION_REVISION) ".log";
|
2020-07-28 00:53:29 +08:00
|
|
|
}
|
2021-02-12 23:56:15 +08:00
|
|
|
|
2020-10-14 22:36:03 +08:00
|
|
|
#undef STR
|
|
|
|
#undef STR_HELPER
|
2020-07-28 00:53:29 +08:00
|
|
|
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
|
2021-02-12 00:18:19 +08:00
|
|
|
std::optional<fs::path> ExtractEmbeddedInstaller(const fs::path extractPath)
|
2020-07-28 00:53:29 +08:00
|
|
|
{
|
|
|
|
auto executableRes = RcResource::create(IDR_BIN_MSIINSTALLER, L"BIN");
|
|
|
|
if (!executableRes)
|
|
|
|
{
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
2021-02-12 00:18:19 +08:00
|
|
|
|
2020-12-18 00:58:15 +08:00
|
|
|
auto installerPath = extractPath / L"PowerToysBootstrappedInstaller-" PRODUCT_VERSION_STRING L".msi";
|
2020-07-28 00:53:29 +08:00
|
|
|
return executableRes->saveAsFile(installerPath) ? std::make_optional(std::move(installerPath)) : std::nullopt;
|
|
|
|
}
|
|
|
|
|
2021-02-12 00:18:19 +08:00
|
|
|
void SetupLogger(fs::path directory, const spdlog::level::level_enum severity)
|
2020-08-07 17:00:14 +08:00
|
|
|
{
|
2021-02-18 14:54:24 +08:00
|
|
|
std::shared_ptr<spdlog::logger> logger;
|
|
|
|
auto nullLogger = spdlog::null_logger_mt("null");
|
2020-10-14 22:36:03 +08:00
|
|
|
try
|
2020-08-07 17:00:14 +08:00
|
|
|
{
|
2020-10-14 22:36:03 +08:00
|
|
|
if (severity != spdlog::level::off)
|
2020-08-07 17:00:14 +08:00
|
|
|
{
|
2021-02-12 23:56:15 +08:00
|
|
|
logger = spdlog::basic_logger_mt("file", (directory / EXE_LOG_FILENAME).wstring());
|
2020-10-14 22:36:03 +08:00
|
|
|
|
|
|
|
std::error_code _;
|
|
|
|
const DWORD msiSev = severity == spdlog::level::debug ? INSTALLLOGMODE_VERBOSE : INSTALLLOGMODE_ERROR;
|
2020-10-20 17:25:13 +08:00
|
|
|
const auto msiLogPath = directory / MSI_LOG_FILENAME;
|
2020-10-14 22:36:03 +08:00
|
|
|
MsiEnableLogW(msiSev, msiLogPath.c_str(), INSTALLLOGATTRIBUTES_APPEND);
|
2020-08-07 17:00:14 +08:00
|
|
|
}
|
2020-10-14 22:36:03 +08:00
|
|
|
else
|
|
|
|
{
|
2021-02-18 14:54:24 +08:00
|
|
|
logger = nullLogger;
|
2020-10-14 22:36:03 +08:00
|
|
|
}
|
2021-02-12 00:18:19 +08:00
|
|
|
|
2020-10-14 22:36:03 +08:00
|
|
|
logger->set_pattern("[%L][%d-%m-%C-%T] %v");
|
|
|
|
logger->set_level(severity);
|
|
|
|
spdlog::set_default_logger(std::move(logger));
|
|
|
|
spdlog::set_level(severity);
|
|
|
|
spdlog::flush_every(std::chrono::seconds(5));
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
2021-02-18 14:54:24 +08:00
|
|
|
spdlog::set_default_logger(nullLogger);
|
2020-08-07 17:00:14 +08:00
|
|
|
}
|
|
|
|
}
|
2020-09-07 21:42:15 +08:00
|
|
|
|
2021-03-25 22:28:29 +08:00
|
|
|
void CleanupSettingsFromOlderVersions()
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
const auto logSettingsFile = fs::path{ PTSettingsHelper::get_root_save_folder_location() } / PTSettingsHelper::log_settings_filename;
|
|
|
|
if (fs::is_regular_file(logSettingsFile))
|
|
|
|
{
|
|
|
|
fs::remove(logSettingsFile);
|
|
|
|
spdlog::info("Removed old log settings file");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
spdlog::info("Old log settings file wasn't found");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch(...)
|
|
|
|
{
|
|
|
|
spdlog::error("Failed to cleanup old log settings");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-12 23:56:15 +08:00
|
|
|
void ShowMessageBoxError(const wchar_t* message)
|
2020-11-27 05:31:00 +08:00
|
|
|
{
|
2021-02-12 23:56:15 +08:00
|
|
|
if (!g_Silent)
|
|
|
|
{
|
|
|
|
MessageBoxW(nullptr,
|
|
|
|
message,
|
|
|
|
GET_RESOURCE_STRING(IDS_BOOTSTRAPPER_PROGRESS_TITLE).c_str(),
|
|
|
|
MB_OK | MB_ICONERROR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShowMessageBoxError(const UINT messageId)
|
|
|
|
{
|
|
|
|
ShowMessageBoxError(GET_RESOURCE_STRING(messageId).c_str());
|
2020-11-27 05:31:00 +08:00
|
|
|
}
|
|
|
|
|
2021-02-12 00:18:19 +08:00
|
|
|
int Bootstrapper(HINSTANCE hInstance)
|
2020-07-28 00:53:29 +08:00
|
|
|
{
|
|
|
|
winrt::init_apartment();
|
2020-12-01 04:37:31 +08:00
|
|
|
char* programFilesDir = nullptr;
|
|
|
|
size_t size = 0;
|
|
|
|
std::string defaultInstallDir;
|
2021-02-12 00:18:19 +08:00
|
|
|
|
2020-12-01 04:37:31 +08:00
|
|
|
if (!_dupenv_s(&programFilesDir, &size, "PROGRAMFILES"))
|
|
|
|
{
|
|
|
|
defaultInstallDir += programFilesDir;
|
|
|
|
defaultInstallDir += "\\PowerToys";
|
|
|
|
}
|
2021-02-12 23:56:15 +08:00
|
|
|
|
2020-10-14 22:36:03 +08:00
|
|
|
cxxopts::Options options{ "PowerToysBootstrapper" };
|
2021-02-12 00:18:19 +08:00
|
|
|
|
2020-10-14 22:36:03 +08:00
|
|
|
// clang-format off
|
|
|
|
options.add_options()
|
|
|
|
("h,help", "Show help")
|
|
|
|
("no_full_ui", "Use reduced UI for MSI")
|
2021-04-20 19:47:59 +08:00
|
|
|
("s,silent", "Suppress all UI, notifications and does not start PowerToys")
|
2020-10-14 22:36:03 +08:00
|
|
|
("no_start_pt", "Do not launch PowerToys after the installation is complete")
|
2021-04-20 19:47:59 +08:00
|
|
|
("start_pt", "Always launch PowerToys after the installation is complete")
|
2020-10-14 22:36:03 +08:00
|
|
|
("skip_dotnet_install", "Skip dotnet 3.X installation even if it's not detected")
|
2020-10-20 17:25:13 +08:00
|
|
|
("log_level", "Log level. Possible values: off|debug|error", cxxopts::value<std::string>()->default_value("off"))
|
2020-12-01 04:37:31 +08:00
|
|
|
("log_dir", "Log directory", cxxopts::value<std::string>()->default_value("."))
|
2020-12-18 00:58:15 +08:00
|
|
|
("install_dir", "Installation directory", cxxopts::value<std::string>()->default_value(defaultInstallDir))
|
|
|
|
("extract_msi", "Extract MSI to the working directory and exit. Use only if you must access MSI directly.");
|
2020-10-14 22:36:03 +08:00
|
|
|
// clang-format on
|
2021-02-12 23:56:15 +08:00
|
|
|
|
2020-10-14 22:36:03 +08:00
|
|
|
cxxopts::ParseResult cmdArgs;
|
2020-10-20 17:07:35 +08:00
|
|
|
bool showHelp = false;
|
2020-10-14 22:36:03 +08:00
|
|
|
try
|
|
|
|
{
|
|
|
|
cmdArgs = options.parse(__argc, const_cast<const char**>(__argv));
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
2020-11-30 22:42:46 +08:00
|
|
|
showHelp = true;
|
2020-10-14 22:36:03 +08:00
|
|
|
}
|
2020-10-20 17:07:35 +08:00
|
|
|
|
|
|
|
showHelp = showHelp || cmdArgs["help"].as<bool>();
|
|
|
|
if (showHelp)
|
|
|
|
{
|
|
|
|
std::ostringstream helpMsg;
|
|
|
|
helpMsg << options.help();
|
|
|
|
MessageBoxA(nullptr, helpMsg.str().c_str(), "Help", MB_OK | MB_ICONINFORMATION);
|
|
|
|
return 0;
|
|
|
|
}
|
2020-12-18 00:58:15 +08:00
|
|
|
|
2021-02-12 23:56:15 +08:00
|
|
|
g_Silent = cmdArgs["silent"].as<bool>();
|
2020-10-14 22:36:03 +08:00
|
|
|
const bool noFullUI = cmdArgs["no_full_ui"].as<bool>();
|
|
|
|
const bool skipDotnetInstall = cmdArgs["skip_dotnet_install"].as<bool>();
|
|
|
|
const bool noStartPT = cmdArgs["no_start_pt"].as<bool>();
|
2021-04-20 19:47:59 +08:00
|
|
|
const bool startPT = cmdArgs["start_pt"].as<bool>();
|
2020-10-14 22:36:03 +08:00
|
|
|
const auto logLevel = cmdArgs["log_level"].as<std::string>();
|
2020-10-20 17:25:13 +08:00
|
|
|
const auto logDirArg = cmdArgs["log_dir"].as<std::string>();
|
2020-12-01 04:37:31 +08:00
|
|
|
const auto installDirArg = cmdArgs["install_dir"].as<std::string>();
|
2021-04-20 19:47:59 +08:00
|
|
|
const bool extractMsiOnly = cmdArgs["extract_msi"].as<bool>();
|
2020-12-18 00:58:15 +08:00
|
|
|
|
2020-12-01 04:37:31 +08:00
|
|
|
std::wstring installFolderProp;
|
|
|
|
if (!installDirArg.empty())
|
|
|
|
{
|
|
|
|
std::string installDir;
|
|
|
|
if (installDirArg.find(' ') != std::string::npos)
|
|
|
|
{
|
|
|
|
installDir = "\"" + installDirArg + "\"";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
installDir = installDirArg;
|
|
|
|
}
|
|
|
|
|
|
|
|
installFolderProp = std::wstring(installDir.length(), L' ');
|
|
|
|
std::copy(installDir.begin(), installDir.end(), installFolderProp.begin());
|
|
|
|
installFolderProp = L"INSTALLFOLDER=" + installFolderProp;
|
|
|
|
}
|
|
|
|
|
2020-10-20 17:25:13 +08:00
|
|
|
fs::path logDir = ".";
|
|
|
|
try
|
|
|
|
{
|
|
|
|
fs::path logDirArgPath = logDirArg;
|
|
|
|
if (fs::exists(logDirArgPath) && fs::is_directory(logDirArgPath))
|
|
|
|
{
|
|
|
|
logDir = logDirArgPath;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2021-03-17 21:49:07 +08:00
|
|
|
spdlog::level::level_enum severity = spdlog::level::off;
|
2020-10-14 22:36:03 +08:00
|
|
|
if (logLevel == "debug")
|
2020-08-26 18:46:19 +08:00
|
|
|
{
|
2020-10-14 22:36:03 +08:00
|
|
|
severity = spdlog::level::debug;
|
|
|
|
}
|
|
|
|
else if (logLevel == "error")
|
|
|
|
{
|
|
|
|
severity = spdlog::level::err;
|
|
|
|
}
|
2021-02-12 00:18:19 +08:00
|
|
|
|
|
|
|
SetupLogger(logDir, severity);
|
2021-04-20 19:47:59 +08:00
|
|
|
spdlog::debug("PowerToys Bootstrapper is launched\nnoFullUI: {}\nsilent: {}\nno_start_pt: {}\nskip_dotnet_install: {}\nlog_level: {}\ninstall_dir: {}\nextract_msi: {}\n", noFullUI, g_Silent, noStartPT, skipDotnetInstall, logLevel, installDirArg, extractMsiOnly);
|
2020-12-18 00:58:15 +08:00
|
|
|
|
2021-03-17 21:49:07 +08:00
|
|
|
const VersionHelper myVersion(VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION);
|
|
|
|
|
|
|
|
// Do not support installing on Windows < 1903
|
|
|
|
if (myVersion >= VersionHelper{0, 36, 0} && updating::is_old_windows_version())
|
|
|
|
{
|
|
|
|
ShowMessageBoxError(IDS_OLD_WINDOWS_ERROR);
|
|
|
|
spdlog::error("PowerToys {} requires at least Windows 1903 to run.", myVersion.toString());
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-12-18 00:58:15 +08:00
|
|
|
// If a user requested an MSI -> extract it and exit
|
2021-04-20 19:47:59 +08:00
|
|
|
if (extractMsiOnly)
|
2020-12-18 00:58:15 +08:00
|
|
|
{
|
2021-02-12 00:18:19 +08:00
|
|
|
if (const auto installerPath = ExtractEmbeddedInstaller(fs::current_path()))
|
2020-12-18 00:58:15 +08:00
|
|
|
{
|
2021-02-12 23:56:15 +08:00
|
|
|
spdlog::debug("MSI installer extracted to {}", installerPath->string());
|
2020-12-18 00:58:15 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
spdlog::error("MSI installer couldn't be extracted");
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2020-10-14 22:36:03 +08:00
|
|
|
|
2021-02-12 23:56:15 +08:00
|
|
|
// Check if there's a newer version installed
|
|
|
|
const auto installedVersion = updating::get_installed_powertoys_version();
|
|
|
|
if (installedVersion && *installedVersion >= myVersion)
|
|
|
|
{
|
|
|
|
spdlog::error(L"Detected a newer version {} vs {}", (*installedVersion).toWstring(), myVersion.toWstring());
|
|
|
|
ShowMessageBoxError(IDS_NEWER_VERSION_ERROR);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-12-18 00:58:15 +08:00
|
|
|
// Setup MSI UI visibility and restart as elevated if required
|
2020-10-14 22:36:03 +08:00
|
|
|
if (!noFullUI)
|
2020-08-07 17:00:14 +08:00
|
|
|
{
|
|
|
|
MsiSetInternalUI(INSTALLUILEVEL_FULL, nullptr);
|
|
|
|
}
|
2021-02-12 00:18:19 +08:00
|
|
|
|
2021-02-12 23:56:15 +08:00
|
|
|
if (g_Silent)
|
2020-08-07 17:00:14 +08:00
|
|
|
{
|
|
|
|
if (is_process_elevated())
|
|
|
|
{
|
|
|
|
MsiSetInternalUI(INSTALLUILEVEL_NONE, nullptr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-10-14 22:36:03 +08:00
|
|
|
spdlog::debug("MSI doesn't support silent mode without elevation => restarting elevated");
|
|
|
|
// MSI fails to run in silent mode due to a suppressed UAC w/o elevation,
|
|
|
|
// so we restart ourselves elevated with the same args
|
2020-08-07 17:00:14 +08:00
|
|
|
std::wstring params;
|
2020-10-14 22:36:03 +08:00
|
|
|
int nCmdArgs = 0;
|
|
|
|
LPWSTR* argList = CommandLineToArgvW(GetCommandLineW(), &nCmdArgs);
|
2020-08-07 17:00:14 +08:00
|
|
|
for (int i = 1; i < nCmdArgs; ++i)
|
|
|
|
{
|
2020-12-01 04:37:31 +08:00
|
|
|
if (std::wstring_view{ argList[i] }.find(L' ') != std::wstring_view::npos)
|
|
|
|
{
|
|
|
|
params += L'"';
|
|
|
|
params += argList[i];
|
|
|
|
params += L'"';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
params += argList[i];
|
|
|
|
}
|
|
|
|
|
2020-08-07 17:00:14 +08:00
|
|
|
if (i != nCmdArgs - 1)
|
|
|
|
{
|
|
|
|
params += L' ';
|
|
|
|
}
|
|
|
|
}
|
2021-02-12 00:18:19 +08:00
|
|
|
|
2020-08-07 17:00:14 +08:00
|
|
|
const auto processHandle = run_elevated(argList[0], params.c_str());
|
|
|
|
if (!processHandle)
|
|
|
|
{
|
2020-10-14 22:36:03 +08:00
|
|
|
spdlog::error("Couldn't restart elevated to enable silent mode! ({})", GetLastError());
|
2020-08-07 17:00:14 +08:00
|
|
|
return 1;
|
|
|
|
}
|
2021-02-12 00:18:19 +08:00
|
|
|
|
2020-08-07 17:00:14 +08:00
|
|
|
if (WaitForSingleObject(processHandle, 3600000) == WAIT_OBJECT_0)
|
|
|
|
{
|
|
|
|
DWORD exitCode = 0;
|
|
|
|
GetExitCodeProcess(processHandle, &exitCode);
|
|
|
|
return exitCode;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-10-14 22:36:03 +08:00
|
|
|
spdlog::error("Elevated setup process timed out after 60m => using basic MSI UI ({})", GetLastError());
|
2020-08-07 17:00:14 +08:00
|
|
|
// Couldn't install using the completely silent mode in an hour, use basic UI.
|
|
|
|
TerminateProcess(processHandle, 0);
|
|
|
|
MsiSetInternalUI(INSTALLUILEVEL_BASIC, nullptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-18 00:58:15 +08:00
|
|
|
// Try killing PowerToys and prevent future processes launch by acquiring app mutex
|
2020-07-28 00:53:29 +08:00
|
|
|
for (auto& handle : getProcessHandlesByName(L"PowerToys.exe", PROCESS_TERMINATE))
|
|
|
|
{
|
|
|
|
TerminateProcess(handle.get(), 0);
|
|
|
|
}
|
2021-02-12 00:18:19 +08:00
|
|
|
|
2020-07-28 00:53:29 +08:00
|
|
|
auto powerToysMutex = createAppMutex(POWERTOYS_MSI_MUTEX_NAME);
|
|
|
|
auto instanceMutex = createAppMutex(POWERTOYS_BOOTSTRAPPER_MUTEX_NAME);
|
|
|
|
if (!instanceMutex)
|
|
|
|
{
|
2021-02-12 23:56:15 +08:00
|
|
|
spdlog::error("Couldn't acquire PowerToys global mutex. Setup couldn't terminate PowerToys.exe process");
|
2020-07-28 00:53:29 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-10-14 22:36:03 +08:00
|
|
|
spdlog::debug("Extracting embedded MSI installer");
|
2021-02-12 00:18:19 +08:00
|
|
|
const auto installerPath = ExtractEmbeddedInstaller(fs::temp_directory_path());
|
2020-07-28 00:53:29 +08:00
|
|
|
if (!installerPath)
|
|
|
|
{
|
2021-02-12 23:56:15 +08:00
|
|
|
ShowMessageBoxError(IDS_INSTALLER_EXTRACT_ERROR);
|
2020-10-14 22:36:03 +08:00
|
|
|
spdlog::error("Couldn't install the MSI installer ({})", GetLastError());
|
2020-07-28 00:53:29 +08:00
|
|
|
return 1;
|
|
|
|
}
|
2021-02-12 00:18:19 +08:00
|
|
|
|
2020-07-28 00:53:29 +08:00
|
|
|
auto removeExtractedInstaller = wil::scope_exit([&] {
|
|
|
|
std::error_code _;
|
|
|
|
fs::remove(*installerPath, _);
|
|
|
|
});
|
|
|
|
|
2021-02-12 23:56:15 +08:00
|
|
|
spdlog::debug("Acquiring existing MSI package path if exists");
|
2020-07-28 00:53:29 +08:00
|
|
|
const auto package_path = updating::get_msi_package_path();
|
2020-10-14 22:36:03 +08:00
|
|
|
if (!package_path.empty())
|
|
|
|
{
|
2021-02-12 23:56:15 +08:00
|
|
|
spdlog::debug(L"Existing MSI package path found: {}", package_path);
|
2020-10-14 22:36:03 +08:00
|
|
|
}
|
|
|
|
else
|
2020-07-28 00:53:29 +08:00
|
|
|
{
|
2020-10-14 22:36:03 +08:00
|
|
|
spdlog::debug("Existing MSI package path not found");
|
|
|
|
}
|
2021-02-12 00:18:19 +08:00
|
|
|
|
2020-11-27 05:31:00 +08:00
|
|
|
if (!package_path.empty() && !updating::uninstall_msi_version(package_path, Strings))
|
2020-10-14 22:36:03 +08:00
|
|
|
{
|
|
|
|
spdlog::error("Couldn't install the existing MSI package ({})", GetLastError());
|
2021-02-12 23:56:15 +08:00
|
|
|
ShowMessageBoxError(IDS_UNINSTALL_PREVIOUS_VERSION_ERROR);
|
2020-07-28 00:53:29 +08:00
|
|
|
}
|
2021-02-12 00:18:19 +08:00
|
|
|
|
2020-10-14 22:36:03 +08:00
|
|
|
const bool installDotnet = !skipDotnetInstall;
|
2021-02-12 23:56:15 +08:00
|
|
|
if (!g_Silent)
|
2020-08-26 18:46:19 +08:00
|
|
|
{
|
2021-02-12 00:18:19 +08:00
|
|
|
OpenProgressBarDialog(hInstance, 0, GET_RESOURCE_STRING(IDS_BOOTSTRAPPER_PROGRESS_TITLE).c_str(), GET_RESOURCE_STRING(IDS_DOWNLOADING_DOTNET).c_str());
|
2020-08-26 18:46:19 +08:00
|
|
|
}
|
2020-09-07 21:42:15 +08:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
2020-10-14 22:36:03 +08:00
|
|
|
if (installDotnet)
|
2020-09-07 21:42:15 +08:00
|
|
|
{
|
2020-10-14 22:36:03 +08:00
|
|
|
spdlog::debug("Detecting if dotnet is installed");
|
|
|
|
const bool dotnetInstalled = updating::dotnet_is_installed();
|
2020-12-18 00:58:15 +08:00
|
|
|
spdlog::debug("Dotnet is already installed: {}", dotnetInstalled);
|
2020-11-27 05:31:00 +08:00
|
|
|
if (!dotnetInstalled)
|
2020-10-14 22:36:03 +08:00
|
|
|
{
|
2021-02-12 00:18:19 +08:00
|
|
|
bool installedSuccessfully = false;
|
2020-11-27 05:31:00 +08:00
|
|
|
if (const auto dotnet_installer_path = updating::download_dotnet())
|
|
|
|
{
|
|
|
|
// Dotnet installer has its own progress bar
|
2021-02-12 00:18:19 +08:00
|
|
|
CloseProgressBarDialog();
|
2021-02-12 23:56:15 +08:00
|
|
|
installedSuccessfully = updating::install_dotnet(*dotnet_installer_path, g_Silent);
|
2021-02-12 00:18:19 +08:00
|
|
|
if (!installedSuccessfully)
|
2020-11-27 05:31:00 +08:00
|
|
|
{
|
|
|
|
spdlog::error("Couldn't install dotnet");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
spdlog::error("Couldn't download dotnet");
|
|
|
|
}
|
|
|
|
|
2021-02-12 00:18:19 +08:00
|
|
|
if (!installedSuccessfully)
|
2020-11-27 05:31:00 +08:00
|
|
|
{
|
2021-02-12 23:56:15 +08:00
|
|
|
ShowMessageBoxError(IDS_DOTNET_INSTALL_ERROR);
|
2020-11-27 05:31:00 +08:00
|
|
|
}
|
2020-10-14 22:36:03 +08:00
|
|
|
}
|
2020-09-07 21:42:15 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (...)
|
2020-07-28 00:53:29 +08:00
|
|
|
{
|
2020-10-14 22:36:03 +08:00
|
|
|
spdlog::error("Unknown exception during dotnet installation");
|
2021-02-12 23:56:15 +08:00
|
|
|
ShowMessageBoxError(IDS_DOTNET_INSTALL_ERROR);
|
2020-07-28 00:53:29 +08:00
|
|
|
}
|
2021-03-25 22:28:29 +08:00
|
|
|
|
2020-11-27 05:31:00 +08:00
|
|
|
// At this point, there's no reason to show progress bar window, since MSI installers have their own
|
2021-02-12 00:18:19 +08:00
|
|
|
CloseProgressBarDialog();
|
2020-07-28 00:53:29 +08:00
|
|
|
|
2020-12-18 00:58:15 +08:00
|
|
|
const std::wstring msiProps = installFolderProp;
|
2020-10-14 22:36:03 +08:00
|
|
|
spdlog::debug("Launching MSI installation for new package {}", installerPath->string());
|
2020-08-26 18:46:19 +08:00
|
|
|
const bool installationDone = MsiInstallProductW(installerPath->c_str(), msiProps.c_str()) == ERROR_SUCCESS;
|
2020-07-28 00:53:29 +08:00
|
|
|
if (!installationDone)
|
|
|
|
{
|
2020-10-14 22:36:03 +08:00
|
|
|
spdlog::error("Couldn't install new MSI package ({})", GetLastError());
|
2020-07-28 00:53:29 +08:00
|
|
|
return 1;
|
|
|
|
}
|
2020-11-27 05:31:00 +08:00
|
|
|
|
2020-10-14 22:36:03 +08:00
|
|
|
spdlog::debug("Installation completed");
|
2020-08-07 17:00:14 +08:00
|
|
|
|
2021-04-20 19:47:59 +08:00
|
|
|
if ((!noStartPT && !g_Silent) || startPT)
|
2020-07-28 00:53:29 +08:00
|
|
|
{
|
2020-10-14 22:36:03 +08:00
|
|
|
spdlog::debug("Starting the newly installed PowerToys.exe");
|
2020-08-07 17:00:14 +08:00
|
|
|
auto newPTPath = updating::get_msi_package_installed_path();
|
|
|
|
if (!newPTPath)
|
|
|
|
{
|
2020-10-14 22:36:03 +08:00
|
|
|
spdlog::error("Couldn't determine new MSI package install location ({})", GetLastError());
|
2020-08-07 17:00:14 +08:00
|
|
|
return 1;
|
|
|
|
}
|
2021-02-12 00:18:19 +08:00
|
|
|
|
2020-07-28 00:53:29 +08:00
|
|
|
*newPTPath += L"\\PowerToys.exe";
|
|
|
|
SHELLEXECUTEINFOW sei{ sizeof(sei) };
|
|
|
|
sei.fMask = { SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC | SEE_MASK_NO_CONSOLE };
|
|
|
|
sei.lpFile = newPTPath->c_str();
|
|
|
|
sei.nShow = SW_SHOWNORMAL;
|
|
|
|
ShellExecuteExW(&sei);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2020-09-07 21:42:15 +08:00
|
|
|
|
2020-11-27 05:31:00 +08:00
|
|
|
int WINAPI WinMain(HINSTANCE hi, HINSTANCE, LPSTR, int)
|
2020-09-07 21:42:15 +08:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2021-02-12 00:18:19 +08:00
|
|
|
return Bootstrapper(hi);
|
2020-09-07 21:42:15 +08:00
|
|
|
}
|
|
|
|
catch (const std::exception& ex)
|
|
|
|
{
|
2021-02-12 23:56:15 +08:00
|
|
|
std::string messageA{ "Unhandled std exception encountered\n" };
|
|
|
|
messageA.append(ex.what());
|
|
|
|
|
|
|
|
spdlog::error(messageA.c_str());
|
|
|
|
|
|
|
|
std::wstring messageW{};
|
|
|
|
std::copy(messageA.begin(), messageA.end(), messageW.begin());
|
|
|
|
ShowMessageBoxError(messageW.c_str());
|
2020-09-07 21:42:15 +08:00
|
|
|
}
|
|
|
|
catch (winrt::hresult_error const& ex)
|
|
|
|
{
|
2021-02-12 23:56:15 +08:00
|
|
|
std::wstring message{ L"Unhandled winrt exception encountered\n" };
|
|
|
|
message.append(ex.message().c_str());
|
|
|
|
|
2021-02-18 14:54:24 +08:00
|
|
|
spdlog::error(message.c_str());
|
2021-02-12 23:56:15 +08:00
|
|
|
|
|
|
|
ShowMessageBoxError(message.c_str());
|
2020-09-07 21:42:15 +08:00
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
auto lastErrorMessage = get_last_error_message(GetLastError());
|
2021-02-12 23:56:15 +08:00
|
|
|
std::wstring message{ L"Unknown exception encountered\n" };
|
|
|
|
message.append(lastErrorMessage ? std::move(*lastErrorMessage) : L"");
|
|
|
|
|
2021-02-18 14:54:24 +08:00
|
|
|
spdlog::error(message.c_str());
|
2021-02-12 23:56:15 +08:00
|
|
|
|
|
|
|
ShowMessageBoxError(message.c_str());
|
2020-09-07 21:42:15 +08:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|