Skip to content

Commit

Permalink
bootstrapper: add --extract_msi arg for users that must access MSI (#…
Browse files Browse the repository at this point in the history
…8646)

* bootstrapper: add --extract_msi arg for users that must access MSI

- clean up setting outdated MSI properties
- minor fixes
  • Loading branch information
yuyoyuppe committed Dec 17, 2020
1 parent e58ff6c commit 0709b06
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 14 deletions.
38 changes: 27 additions & 11 deletions installer/PowerToysBootstrapper/bootstrapper/bootstrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

#include "progressbar_window.h"


auto Strings = create_notifications_strings();

#define STR_HELPER(x) #x
Expand All @@ -37,14 +36,14 @@ namespace // Strings in this namespace should not be localized

namespace fs = std::filesystem;

std::optional<fs::path> extractEmbeddedInstaller()
std::optional<fs::path> extractEmbeddedInstaller(const fs::path extractPath)
{
auto executableRes = RcResource::create(IDR_BIN_MSIINSTALLER, L"BIN");
if (!executableRes)
{
return std::nullopt;
}
auto installerPath = fs::temp_directory_path() / L"PowerToysBootstrappedInstaller-" PRODUCT_VERSION_STRING L".msi";
auto installerPath = extractPath / L"PowerToysBootstrappedInstaller-" PRODUCT_VERSION_STRING L".msi";
return executableRes->saveAsFile(installerPath) ? std::make_optional(std::move(installerPath)) : std::nullopt;
}

Expand Down Expand Up @@ -106,7 +105,8 @@ int bootstrapper(HINSTANCE hInstance)
("skip_dotnet_install", "Skip dotnet 3.X installation even if it's not detected")
("log_level", "Log level. Possible values: off|debug|error", cxxopts::value<std::string>()->default_value("off"))
("log_dir", "Log directory", cxxopts::value<std::string>()->default_value("."))
("install_dir", "Installation directory", cxxopts::value<std::string>()->default_value(defaultInstallDir));
("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.");
// clang-format on
cxxopts::ParseResult cmdArgs;
bool showHelp = false;
Expand All @@ -127,13 +127,16 @@ int bootstrapper(HINSTANCE hInstance)
MessageBoxA(nullptr, helpMsg.str().c_str(), "Help", MB_OK | MB_ICONINFORMATION);
return 0;
}

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 noStartPT = cmdArgs["no_start_pt"].as<bool>();
const auto logLevel = cmdArgs["log_level"].as<std::string>();
const auto logDirArg = cmdArgs["log_dir"].as<std::string>();
const auto installDirArg = cmdArgs["install_dir"].as<std::string>();
const bool extract_msi_only = cmdArgs["extract_msi"].as<bool>();

spdlog::level::level_enum severity = spdlog::level::off;

std::wstring installFolderProp;
Expand Down Expand Up @@ -176,8 +179,23 @@ int bootstrapper(HINSTANCE hInstance)
severity = spdlog::level::err;
}
setup_log(logDir, severity);
spdlog::debug("PowerToys Bootstrapper is launched!\nnoFullUI: {}\nsilent: {}\nno_start_pt: {}\nskip_dotnet_install: {}\nlog_level: {}\ninstall_dir: {}", noFullUI, silent, noStartPT, skipDotnetInstall, logLevel, installDirArg);
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);

// If a user requested an MSI -> extract it and exit
if (extract_msi_only)
{
if (const auto installerPath = extractEmbeddedInstaller(fs::current_path()))
{
spdlog::info("MSI installer was extracted to {}", installerPath->string());
}
else
{
spdlog::error("MSI installer couldn't be extracted");
}
return 0;
}

// Setup MSI UI visibility and restart as elevated if required
if (!noFullUI)
{
MsiSetInternalUI(INSTALLUILEVEL_FULL, nullptr);
Expand Down Expand Up @@ -236,13 +254,12 @@ int bootstrapper(HINSTANCE hInstance)
}
}

// Try killing PowerToys and prevent future processes launch
// Try killing PowerToys and prevent future processes launch by acquiring app mutex
for (auto& handle : getProcessHandlesByName(L"PowerToys.exe", PROCESS_TERMINATE))
{
TerminateProcess(handle.get(), 0);
}
auto powerToysMutex = createAppMutex(POWERTOYS_MSI_MUTEX_NAME);

auto instanceMutex = createAppMutex(POWERTOYS_BOOTSTRAPPER_MUTEX_NAME);
if (!instanceMutex)
{
Expand All @@ -264,7 +281,7 @@ int bootstrapper(HINSTANCE hInstance)
}

spdlog::debug("Extracting embedded MSI installer");
const auto installerPath = extractEmbeddedInstaller();
const auto installerPath = extractEmbeddedInstaller(fs::temp_directory_path());
if (!installerPath)
{
if (!silent)
Expand Down Expand Up @@ -309,7 +326,7 @@ int bootstrapper(HINSTANCE hInstance)
{
spdlog::debug("Detecting if dotnet is installed");
const bool dotnetInstalled = updating::dotnet_is_installed();
spdlog::debug("Dotnet is installed: {}", dotnetInstalled);
spdlog::debug("Dotnet is already installed: {}", dotnetInstalled);
if (!dotnetInstalled)
{
bool installed_successfully = false;
Expand Down Expand Up @@ -347,8 +364,7 @@ int bootstrapper(HINSTANCE hInstance)
// At this point, there's no reason to show progress bar window, since MSI installers have their own
close_progressbar_window();

// Always skip dotnet install, because we should've installed it from here earlier
std::wstring msiProps = L"SKIPDOTNETINSTALL=1 " + installFolderProp;
const std::wstring msiProps = installFolderProp;
spdlog::debug("Launching MSI installation for new package {}", installerPath->string());
const bool installationDone = MsiInstallProductW(installerPath->c_str(), msiProps.c_str()) == ERROR_SUCCESS;
if (!installationDone)
Expand Down
1 change: 0 additions & 1 deletion installer/PowerToysSetup/Product.wxs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@
<Property Id="INSTALLSTARTMENUSHORTCUT" Value="1"/>
<Property Id="CREATESCHEDULEDTASK" Value="1"/>
<Property Id="WixShellExecTarget" Value="[#action_runner.exe]" />
<Property Id="SKIPDOTNETINSTALL" Value="0"/>

<Property Id ="EXISTINGPOWERRENAMEEXTPATH">
<RegistrySearch Id="ExistingExtPath" Root="HKCR" Key="CLSID\{0440049F-D1DC-4E46-B27B-98393D79486B}\InprocServer32" Type="raw"/>
Expand Down
4 changes: 2 additions & 2 deletions src/action_runner/action_runner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
}
std::wstring_view action{ args[1] };

if (action == L"-run-non-elevated")
if (action == RUN_NONELEVATED_CMDARG)
{
int nextArg = 2;

Expand Down Expand Up @@ -235,7 +235,7 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
}
}
}
else if (action == L"-uninstall_msi")
else if (action == UNINSTALL_MSI_CMDARG)
{
return uninstall_msi_action();
}
Expand Down
4 changes: 4 additions & 0 deletions src/runner/action_runner_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,8 @@ const inline wchar_t* UPDATE_NOW_LAUNCH_STAGE2_CMDARG = L"-update_now_stage_2";
const inline wchar_t* UPDATE_STAGE2_RESTART_PT_CMDARG = L"restart";
const inline wchar_t* UPDATE_STAGE2_DONT_START_PT_CMDARG = L"dont_start";

const inline wchar_t * UNINSTALL_MSI_CMDARG = L"-uninstall_msi";
const inline wchar_t * RUN_NONELEVATED_CMDARG = L"-run-non-elevated";

const inline wchar_t* UPDATE_REPORT_SUCCESS = L"-report_update_success";

0 comments on commit 0709b06

Please sign in to comment.