Skip to content

Commit

Permalink
[Setup] Always elevate bootstrapper to avoid multiple UAC prompts on …
Browse files Browse the repository at this point in the history
…upgrade
  • Loading branch information
yuyoyuppe committed Oct 25, 2021
1 parent 79aba4e commit 0d422e5
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 81 deletions.
6 changes: 4 additions & 2 deletions .github/actions/spell-check/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ CANRENAME
Captureascreenshot
CAPTURECHANGED
CASESENSITIVE
cassert
CAtl
CCDDEE
ccf
Expand Down Expand Up @@ -999,7 +1000,6 @@ IRepository
IResult
ISavable
isbi
iss
ISearch
IService
isetting
Expand All @@ -1008,6 +1008,7 @@ IShell
ISingle
ISmart
isocpp
iss
IStorage
IStream
istreambuf
Expand All @@ -1018,9 +1019,9 @@ ITab
ITask
ITemplate
ITEMSTATEICONCLICK
ITerminal
ITest
ith
ITerminal
IThrottled
IThumbnail
ITrigger
Expand Down Expand Up @@ -1327,6 +1328,7 @@ msedge
MSGFLT
mshtmdid
msi
msiexec
MSIFASTINSTALL
MSIHANDLE
MSIINSTALLER
Expand Down
107 changes: 54 additions & 53 deletions installer/PowerToysBootstrapper/bootstrapper/bootstrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,51 @@ std::optional<InstalledVersionInfo> get_installed_powertoys_version()
};
}

void ReLaunchElevatedAndExit()
{
std::wstring params;
int nCmdArgs = 0;
LPWSTR* argList = CommandLineToArgvW(GetCommandLineW(), &nCmdArgs);
for (int i = 1; i < nCmdArgs; ++i)
{
if (std::wstring_view{ argList[i] }.find(L' ') != std::wstring_view::npos)
{
params += L'"';
params += argList[i];
params += L'"';
}
else
{
params += argList[i];
}

if (i != nCmdArgs - 1)
{
params += L' ';
}
}

const auto processHandle = run_elevated(argList[0], params.c_str());
if (!processHandle)
{
spdlog::error("Couldn't restart elevated: ({})", GetLastError());
return;
}

if (WaitForSingleObject(processHandle, 3600000) == WAIT_OBJECT_0)
{
DWORD exitCode = 0;
GetExitCodeProcess(processHandle, &exitCode);
std::exit(exitCode);
}
else
{
spdlog::error("Elevated setup process timed out after 60m: ({})", GetLastError());
TerminateProcess(processHandle, 0);
std::exit(1);
}
}

int Bootstrapper(HINSTANCE hInstance)
{
winrt::init_apartment();
Expand Down Expand Up @@ -299,66 +344,22 @@ int Bootstrapper(HINSTANCE hInstance)
}
}

// Setup MSI UI visibility and restart as elevated if required
// Always elevate bootstrapper process since it invokes msiexec multiple times,
// so we can avoid multiple UAC confirmations
if (!is_process_elevated())
{
ReLaunchElevatedAndExit();
}

// Setup MSI UI visibility
if (!noFullUI)
{
MsiSetInternalUI(INSTALLUILEVEL_FULL, nullptr);
}

if (g_Silent)
{
if (is_process_elevated())
{
MsiSetInternalUI(INSTALLUILEVEL_NONE, nullptr);
}
else
{
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
std::wstring params;
int nCmdArgs = 0;
LPWSTR* argList = CommandLineToArgvW(GetCommandLineW(), &nCmdArgs);
for (int i = 1; i < nCmdArgs; ++i)
{
if (std::wstring_view{ argList[i] }.find(L' ') != std::wstring_view::npos)
{
params += L'"';
params += argList[i];
params += L'"';
}
else
{
params += argList[i];
}

if (i != nCmdArgs - 1)
{
params += L' ';
}
}

const auto processHandle = run_elevated(argList[0], params.c_str());
if (!processHandle)
{
spdlog::error("Couldn't restart elevated to enable silent mode! ({})", GetLastError());
return 1;
}

if (WaitForSingleObject(processHandle, 3600000) == WAIT_OBJECT_0)
{
DWORD exitCode = 0;
GetExitCodeProcess(processHandle, &exitCode);
return exitCode;
}
else
{
spdlog::error("Elevated setup process timed out after 60m => using basic MSI UI ({})", GetLastError());
// Couldn't install using the completely silent mode in an hour, use basic UI.
TerminateProcess(processHandle, 0);
MsiSetInternalUI(INSTALLUILEVEL_BASIC, nullptr);
}
}
MsiSetInternalUI(INSTALLUILEVEL_NONE, nullptr);
}

// Try killing PowerToys and prevent future processes launch by acquiring app mutex
Expand Down
2 changes: 1 addition & 1 deletion installer/PowerToysSetupCustomActions/CustomAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ UINT __stdcall UnApplyModulesRegistryChangeSetsCA(MSIHANDLE hInstall)
ExitOnFailure(hr, "Failed to get installfolder.");
for (const auto& changeset : getAllModulesChangesets(installationFolder, false))
{
changeset.unapply();
changeset.unApply();
}

ExitOnFailure(hr, "Failed to extract msix");
Expand Down
22 changes: 11 additions & 11 deletions src/common/utils/modulesRegistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace fs = std::filesystem;

inline registry::Changeset getSvgPreviewHandlerChangset(const std::wstring installationDir, const bool perUser)
inline registry::ChangeSet getSvgPreviewHandlerChangeset(const std::wstring installationDir, const bool perUser)
{
using namespace registry::shellex;
return generatePreviewHandler(PreviewHandlerType::preview,
Expand All @@ -22,7 +22,7 @@ inline registry::Changeset getSvgPreviewHandlerChangset(const std::wstring insta
L".svg");
}

inline registry::Changeset getMdPreviewHandlerChangset(const std::wstring installationDir, const bool perUser)
inline registry::ChangeSet getMdPreviewHandlerChangeset(const std::wstring installationDir, const bool perUser)
{
using namespace registry::shellex;
return generatePreviewHandler(PreviewHandlerType::preview,
Expand All @@ -36,7 +36,7 @@ inline registry::Changeset getMdPreviewHandlerChangset(const std::wstring instal
L".md");
}

inline registry::Changeset getPdfPreviewHandlerChangset(const std::wstring installationDir, const bool perUser)
inline registry::ChangeSet getPdfPreviewHandlerChangeset(const std::wstring installationDir, const bool perUser)
{
using namespace registry::shellex;
return generatePreviewHandler(PreviewHandlerType::preview,
Expand All @@ -50,7 +50,7 @@ inline registry::Changeset getPdfPreviewHandlerChangset(const std::wstring insta
L".pdf");
}

inline registry::Changeset getSvgThumbnailHandlerChangset(const std::wstring installationDir, const bool perUser)
inline registry::ChangeSet getSvgThumbnailHandlerChangeset(const std::wstring installationDir, const bool perUser)
{
using namespace registry::shellex;
return generatePreviewHandler(PreviewHandlerType::thumbnail,
Expand All @@ -64,7 +64,7 @@ inline registry::Changeset getSvgThumbnailHandlerChangset(const std::wstring ins
L".svg");
}

inline registry::Changeset getPdfThumbnailHandlerChangset(const std::wstring installationDir, const bool perUser)
inline registry::ChangeSet getPdfThumbnailHandlerChangeset(const std::wstring installationDir, const bool perUser)
{
using namespace registry::shellex;
return generatePreviewHandler(PreviewHandlerType::thumbnail,
Expand All @@ -78,11 +78,11 @@ inline registry::Changeset getPdfThumbnailHandlerChangset(const std::wstring ins
L".pdf");
}

inline std::vector<registry::Changeset> getAllModulesChangesets(const std::wstring installationDir, const bool perUser)
inline std::vector<registry::ChangeSet> getAllModulesChangesets(const std::wstring installationDir, const bool perUser)
{
return { getSvgPreviewHandlerChangset(installationDir, perUser),
getMdPreviewHandlerChangset(installationDir, perUser),
getPdfPreviewHandlerChangset(installationDir, perUser),
getSvgThumbnailHandlerChangset(installationDir, perUser),
getPdfThumbnailHandlerChangset(installationDir, perUser) };
return { getSvgPreviewHandlerChangeset(installationDir, perUser),
getMdPreviewHandlerChangeset(installationDir, perUser),
getPdfPreviewHandlerChangeset(installationDir, perUser),
getSvgThumbnailHandlerChangeset(installationDir, perUser),
getPdfThumbnailHandlerChangeset(installationDir, perUser) };
}
12 changes: 6 additions & 6 deletions src/common/utils/registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ namespace registry
valueSize) == ERROR_SUCCESS;
}

bool unapply() const
bool unApply() const
{
HKEY key{};
if (RegOpenKeyExW(scope, path.c_str(), 0, KEY_ALL_ACCESS, &key) != ERROR_SUCCESS)
Expand Down Expand Up @@ -207,7 +207,7 @@ namespace registry
}
};

struct Changeset
struct ChangeSet
{
std::vector<ValueChange> changes;

Expand All @@ -233,12 +233,12 @@ namespace registry
return ok;
}

bool unapply() const
bool unApply() const
{
bool ok = true;
for (const auto& c : changes)
{
ok = c.unapply() && ok;
ok = c.unApply() && ok;
}
return ok;
}
Expand All @@ -256,7 +256,7 @@ namespace registry
thumbnail
};

inline registry::Changeset generatePreviewHandler(const PreviewHandlerType handlerType,
inline registry::ChangeSet generatePreviewHandler(const PreviewHandlerType handlerType,
const bool perUser,
std::wstring handlerClsid,
std::wstring powertoysVersion,
Expand Down Expand Up @@ -323,7 +323,7 @@ namespace registry
changes.push_back({ scope, previewHandlerListPath, handlerClsid, displayName });
}

return registry::Changeset{ .changes = std::move(changes) };
return registry::ChangeSet{ .changes = std::move(changes) };
}
}
}
14 changes: 7 additions & 7 deletions src/modules/previewpane/powerpreview/powerpreview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,23 @@ PowerPreviewModule::PowerPreviewModule() :
const bool installPerUser = false;
m_fileExplorerModules.push_back({ .settingName = L"svg-previewer-toggle-setting",
.settingDescription = GET_RESOURCE_STRING(IDS_PREVPANE_SVG_SETTINGS_DESCRIPTION),
.registryChanges = getSvgPreviewHandlerChangset(installationDir, installPerUser) });
.registryChanges = getSvgPreviewHandlerChangeset(installationDir, installPerUser) });

m_fileExplorerModules.push_back({ .settingName = L"md-previewer-toggle-setting",
.settingDescription = GET_RESOURCE_STRING(IDS_PREVPANE_MD_SETTINGS_DESCRIPTION),
.registryChanges = getMdPreviewHandlerChangset(installationDir, installPerUser) });
.registryChanges = getMdPreviewHandlerChangeset(installationDir, installPerUser) });

m_fileExplorerModules.push_back({ .settingName = L"pdf-previewer-toggle-setting",
.settingDescription = GET_RESOURCE_STRING(IDS_PREVPANE_PDF_SETTINGS_DESCRIPTION),
.registryChanges = getPdfPreviewHandlerChangset(installationDir, installPerUser) });
.registryChanges = getPdfPreviewHandlerChangeset(installationDir, installPerUser) });

m_fileExplorerModules.push_back({ .settingName = L"svg-thumbnail-toggle-setting",
.settingDescription = GET_RESOURCE_STRING(IDS_SVG_THUMBNAIL_PROVIDER_SETTINGS_DESCRIPTION),
.registryChanges = getSvgThumbnailHandlerChangset(installationDir, installPerUser) });
.registryChanges = getSvgThumbnailHandlerChangeset(installationDir, installPerUser) });

m_fileExplorerModules.push_back({ .settingName = L"pdf-thumbnail-toggle-setting",
.settingDescription = GET_RESOURCE_STRING(IDS_PDF_THUMBNAIL_PROVIDER_SETTINGS_DESCRIPTION),
.registryChanges = getPdfThumbnailHandlerChangset(installationDir, installPerUser) });
.registryChanges = getPdfThumbnailHandlerChangeset(installationDir, installPerUser) });

try
{
Expand Down Expand Up @@ -133,7 +133,7 @@ void PowerPreviewModule::disable()
{
for (auto& fileExplorerModule : m_fileExplorerModules)
{
fileExplorerModule.registryChanges.unapply();
fileExplorerModule.registryChanges.unApply();
}
}
else
Expand Down Expand Up @@ -197,7 +197,7 @@ void PowerPreviewModule::apply_settings(const PowerToysSettings::PowerToyValues&
}

// (Un)Apply registry changes depending on the new setting value
const bool updated = *toggle ? fileExplorerModule.registryChanges.apply() : fileExplorerModule.registryChanges.unapply();
const bool updated = *toggle ? fileExplorerModule.registryChanges.apply() : fileExplorerModule.registryChanges.unApply();

if (updated)
{
Expand Down
2 changes: 1 addition & 1 deletion src/modules/previewpane/powerpreview/powerpreview.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ struct FileExplorerModule
{
std::wstring settingName;
std::wstring settingDescription;
registry::Changeset registryChanges;
registry::ChangeSet registryChanges;
};

// Implement the PowerToy Module Interface and all the required methods.
Expand Down

0 comments on commit 0d422e5

Please sign in to comment.