mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 11:48:06 +01:00
[bootstrapper] change newer version detected action (#9679)
* [bootstrapper] change new version detected action when a new version is detected, don't run the new version MSI instead show an error dialog and exit improve the error dialog logic add more logging * [spell checker] add new terms
This commit is contained in:
2
.github/actions/spell-check/expect.txt
vendored
2
.github/actions/spell-check/expect.txt
vendored
@@ -371,6 +371,7 @@ CSY
|
|||||||
CTAB
|
CTAB
|
||||||
CTest
|
CTest
|
||||||
ctime
|
ctime
|
||||||
|
CTLCOLORSTATIC
|
||||||
ctor
|
ctor
|
||||||
CTRLALTDEL
|
CTRLALTDEL
|
||||||
Ctx
|
Ctx
|
||||||
@@ -2232,6 +2233,7 @@ uint
|
|||||||
uintptr
|
uintptr
|
||||||
UIPI
|
UIPI
|
||||||
UIs
|
UIs
|
||||||
|
UITo
|
||||||
ul
|
ul
|
||||||
ULARGE
|
ULARGE
|
||||||
ULLONG
|
ULLONG
|
||||||
|
|||||||
@@ -128,19 +128,19 @@
|
|||||||
<value>PowerToys: uninstall previous version?</value>
|
<value>PowerToys: uninstall previous version?</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="INSTALLER_EXTRACT_ERROR" xml:space="preserve">
|
<data name="INSTALLER_EXTRACT_ERROR" xml:space="preserve">
|
||||||
<value>Couldn't extract MSI installer!</value>
|
<value>Couldn't extract MSI installer.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="EXTRACTING_INSTALLER" xml:space="preserve">
|
<data name="EXTRACTING_INSTALLER" xml:space="preserve">
|
||||||
<value>Extracting PowerToys MSI...</value>
|
<value>Extracting PowerToys MSI...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="UNINSTALL_PREVIOUS_VERSION_ERROR" xml:space="preserve">
|
<data name="UNINSTALL_PREVIOUS_VERSION_ERROR" xml:space="preserve">
|
||||||
<value>Couldn't uninstall previous PowerToys version!</value>
|
<value>Couldn't uninstall previous PowerToys version.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DOWNLOADING_DOTNET" xml:space="preserve">
|
<data name="DOWNLOADING_DOTNET" xml:space="preserve">
|
||||||
<value>Downloading .NET Core Runtime...</value>
|
<value>Downloading .NET Core...</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DOTNET_INSTALL_ERROR" xml:space="preserve">
|
<data name="DOTNET_INSTALL_ERROR" xml:space="preserve">
|
||||||
<value>Couldn't install dotnet!</value>
|
<value>Couldn't install .NET Core.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="NEW_VERSION_INSTALLATION_ERROR" xml:space="preserve">
|
<data name="NEW_VERSION_INSTALLATION_ERROR" xml:space="preserve">
|
||||||
<value>Couldn't install new PowerToys version.</value>
|
<value>Couldn't install new PowerToys version.</value>
|
||||||
@@ -155,4 +155,7 @@
|
|||||||
<data name="GITHUB_NEW_VERSION_CHECK_ERROR" xml:space="preserve">
|
<data name="GITHUB_NEW_VERSION_CHECK_ERROR" xml:space="preserve">
|
||||||
<value>Failed to connect to the server. Check your network connection or retry later.</value>
|
<value>Failed to connect to the server. Check your network connection or retry later.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="NEWER_VERSION_ERROR" xml:space="preserve">
|
||||||
|
<value>A newer version is already installed.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
#include "progressbar_window.h"
|
#include "progressbar_window.h"
|
||||||
|
|
||||||
auto Strings = create_notifications_strings();
|
auto Strings = create_notifications_strings();
|
||||||
|
static bool g_Silent = false;
|
||||||
|
static bool g_LoggerEnabled = false;
|
||||||
|
|
||||||
#define STR_HELPER(x) #x
|
#define STR_HELPER(x) #x
|
||||||
#define STR(x) STR_HELPER(x)
|
#define STR(x) STR_HELPER(x)
|
||||||
@@ -25,12 +27,10 @@ auto Strings = create_notifications_strings();
|
|||||||
namespace // Strings in this namespace should not be localized
|
namespace // Strings in this namespace should not be localized
|
||||||
{
|
{
|
||||||
const wchar_t APPLICATION_ID[] = L"PowerToysInstaller";
|
const wchar_t APPLICATION_ID[] = L"PowerToysInstaller";
|
||||||
const wchar_t INSTALLATION_MSGBOX_TITLE[] = L"PowerToys Installation";
|
const char EXE_LOG_FILENAME[] = "powertoys-bootstrapper-exe-" STR(VERSION_MAJOR) "." STR(VERSION_MINOR) "." STR(VERSION_REVISION) ".log";
|
||||||
const wchar_t TOAST_TAG[] = L"PowerToysInstallerProgress";
|
|
||||||
const char LOG_FILENAME[] = "powertoys-bootstrapper-" STR(VERSION_MAJOR) "." STR(VERSION_MINOR) "." STR(VERSION_REVISION) ".log";
|
|
||||||
const char MSI_LOG_FILENAME[] = "powertoys-bootstrapper-msi-" STR(VERSION_MAJOR) "." STR(VERSION_MINOR) "." STR(VERSION_REVISION) ".log";
|
const char MSI_LOG_FILENAME[] = "powertoys-bootstrapper-msi-" STR(VERSION_MAJOR) "." STR(VERSION_MINOR) "." STR(VERSION_REVISION) ".log";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef STR
|
#undef STR
|
||||||
#undef STR_HELPER
|
#undef STR_HELPER
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ void SetupLogger(fs::path directory, const spdlog::level::level_enum severity)
|
|||||||
std::shared_ptr<spdlog::logger> logger;
|
std::shared_ptr<spdlog::logger> logger;
|
||||||
if (severity != spdlog::level::off)
|
if (severity != spdlog::level::off)
|
||||||
{
|
{
|
||||||
logger = spdlog::basic_logger_mt("file", (directory / LOG_FILENAME).wstring());
|
logger = spdlog::basic_logger_mt("file", (directory / EXE_LOG_FILENAME).wstring());
|
||||||
|
|
||||||
std::error_code _;
|
std::error_code _;
|
||||||
const DWORD msiSev = severity == spdlog::level::debug ? INSTALLLOGMODE_VERBOSE : INSTALLLOGMODE_ERROR;
|
const DWORD msiSev = severity == spdlog::level::debug ? INSTALLLOGMODE_VERBOSE : INSTALLLOGMODE_ERROR;
|
||||||
@@ -72,18 +72,27 @@ void SetupLogger(fs::path directory, const spdlog::level::level_enum severity)
|
|||||||
spdlog::set_default_logger(std::move(logger));
|
spdlog::set_default_logger(std::move(logger));
|
||||||
spdlog::set_level(severity);
|
spdlog::set_level(severity);
|
||||||
spdlog::flush_every(std::chrono::seconds(5));
|
spdlog::flush_every(std::chrono::seconds(5));
|
||||||
|
g_LoggerEnabled = true;
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShowMessageBoxError(const wchar_t* message, const wchar_t* title)
|
void ShowMessageBoxError(const wchar_t* message)
|
||||||
{
|
{
|
||||||
MessageBoxW(nullptr,
|
if (!g_Silent)
|
||||||
message,
|
{
|
||||||
title,
|
MessageBoxW(nullptr,
|
||||||
MB_OK | MB_ICONERROR);
|
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());
|
||||||
}
|
}
|
||||||
|
|
||||||
int Bootstrapper(HINSTANCE hInstance)
|
int Bootstrapper(HINSTANCE hInstance)
|
||||||
@@ -134,8 +143,8 @@ int Bootstrapper(HINSTANCE hInstance)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_Silent = cmdArgs["silent"].as<bool>();
|
||||||
const bool noFullUI = cmdArgs["no_full_ui"].as<bool>();
|
const bool noFullUI = cmdArgs["no_full_ui"].as<bool>();
|
||||||
const bool silent = cmdArgs["silent"].as<bool>();
|
|
||||||
const bool skipDotnetInstall = cmdArgs["skip_dotnet_install"].as<bool>();
|
const bool skipDotnetInstall = cmdArgs["skip_dotnet_install"].as<bool>();
|
||||||
const bool noStartPT = cmdArgs["no_start_pt"].as<bool>();
|
const bool noStartPT = cmdArgs["no_start_pt"].as<bool>();
|
||||||
const auto logLevel = cmdArgs["log_level"].as<std::string>();
|
const auto logLevel = cmdArgs["log_level"].as<std::string>();
|
||||||
@@ -186,14 +195,14 @@ int Bootstrapper(HINSTANCE hInstance)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SetupLogger(logDir, severity);
|
SetupLogger(logDir, severity);
|
||||||
spdlog::debug("PowerToys Bootstrapper is launched\nnoFullUI: {}\nsilent: {}\nno_start_pt: {}\nskip_dotnet_install: {}\nlog_level: {}\ninstall_dir: {}\nextract_msi: {}\n", noFullUI, silent, noStartPT, skipDotnetInstall, logLevel, installDirArg, extract_msi_only);
|
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, extract_msi_only);
|
||||||
|
|
||||||
// If a user requested an MSI -> extract it and exit
|
// If a user requested an MSI -> extract it and exit
|
||||||
if (extract_msi_only)
|
if (extract_msi_only)
|
||||||
{
|
{
|
||||||
if (const auto installerPath = ExtractEmbeddedInstaller(fs::current_path()))
|
if (const auto installerPath = ExtractEmbeddedInstaller(fs::current_path()))
|
||||||
{
|
{
|
||||||
spdlog::info("MSI installer was extracted to {}", installerPath->string());
|
spdlog::debug("MSI installer extracted to {}", installerPath->string());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -202,13 +211,23 @@ int Bootstrapper(HINSTANCE hInstance)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if there's a newer version installed
|
||||||
|
const VersionHelper myVersion(VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
// Setup MSI UI visibility and restart as elevated if required
|
// Setup MSI UI visibility and restart as elevated if required
|
||||||
if (!noFullUI)
|
if (!noFullUI)
|
||||||
{
|
{
|
||||||
MsiSetInternalUI(INSTALLUILEVEL_FULL, nullptr);
|
MsiSetInternalUI(INSTALLUILEVEL_FULL, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (silent)
|
if (g_Silent)
|
||||||
{
|
{
|
||||||
if (is_process_elevated())
|
if (is_process_elevated())
|
||||||
{
|
{
|
||||||
@@ -274,32 +293,15 @@ int Bootstrapper(HINSTANCE hInstance)
|
|||||||
auto instanceMutex = createAppMutex(POWERTOYS_BOOTSTRAPPER_MUTEX_NAME);
|
auto instanceMutex = createAppMutex(POWERTOYS_BOOTSTRAPPER_MUTEX_NAME);
|
||||||
if (!instanceMutex)
|
if (!instanceMutex)
|
||||||
{
|
{
|
||||||
spdlog::error("Couldn't acquire PowerToys global mutex. That means setup couldn't kill PowerToys.exe process");
|
spdlog::error("Couldn't acquire PowerToys global mutex. Setup couldn't terminate PowerToys.exe process");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if there's a newer version installed, and launch its installer if so.
|
|
||||||
const VersionHelper myVersion(VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION);
|
|
||||||
if (const auto installedVersion = updating::get_installed_powertoys_version(); installedVersion && *installedVersion >= myVersion)
|
|
||||||
{
|
|
||||||
auto msi_path = updating::get_msi_package_path();
|
|
||||||
if (!msi_path.empty())
|
|
||||||
{
|
|
||||||
spdlog::error(L"Detected a newer {} version => launching its installer", installedVersion->toWstring());
|
|
||||||
MsiInstallProductW(msi_path.c_str(), nullptr);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spdlog::debug("Extracting embedded MSI installer");
|
spdlog::debug("Extracting embedded MSI installer");
|
||||||
const auto installerPath = ExtractEmbeddedInstaller(fs::temp_directory_path());
|
const auto installerPath = ExtractEmbeddedInstaller(fs::temp_directory_path());
|
||||||
if (!installerPath)
|
if (!installerPath)
|
||||||
{
|
{
|
||||||
if (!silent)
|
ShowMessageBoxError(IDS_INSTALLER_EXTRACT_ERROR);
|
||||||
{
|
|
||||||
ShowMessageBoxError(GET_RESOURCE_STRING(IDS_INSTALLER_EXTRACT_ERROR).c_str(), INSTALLATION_MSGBOX_TITLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
spdlog::error("Couldn't install the MSI installer ({})", GetLastError());
|
spdlog::error("Couldn't install the MSI installer ({})", GetLastError());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -309,11 +311,11 @@ int Bootstrapper(HINSTANCE hInstance)
|
|||||||
fs::remove(*installerPath, _);
|
fs::remove(*installerPath, _);
|
||||||
});
|
});
|
||||||
|
|
||||||
spdlog::debug("Acquiring existing MSI package path");
|
spdlog::debug("Acquiring existing MSI package path if exists");
|
||||||
const auto package_path = updating::get_msi_package_path();
|
const auto package_path = updating::get_msi_package_path();
|
||||||
if (!package_path.empty())
|
if (!package_path.empty())
|
||||||
{
|
{
|
||||||
spdlog::debug(L"Existing MSI package path: {}", package_path);
|
spdlog::debug(L"Existing MSI package path found: {}", package_path);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -323,14 +325,11 @@ int Bootstrapper(HINSTANCE hInstance)
|
|||||||
if (!package_path.empty() && !updating::uninstall_msi_version(package_path, Strings))
|
if (!package_path.empty() && !updating::uninstall_msi_version(package_path, Strings))
|
||||||
{
|
{
|
||||||
spdlog::error("Couldn't install the existing MSI package ({})", GetLastError());
|
spdlog::error("Couldn't install the existing MSI package ({})", GetLastError());
|
||||||
if (!silent)
|
ShowMessageBoxError(IDS_UNINSTALL_PREVIOUS_VERSION_ERROR);
|
||||||
{
|
|
||||||
ShowMessageBoxError(GET_RESOURCE_STRING(IDS_UNINSTALL_PREVIOUS_VERSION_ERROR).c_str(), INSTALLATION_MSGBOX_TITLE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool installDotnet = !skipDotnetInstall;
|
const bool installDotnet = !skipDotnetInstall;
|
||||||
if (!silent)
|
if (!g_Silent)
|
||||||
{
|
{
|
||||||
OpenProgressBarDialog(hInstance, 0, GET_RESOURCE_STRING(IDS_BOOTSTRAPPER_PROGRESS_TITLE).c_str(), GET_RESOURCE_STRING(IDS_DOWNLOADING_DOTNET).c_str());
|
OpenProgressBarDialog(hInstance, 0, GET_RESOURCE_STRING(IDS_BOOTSTRAPPER_PROGRESS_TITLE).c_str(), GET_RESOURCE_STRING(IDS_DOWNLOADING_DOTNET).c_str());
|
||||||
}
|
}
|
||||||
@@ -349,7 +348,7 @@ int Bootstrapper(HINSTANCE hInstance)
|
|||||||
{
|
{
|
||||||
// Dotnet installer has its own progress bar
|
// Dotnet installer has its own progress bar
|
||||||
CloseProgressBarDialog();
|
CloseProgressBarDialog();
|
||||||
installedSuccessfully = updating::install_dotnet(*dotnet_installer_path, silent);
|
installedSuccessfully = updating::install_dotnet(*dotnet_installer_path, g_Silent);
|
||||||
if (!installedSuccessfully)
|
if (!installedSuccessfully)
|
||||||
{
|
{
|
||||||
spdlog::error("Couldn't install dotnet");
|
spdlog::error("Couldn't install dotnet");
|
||||||
@@ -362,10 +361,7 @@ int Bootstrapper(HINSTANCE hInstance)
|
|||||||
|
|
||||||
if (!installedSuccessfully)
|
if (!installedSuccessfully)
|
||||||
{
|
{
|
||||||
if (!silent)
|
ShowMessageBoxError(IDS_DOTNET_INSTALL_ERROR);
|
||||||
{
|
|
||||||
ShowMessageBoxError(GET_RESOURCE_STRING(IDS_DOTNET_INSTALL_ERROR).c_str(), INSTALLATION_MSGBOX_TITLE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -373,7 +369,7 @@ int Bootstrapper(HINSTANCE hInstance)
|
|||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
spdlog::error("Unknown exception during dotnet installation");
|
spdlog::error("Unknown exception during dotnet installation");
|
||||||
MessageBoxW(nullptr, L".NET Core installation", L"Unknown exception encountered!", MB_OK | MB_ICONERROR);
|
ShowMessageBoxError(IDS_DOTNET_INSTALL_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
// At this point, there's no reason to show progress bar window, since MSI installers have their own
|
// At this point, there's no reason to show progress bar window, since MSI installers have their own
|
||||||
@@ -390,7 +386,7 @@ int Bootstrapper(HINSTANCE hInstance)
|
|||||||
|
|
||||||
spdlog::debug("Installation completed");
|
spdlog::debug("Installation completed");
|
||||||
|
|
||||||
if (!noStartPT && !silent)
|
if (!noStartPT && !g_Silent)
|
||||||
{
|
{
|
||||||
spdlog::debug("Starting the newly installed PowerToys.exe");
|
spdlog::debug("Starting the newly installed PowerToys.exe");
|
||||||
auto newPTPath = updating::get_msi_package_installed_path();
|
auto newPTPath = updating::get_msi_package_installed_path();
|
||||||
@@ -419,18 +415,42 @@ int WINAPI WinMain(HINSTANCE hi, HINSTANCE, LPSTR, int)
|
|||||||
}
|
}
|
||||||
catch (const std::exception& ex)
|
catch (const std::exception& ex)
|
||||||
{
|
{
|
||||||
MessageBoxA(nullptr, ex.what(), "Unhandled std exception encountered!", MB_OK | MB_ICONERROR);
|
std::string messageA{ "Unhandled std exception encountered\n" };
|
||||||
|
messageA.append(ex.what());
|
||||||
|
|
||||||
|
if (g_LoggerEnabled)
|
||||||
|
{
|
||||||
|
spdlog::error(messageA.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring messageW{};
|
||||||
|
std::copy(messageA.begin(), messageA.end(), messageW.begin());
|
||||||
|
ShowMessageBoxError(messageW.c_str());
|
||||||
}
|
}
|
||||||
catch (winrt::hresult_error const& ex)
|
catch (winrt::hresult_error const& ex)
|
||||||
{
|
{
|
||||||
winrt::hstring message = ex.message();
|
std::wstring message{ L"Unhandled winrt exception encountered\n" };
|
||||||
MessageBoxW(nullptr, message.c_str(), L"Unhandled winrt exception encountered!", MB_OK | MB_ICONERROR);
|
message.append(ex.message().c_str());
|
||||||
|
|
||||||
|
if (g_LoggerEnabled)
|
||||||
|
{
|
||||||
|
spdlog::error(message.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
ShowMessageBoxError(message.c_str());
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
auto lastErrorMessage = get_last_error_message(GetLastError());
|
auto lastErrorMessage = get_last_error_message(GetLastError());
|
||||||
std::wstring message = lastErrorMessage ? std::move(*lastErrorMessage) : L"";
|
std::wstring message{ L"Unknown exception encountered\n" };
|
||||||
MessageBoxW(nullptr, message.c_str(), L"Unknown exception encountered!", MB_OK | MB_ICONERROR);
|
message.append(lastErrorMessage ? std::move(*lastErrorMessage) : L"");
|
||||||
|
|
||||||
|
if (g_LoggerEnabled)
|
||||||
|
{
|
||||||
|
spdlog::error(message.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
ShowMessageBoxError(message.c_str());
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user