mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-03 09:46:54 +02:00
[Setup] Always elevate bootstrapper to avoid multiple UAC prompts on upgrade
This commit is contained in:
committed by
Andrey Nekrasov
parent
092ee49139
commit
59108365f1
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user