[Setup] Always elevate bootstrapper to avoid multiple UAC prompts on upgrade
This commit is contained in:
Родитель
092ee49139
Коммит
59108365f1
|
@ -206,6 +206,7 @@ CANRENAME
|
|||
Captureascreenshot
|
||||
CAPTURECHANGED
|
||||
CASESENSITIVE
|
||||
cassert
|
||||
CAtl
|
||||
CCDDEE
|
||||
ccf
|
||||
|
@ -1010,7 +1011,6 @@ IRepository
|
|||
IResult
|
||||
ISavable
|
||||
isbi
|
||||
iss
|
||||
ISearch
|
||||
IService
|
||||
isetting
|
||||
|
@ -1019,6 +1019,7 @@ IShell
|
|||
ISingle
|
||||
ISmart
|
||||
isocpp
|
||||
iss
|
||||
IStorage
|
||||
IStream
|
||||
istreambuf
|
||||
|
@ -1029,9 +1030,9 @@ ITab
|
|||
ITask
|
||||
ITemplate
|
||||
ITEMSTATEICONCLICK
|
||||
ITerminal
|
||||
ITest
|
||||
ith
|
||||
ITerminal
|
||||
IThrottled
|
||||
IThumbnail
|
||||
ITrigger
|
||||
|
@ -1342,6 +1343,7 @@ msedge
|
|||
MSGFLT
|
||||
mshtmdid
|
||||
msi
|
||||
msiexec
|
||||
MSIFASTINSTALL
|
||||
MSIHANDLE
|
||||
MSIINSTALLER
|
||||
|
|
|
@ -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();
|
||||
|
@ -299,7 +344,14 @@ 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);
|
||||
|
@ -307,58 +359,7 @@ int Bootstrapper(HINSTANCE hInstance)
|
|||
|
||||
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
|
||||
|
|
|
@ -52,11 +52,11 @@ UINT __stdcall ApplyModulesRegistryChangeSetsCA(MSIHANDLE hInstall)
|
|||
ExitOnFailure(hr, "Failed to initialize");
|
||||
hr = getInstallFolder(hInstall, installationFolder);
|
||||
ExitOnFailure(hr, "Failed to get installfolder.");
|
||||
for (const auto& changeset : getAllModulesChangesets(installationFolder, false))
|
||||
for (const auto& changeSet : getAllModulesChangeSets(installationFolder, false))
|
||||
{
|
||||
if (!changeset.apply())
|
||||
if (!changeSet.apply())
|
||||
{
|
||||
WcaLog(LOGMSG_STANDARD, "Couldn't apply registry changeset");
|
||||
WcaLog(LOGMSG_STANDARD, "Couldn't apply registry changeSet");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,9 +77,9 @@ UINT __stdcall UnApplyModulesRegistryChangeSetsCA(MSIHANDLE hInstall)
|
|||
ExitOnFailure(hr, "Failed to initialize");
|
||||
hr = getInstallFolder(hInstall, installationFolder);
|
||||
ExitOnFailure(hr, "Failed to get installfolder.");
|
||||
for (const auto& changeset : getAllModulesChangesets(installationFolder, false))
|
||||
for (const auto& changeSet : getAllModulesChangeSets(installationFolder, false))
|
||||
{
|
||||
changeset.unapply();
|
||||
changeSet.unApply();
|
||||
}
|
||||
|
||||
ExitOnFailure(hr, "Failed to extract msix");
|
||||
|
|
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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) };
|
||||
}
|
|
@ -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)
|
||||
|
@ -207,7 +207,7 @@ namespace registry
|
|||
}
|
||||
};
|
||||
|
||||
struct Changeset
|
||||
struct ChangeSet
|
||||
{
|
||||
std::vector<ValueChange> changes;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
@ -133,7 +133,7 @@ void PowerPreviewModule::disable()
|
|||
{
|
||||
for (auto& fileExplorerModule : m_fileExplorerModules)
|
||||
{
|
||||
fileExplorerModule.registryChanges.unapply();
|
||||
fileExplorerModule.registryChanges.unApply();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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.
|
||||
|
|
Загрузка…
Ссылка в новой задаче