Dev/yuyoyuppe/autoupdate polishing (#11693)

* [Updating] Create a dedicated executable project for updating procedures

* [Updating] Use PowerToys.Update for update procedures (#11495)

* [Updating] Use PowerToys.Update for update procedures

* [Setup] Remove toast notifications and other dependencies from bootstrapper

* [Installer] Remove Winstore, redundant strings

* [Settings] Remove deprecated 'packaged' setting
This commit is contained in:
Andrey Nekrasov
2021-06-14 12:55:59 +03:00
committed by GitHub
parent 5b804a1ff6
commit cdd06d7e98
58 changed files with 914 additions and 1154 deletions

View File

@@ -0,0 +1,9 @@
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
namespace cmdArg
{
const inline wchar_t* RUN_NONELEVATED = L"-run-non-elevated";
}

View File

@@ -97,9 +97,6 @@
<data name="GITHUB_NEW_VERSION_UPDATE_NOW" xml:space="preserve">
<value>Update now</value>
</data>
<data name="UNINSTALLATION_UNKNOWN_ERROR" xml:space="preserve">
<value>Error: please uninstall the previous version of PowerToys manually.</value>
</data>
<data name="GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT" xml:space="preserve">
<value>An update to PowerToys is available. Visit our GitHub page to update.</value>
</data>
@@ -109,12 +106,6 @@
<data name="TOAST_TITLE" xml:space="preserve">
<value>PowerToys Update</value>
</data>
<data name="OFFER_UNINSTALL_MSI" xml:space="preserve">
<value>We've detected a previous installation of PowerToys. Would you like to remove it?</value>
</data>
<data name="OFFER_UNINSTALL_MSI_TITLE" xml:space="preserve">
<value>PowerToys: uninstall previous version?</value>
</data>
<data name="SETTINGS_MENU_TEXT" xml:space="preserve">
<value>Settings</value>
</data>

View File

@@ -2,63 +2,101 @@
#include "Generated Files/resource.h"
#include "action_runner_utils.h"
#include "ActionRunnerUtils.h"
#include "general_settings.h"
#include "update_utils.h"
#include "UpdateUtils.h"
#include <common/logger/logger.h>
#include <common/notifications/notifications.h>
#include <common/updating/installer.h>
#include <common/updating/http_client.h>
#include <common/updating/updating.h>
#include <common/updating/updateState.h>
#include <common/utils/HttpClient.h>
#include <common/utils/process_path.h>
#include <common/utils/resources.h>
#include <common/utils/timeutil.h>
auto Strings = create_notifications_strings();
#include <common/version/version.h>
namespace
{
constexpr int64_t UPDATE_CHECK_INTERVAL_MINUTES = 60 * 24;
constexpr int64_t UPDATE_CHECK_AFTER_FAILED_INTERVAL_MINUTES = 60 * 2;
}
using namespace notifications;
using namespace updating;
bool start_msi_uninstallation_sequence()
std::wstring CurrentVersionToNextVersion(const new_version_download_info& info)
{
const auto package_path = updating::get_msi_package_path();
auto result = VersionHelper{ VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION }.toWstring();
result += L" -> ";
result += info.version.toWstring();
return result;
}
if (package_path.empty())
{
// No MSI version detected
return true;
}
void ShowNewVersionAvailable(const new_version_download_info& info)
{
remove_toasts_by_tag(UPDATING_PROCESS_TOAST_TAG);
if (!updating::offer_msi_uninstallation(Strings))
{
// User declined to uninstall or opted for "Don't show again"
return false;
}
auto sei = launch_action_runner(L"-uninstall_msi");
toast_params toast_params{ UPDATING_PROCESS_TOAST_TAG, false };
std::wstring contents = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_AVAILABLE);
contents += L'\n';
contents += CurrentVersionToNextVersion(info);
WaitForSingleObject(sei.hProcess, INFINITE);
DWORD exit_code = 0;
GetExitCodeProcess(sei.hProcess, &exit_code);
CloseHandle(sei.hProcess);
return exit_code == 0;
show_toast_with_activations(std::move(contents),
GET_RESOURCE_STRING(IDS_TOAST_TITLE),
{},
{ link_button{ GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_UPDATE_NOW),
L"powertoys://update_now/" },
link_button{ GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_MORE_INFO),
L"powertoys://open_settings/" } },
std::move(toast_params));
}
void ShowOpenSettingsForUpdate()
{
remove_toasts_by_tag(UPDATING_PROCESS_TOAST_TAG);
toast_params toast_params{ UPDATING_PROCESS_TOAST_TAG, false };
std::vector<action_t> actions = {
link_button{ GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_MORE_INFO),
L"powertoys://open_settings/" },
};
show_toast_with_activations(GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_AVAILABLE),
GET_RESOURCE_STRING(IDS_TOAST_TITLE),
{},
std::move(actions),
std::move(toast_params));
}
SHELLEXECUTEINFOW LaunchPowerToysUpdate(const wchar_t* cmdline)
{
std::wstring powertoysUpdaterPath;
powertoysUpdaterPath = get_module_folderpath();
powertoysUpdaterPath += L"\\PowerToys.Update.exe";
SHELLEXECUTEINFOW sei{ sizeof(sei) };
sei.fMask = { SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS };
sei.lpFile = powertoysUpdaterPath.c_str();
sei.nShow = SW_SHOWNORMAL;
sei.lpParameters = cmdline;
ShellExecuteExW(&sei);
return sei;
}
using namespace updating;
bool could_be_costly_connection()
bool IsMeteredConnection()
{
using namespace winrt::Windows::Networking::Connectivity;
ConnectionProfile internetConnectionProfile = NetworkInformation::GetInternetConnectionProfile();
return internetConnectionProfile && internetConnectionProfile.IsWwanConnectionProfile();
}
void process_new_version_info(const github_version_info& version_info,
UpdateState& state,
const bool download_update,
const bool show_notifications)
void ProcessNewVersionInfo(const github_version_info& version_info,
UpdateState& state,
const bool download_update,
const bool show_notifications)
{
state.githubUpdateLastCheckedDate.emplace(timeutil::now());
if (std::holds_alternative<version_up_to_date>(version_info))
@@ -89,7 +127,7 @@ void process_new_version_info(const github_version_info& version_info,
state.downloadedInstallerFilename = new_version_info.installer_filename;
if (show_notifications)
{
notifications::show_new_version_available(new_version_info, Strings);
ShowNewVersionAvailable(new_version_info);
}
}
else
@@ -106,12 +144,12 @@ void process_new_version_info(const github_version_info& version_info,
state.downloadedInstallerFilename = {};
if (show_notifications)
{
notifications::show_open_settings_for_update(Strings);
ShowOpenSettingsForUpdate();
}
}
}
void periodic_update_worker()
void PeriodicUpdateWorker()
{
for (;;)
{
@@ -129,15 +167,15 @@ void periodic_update_worker()
std::this_thread::sleep_for(std::chrono::minutes{ sleep_minutes_till_next_update });
const bool download_update = !could_be_costly_connection() && get_general_settings().downloadUpdatesAutomatically;
const bool download_update = !IsMeteredConnection() && get_general_settings().downloadUpdatesAutomatically;
bool version_info_obtained = false;
try
{
const auto new_version_info = get_github_version_info_async(Strings).get();
const auto new_version_info = get_github_version_info_async().get();
if (new_version_info.has_value())
{
version_info_obtained = true;
process_new_version_info(*new_version_info, state, download_update, true);
ProcessNewVersionInfo(*new_version_info, state, download_update, true);
}
else
{
@@ -162,27 +200,27 @@ void periodic_update_worker()
}
}
void check_for_updates_settings_callback()
void CheckForUpdatesCallback()
{
Logger::trace(L"Check for updates callback invoked");
auto state = UpdateState::read();
try
{
auto new_version_info = get_github_version_info_async(Strings).get();
auto new_version_info = get_github_version_info_async().get();
if (!new_version_info)
{
// If we couldn't get a new version from github for some reason, assume we're up to date, but also log error
new_version_info = version_up_to_date{};
Logger::error(L"Couldn't obtain version info from github: {}", new_version_info.error());
}
const bool download_update = !could_be_costly_connection() && get_general_settings().downloadUpdatesAutomatically;
process_new_version_info(*new_version_info, state, download_update, false);
const bool download_update = !IsMeteredConnection() && get_general_settings().downloadUpdatesAutomatically;
ProcessNewVersionInfo(*new_version_info, state, download_update, false);
UpdateState::store([&](UpdateState& v) {
v = std::move(state);
});
}
catch (...)
{
Logger::error("check_for_updates_settings_callback: error while processing version info");
Logger::error("CheckForUpdatesCallback: error while processing version info");
}
}

View File

@@ -1,9 +1,9 @@
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <common/updating/updating.h>
SHELLEXECUTEINFOW launch_action_runner(const wchar_t* cmdline);
void PeriodicUpdateWorker();
void CheckForUpdatesCallback();
namespace cmdArg
{
@@ -16,8 +16,7 @@ namespace cmdArg
const inline wchar_t* UPDATE_STAGE2_RESTART_PT = L"restart";
const inline wchar_t* UPDATE_STAGE2_DONT_START_PT = L"dont_start";
const inline wchar_t* UNINSTALL_MSI = L"-uninstall_msi";
const inline wchar_t* RUN_NONELEVATED = L"-run-non-elevated";
const inline wchar_t* UPDATE_REPORT_SUCCESS = L"-report_update_success";
}
SHELLEXECUTEINFOW LaunchPowerToysUpdate(const wchar_t* cmdline);

View File

@@ -1,28 +0,0 @@
#include "pch.h"
#include "action_runner_utils.h"
#include <common/utils/process_path.h>
#include <common/winstore/winstore.h>
SHELLEXECUTEINFOW launch_action_runner(const wchar_t* cmdline)
{
std::wstring action_runner_path;
if (winstore::running_as_packaged())
{
action_runner_path = winrt::Windows::ApplicationModel::Package::Current().InstalledLocation().Path();
}
else
{
action_runner_path = get_module_folderpath();
}
action_runner_path += L"\\PowerToys.ActionRunner.exe";
SHELLEXECUTEINFOW sei{ sizeof(sei) };
sei.fMask = { SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS };
sei.lpFile = action_runner_path.c_str();
sei.nShow = SW_SHOWNORMAL;
sei.lpParameters = cmdline;
ShellExecuteExW(&sei);
return sei;
}

View File

@@ -6,7 +6,6 @@
#include <common/SettingsAPI/settings_helpers.h>
#include "powertoy_module.h"
#include <common/themes/windows_colors.h>
#include <common/winstore/winstore.h>
#include "trace.h"
#include <common/utils/elevation.h>
@@ -22,7 +21,6 @@ json::JsonObject GeneralSettings::to_json()
{
json::JsonObject result;
result.SetNamedValue(L"packaged", json::value(isPackaged));
result.SetNamedValue(L"startup", json::value(isStartupEnabled));
if (!startupDisabledReason.empty())
{
@@ -65,7 +63,6 @@ GeneralSettings get_general_settings()
{
const bool is_user_admin = check_user_is_admin();
GeneralSettings settings{
.isPackaged = winstore::running_as_packaged(),
.isElevated = is_process_elevated(),
.isRunElevated = run_as_elevated,
.isAdmin = is_user_admin,
@@ -75,31 +72,7 @@ GeneralSettings get_general_settings()
.powerToysVersion = get_product_version()
};
if (winstore::running_as_packaged())
{
const auto task_state = winstore::get_startup_task_status_async().get();
switch (task_state)
{
case winstore::StartupTaskState::Disabled:
settings.isStartupEnabled = false;
break;
case winstore::StartupTaskState::Enabled:
settings.isStartupEnabled = true;
break;
case winstore::StartupTaskState::DisabledByPolicy:
settings.startupDisabledReason = GET_RESOURCE_STRING(IDS_STARTUP_DISABLED_BY_POLICY);
settings.isStartupEnabled = false;
break;
case winstore::StartupTaskState::DisabledByUser:
settings.startupDisabledReason = GET_RESOURCE_STRING(IDS_STARTUP_DISABLED_BY_USER);
settings.isStartupEnabled = false;
break;
}
}
else
{
settings.isStartupEnabled = is_auto_start_task_active_for_this_user();
}
settings.isStartupEnabled = is_auto_start_task_active_for_this_user();
for (auto& [name, powertoy] : modules())
{
@@ -118,40 +91,33 @@ void apply_general_settings(const json::JsonObject& general_configs, bool save)
if (json::has(general_configs, L"startup", json::JsonValueType::Boolean))
{
const bool startup = general_configs.GetNamedBoolean(L"startup");
if (winstore::running_as_packaged())
if (startup)
{
winstore::switch_startup_task_state_async(startup).wait();
}
else
{
if (startup)
if (is_process_elevated())
{
if (is_process_elevated())
{
delete_auto_start_task_for_this_user();
create_auto_start_task_for_this_user(general_configs.GetNamedBoolean(L"run_elevated", false));
}
else
{
if (!is_auto_start_task_active_for_this_user())
{
delete_auto_start_task_for_this_user();
create_auto_start_task_for_this_user(false);
run_as_elevated = false;
}
else if (!general_configs.GetNamedBoolean(L"run_elevated", false))
{
delete_auto_start_task_for_this_user();
create_auto_start_task_for_this_user(false);
}
}
delete_auto_start_task_for_this_user();
create_auto_start_task_for_this_user(general_configs.GetNamedBoolean(L"run_elevated", false));
}
else
{
delete_auto_start_task_for_this_user();
if (!is_auto_start_task_active_for_this_user())
{
delete_auto_start_task_for_this_user();
create_auto_start_task_for_this_user(false);
run_as_elevated = false;
}
else if (!general_configs.GetNamedBoolean(L"run_elevated", false))
{
delete_auto_start_task_for_this_user();
create_auto_start_task_for_this_user(false);
}
}
}
else
{
delete_auto_start_task_for_this_user();
}
}
if (json::has(general_configs, L"enabled"))
{

View File

@@ -4,7 +4,6 @@
struct GeneralSettings
{
bool isPackaged;
bool isStartupEnabled;
std::wstring startupDisabledReason;
std::map<std::wstring, bool> isModulesEnabledMap;

View File

@@ -22,10 +22,9 @@
#include <common/utils/elevation.h>
#include <common/utils/processApi.h>
#include <common/utils/resources.h>
#include <common/winstore/winstore.h>
#include "update_utils.h"
#include "action_runner_utils.h"
#include "UpdateUtils.h"
#include "ActionRunnerUtils.h"
#include <winrt/Windows.System.h>
@@ -45,8 +44,6 @@
#include <common/utils/window.h>
#include <common/version/version.h>
extern updating::notifications::strings Strings;
namespace
{
const wchar_t PT_URI_PROTOCOL_SCHEME[] = L"powertoys://";
@@ -120,26 +117,15 @@ int runner(bool isProcessElevated, bool openSettings, bool openOobe)
debug_verify_launcher_assets();
std::thread{ [] {
periodic_update_worker();
PeriodicUpdateWorker();
} }.detach();
if (winstore::running_as_packaged())
{
std::thread{ [] {
start_msi_uninstallation_sequence();
} }.detach();
}
else
{
std::thread{ [] {
if (updating::uninstall_previous_msix_version_async().get())
{
notifications::show_toast(GET_RESOURCE_STRING(IDS_OLDER_MSIX_UNINSTALLED).c_str(), L"PowerToys");
}
} }.detach();
}
notifications::register_background_toast_handler();
std::thread{ [] {
if (updating::uninstall_previous_msix_version_async().get())
{
notifications::show_toast(GET_RESOURCE_STRING(IDS_OLDER_MSIX_UNINSTALLED).c_str(), L"PowerToys");
}
} }.detach();
chdir_current_executable();
// Load Powertoys DLLs
@@ -258,7 +244,7 @@ toast_notification_handler_result toast_notification_handler(const std::wstring_
else if (param.starts_with(update_now))
{
std::wstring args{ cmdArg::UPDATE_NOW_LAUNCH_STAGE1 };
launch_action_runner(args.c_str());
LaunchPowerToysUpdate(args.c_str());
return toast_notification_handler_result::exit_success;
}
else if (param == couldnt_toggle_powerpreview_modules_disable)

View File

@@ -46,7 +46,6 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\common\interop\two_way_pipe_message_ipc.cpp" />
<ClCompile Include="action_runner_utils.cpp" />
<ClCompile Include="auto_start_helper.cpp" />
<ClCompile Include="CentralizedHotkeys.cpp" />
<ClCompile Include="general_settings.cpp" />
@@ -62,17 +61,17 @@
<ClCompile Include="trace.cpp" />
<ClCompile Include="tray_icon.cpp" />
<ClCompile Include="unhandled_exception_handler.cpp" />
<ClCompile Include="update_utils.cpp" />
<ClCompile Include="UpdateUtils.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="action_runner_utils.h" />
<ClInclude Include="ActionRunnerUtils.h" />
<ClInclude Include="auto_start_helper.h" />
<ClInclude Include="CentralizedHotkeys.h" />
<ClInclude Include="general_settings.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="centralized_kb_hook.h" />
<ClInclude Include="settings_telemetry.h" />
<ClInclude Include="update_utils.h" />
<ClInclude Include="UpdateUtils.h" />
<ClInclude Include="powertoy_module.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="restart_elevated.h" />
@@ -111,9 +110,6 @@
<ProjectReference Include="..\common\updating\updating.vcxproj">
<Project>{17da04df-e393-4397-9cf0-84dabe11032e}</Project>
</ProjectReference>
<ProjectReference Include="..\common\WinStore\Winstore.vcxproj">
<Project>{c502a854-53ac-4ebb-8dc0-e4af2191e4f6}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

View File

@@ -27,10 +27,7 @@
<ClCompile Include="restart_elevated.cpp">
<Filter>Utils</Filter>
</ClCompile>
<ClCompile Include="update_utils.cpp">
<Filter>Utils</Filter>
</ClCompile>
<ClCompile Include="action_runner_utils.cpp">
<ClCompile Include="UpdateUtils.cpp">
<Filter>Utils</Filter>
</ClCompile>
<ClCompile Include="centralized_kb_hook.cpp">
@@ -72,10 +69,10 @@
<ClInclude Include="restart_elevated.h">
<Filter>Utils</Filter>
</ClInclude>
<ClInclude Include="update_utils.h">
<ClInclude Include="UpdateUtils.h">
<Filter>Utils</Filter>
</ClInclude>
<ClInclude Include="action_runner_utils.h">
<ClInclude Include="ActionRunnerUtils.h">
<Filter>Utils</Filter>
</ClInclude>
<ClInclude Include="resource.h">

View File

@@ -9,7 +9,7 @@
#include "tray_icon.h"
#include "general_settings.h"
#include "restart_elevated.h"
#include "update_utils.h"
#include "UpdateUtils.h"
#include "centralized_kb_hook.h"
#include <common/utils/json.h>
@@ -84,7 +84,7 @@ std::optional<std::wstring> dispatch_json_action_to_module(const json::JsonObjec
}
else if (action == L"check_for_updates")
{
check_for_updates_settings_callback();
CheckForUpdatesCallback();
}
else if (action == L"request_update_state_date")
{

View File

@@ -1,7 +0,0 @@
#pragma once
#include <common/updating/updating.h>
bool start_msi_uninstallation_sequence();
void periodic_update_worker();
void check_for_updates_settings_callback();