mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-01-18 22:43:31 +08:00
[Auto-update] Auto-update improvements (#11356)
* [Updating] Refactor autoupdate mechanism to use Settings window buttons * [Updating] Don't use underscores in update_state (#11029) * [Updating] Rename action_runner to be consisent with accepted format * [Updating] Make UpdateState values explicit * [Setup] Set default bootstrapper log severity to debug * [BugReport] Include all found bootstrapper logs * [Setup] Use capital letter for ActionRunner * [Updating] Simple UI to test UpdateState * [Action Runner] cleanup and coding style * [BugReportTool] fix coding convension * [Auto-update][PT Settings] Updated general page in the Settings (#11227) * [Auto-update][PT Settings] File watcher monitoring UpdateState.json (#11282) * Handle button clicks (#11288) * [Updating] Document ActionRunner cmd flags * [Auto-update][PT Settings] Updated UI (#11335) * [Updating] Do not reset update state when msi cancellation detected * [Updating] Directly launch update_now PT action instead of using custom URI scheme * Checking for updates UI (#11354) * [Updating] Fix cannotDownload state in action runner * [Updating] Reset update state to CannotDownload if action runner encountered an error * [Updating][PT Settings] downloading label, disable button in error state * Changed error message * [Updating rename CannotDownload to ErrorDownloading * [Updating] Add trace logging for Check for updates callback * [Updating][PT Settings] simplify downloading checks * [Updating][PT Settings] Updated text labels * [Updating][PT Settings] Retry to load settings if failed * [Updating][PT Settings] Text fix * [Updating][PT Settings] Installed version links removed * [Updating][PT Settings] Error text updated * [Updating][PT Settings] Show label after version checked * [Updating][PT Settings] Text foreground fix * [Updating][PT Settings] Clean up * [Updating] Do not reset releasePageUrl in case of error/cancellation * [Updating][PT Settings] fixed missing string * [Updating][PT Settings] checked for updates state fix Co-authored-by: yuyoyuppe <a.yuyoyuppe@gmail.com> Co-authored-by: Andrey Nekrasov <yuyoyuppe@users.noreply.github.com> Co-authored-by: Enrico Giordani <enrico.giordani@gmail.com>
This commit is contained in:
parent
d55badf14a
commit
b96b4fcb0f
@ -64,7 +64,7 @@ build:
|
||||
- from: 'x64/Release'
|
||||
to: 'Build_Output'
|
||||
include:
|
||||
- 'action_runner.exe'
|
||||
- 'PowerToys.ActionRunner.exe'
|
||||
- 'BugReportTool\BugReportTool.exe'
|
||||
- 'modules\ColorPicker\ColorPicker.dll'
|
||||
- 'modules\ColorPicker\ColorPickerUI.dll'
|
||||
|
@ -100,7 +100,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ImageResizerExt", "src\modu
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageResizerUITest", "src\modules\imageresizer\tests\ImageResizerUITest.csproj", "{E0CC7526-D85E-43AC-844F-D5DF0D2F5AB8}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "action_runner", "src\action_runner\action_runner.vcxproj", "{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ActionRunner", "src\ActionRunner\ActionRunner.vcxproj", "{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{17DA04DF-E393-4397-9CF0-84DABE11032E} = {17DA04DF-E393-4397-9CF0-84DABE11032E}
|
||||
EndProjectSection
|
||||
|
@ -70,54 +70,18 @@
|
||||
<data name="GITHUB_NEW_VERSION_AVAILABLE" xml:space="preserve">
|
||||
<value>An update to PowerToys is available.</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_DOWNLOAD_STARTED" xml:space="preserve">
|
||||
<value>PowerToys download started.</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_READY_TO_INSTALL" xml:space="preserve">
|
||||
<value>An update to PowerToys is ready to install.</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_DOWNLOAD_INSTALL_ERROR" xml:space="preserve">
|
||||
<value>Error: couldn't download PowerToys installer. Visit our GitHub page to update.</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_UPDATE_NOW" xml:space="preserve">
|
||||
<value>Update now</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_UPDATE_AFTER_RESTART" xml:space="preserve">
|
||||
<value>At next launch</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>
|
||||
<data name="GITHUB_NEW_VERSION_UP_TO_DATE" xml:space="preserve">
|
||||
<value>PowerToys is up to date.</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_VISIT" xml:space="preserve">
|
||||
<value>Visit</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_MORE_INFO" xml:space="preserve">
|
||||
<value>More info...</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_ABORT" xml:space="preserve">
|
||||
<value>Abort</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_SNOOZE_TITLE" xml:space="preserve">
|
||||
<value>Click Snooze to be reminded in:</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_UPDATE_SNOOZE_1D" xml:space="preserve">
|
||||
<value>1 day</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_UPDATE_SNOOZE_5D" xml:space="preserve">
|
||||
<value>5 days</value>
|
||||
</data>
|
||||
<data name="DOWNLOAD_IN_PROGRESS" xml:space="preserve">
|
||||
<value>Downloading...</value>
|
||||
</data>
|
||||
<data name="DOWNLOAD_COMPLETE" xml:space="preserve">
|
||||
<value>Download complete</value>
|
||||
</data>
|
||||
<data name="TOAST_TITLE" xml:space="preserve">
|
||||
<value>PowerToys Update</value>
|
||||
</data>
|
||||
@ -144,16 +108,6 @@
|
||||
</data>
|
||||
<data name="NEW_VERSION_INSTALLATION_ERROR" xml:space="preserve">
|
||||
<value>Couldn't install new PowerToys version.</value>
|
||||
</data>
|
||||
<data name="SNOOZE_BUTTON" xml:space="preserve">
|
||||
<value>Snooze</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_USING_LOCAL_BUILD_ERROR" xml:space="preserve">
|
||||
<value>Updating from a local build is not supported.</value>
|
||||
<comment>User cannot autoupdate from a locally-built PowerToys version</comment>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_CHECK_ERROR" xml:space="preserve">
|
||||
<value>Failed to connect to the server. Check your network connection or retry later.</value>
|
||||
</data>
|
||||
<data name="NEWER_VERSION_ERROR" xml:space="preserve">
|
||||
<value>A newer version is already installed.</value>
|
||||
|
@ -207,12 +207,8 @@ int Bootstrapper(HINSTANCE hInstance)
|
||||
{
|
||||
}
|
||||
|
||||
spdlog::level::level_enum severity = spdlog::level::off;
|
||||
if (logLevel == "debug")
|
||||
{
|
||||
severity = spdlog::level::debug;
|
||||
}
|
||||
else if (logLevel == "error")
|
||||
spdlog::level::level_enum severity = spdlog::level::debug;
|
||||
if (logLevel == "error")
|
||||
{
|
||||
severity = spdlog::level::err;
|
||||
}
|
||||
@ -359,6 +355,7 @@ int Bootstrapper(HINSTANCE hInstance)
|
||||
{
|
||||
spdlog::error("Couldn't install the existing MSI package ({})", GetLastError());
|
||||
ShowMessageBoxError(IDS_UNINSTALL_PREVIOUS_VERSION_ERROR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const bool installDotnet = !skipDotnetInstall;
|
||||
|
@ -71,7 +71,7 @@
|
||||
<WixVariable Id="WixUILicenseRtf" Value="$(var.RepoDir)\installer\License.rtf" />
|
||||
<Property Id="INSTALLSTARTMENUSHORTCUT" Value="1"/>
|
||||
<Property Id="CREATESCHEDULEDTASK" Value="1"/>
|
||||
<Property Id="WixShellExecTarget" Value="[#action_runner.exe]" />
|
||||
<Property Id="WixShellExecTarget" Value="[#PowerToys_ActionRunner.exe]" />
|
||||
|
||||
<Property Id ="EXISTINGPOWERRENAMEEXTPATH">
|
||||
<RegistrySearch Id="ExistingExtPath" Root="HKCR" Key="CLSID\{0440049F-D1DC-4E46-B27B-98393D79486B}\InprocServer32" Type="raw"/>
|
||||
@ -324,8 +324,8 @@
|
||||
<Component Id="BackgroundActivator_dll" Guid="23B25EE4-BCA2-45DF-BBCD-82FBDF01C5AB" Win64="yes">
|
||||
<File Id="BackgroundActivatorDLL.dll" KeyPath="yes" Checksum="yes" />
|
||||
</Component>
|
||||
<Component Id="action_runner_exe" Guid="626ABB17-16F0-4007-9A58-6998724A5E14" Win64="yes">
|
||||
<File Id="action_runner.exe" KeyPath="yes" Checksum="yes" />
|
||||
<Component Id="PowerToys_ActionRunner_exe" Guid="626ABB17-16F0-4007-9A58-6998724A5E14" Win64="yes">
|
||||
<File Id="PowerToys.ActionRunner.exe" KeyPath="yes" Checksum="yes" />
|
||||
</Component>
|
||||
<Component Id="License_rtf" Guid="3E5AE43B-CFB4-449B-A346-94CAAFF3312E" Win64="yes">
|
||||
<File Source="$(var.RepoDir)\installer\License.rtf" Id="License.rtf" KeyPath="yes" />
|
||||
@ -792,7 +792,7 @@
|
||||
<ComponentRef Id="powertoys_exe" />
|
||||
<ComponentRef Id="PowerToysStartMenuShortcut"/>
|
||||
<ComponentRef Id="BackgroundActivator_dll" />
|
||||
<ComponentRef Id="action_runner_exe" />
|
||||
<ComponentRef Id="PowerToys_ActionRunner_exe" />
|
||||
<ComponentRef Id="powertoys_toast_clsid" />
|
||||
<ComponentRef Id="License_rtf" />
|
||||
<ComponentRef Id="Notice_md" />
|
||||
|
@ -67,54 +67,18 @@
|
||||
<data name="GITHUB_NEW_VERSION_AVAILABLE" xml:space="preserve">
|
||||
<value>An update to PowerToys is available.</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_DOWNLOAD_STARTED" xml:space="preserve">
|
||||
<value>PowerToys download started.</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_READY_TO_INSTALL" xml:space="preserve">
|
||||
<value>An update to PowerToys is ready to install.</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_DOWNLOAD_INSTALL_ERROR" xml:space="preserve">
|
||||
<value>Error: couldn't download PowerToys installer. Visit our GitHub page to update.</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_UPDATE_NOW" xml:space="preserve">
|
||||
<value>Update now</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_UPDATE_AFTER_RESTART" xml:space="preserve">
|
||||
<value>At next launch</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>
|
||||
<data name="GITHUB_NEW_VERSION_UP_TO_DATE" xml:space="preserve">
|
||||
<value>PowerToys is up to date.</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_VISIT" xml:space="preserve">
|
||||
<value>Visit</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_MORE_INFO" xml:space="preserve">
|
||||
<value>More info...</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_ABORT" xml:space="preserve">
|
||||
<value>Abort</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_SNOOZE_TITLE" xml:space="preserve">
|
||||
<value>Click Snooze to be reminded in:</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_UPDATE_SNOOZE_1D" xml:space="preserve">
|
||||
<value>1 day</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_UPDATE_SNOOZE_5D" xml:space="preserve">
|
||||
<value>5 days</value>
|
||||
</data>
|
||||
<data name="DOWNLOAD_IN_PROGRESS" xml:space="preserve">
|
||||
<value>Downloading...</value>
|
||||
</data>
|
||||
<data name="DOWNLOAD_COMPLETE" xml:space="preserve">
|
||||
<value>Download complete</value>
|
||||
</data>
|
||||
<data name="TOAST_TITLE" xml:space="preserve">
|
||||
<value>PowerToys Update</value>
|
||||
</data>
|
||||
@ -124,14 +88,4 @@
|
||||
<data name="OFFER_UNINSTALL_MSI_TITLE" xml:space="preserve">
|
||||
<value>PowerToys: uninstall previous version?</value>
|
||||
</data>
|
||||
<data name="SNOOZE_BUTTON" xml:space="preserve">
|
||||
<value>Snooze</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_USING_LOCAL_BUILD_ERROR" xml:space="preserve">
|
||||
<value>Updating from a local build is not supported.</value>
|
||||
<comment>User cannot autoupdate from a locally-built PowerToys version</comment>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_CHECK_ERROR" xml:space="preserve">
|
||||
<value>Failed to connect to the server. Check your network connection or retry later.</value>
|
||||
</data>
|
||||
</root>
|
@ -1,3 +1,7 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include "Generated Files/resource.h"
|
||||
|
||||
@ -8,6 +12,7 @@
|
||||
#include <string_view>
|
||||
|
||||
#include <common/updating/updating.h>
|
||||
#include <common/updating/updateState.h>
|
||||
#include <common/updating/installer.h>
|
||||
#include <common/updating/http_client.h>
|
||||
#include <common/updating/dotnet_installation.h>
|
||||
@ -15,6 +20,7 @@
|
||||
#include <common/utils/elevation.h>
|
||||
#include <common/utils/process_path.h>
|
||||
#include <common/utils/resources.h>
|
||||
#include <common/utils/timeutil.h>
|
||||
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
|
||||
@ -29,13 +35,16 @@
|
||||
|
||||
auto Strings = create_notifications_strings();
|
||||
|
||||
int uninstall_msi_action()
|
||||
using namespace cmdArg;
|
||||
|
||||
int UninstallMsiAction()
|
||||
{
|
||||
const auto package_path = updating::get_msi_package_path();
|
||||
if (package_path.empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!updating::uninstall_msi_version(package_path, Strings))
|
||||
{
|
||||
return -1;
|
||||
@ -55,44 +64,92 @@ int uninstall_msi_action()
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
std::optional<fs::path> copy_self_to_temp_dir()
|
||||
std::optional<fs::path> CopySelfToTempDir()
|
||||
{
|
||||
std::error_code error;
|
||||
auto dst_path = fs::temp_directory_path() / "action_runner.exe";
|
||||
auto dst_path = fs::temp_directory_path() / "PowerToys.ActionRunner.exe";
|
||||
fs::copy_file(get_module_filename(), dst_path, fs::copy_options::overwrite_existing, error);
|
||||
if (error)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return std::move(dst_path);
|
||||
}
|
||||
|
||||
bool install_new_version_stage_1(const std::wstring_view installer_filename, const bool must_restart = false)
|
||||
std::optional<fs::path> ObtainInstallerPath()
|
||||
{
|
||||
const fs::path installer{ updating::get_pending_updates_path() / installer_filename };
|
||||
using namespace updating;
|
||||
|
||||
if (!fs::is_regular_file(installer))
|
||||
auto state = UpdateState::read();
|
||||
if (state.state == UpdateState::readyToDownload || state.state == UpdateState::errorDownloading)
|
||||
{
|
||||
const auto new_version_info = get_github_version_info_async(Strings).get();
|
||||
if (!new_version_info)
|
||||
{
|
||||
Logger::error(L"Couldn't obtain github version info: {}", new_version_info.error());
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!std::holds_alternative<new_version_download_info>(*new_version_info))
|
||||
{
|
||||
Logger::error("Invoked with -update_now argument, but no update was available");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto downloaded_installer = download_new_version(std::get<new_version_download_info>(*new_version_info)).get();
|
||||
if (!downloaded_installer)
|
||||
{
|
||||
Logger::error("Couldn't download new installer");
|
||||
}
|
||||
|
||||
return downloaded_installer;
|
||||
}
|
||||
else if (state.state == UpdateState::readyToInstall)
|
||||
{
|
||||
fs::path installer{ get_pending_updates_path() / state.downloadedInstallerFilename };
|
||||
if (fs::is_regular_file(installer))
|
||||
{
|
||||
return std::move(installer);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::error(L"Couldn't find a downloaded installer {}", installer.native());
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::error("Invoked with -update_now argument, but update state was invalid");
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
bool InstallNewVersionStage1()
|
||||
{
|
||||
const auto installer = ObtainInstallerPath();
|
||||
if (!installer)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (auto copy_in_temp = copy_self_to_temp_dir())
|
||||
if (auto copy_in_temp = CopySelfToTempDir())
|
||||
{
|
||||
// detect if PT was running
|
||||
// Detect if PT was running
|
||||
const auto pt_main_window = FindWindowW(pt_tray_icon_window_class, nullptr);
|
||||
const bool launch_powertoys = must_restart || pt_main_window != nullptr;
|
||||
const bool launch_powertoys = pt_main_window != nullptr;
|
||||
if (pt_main_window != nullptr)
|
||||
{
|
||||
SendMessageW(pt_main_window, WM_CLOSE, 0, 0);
|
||||
}
|
||||
|
||||
std::wstring arguments{ UPDATE_NOW_LAUNCH_STAGE2_CMDARG };
|
||||
std::wstring arguments{ UPDATE_NOW_LAUNCH_STAGE2 };
|
||||
arguments += L" \"";
|
||||
arguments += installer.c_str();
|
||||
arguments += installer->c_str();
|
||||
arguments += L"\" \"";
|
||||
arguments += get_module_folderpath();
|
||||
arguments += L"\" ";
|
||||
arguments += launch_powertoys ? UPDATE_STAGE2_RESTART_PT_CMDARG : UPDATE_STAGE2_DONT_START_PT_CMDARG;
|
||||
arguments += launch_powertoys ? UPDATE_STAGE2_RESTART_PT : UPDATE_STAGE2_DONT_START_PT;
|
||||
SHELLEXECUTEINFOW sei{ sizeof(sei) };
|
||||
sei.fMask = { SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC };
|
||||
sei.lpFile = copy_in_temp->c_str();
|
||||
@ -107,7 +164,7 @@ bool install_new_version_stage_1(const std::wstring_view installer_filename, con
|
||||
}
|
||||
}
|
||||
|
||||
bool install_new_version_stage_2(std::wstring installer_path, std::wstring_view install_path, bool launch_powertoys)
|
||||
bool InstallNewVersionStage2(std::wstring installer_path, std::wstring_view install_path, bool launch_powertoys)
|
||||
{
|
||||
std::transform(begin(installer_path), end(installer_path), begin(installer_path), ::towlower);
|
||||
|
||||
@ -134,25 +191,36 @@ bool install_new_version_stage_2(std::wstring installer_path, std::wstring_view
|
||||
{
|
||||
parameters += L"--no_start_pt";
|
||||
}
|
||||
|
||||
sei.lpParameters = parameters.c_str();
|
||||
|
||||
success = ShellExecuteExW(&sei) == TRUE;
|
||||
|
||||
// Wait for the install completion
|
||||
if (success)
|
||||
{
|
||||
WaitForSingleObject(sei.hProcess, INFINITE);
|
||||
DWORD exitCode = 0;
|
||||
GetExitCodeProcess(sei.hProcess, &exitCode);
|
||||
success = exitCode == 0;
|
||||
CloseHandle(sei.hProcess);
|
||||
}
|
||||
}
|
||||
|
||||
std::error_code _;
|
||||
fs::remove(installer_path, _);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::error_code _;
|
||||
fs::remove(installer_path, _);
|
||||
|
||||
UpdateState::store([&](UpdateState& state) {
|
||||
state = {};
|
||||
state.githubUpdateLastCheckedDate.emplace(timeutil::now());
|
||||
state.state = UpdateState::upToDate;
|
||||
});
|
||||
|
||||
if (launch_powertoys)
|
||||
{
|
||||
std::wstring new_pt_path{ install_path };
|
||||
@ -164,6 +232,7 @@ bool install_new_version_stage_2(std::wstring installer_path, std::wstring_view
|
||||
sei.lpParameters = UPDATE_REPORT_SUCCESS;
|
||||
return ShellExecuteExW(&sei) == TRUE;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -175,13 +244,14 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::wstring_view action{ args[1] };
|
||||
|
||||
std::filesystem::path logFilePath(PTSettingsHelper::get_root_save_folder_location());
|
||||
logFilePath.append(LogSettings::actionRunnerLogPath);
|
||||
Logger::init(LogSettings::actionRunnerLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location());
|
||||
|
||||
if (action == RUN_NONELEVATED_CMDARG)
|
||||
if (action == RUN_NONELEVATED)
|
||||
{
|
||||
int nextArg = 2;
|
||||
|
||||
@ -227,7 +297,6 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
|
||||
|
||||
run_same_elevation(target.data(), params, pidBuffer);
|
||||
|
||||
// cleanup
|
||||
if (!pidFile.empty())
|
||||
{
|
||||
if (pidBuffer)
|
||||
@ -243,24 +312,36 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (action == UNINSTALL_MSI_CMDARG)
|
||||
else if (action == UNINSTALL_MSI)
|
||||
{
|
||||
return uninstall_msi_action();
|
||||
return UninstallMsiAction();
|
||||
}
|
||||
else if (action == UPDATE_NOW_LAUNCH_STAGE1_CMDARG)
|
||||
else if (action == UPDATE_NOW_LAUNCH_STAGE1)
|
||||
{
|
||||
std::wstring_view installerFilename{ args[2] };
|
||||
return !install_new_version_stage_1(installerFilename);
|
||||
const bool failed = !InstallNewVersionStage1();
|
||||
if (failed)
|
||||
{
|
||||
UpdateState::store([&](UpdateState& state) {
|
||||
state.downloadedInstallerFilename = {};
|
||||
state.githubUpdateLastCheckedDate.emplace(timeutil::now());
|
||||
state.state = UpdateState::errorDownloading;
|
||||
});
|
||||
}
|
||||
return failed;
|
||||
}
|
||||
else if (action == UPDATE_NOW_LAUNCH_STAGE1_START_PT_CMDARG)
|
||||
{
|
||||
std::wstring_view installerFilename{ args[2] };
|
||||
return !install_new_version_stage_1(installerFilename, true);
|
||||
}
|
||||
else if (action == UPDATE_NOW_LAUNCH_STAGE2_CMDARG)
|
||||
else if (action == UPDATE_NOW_LAUNCH_STAGE2)
|
||||
{
|
||||
using namespace std::string_view_literals;
|
||||
return !install_new_version_stage_2(args[2], args[3], args[4] == std::wstring_view{ UPDATE_STAGE2_RESTART_PT_CMDARG });
|
||||
const bool failed = !InstallNewVersionStage2(args[2], args[3], args[4] == std::wstring_view{ UPDATE_STAGE2_RESTART_PT });
|
||||
if (failed)
|
||||
{
|
||||
UpdateState::store([&](UpdateState& state) {
|
||||
state.downloadedInstallerFilename = {};
|
||||
state.githubUpdateLastCheckedDate.emplace(timeutil::now());
|
||||
state.state = UpdateState::errorDownloading;
|
||||
});
|
||||
}
|
||||
return failed;
|
||||
}
|
||||
|
||||
return 0;
|
@ -2,13 +2,13 @@
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<Target Name="GenerateResourceFiles" BeforeTargets="PrepareForBuild">
|
||||
<Exec Command="powershell -NonInteractive -executionpolicy Unrestricted $(SolutionDir)tools\build\convert-resx-to-rc.ps1 $(MSBuildThisFileDirectory) resource.base.h resource.h action_runner.base.rc action_runner.rc" />
|
||||
<Exec Command="powershell -NonInteractive -executionpolicy Unrestricted $(SolutionDir)tools\build\convert-resx-to-rc.ps1 $(MSBuildThisFileDirectory) resource.base.h resource.h actionRunner.base.rc actionRunner.rc" />
|
||||
</Target>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<ProjectGuid>{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}</ProjectGuid>
|
||||
<RootNamespace>action_runner</RootNamespace>
|
||||
<ProjectName>action_runner</ProjectName>
|
||||
<RootNamespace>actionRunner</RootNamespace>
|
||||
<ProjectName>PowerToys.ActionRunner</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<Import Project="..\..\deps\expected.props" />
|
||||
@ -20,16 +20,7 @@
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ImportGroup>
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
@ -44,7 +35,7 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="action_runner.cpp" />
|
||||
<ClCompile Include="ActionRunner.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\common\logger\logger.vcxproj">
|
||||
@ -61,12 +52,11 @@
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\runner\updating.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="action_runner.base.rc" />
|
||||
<ResourceCompile Include="Generated Files/action_runner.rc" />
|
||||
<None Include="ActionRunner.base.rc" />
|
||||
<ResourceCompile Include="Generated Files\ActionRunner.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
@ -83,4 +73,4 @@
|
||||
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
</Project>
|
@ -1,11 +1,11 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by action_runner.rc
|
||||
// Used by PowerToys.ActionRunner.rc
|
||||
|
||||
//////////////////////////////
|
||||
// Non-localizable
|
||||
|
||||
#define FILE_DESCRIPTION "PowerToys ActionRunner"
|
||||
#define INTERNAL_NAME "action_runner"
|
||||
#define ORIGINAL_FILENAME "action_runner.exe"
|
||||
#define INTERNAL_NAME "PowerToys.ActionRunner"
|
||||
#define ORIGINAL_FILENAME "PowerToys.ActionRunner.exe"
|
||||
|
@ -57,6 +57,5 @@ namespace notifications
|
||||
}
|
||||
RegCloseKey(key);
|
||||
return timeutil::diff::in_days(timeutil::now(), last_disabled_time) < disable_interval_in_days;
|
||||
return false;
|
||||
}
|
||||
}
|
@ -81,7 +81,7 @@ namespace updating
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
updating::notifications::show_uninstallation_error(strings);
|
||||
MessageBoxW(nullptr, strings.UNINSTALLATION_UNKNOWN_ERROR.c_str(), strings.NOTIFICATION_TITLE.c_str(), MB_OK | MB_ICONERROR);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -14,7 +14,7 @@ namespace updating
|
||||
namespace notifications
|
||||
{
|
||||
using namespace ::notifications;
|
||||
std::wstring current_version_to_next_version(const updating::new_version_download_info& info)
|
||||
std::wstring current_version_to_next_version(const new_version_download_info& info)
|
||||
{
|
||||
auto current_version_to_next_version = VersionHelper{ VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION }.toWstring();
|
||||
current_version_to_next_version += L" -> ";
|
||||
@ -22,15 +22,7 @@ namespace updating
|
||||
return current_version_to_next_version;
|
||||
}
|
||||
|
||||
void show_unavailable(const notifications::strings& strings, std::wstring reason)
|
||||
{
|
||||
remove_toasts_by_tag(UPDATING_PROCESS_TOAST_TAG);
|
||||
|
||||
toast_params toast_params{ UPDATING_PROCESS_TOAST_TAG, false };
|
||||
show_toast(std::move(reason), strings.TOAST_TITLE, std::move(toast_params));
|
||||
}
|
||||
|
||||
void show_available(const updating::new_version_download_info& info, const notifications::strings& strings)
|
||||
void show_new_version_available(const new_version_download_info& info, const strings& strings)
|
||||
{
|
||||
remove_toasts_by_tag(UPDATING_PROCESS_TOAST_TAG);
|
||||
|
||||
@ -40,106 +32,30 @@ namespace updating
|
||||
contents += current_version_to_next_version(info);
|
||||
|
||||
show_toast_with_activations(std::move(contents),
|
||||
strings.TOAST_TITLE,
|
||||
strings.NOTIFICATION_TITLE,
|
||||
{},
|
||||
{ link_button{ strings.GITHUB_NEW_VERSION_UPDATE_NOW,
|
||||
L"powertoys://download_and_install_update/" },
|
||||
L"powertoys://update_now/" },
|
||||
link_button{ strings.GITHUB_NEW_VERSION_MORE_INFO,
|
||||
info.release_page_uri.ToString().c_str() } },
|
||||
L"powertoys://open_settings/" } },
|
||||
std::move(toast_params));
|
||||
}
|
||||
|
||||
void show_download_start(const updating::new_version_download_info& info, const notifications::strings& strings)
|
||||
{
|
||||
remove_toasts_by_tag(UPDATING_PROCESS_TOAST_TAG);
|
||||
|
||||
progress_bar_params progress_bar_params;
|
||||
std::wstring progress_title{ info.version.toWstring() };
|
||||
progress_title += L' ';
|
||||
progress_title += strings.DOWNLOAD_IN_PROGRESS;
|
||||
|
||||
progress_bar_params.progress_title = progress_title;
|
||||
progress_bar_params.progress = .0f;
|
||||
toast_params toast_params{ UPDATING_PROCESS_TOAST_TAG, false, std::move(progress_bar_params) };
|
||||
show_toast_with_activations(strings.GITHUB_NEW_VERSION_DOWNLOAD_STARTED,
|
||||
strings.TOAST_TITLE,
|
||||
{},
|
||||
{},
|
||||
std::move(toast_params));
|
||||
}
|
||||
|
||||
void show_visit_github(const updating::new_version_download_info& info, const notifications::strings& strings)
|
||||
void show_open_settings_for_update(const strings& strings)
|
||||
{
|
||||
remove_toasts_by_tag(UPDATING_PROCESS_TOAST_TAG);
|
||||
|
||||
toast_params toast_params{ UPDATING_PROCESS_TOAST_TAG, false };
|
||||
std::wstring contents = strings.GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT;
|
||||
contents += L'\n';
|
||||
contents += current_version_to_next_version(info);
|
||||
show_toast_with_activations(std::move(contents),
|
||||
strings.TOAST_TITLE,
|
||||
|
||||
std::vector<action_t> actions = {
|
||||
link_button{ strings.GITHUB_NEW_VERSION_MORE_INFO,
|
||||
L"powertoys://open_settings/" },
|
||||
};
|
||||
show_toast_with_activations(strings.GITHUB_NEW_VERSION_AVAILABLE,
|
||||
strings.NOTIFICATION_TITLE,
|
||||
{},
|
||||
{ link_button{ strings.GITHUB_NEW_VERSION_VISIT,
|
||||
info.release_page_uri.ToString().c_str() } },
|
||||
std::move(actions),
|
||||
std::move(toast_params));
|
||||
}
|
||||
|
||||
void show_install_error(const updating::new_version_download_info& info, const notifications::strings& strings)
|
||||
{
|
||||
remove_toasts_by_tag(UPDATING_PROCESS_TOAST_TAG);
|
||||
|
||||
toast_params toast_params{ UPDATING_PROCESS_TOAST_TAG, false };
|
||||
std::wstring contents = strings.GITHUB_NEW_VERSION_DOWNLOAD_INSTALL_ERROR;
|
||||
contents += L'\n';
|
||||
contents += current_version_to_next_version(info);
|
||||
show_toast_with_activations(std::move(contents),
|
||||
strings.TOAST_TITLE,
|
||||
{},
|
||||
{ link_button{ strings.GITHUB_NEW_VERSION_VISIT, info.release_page_uri.ToString().c_str() } },
|
||||
std::move(toast_params));
|
||||
}
|
||||
|
||||
void show_version_ready(const updating::new_version_download_info& info, const notifications::strings& strings)
|
||||
{
|
||||
remove_toasts_by_tag(UPDATING_PROCESS_TOAST_TAG);
|
||||
|
||||
toast_params toast_params{ UPDATING_PROCESS_TOAST_TAG, false };
|
||||
std::wstring new_version_ready{ strings.GITHUB_NEW_VERSION_READY_TO_INSTALL };
|
||||
new_version_ready += L'\n';
|
||||
new_version_ready += current_version_to_next_version(info);
|
||||
|
||||
show_toast_with_activations(std::move(new_version_ready),
|
||||
strings.TOAST_TITLE,
|
||||
{},
|
||||
{ link_button{ strings.GITHUB_NEW_VERSION_UPDATE_NOW,
|
||||
L"powertoys://update_now/" + info.installer_filename },
|
||||
link_button{ strings.GITHUB_NEW_VERSION_UPDATE_AFTER_RESTART,
|
||||
L"powertoys://schedule_update/" + info.installer_filename },
|
||||
snooze_button{
|
||||
strings.GITHUB_NEW_VERSION_SNOOZE_TITLE,
|
||||
{ { strings.GITHUB_NEW_VERSION_UPDATE_SNOOZE_1D, 24 * 60 },
|
||||
{ strings.GITHUB_NEW_VERSION_UPDATE_SNOOZE_5D, 120 * 60 } },
|
||||
strings.SNOOZE_BUTTON } },
|
||||
std::move(toast_params));
|
||||
}
|
||||
|
||||
void show_uninstallation_error(const notifications::strings& strings)
|
||||
{
|
||||
remove_toasts_by_tag(UPDATING_PROCESS_TOAST_TAG);
|
||||
|
||||
show_toast(strings.UNINSTALLATION_UNKNOWN_ERROR, strings.TOAST_TITLE);
|
||||
}
|
||||
|
||||
void update_download_progress(const updating::new_version_download_info& info, float progress, const notifications::strings& strings)
|
||||
{
|
||||
progress_bar_params progress_bar_params;
|
||||
|
||||
std::wstring progress_title{ info.version.toWstring() };
|
||||
progress_title += L' ';
|
||||
progress_title += progress < 1 ? strings.DOWNLOAD_IN_PROGRESS : strings.DOWNLOAD_COMPLETE;
|
||||
progress_bar_params.progress_title = progress_title;
|
||||
progress_bar_params.progress = progress;
|
||||
update_toast_progress_bar(UPDATING_PROCESS_TOAST_TAG, progress_bar_params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,71 +10,31 @@ namespace updating
|
||||
{
|
||||
struct strings
|
||||
{
|
||||
std::wstring DOWNLOAD_COMPLETE;
|
||||
std::wstring DOWNLOAD_IN_PROGRESS;
|
||||
|
||||
std::wstring GITHUB_NEW_VERSION_ABORT;
|
||||
std::wstring GITHUB_NEW_VERSION_AVAILABLE;
|
||||
std::wstring GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT;
|
||||
std::wstring GITHUB_NEW_VERSION_CHECK_ERROR;
|
||||
std::wstring GITHUB_NEW_VERSION_DOWNLOAD_INSTALL_ERROR;
|
||||
std::wstring GITHUB_NEW_VERSION_DOWNLOAD_STARTED;
|
||||
std::wstring GITHUB_NEW_VERSION_MORE_INFO;
|
||||
std::wstring GITHUB_NEW_VERSION_READY_TO_INSTALL;
|
||||
std::wstring GITHUB_NEW_VERSION_SNOOZE_TITLE;
|
||||
std::wstring GITHUB_NEW_VERSION_UP_TO_DATE;
|
||||
std::wstring GITHUB_NEW_VERSION_UPDATE_NOW;
|
||||
std::wstring GITHUB_NEW_VERSION_UPDATE_AFTER_RESTART;
|
||||
std::wstring GITHUB_NEW_VERSION_UPDATE_SNOOZE_1D;
|
||||
std::wstring GITHUB_NEW_VERSION_UPDATE_SNOOZE_5D;
|
||||
std::wstring GITHUB_NEW_VERSION_USING_LOCAL_BUILD_ERROR;
|
||||
std::wstring GITHUB_NEW_VERSION_VISIT;
|
||||
|
||||
std::wstring OFFER_UNINSTALL_MSI;
|
||||
std::wstring OFFER_UNINSTALL_MSI_TITLE;
|
||||
|
||||
std::wstring SNOOZE_BUTTON;
|
||||
std::wstring TOAST_TITLE;
|
||||
std::wstring NOTIFICATION_TITLE;
|
||||
|
||||
std::wstring UNINSTALLATION_UNKNOWN_ERROR;
|
||||
};
|
||||
|
||||
void show_unavailable(const notifications::strings& strings, std::wstring reason);
|
||||
void show_available(const updating::new_version_download_info& info, const strings&);
|
||||
void show_download_start(const updating::new_version_download_info& info, const strings&);
|
||||
void show_visit_github(const updating::new_version_download_info& info, const strings&);
|
||||
void show_install_error(const updating::new_version_download_info& info, const strings&);
|
||||
void show_version_ready(const updating::new_version_download_info& info, const strings&);
|
||||
void show_uninstallation_error(const notifications::strings& strings);
|
||||
|
||||
void update_download_progress(const updating::new_version_download_info& info, float progress, const notifications::strings& strings);
|
||||
void show_new_version_available(const new_version_download_info& info, const strings& strings);
|
||||
void show_open_settings_for_update(const strings& strings);
|
||||
}
|
||||
}
|
||||
|
||||
#define create_notifications_strings() \
|
||||
::updating::notifications::strings \
|
||||
{ \
|
||||
.DOWNLOAD_COMPLETE = GET_RESOURCE_STRING(IDS_DOWNLOAD_COMPLETE), \
|
||||
.DOWNLOAD_IN_PROGRESS = GET_RESOURCE_STRING(IDS_DOWNLOAD_IN_PROGRESS), \
|
||||
.GITHUB_NEW_VERSION_ABORT = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_ABORT), \
|
||||
.GITHUB_NEW_VERSION_AVAILABLE = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_AVAILABLE), \
|
||||
.GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT), \
|
||||
.GITHUB_NEW_VERSION_CHECK_ERROR = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_CHECK_ERROR), \
|
||||
.GITHUB_NEW_VERSION_DOWNLOAD_INSTALL_ERROR = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_DOWNLOAD_INSTALL_ERROR), \
|
||||
.GITHUB_NEW_VERSION_DOWNLOAD_STARTED = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_DOWNLOAD_STARTED), \
|
||||
.GITHUB_NEW_VERSION_MORE_INFO = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_MORE_INFO), \
|
||||
.GITHUB_NEW_VERSION_READY_TO_INSTALL = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_READY_TO_INSTALL), \
|
||||
.GITHUB_NEW_VERSION_SNOOZE_TITLE = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_SNOOZE_TITLE), \
|
||||
.GITHUB_NEW_VERSION_UP_TO_DATE = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_UP_TO_DATE), \
|
||||
.GITHUB_NEW_VERSION_UPDATE_NOW = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_UPDATE_NOW), \
|
||||
.GITHUB_NEW_VERSION_UPDATE_AFTER_RESTART = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_UPDATE_AFTER_RESTART), \
|
||||
.GITHUB_NEW_VERSION_UPDATE_SNOOZE_1D = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_UPDATE_SNOOZE_1D), \
|
||||
.GITHUB_NEW_VERSION_UPDATE_SNOOZE_5D = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_UPDATE_SNOOZE_5D), \
|
||||
.GITHUB_NEW_VERSION_USING_LOCAL_BUILD_ERROR = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_USING_LOCAL_BUILD_ERROR), \
|
||||
.GITHUB_NEW_VERSION_VISIT = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_VISIT), \
|
||||
.OFFER_UNINSTALL_MSI = GET_RESOURCE_STRING(IDS_OFFER_UNINSTALL_MSI), \
|
||||
.OFFER_UNINSTALL_MSI_TITLE = GET_RESOURCE_STRING(IDS_OFFER_UNINSTALL_MSI_TITLE), \
|
||||
.SNOOZE_BUTTON = GET_RESOURCE_STRING(IDS_SNOOZE_BUTTON), \
|
||||
.TOAST_TITLE = GET_RESOURCE_STRING(IDS_TOAST_TITLE), \
|
||||
.NOTIFICATION_TITLE = GET_RESOURCE_STRING(IDS_TOAST_TITLE), \
|
||||
.UNINSTALLATION_UNKNOWN_ERROR = GET_RESOURCE_STRING(IDS_UNINSTALLATION_UNKNOWN_ERROR) \
|
||||
}
|
||||
|
@ -27,9 +27,11 @@
|
||||
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Foundation.Collections.h>
|
||||
#include <winrt/Windows.Networking.Connectivity.h>
|
||||
#include <winrt/Windows.ApplicationModel.h>
|
||||
#include <winrt/Windows.Management.Deployment.h>
|
||||
#include <winrt/Windows.System.h>
|
||||
|
||||
#include <wil/resource.h>
|
||||
|
||||
#endif //PCH_H
|
||||
|
||||
|
70
src/common/updating/updateState.cpp
Normal file
70
src/common/updating/updateState.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
#include "pch.h"
|
||||
#include "updateState.h"
|
||||
|
||||
#include <common/utils/json.h>
|
||||
#include <common/utils/timeutil.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
const wchar_t PERSISTENT_STATE_FILENAME[] = L"\\UpdateState.json";
|
||||
const wchar_t UPDATE_STATE_MUTEX[] = L"Local\\PowerToysRunnerUpdateStateMutex";
|
||||
}
|
||||
|
||||
UpdateState deserialize(const json::JsonObject& json)
|
||||
{
|
||||
UpdateState result;
|
||||
|
||||
result.state = static_cast<UpdateState::State>(json.GetNamedNumber(L"state", UpdateState::upToDate));
|
||||
result.releasePageUrl = json.GetNamedString(L"releasePageUrl", L"");
|
||||
result.githubUpdateLastCheckedDate = timeutil::from_string(json.GetNamedString(L"githubUpdateLastCheckedDate", L"invalid").c_str());
|
||||
result.downloadedInstallerFilename = json.GetNamedString(L"downloadedInstallerFilename", L"");
|
||||
return result;
|
||||
}
|
||||
|
||||
json::JsonObject serialize(const UpdateState& state)
|
||||
{
|
||||
json::JsonObject json;
|
||||
|
||||
if (state.githubUpdateLastCheckedDate.has_value())
|
||||
{
|
||||
json.SetNamedValue(L"githubUpdateLastCheckedDate", json::value(timeutil::to_string(*state.githubUpdateLastCheckedDate)));
|
||||
}
|
||||
json.SetNamedValue(L"releasePageUrl", json::value(state.releasePageUrl));
|
||||
json.SetNamedValue(L"state", json::value(static_cast<double>(state.state)));
|
||||
json.SetNamedValue(L"downloadedInstallerFilename", json::value(state.downloadedInstallerFilename));
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
UpdateState UpdateState::read()
|
||||
{
|
||||
const auto filename = PTSettingsHelper::get_root_save_folder_location() + PERSISTENT_STATE_FILENAME;
|
||||
std::optional<json::JsonObject> json;
|
||||
{
|
||||
wil::unique_mutex_nothrow mutex{ CreateMutexW(nullptr, FALSE, UPDATE_STATE_MUTEX) };
|
||||
auto lock = mutex.acquire();
|
||||
json = json::from_file(filename);
|
||||
}
|
||||
return json ? deserialize(*json) : UpdateState{};
|
||||
}
|
||||
|
||||
void UpdateState::store(std::function<void(UpdateState&)> stateModifier)
|
||||
{
|
||||
const auto filename = PTSettingsHelper::get_root_save_folder_location() + PERSISTENT_STATE_FILENAME;
|
||||
|
||||
std::optional<json::JsonObject> json;
|
||||
{
|
||||
wil::unique_mutex_nothrow mutex{ CreateMutexW(nullptr, FALSE, UPDATE_STATE_MUTEX) };
|
||||
auto lock = mutex.acquire();
|
||||
json = json::from_file(filename);
|
||||
UpdateState state;
|
||||
if (json)
|
||||
{
|
||||
state = deserialize(*json);
|
||||
}
|
||||
stateModifier(state);
|
||||
json.emplace(serialize(state));
|
||||
json::to_file(filename, *json);
|
||||
}
|
||||
}
|
25
src/common/updating/updateState.h
Normal file
25
src/common/updating/updateState.h
Normal file
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <ctime>
|
||||
#include <optional>
|
||||
#include <functional>
|
||||
|
||||
// All fields must be default-initialized
|
||||
struct UpdateState
|
||||
{
|
||||
enum State
|
||||
{
|
||||
upToDate = 0,
|
||||
errorDownloading = 1,
|
||||
readyToDownload = 2,
|
||||
readyToInstall = 3
|
||||
} state = upToDate;
|
||||
std::wstring releasePageUrl;
|
||||
std::optional<std::time_t> githubUpdateLastCheckedDate;
|
||||
std::wstring downloadedInstallerFilename;
|
||||
|
||||
// To prevent concurrent modification of the file, we enforce this interface, which locks the file while
|
||||
// the state_modifier is active.
|
||||
static void store(std::function<void(UpdateState&)> stateModifier);
|
||||
static UpdateState read();
|
||||
};
|
@ -15,12 +15,27 @@ namespace // Strings in this namespace should not be localized
|
||||
{
|
||||
const wchar_t LATEST_RELEASE_ENDPOINT[] = L"https://api.github.com/repos/microsoft/PowerToys/releases/latest";
|
||||
const wchar_t ALL_RELEASES_ENDPOINT[] = L"https://api.github.com/repos/microsoft/PowerToys/releases";
|
||||
|
||||
const wchar_t LOCAL_BUILD_ERROR[] = L"Local build cannot be updated";
|
||||
const wchar_t NETWORK_ERROR[] = L"Network error";
|
||||
|
||||
const size_t MAX_DOWNLOAD_ATTEMPTS = 3;
|
||||
}
|
||||
|
||||
namespace updating
|
||||
{
|
||||
Uri extract_release_page_url(const json::JsonObject& release_object)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Uri{ release_object.GetNamedString(L"html_url") };
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::optional<VersionHelper> extract_version_from_release_object(const json::JsonObject& release_object)
|
||||
{
|
||||
try
|
||||
@ -66,7 +81,7 @@ namespace updating
|
||||
// If the current version starts with 0.0.*, it means we're on a local build from a farm and shouldn't check for updates.
|
||||
if (VERSION_MAJOR == 0 && VERSION_MINOR == 0)
|
||||
{
|
||||
co_return nonstd::make_unexpected(strings.GITHUB_NEW_VERSION_USING_LOCAL_BUILD_ERROR);
|
||||
co_return nonstd::make_unexpected(LOCAL_BUILD_ERROR);
|
||||
}
|
||||
|
||||
try
|
||||
@ -109,24 +124,16 @@ namespace updating
|
||||
co_return version_up_to_date{};
|
||||
}
|
||||
|
||||
Uri release_page_url{ release_object.GetNamedString(L"html_url") };
|
||||
auto installer_download_url = extract_installer_asset_download_info(release_object);
|
||||
co_return new_version_download_info{ std::move(release_page_url),
|
||||
auto [installer_download_url, installer_filename] = extract_installer_asset_download_info(release_object);
|
||||
co_return new_version_download_info{ extract_release_page_url(release_object),
|
||||
std::move(github_version),
|
||||
std::move(installer_download_url.first),
|
||||
std::move(installer_download_url.second) };
|
||||
std::move(installer_download_url),
|
||||
std::move(installer_filename) };
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
co_return nonstd::make_unexpected(strings.GITHUB_NEW_VERSION_CHECK_ERROR);
|
||||
}
|
||||
|
||||
bool could_be_costly_connection()
|
||||
{
|
||||
using namespace winrt::Windows::Networking::Connectivity;
|
||||
ConnectionProfile internetConnectionProfile = NetworkInformation::GetInternetConnectionProfile();
|
||||
return internetConnectionProfile.IsWwanConnectionProfile();
|
||||
co_return nonstd::make_unexpected(NETWORK_ERROR);
|
||||
}
|
||||
|
||||
std::filesystem::path get_pending_updates_path()
|
||||
@ -136,86 +143,40 @@ namespace updating
|
||||
return { std::move(path_str) };
|
||||
}
|
||||
|
||||
std::filesystem::path create_download_path()
|
||||
std::optional<std::filesystem::path> create_download_path()
|
||||
{
|
||||
auto installer_download_dst = get_pending_updates_path();
|
||||
std::error_code _;
|
||||
std::filesystem::create_directories(installer_download_dst, _);
|
||||
return installer_download_dst;
|
||||
auto installer_download_path = get_pending_updates_path();
|
||||
std::error_code ec;
|
||||
std::filesystem::create_directories(installer_download_path, ec);
|
||||
return !ec ? std::optional{ installer_download_path } : std::nullopt;
|
||||
}
|
||||
|
||||
std::future<bool> try_autoupdate(const bool download_updates_automatically, const notifications::strings& strings)
|
||||
std::future<std::optional<std::filesystem::path>> download_new_version(const new_version_download_info& new_version)
|
||||
{
|
||||
const auto version_check_result = co_await get_github_version_info_async(strings);
|
||||
if (!version_check_result)
|
||||
auto installer_download_path = create_download_path();
|
||||
if (!installer_download_path)
|
||||
{
|
||||
co_return false;
|
||||
co_return std::nullopt;
|
||||
}
|
||||
if (std::holds_alternative<version_up_to_date>(*version_check_result))
|
||||
{
|
||||
co_return true;
|
||||
}
|
||||
const auto new_version = std::get<new_version_download_info>(*version_check_result);
|
||||
|
||||
if (download_updates_automatically && !could_be_costly_connection())
|
||||
*installer_download_path /= new_version.installer_filename;
|
||||
|
||||
bool download_success = false;
|
||||
for (size_t i = 0; i < MAX_DOWNLOAD_ATTEMPTS; ++i)
|
||||
{
|
||||
auto installer_download_dst = create_download_path() / new_version.installer_filename;
|
||||
bool download_success = false;
|
||||
for (size_t i = 0; i < MAX_DOWNLOAD_ATTEMPTS; ++i)
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
http::HttpClient client;
|
||||
co_await client.download(new_version.installer_download_url, installer_download_dst);
|
||||
download_success = true;
|
||||
break;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// reattempt to download or do nothing
|
||||
}
|
||||
http::HttpClient client;
|
||||
co_await client.download(new_version.installer_download_url, *installer_download_path);
|
||||
download_success = true;
|
||||
break;
|
||||
}
|
||||
if (!download_success)
|
||||
catch (...)
|
||||
{
|
||||
updating::notifications::show_install_error(new_version, strings);
|
||||
co_return false;
|
||||
// reattempt to download or do nothing
|
||||
}
|
||||
|
||||
updating::notifications::show_version_ready(new_version, strings);
|
||||
}
|
||||
else
|
||||
{
|
||||
updating::notifications::show_visit_github(new_version, strings);
|
||||
}
|
||||
co_return true;
|
||||
co_return download_success ? installer_download_path : std::nullopt;
|
||||
}
|
||||
|
||||
std::future<std::wstring> download_update(const notifications::strings& strings)
|
||||
{
|
||||
const auto version_check_result = co_await get_github_version_info_async(strings);
|
||||
if (!version_check_result || std::holds_alternative<version_up_to_date>(*version_check_result))
|
||||
{
|
||||
co_return L"";
|
||||
}
|
||||
const auto new_version = std::get<new_version_download_info>(*version_check_result);
|
||||
auto installer_download_dst = create_download_path() / new_version.installer_filename;
|
||||
updating::notifications::show_download_start(new_version, strings);
|
||||
|
||||
try
|
||||
{
|
||||
auto progressUpdateHandle = [&](float progress) {
|
||||
updating::notifications::update_download_progress(new_version, progress, strings);
|
||||
};
|
||||
|
||||
http::HttpClient client;
|
||||
co_await client.download(new_version.installer_download_url, installer_download_dst, progressUpdateHandle);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
updating::notifications::show_install_error(new_version, strings);
|
||||
co_return L"";
|
||||
}
|
||||
|
||||
co_return new_version.installer_filename;
|
||||
}
|
||||
}
|
||||
|
@ -14,9 +14,9 @@
|
||||
namespace updating
|
||||
{
|
||||
using winrt::Windows::Foundation::Uri;
|
||||
struct version_up_to_date {};
|
||||
using github_version_info = std::variant<new_version_download_info, version_up_to_date>;
|
||||
|
||||
struct version_up_to_date
|
||||
{
|
||||
};
|
||||
struct new_version_download_info
|
||||
{
|
||||
Uri release_page_uri = nullptr;
|
||||
@ -24,11 +24,10 @@ namespace updating
|
||||
Uri installer_download_url = nullptr;
|
||||
std::wstring installer_filename;
|
||||
};
|
||||
using github_version_info = std::variant<new_version_download_info, version_up_to_date>;
|
||||
|
||||
// Returns whether the update check has succeeded
|
||||
std::future<bool> try_autoupdate(const bool download_updates_automatically, const notifications::strings&);
|
||||
std::future<std::optional<std::filesystem::path>> download_new_version(const new_version_download_info& new_version);
|
||||
std::filesystem::path get_pending_updates_path();
|
||||
std::future<std::wstring> download_update(const notifications::strings&);
|
||||
std::future<nonstd::expected<github_version_info, std::wstring>> get_github_version_info_async(const notifications::strings& strings, const bool prerelease = false);
|
||||
|
||||
// non-localized
|
||||
|
@ -40,6 +40,7 @@
|
||||
<ClInclude Include="installer.h" />
|
||||
<ClInclude Include="notifications.h" />
|
||||
<ClInclude Include="updating.h" />
|
||||
<ClInclude Include="updateState.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="winstore.h" />
|
||||
</ItemGroup>
|
||||
@ -49,6 +50,7 @@
|
||||
<ClCompile Include="installer.cpp" />
|
||||
<ClCompile Include="notifications.cpp" />
|
||||
<ClCompile Include="updating.cpp" />
|
||||
<ClCompile Include="updateState.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
|
@ -225,7 +225,7 @@ public:
|
||||
params += L" -powerToysPid " + std::to_wstring(powertoys_pid) + L" ";
|
||||
params += L"--centralized-kb-hook ";
|
||||
|
||||
action_runner_path += L"\\action_runner.exe";
|
||||
action_runner_path += L"\\PowerToys.ActionRunner.exe";
|
||||
// Set up the shared file from which to retrieve the PID of PowerLauncher
|
||||
HANDLE hMapFile = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(DWORD), POWER_LAUNCHER_PID_SHARED_FILE);
|
||||
if (!hMapFile)
|
||||
|
@ -94,54 +94,18 @@
|
||||
<data name="GITHUB_NEW_VERSION_AVAILABLE" xml:space="preserve">
|
||||
<value>An update to PowerToys is available.</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_DOWNLOAD_STARTED" xml:space="preserve">
|
||||
<value>PowerToys download started.</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_READY_TO_INSTALL" xml:space="preserve">
|
||||
<value>An update to PowerToys is ready to install.</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_DOWNLOAD_INSTALL_ERROR" xml:space="preserve">
|
||||
<value>Error: couldn't download PowerToys installer. Visit our GitHub page to update.</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_UPDATE_NOW" xml:space="preserve">
|
||||
<value>Update now</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_UPDATE_AFTER_RESTART" xml:space="preserve">
|
||||
<value>At next launch</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>
|
||||
<data name="GITHUB_NEW_VERSION_UP_TO_DATE" xml:space="preserve">
|
||||
<value>PowerToys is up to date.</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_VISIT" xml:space="preserve">
|
||||
<value>Visit</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_MORE_INFO" xml:space="preserve">
|
||||
<value>More info...</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_ABORT" xml:space="preserve">
|
||||
<value>Abort</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_SNOOZE_TITLE" xml:space="preserve">
|
||||
<value>Click Snooze to be reminded in:</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_UPDATE_SNOOZE_1D" xml:space="preserve">
|
||||
<value>1 day</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_UPDATE_SNOOZE_5D" xml:space="preserve">
|
||||
<value>5 days</value>
|
||||
</data>
|
||||
<data name="DOWNLOAD_IN_PROGRESS" xml:space="preserve">
|
||||
<value>Downloading...</value>
|
||||
</data>
|
||||
<data name="DOWNLOAD_COMPLETE" xml:space="preserve">
|
||||
<value>Download complete</value>
|
||||
</data>
|
||||
<data name="TOAST_TITLE" xml:space="preserve">
|
||||
<value>PowerToys Update</value>
|
||||
</data>
|
||||
@ -151,9 +115,6 @@
|
||||
<data name="OFFER_UNINSTALL_MSI_TITLE" xml:space="preserve">
|
||||
<value>PowerToys: uninstall previous version?</value>
|
||||
</data>
|
||||
<data name="SNOOZE_BUTTON" xml:space="preserve">
|
||||
<value>Snooze</value>
|
||||
</data>
|
||||
<data name="SETTINGS_MENU_TEXT" xml:space="preserve">
|
||||
<value>Settings</value>
|
||||
</data>
|
||||
@ -167,11 +128,4 @@
|
||||
<data name="BUGREPORT_SUCCESS" xml:space="preserve">
|
||||
<value>Bug report .zip file has been created on your Desktop.</value>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_USING_LOCAL_BUILD_ERROR" xml:space="preserve">
|
||||
<value>Updating from a local build is not supported.</value>
|
||||
<comment>User cannot autoupdate from a locally-built PowerToys version</comment>
|
||||
</data>
|
||||
<data name="GITHUB_NEW_VERSION_CHECK_ERROR" xml:space="preserve">
|
||||
<value>Failed to connect to the server. Check your network connection or retry later.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
@ -17,7 +17,7 @@ SHELLEXECUTEINFOW launch_action_runner(const wchar_t* cmdline)
|
||||
action_runner_path = get_module_folderpath();
|
||||
}
|
||||
|
||||
action_runner_path += L"\\action_runner.exe";
|
||||
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();
|
||||
|
@ -5,15 +5,19 @@
|
||||
|
||||
SHELLEXECUTEINFOW launch_action_runner(const wchar_t* cmdline);
|
||||
|
||||
const inline wchar_t* UPDATE_NOW_LAUNCH_STAGE1_START_PT_CMDARG = L"-update_now_and_start_pt";
|
||||
const inline wchar_t* UPDATE_NOW_LAUNCH_STAGE1_CMDARG = L"-update_now";
|
||||
namespace cmdArg
|
||||
{
|
||||
// Starts first stage of the PowerToys auto-update process, which involves copying action runner to a temp path and
|
||||
// restarting it from there, so it doesn't interfere with the installation process.
|
||||
const inline wchar_t* UPDATE_NOW_LAUNCH_STAGE1 = L"-update_now";
|
||||
// Stage 2 consists of starting the installer and optionally launching newly installed PowerToys binary.
|
||||
// That's indicated by the following 2 flags.
|
||||
const inline wchar_t* UPDATE_NOW_LAUNCH_STAGE2 = L"-update_now_stage_2";
|
||||
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* 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";
|
||||
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";
|
||||
}
|
||||
|
@ -17,13 +17,13 @@
|
||||
#include <common/notifications/dont_show_again.h>
|
||||
#include <common/updating/installer.h>
|
||||
#include <common/updating/updating.h>
|
||||
#include <common/updating/updateState.h>
|
||||
#include <common/utils/appMutex.h>
|
||||
#include <common/utils/elevation.h>
|
||||
#include <common/utils/processApi.h>
|
||||
#include <common/utils/resources.h>
|
||||
#include <common/winstore/winstore.h>
|
||||
|
||||
#include "update_state.h"
|
||||
#include "update_utils.h"
|
||||
#include "action_runner_utils.h"
|
||||
|
||||
@ -96,7 +96,7 @@ void debug_verify_launcher_assets()
|
||||
const auto assetPath = powertoysRoot / asset;
|
||||
if (!fs::is_regular_file(assetPath))
|
||||
{
|
||||
Logger::error("{} couldn't be found.", assetPath.string());
|
||||
Logger::error("{} couldn't be found.", assetPath.string());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -125,7 +125,7 @@ int runner(bool isProcessElevated, bool openSettings, bool openOobe)
|
||||
debug_verify_launcher_assets();
|
||||
|
||||
std::thread{ [] {
|
||||
github_update_worker();
|
||||
periodic_update_worker();
|
||||
} }.detach();
|
||||
|
||||
if (winstore::running_as_packaged())
|
||||
@ -227,7 +227,7 @@ SpecialMode should_run_in_special_mode(const int n_cmd_args, LPWSTR* cmd_arg_lis
|
||||
{
|
||||
return SpecialMode::ToastNotificationHandler;
|
||||
}
|
||||
else if (n_cmd_args == 2 && !wcscmp(UPDATE_REPORT_SUCCESS, cmd_arg_list[i]))
|
||||
else if (n_cmd_args == 2 && !wcscmp(cmdArg::UPDATE_REPORT_SUCCESS, cmd_arg_list[i]))
|
||||
{
|
||||
return SpecialMode::ReportSuccessfulUpdate;
|
||||
}
|
||||
@ -252,9 +252,7 @@ toast_notification_handler_result toast_notification_handler(const std::wstring_
|
||||
{
|
||||
const std::wstring_view cant_drag_elevated_disable = L"cant_drag_elevated_disable/";
|
||||
const std::wstring_view couldnt_toggle_powerpreview_modules_disable = L"couldnt_toggle_powerpreview_modules_disable/";
|
||||
const std::wstring_view download_and_install_update = L"download_and_install_update/";
|
||||
const std::wstring_view open_settings = L"open_settings/";
|
||||
const std::wstring_view schedule_update = L"schedule_update/";
|
||||
const std::wstring_view update_now = L"update_now/";
|
||||
|
||||
if (param == cant_drag_elevated_disable)
|
||||
@ -263,46 +261,10 @@ toast_notification_handler_result toast_notification_handler(const std::wstring_
|
||||
}
|
||||
else if (param.starts_with(update_now))
|
||||
{
|
||||
std::wstring args{ UPDATE_NOW_LAUNCH_STAGE1_CMDARG };
|
||||
const auto installerFilename = param.data() + size(update_now);
|
||||
args += L' ';
|
||||
args += installerFilename;
|
||||
std::wstring args{ cmdArg::UPDATE_NOW_LAUNCH_STAGE1 };
|
||||
launch_action_runner(args.c_str());
|
||||
return toast_notification_handler_result::exit_success;
|
||||
}
|
||||
else if (param.starts_with(schedule_update))
|
||||
{
|
||||
const auto installerFilename = param.data() + size(schedule_update);
|
||||
UpdateState::store([=](UpdateState& state) {
|
||||
state.pending_update = true;
|
||||
state.pending_installer_filename = installerFilename;
|
||||
});
|
||||
|
||||
return toast_notification_handler_result::exit_success;
|
||||
}
|
||||
else if (param.starts_with(download_and_install_update))
|
||||
{
|
||||
try
|
||||
{
|
||||
std::wstring installer_filename = updating::download_update(Strings).get();
|
||||
|
||||
std::wstring args{ UPDATE_NOW_LAUNCH_STAGE1_CMDARG };
|
||||
args += L' ';
|
||||
args += installer_filename;
|
||||
launch_action_runner(args.c_str());
|
||||
|
||||
return toast_notification_handler_result::exit_success;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
MessageBoxW(nullptr,
|
||||
GET_RESOURCE_STRING(IDS_DOWNLOAD_UPDATE_ERROR).c_str(),
|
||||
L"PowerToys",
|
||||
MB_ICONWARNING | MB_OK);
|
||||
|
||||
return toast_notification_handler_result::exit_error;
|
||||
}
|
||||
}
|
||||
else if (param == couldnt_toggle_powerpreview_modules_disable)
|
||||
{
|
||||
return notifications::disable_toast(notifications::PreviewModulesDontShowAgainRegistryPath) ? toast_notification_handler_result::exit_success : toast_notification_handler_result::exit_error;
|
||||
@ -334,11 +296,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
L"(ML;;NX;;;LW)"; // Integrity label on No execute up for Low mandatory level
|
||||
initializeCOMSecurity(securityDescriptor);
|
||||
|
||||
if (launch_pending_update())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int n_cmd_args = 0;
|
||||
LPWSTR* cmd_arg_list = CommandLineToArgvW(GetCommandLineW(), &n_cmd_args);
|
||||
switch (should_run_in_special_mode(n_cmd_args, cmd_arg_list))
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <ProjectTelemetry.h>
|
||||
|
||||
#include <winrt/Windows.ApplicationModel.h>
|
||||
#include <winrt/Windows.Networking.Connectivity.h>
|
||||
#include <winrt/Windows.Storage.h>
|
||||
|
||||
#include <wil/resource.h>
|
||||
|
@ -63,7 +63,6 @@
|
||||
<ClCompile Include="tray_icon.cpp" />
|
||||
<ClCompile Include="unhandled_exception_handler.cpp" />
|
||||
<ClCompile Include="update_utils.cpp" />
|
||||
<ClCompile Include="update_state.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="action_runner_utils.h" />
|
||||
@ -74,7 +73,6 @@
|
||||
<ClInclude Include="centralized_kb_hook.h" />
|
||||
<ClInclude Include="settings_telemetry.h" />
|
||||
<ClInclude Include="update_utils.h" />
|
||||
<ClInclude Include="update_state.h" />
|
||||
<ClInclude Include="powertoy_module.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="restart_elevated.h" />
|
||||
|
@ -27,9 +27,6 @@
|
||||
<ClCompile Include="restart_elevated.cpp">
|
||||
<Filter>Utils</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="update_state.cpp">
|
||||
<Filter>Utils</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="update_utils.cpp">
|
||||
<Filter>Utils</Filter>
|
||||
</ClCompile>
|
||||
@ -75,9 +72,6 @@
|
||||
<ClInclude Include="restart_elevated.h">
|
||||
<Filter>Utils</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="update_state.h">
|
||||
<Filter>Utils</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="update_utils.h">
|
||||
<Filter>Utils</Filter>
|
||||
</ClInclude>
|
||||
|
@ -8,9 +8,7 @@
|
||||
#include <common/interop/two_way_pipe_message_ipc.h>
|
||||
#include "tray_icon.h"
|
||||
#include "general_settings.h"
|
||||
#include <common/themes/windows_colors.h>
|
||||
#include "restart_elevated.h"
|
||||
#include "update_state.h"
|
||||
#include "update_utils.h"
|
||||
#include "centralized_kb_hook.h"
|
||||
|
||||
@ -23,6 +21,8 @@
|
||||
#include <common/utils/process_path.h>
|
||||
#include <common/utils/timeutil.h>
|
||||
#include <common/utils/winapi_error.h>
|
||||
#include <common/updating/updateState.h>
|
||||
#include <common/themes/windows_colors.h>
|
||||
|
||||
#define BUFSIZE 1024
|
||||
|
||||
@ -84,34 +84,16 @@ std::optional<std::wstring> dispatch_json_action_to_module(const json::JsonObjec
|
||||
}
|
||||
else if (action == L"check_for_updates")
|
||||
{
|
||||
if (auto update_check_result = check_for_updates())
|
||||
{
|
||||
VersionHelper latestVersion{ VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION };
|
||||
bool isVersionLatest = true;
|
||||
if (auto new_version = std::get_if<updating::new_version_download_info>(&*update_check_result))
|
||||
{
|
||||
latestVersion = new_version->version;
|
||||
isVersionLatest = false;
|
||||
}
|
||||
json::JsonObject json;
|
||||
json.SetNamedValue(L"version", json::value(latestVersion.toWstring()));
|
||||
json.SetNamedValue(L"isVersionLatest", json::value(isVersionLatest));
|
||||
|
||||
result.emplace(json.Stringify());
|
||||
|
||||
UpdateState::store([](UpdateState& state) {
|
||||
state.github_update_last_checked_date.emplace(timeutil::now());
|
||||
});
|
||||
}
|
||||
check_for_updates_settings_callback();
|
||||
}
|
||||
else if (action == L"request_update_state_date")
|
||||
{
|
||||
json::JsonObject json;
|
||||
|
||||
auto update_state = UpdateState::read();
|
||||
if (update_state.github_update_last_checked_date)
|
||||
if (update_state.githubUpdateLastCheckedDate)
|
||||
{
|
||||
const time_t date = *update_state.github_update_last_checked_date;
|
||||
const time_t date = *update_state.githubUpdateLastCheckedDate;
|
||||
json.SetNamedValue(L"updateStateDate", json::value(std::to_wstring(date)));
|
||||
}
|
||||
|
||||
@ -336,7 +318,7 @@ void run_settings_window(bool showOobeWindow)
|
||||
// Arg 6: elevated status
|
||||
bool isElevated{ get_general_settings().isElevated };
|
||||
std::wstring settings_elevatedStatus = isElevated ? L"true" : L"false";
|
||||
|
||||
|
||||
// Arg 7: is user an admin
|
||||
bool isAdmin{ get_general_settings().isAdmin };
|
||||
std::wstring settings_isUserAnAdmin = isAdmin ? L"true" : L"false";
|
||||
@ -364,14 +346,14 @@ void run_settings_window(bool showOobeWindow)
|
||||
executable_args.append(settings_isUserAnAdmin);
|
||||
executable_args.append(L" ");
|
||||
executable_args.append(settings_showOobe);
|
||||
|
||||
|
||||
BOOL process_created = false;
|
||||
|
||||
if (is_process_elevated())
|
||||
{
|
||||
// TODO: Revisit this after switching to .NET 5
|
||||
// Due to a bug in .NET, running the Settings process as non-elevated
|
||||
// from an elevated process sometimes results in a crash.
|
||||
// from an elevated process sometimes results in a crash.
|
||||
// process_created = run_settings_non_elevated(executable_path.c_str(), executable_args.data(), &process_info);
|
||||
}
|
||||
|
||||
|
@ -1,68 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "update_state.h"
|
||||
|
||||
#include <common/utils/json.h>
|
||||
#include <common/utils/timeutil.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
const wchar_t PERSISTENT_STATE_FILENAME[] = L"\\update_state.json";
|
||||
const wchar_t UPDATE_STATE_MUTEX[] = L"Local\\PowerToys_Runner_UpdateStateMutex";
|
||||
}
|
||||
|
||||
UpdateState deserialize(const json::JsonObject& json)
|
||||
{
|
||||
UpdateState result;
|
||||
|
||||
result.github_update_last_checked_date = timeutil::from_string(json.GetNamedString(L"github_update_last_checked_date", L"invalid").c_str());
|
||||
result.pending_update = json.GetNamedBoolean(L"pending_update", false);
|
||||
result.pending_installer_filename = json.GetNamedString(L"pending_installer_filename", L"");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
json::JsonObject serialize(const UpdateState& state)
|
||||
{
|
||||
json::JsonObject json;
|
||||
if (state.github_update_last_checked_date.has_value())
|
||||
{
|
||||
json.SetNamedValue(L"github_update_last_checked_date", json::value(timeutil::to_string(*state.github_update_last_checked_date)));
|
||||
}
|
||||
json.SetNamedValue(L"pending_update", json::value(state.pending_update));
|
||||
json.SetNamedValue(L"pending_installer_filename", json::value(state.pending_installer_filename));
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
UpdateState UpdateState::read()
|
||||
{
|
||||
const auto file_name = PTSettingsHelper::get_root_save_folder_location() + PERSISTENT_STATE_FILENAME;
|
||||
std::optional<json::JsonObject> json;
|
||||
{
|
||||
wil::unique_mutex_nothrow mutex{ CreateMutexW(nullptr, FALSE, UPDATE_STATE_MUTEX) };
|
||||
auto lock = mutex.acquire();
|
||||
json = json::from_file(file_name);
|
||||
}
|
||||
return json ? deserialize(*json) : UpdateState{};
|
||||
}
|
||||
|
||||
void UpdateState::store(std::function<void(UpdateState&)> state_modifier)
|
||||
{
|
||||
const auto file_name = PTSettingsHelper::get_root_save_folder_location() + PERSISTENT_STATE_FILENAME;
|
||||
|
||||
std::optional<json::JsonObject> json;
|
||||
{
|
||||
wil::unique_mutex_nothrow mutex{ CreateMutexW(nullptr, FALSE, UPDATE_STATE_MUTEX) };
|
||||
auto lock = mutex.acquire();
|
||||
json = json::from_file(file_name);
|
||||
UpdateState state;
|
||||
if (json)
|
||||
{
|
||||
state = deserialize(*json);
|
||||
}
|
||||
state_modifier(state);
|
||||
json.emplace(serialize(state));
|
||||
json::to_file(file_name, *json);
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <ctime>
|
||||
#include <optional>
|
||||
#include <functional>
|
||||
|
||||
// All fields must be default-initialized
|
||||
struct UpdateState
|
||||
{
|
||||
std::optional<std::time_t> github_update_last_checked_date;
|
||||
bool pending_update = false;
|
||||
std::wstring pending_installer_filename;
|
||||
|
||||
// To prevent concurrent modification of the file, we enforce this interface, which locks the file while
|
||||
// the state_modifier is active.
|
||||
static void store(std::function<void(UpdateState&)> state_modifier);
|
||||
static UpdateState read();
|
||||
};
|
@ -3,14 +3,16 @@
|
||||
#include "Generated Files/resource.h"
|
||||
|
||||
#include "action_runner_utils.h"
|
||||
#include "update_state.h"
|
||||
#include "general_settings.h"
|
||||
#include "update_utils.h"
|
||||
|
||||
#include <common/logger/logger.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/resources.h>
|
||||
#include <common/utils/timeutil.h>
|
||||
#include <runner/general_settings.h>
|
||||
|
||||
auto Strings = create_notifications_strings();
|
||||
|
||||
@ -44,15 +46,80 @@ bool start_msi_uninstallation_sequence()
|
||||
return exit_code == 0;
|
||||
}
|
||||
|
||||
void github_update_worker()
|
||||
using namespace updating;
|
||||
|
||||
bool could_be_costly_connection()
|
||||
{
|
||||
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)
|
||||
{
|
||||
state.githubUpdateLastCheckedDate.emplace(timeutil::now());
|
||||
if (std::holds_alternative<version_up_to_date>(version_info))
|
||||
{
|
||||
state.state = UpdateState::upToDate;
|
||||
state.releasePageUrl = {};
|
||||
state.downloadedInstallerFilename = {};
|
||||
Logger::trace(L"Version is up to date");
|
||||
return;
|
||||
}
|
||||
const auto new_version_info = std::get<new_version_download_info>(version_info);
|
||||
state.releasePageUrl = new_version_info.release_page_uri.ToString().c_str();
|
||||
Logger::trace(L"Discovered new version {}", new_version_info.version.toWstring());
|
||||
|
||||
const bool already_downloaded = state.state == UpdateState::readyToInstall && state.downloadedInstallerFilename == new_version_info.installer_filename;
|
||||
if (already_downloaded)
|
||||
{
|
||||
Logger::trace(L"New version is already downloaded");
|
||||
return;
|
||||
}
|
||||
|
||||
if (download_update)
|
||||
{
|
||||
Logger::trace(L"Downloading installer for a new version");
|
||||
if (download_new_version(new_version_info).get())
|
||||
{
|
||||
state.state = UpdateState::readyToInstall;
|
||||
state.downloadedInstallerFilename = new_version_info.installer_filename;
|
||||
if (show_notifications)
|
||||
{
|
||||
notifications::show_new_version_available(new_version_info, Strings);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
state.state = UpdateState::errorDownloading;
|
||||
state.downloadedInstallerFilename = {};
|
||||
Logger::error("Couldn't download new installer");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::trace(L"New version is ready to download, showing notification");
|
||||
state.state = UpdateState::readyToDownload;
|
||||
state.downloadedInstallerFilename = {};
|
||||
if (show_notifications)
|
||||
{
|
||||
notifications::show_open_settings_for_update(Strings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void periodic_update_worker()
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
auto state = UpdateState::read();
|
||||
int64_t sleep_minutes_till_next_update = 0;
|
||||
if (state.github_update_last_checked_date.has_value())
|
||||
if (state.githubUpdateLastCheckedDate.has_value())
|
||||
{
|
||||
int64_t last_checked_minutes_ago = timeutil::diff::in_minutes(timeutil::now(), *state.github_update_last_checked_date);
|
||||
int64_t last_checked_minutes_ago = timeutil::diff::in_minutes(timeutil::now(), *state.githubUpdateLastCheckedDate);
|
||||
if (last_checked_minutes_ago < 0)
|
||||
{
|
||||
last_checked_minutes_ago = UPDATE_CHECK_INTERVAL_MINUTES;
|
||||
@ -61,22 +128,31 @@ void github_update_worker()
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::minutes{ sleep_minutes_till_next_update });
|
||||
const bool download_updates_automatically = get_general_settings().downloadUpdatesAutomatically;
|
||||
bool update_check_ok = false;
|
||||
|
||||
const bool download_update = !could_be_costly_connection() && get_general_settings().downloadUpdatesAutomatically;
|
||||
bool version_info_obtained = false;
|
||||
try
|
||||
{
|
||||
update_check_ok = updating::try_autoupdate(download_updates_automatically, Strings).get();
|
||||
const auto new_version_info = get_github_version_info_async(Strings).get();
|
||||
if (new_version_info.has_value())
|
||||
{
|
||||
version_info_obtained = true;
|
||||
process_new_version_info(*new_version_info, state, download_update, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::error(L"Couldn't obtain version info from github: {}", new_version_info.error());
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Couldn't autoupdate
|
||||
update_check_ok = false;
|
||||
Logger::error("periodic_update_worker: error while processing version info");
|
||||
}
|
||||
|
||||
if (update_check_ok)
|
||||
if (version_info_obtained)
|
||||
{
|
||||
UpdateState::store([](UpdateState& state) {
|
||||
state.github_update_last_checked_date.emplace(timeutil::now());
|
||||
UpdateState::store([&](UpdateState& v) {
|
||||
v = std::move(state);
|
||||
});
|
||||
}
|
||||
else
|
||||
@ -86,55 +162,27 @@ void github_update_worker()
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<updating::github_version_info> check_for_updates()
|
||||
void check_for_updates_settings_callback()
|
||||
{
|
||||
Logger::trace(L"Check for updates callback invoked");
|
||||
auto state = UpdateState::read();
|
||||
try
|
||||
{
|
||||
auto version_check_result = updating::get_github_version_info_async(Strings).get();
|
||||
if (!version_check_result)
|
||||
auto new_version_info = get_github_version_info_async(Strings).get();
|
||||
if (!new_version_info)
|
||||
{
|
||||
updating::notifications::show_unavailable(Strings, std::move(version_check_result.error()));
|
||||
return std::nullopt;
|
||||
// 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());
|
||||
}
|
||||
|
||||
if (std::holds_alternative<updating::version_up_to_date>(*version_check_result))
|
||||
{
|
||||
updating::notifications::show_unavailable(Strings, Strings.GITHUB_NEW_VERSION_UP_TO_DATE);
|
||||
return std::move(*version_check_result);
|
||||
}
|
||||
|
||||
auto new_version = std::get<updating::new_version_download_info>(*version_check_result);
|
||||
updating::notifications::show_available(new_version, Strings);
|
||||
return std::move(new_version);
|
||||
const bool download_update = !could_be_costly_connection() && get_general_settings().downloadUpdatesAutomatically;
|
||||
process_new_version_info(*new_version_info, state, download_update, false);
|
||||
UpdateState::store([&](UpdateState& v) {
|
||||
v = std::move(state);
|
||||
});
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// Couldn't autoupdate
|
||||
Logger::error("check_for_updates_settings_callback: error while processing version info");
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool launch_pending_update()
|
||||
{
|
||||
try
|
||||
{
|
||||
auto update_state = UpdateState::read();
|
||||
if (update_state.pending_update)
|
||||
{
|
||||
UpdateState::store([](UpdateState& state) {
|
||||
state.pending_update = false;
|
||||
state.pending_installer_filename = {};
|
||||
});
|
||||
std::wstring args{ UPDATE_NOW_LAUNCH_STAGE1_START_PT_CMDARG };
|
||||
args += L' ';
|
||||
args += update_state.pending_installer_filename;
|
||||
|
||||
launch_action_runner(args.c_str());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -3,6 +3,5 @@
|
||||
#include <common/updating/updating.h>
|
||||
|
||||
bool start_msi_uninstallation_sequence();
|
||||
void github_update_worker();
|
||||
std::optional<updating::github_version_info> check_for_updates();
|
||||
bool launch_pending_update();
|
||||
void periodic_update_worker();
|
||||
void check_for_updates_settings_callback();
|
||||
|
@ -0,0 +1,126 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
||||
{
|
||||
public class UpdatingSettings
|
||||
{
|
||||
public enum UpdatingState
|
||||
{
|
||||
UpToDate = 0,
|
||||
ErrorDownloading,
|
||||
ReadyToDownload,
|
||||
ReadyToInstall,
|
||||
}
|
||||
|
||||
// Gets or sets a value of the updating state
|
||||
[JsonPropertyName("state")]
|
||||
public UpdatingState State { get; set; }
|
||||
|
||||
// Gets or sets a value of the release page url
|
||||
[JsonPropertyName("releasePageUrl")]
|
||||
public string ReleasePageLink { get; set; }
|
||||
|
||||
// Gets or sets a value of the github last checked date
|
||||
[JsonPropertyName("githubUpdateLastCheckedDate")]
|
||||
public string LastCheckedDate { get; set; }
|
||||
|
||||
// Gets or sets a value of the updating state
|
||||
[JsonPropertyName("downloadedInstallerFilename")]
|
||||
public string DownloadedInstallerFilename { get; set; }
|
||||
|
||||
// Non-localizable strings: Files
|
||||
public const string SettingsFilePath = "\\Microsoft\\PowerToys\\";
|
||||
public const string SettingsFile = "UpdateState.json";
|
||||
|
||||
public string NewVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
if (ReleasePageLink == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
string version = ReleasePageLink.Substring(ReleasePageLink.LastIndexOf('/') + 1);
|
||||
return version.Trim();
|
||||
}
|
||||
#pragma warning disable CA1031 // Do not catch general exception types
|
||||
catch (Exception)
|
||||
#pragma warning restore CA1031 // Do not catch general exception types
|
||||
{
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public string LastCheckedDateLocalized
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
long seconds = long.Parse(LastCheckedDate, CultureInfo.CurrentCulture);
|
||||
var date = DateTimeOffset.FromUnixTimeSeconds(seconds).UtcDateTime;
|
||||
return date.ToLocalTime().ToString(CultureInfo.CurrentCulture);
|
||||
}
|
||||
#pragma warning disable CA1031 // Do not catch general exception types
|
||||
catch (Exception)
|
||||
#pragma warning restore CA1031 // Do not catch general exception types
|
||||
{
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public UpdatingSettings()
|
||||
{
|
||||
State = UpdatingState.UpToDate;
|
||||
}
|
||||
|
||||
public static UpdatingSettings LoadSettings()
|
||||
{
|
||||
FileSystem fileSystem = new FileSystem();
|
||||
var localAppDataDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
var file = localAppDataDir + SettingsFilePath + SettingsFile;
|
||||
|
||||
if (fileSystem.File.Exists(file))
|
||||
{
|
||||
try
|
||||
{
|
||||
Stream inputStream = fileSystem.File.Open(file, FileMode.Open);
|
||||
StreamReader reader = new StreamReader(inputStream);
|
||||
string data = reader.ReadToEnd();
|
||||
inputStream.Close();
|
||||
reader.Dispose();
|
||||
|
||||
return JsonSerializer.Deserialize<UpdatingSettings>(data);
|
||||
}
|
||||
#pragma warning disable CA1031 // Do not catch general exception types
|
||||
catch (Exception)
|
||||
#pragma warning restore CA1031 // Do not catch general exception types
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public string ToJsonString()
|
||||
{
|
||||
return JsonSerializer.Serialize(this);
|
||||
}
|
||||
}
|
||||
}
|
@ -75,6 +75,12 @@ namespace Microsoft.PowerToys.Settings.UI.Library.Utilities
|
||||
return Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
}
|
||||
|
||||
public static string GetPowerToysInstallationFolder()
|
||||
{
|
||||
var settingsPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
|
||||
return Directory.GetParent(settingsPath).FullName;
|
||||
}
|
||||
|
||||
private static readonly interop.LayoutMapManaged LayoutMap = new interop.LayoutMapManaged();
|
||||
|
||||
public static string GetKeyName(uint key)
|
||||
|
@ -1,9 +1,11 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO.Abstractions;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||
@ -16,10 +18,14 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
||||
{
|
||||
private GeneralSettings GeneralSettingsConfig { get; set; }
|
||||
|
||||
private UpdatingSettings UpdatingSettingsConfig { get; set; }
|
||||
|
||||
public ButtonClickCommand CheckForUpdatesEventHandler { get; set; }
|
||||
|
||||
public ButtonClickCommand RestartElevatedButtonEventHandler { get; set; }
|
||||
|
||||
public ButtonClickCommand UpdateNowButtonEventHandler { get; set; }
|
||||
|
||||
public Func<string, int> UpdateUIThemeCallBack { get; }
|
||||
|
||||
public Func<string, int> SendConfigMSG { get; }
|
||||
@ -34,10 +40,13 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
||||
|
||||
private string _settingsConfigFileFolder = string.Empty;
|
||||
|
||||
public GeneralViewModel(ISettingsRepository<GeneralSettings> settingsRepository, string runAsAdminText, string runAsUserText, bool isElevated, bool isAdmin, Func<string, int> updateTheme, Func<string, int> ipcMSGCallBackFunc, Func<string, int> ipcMSGRestartAsAdminMSGCallBackFunc, Func<string, int> ipcMSGCheckForUpdatesCallBackFunc, string configFileSubfolder = "")
|
||||
private IFileSystemWatcher _fileWatcher;
|
||||
|
||||
public GeneralViewModel(ISettingsRepository<GeneralSettings> settingsRepository, string runAsAdminText, string runAsUserText, bool isElevated, bool isAdmin, Func<string, int> updateTheme, Func<string, int> ipcMSGCallBackFunc, Func<string, int> ipcMSGRestartAsAdminMSGCallBackFunc, Func<string, int> ipcMSGCheckForUpdatesCallBackFunc, string configFileSubfolder = "", Action dispatcherAction = null)
|
||||
{
|
||||
CheckForUpdatesEventHandler = new ButtonClickCommand(CheckForUpdatesClick);
|
||||
RestartElevatedButtonEventHandler = new ButtonClickCommand(RestartElevated);
|
||||
UpdateNowButtonEventHandler = new ButtonClickCommand(UpdateNowClick);
|
||||
|
||||
// To obtain the general settings configuration of PowerToys if it exists, else to create a new file and return the default configurations.
|
||||
if (settingsRepository == null)
|
||||
@ -46,6 +55,11 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
||||
}
|
||||
|
||||
GeneralSettingsConfig = settingsRepository.SettingsConfig;
|
||||
UpdatingSettingsConfig = UpdatingSettings.LoadSettings();
|
||||
if (UpdatingSettingsConfig == null)
|
||||
{
|
||||
UpdatingSettingsConfig = new UpdatingSettings();
|
||||
}
|
||||
|
||||
// set the callback functions value to hangle outgoing IPC message.
|
||||
SendConfigMSG = ipcMSGCallBackFunc;
|
||||
@ -86,6 +100,16 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
||||
RunningAsAdminDefaultText = runAsAdminText;
|
||||
|
||||
_isAdmin = isAdmin;
|
||||
|
||||
_updatingState = UpdatingSettingsConfig.State;
|
||||
_newAvailableVersion = UpdatingSettingsConfig.NewVersion;
|
||||
_newAvailableVersionLink = UpdatingSettingsConfig.ReleasePageLink;
|
||||
_updateCheckedDate = UpdatingSettingsConfig.LastCheckedDateLocalized;
|
||||
|
||||
if (dispatcherAction != null)
|
||||
{
|
||||
_fileWatcher = Helper.GetFileWatcher(string.Empty, UpdatingSettings.SettingsFile, dispatcherAction);
|
||||
}
|
||||
}
|
||||
|
||||
private bool _packaged;
|
||||
@ -98,9 +122,14 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
||||
private bool _isSystemThemeRadioButtonChecked;
|
||||
private bool _autoDownloadUpdates;
|
||||
|
||||
private string _latestAvailableVersion = string.Empty;
|
||||
private UpdatingSettings.UpdatingState _updatingState = UpdatingSettings.UpdatingState.UpToDate;
|
||||
private string _newAvailableVersion = string.Empty;
|
||||
private string _newAvailableVersionLink = string.Empty;
|
||||
private string _updateCheckedDate = string.Empty;
|
||||
|
||||
private bool _isNewVersionDownloading;
|
||||
private bool _isNewVersionChecked;
|
||||
|
||||
// Gets or sets a value indicating whether packaged.
|
||||
public bool Packaged
|
||||
{
|
||||
@ -360,24 +389,90 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
// Temp string. Appears when a user clicks "Check for updates" button and shows latest version available on the Github.
|
||||
public string LatestAvailableVersion
|
||||
public UpdatingSettings.UpdatingState PowerToysUpdatingState
|
||||
{
|
||||
get
|
||||
{
|
||||
return _latestAvailableVersion;
|
||||
return _updatingState;
|
||||
}
|
||||
|
||||
private set
|
||||
{
|
||||
if (value != _updatingState)
|
||||
{
|
||||
_updatingState = value;
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string PowerToysNewAvailableVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
return _newAvailableVersion;
|
||||
}
|
||||
|
||||
private set
|
||||
{
|
||||
if (value != _newAvailableVersion)
|
||||
{
|
||||
_newAvailableVersion = value;
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string PowerToysNewAvailableVersionLink
|
||||
{
|
||||
get
|
||||
{
|
||||
return _newAvailableVersionLink;
|
||||
}
|
||||
|
||||
private set
|
||||
{
|
||||
if (value != _newAvailableVersionLink)
|
||||
{
|
||||
_newAvailableVersionLink = value;
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsNewVersionDownloading
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isNewVersionDownloading;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_latestAvailableVersion != value)
|
||||
if (value != _isNewVersionDownloading)
|
||||
{
|
||||
_latestAvailableVersion = value;
|
||||
_isNewVersionDownloading = value;
|
||||
NotifyPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsNewVersionCheckedAndUpToDate
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isNewVersionChecked;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDownloadAllowed
|
||||
{
|
||||
get
|
||||
{
|
||||
return AutoUpdatesEnabled && !IsNewVersionDownloading;
|
||||
}
|
||||
}
|
||||
|
||||
public void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
// Notify UI of property change
|
||||
@ -390,6 +485,15 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
||||
// callback function to launch the URL to check for updates.
|
||||
private void CheckForUpdatesClick()
|
||||
{
|
||||
IsNewVersionDownloading = string.IsNullOrEmpty(UpdatingSettingsConfig.DownloadedInstallerFilename);
|
||||
NotifyPropertyChanged(nameof(IsDownloadAllowed));
|
||||
|
||||
if (_isNewVersionChecked)
|
||||
{
|
||||
_isNewVersionChecked = !IsNewVersionDownloading;
|
||||
NotifyPropertyChanged(nameof(IsNewVersionCheckedAndUpToDate));
|
||||
}
|
||||
|
||||
GeneralSettingsConfig.CustomActionName = "check_for_updates";
|
||||
|
||||
OutGoingGeneralSettings outsettings = new OutGoingGeneralSettings(GeneralSettingsConfig);
|
||||
@ -398,6 +502,14 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
||||
SendCheckForUpdatesConfigMSG(customaction.ToString());
|
||||
}
|
||||
|
||||
private void UpdateNowClick()
|
||||
{
|
||||
IsNewVersionDownloading = string.IsNullOrEmpty(UpdatingSettingsConfig.DownloadedInstallerFilename);
|
||||
NotifyPropertyChanged(nameof(IsDownloadAllowed));
|
||||
|
||||
Process.Start(new ProcessStartInfo(Helper.GetPowerToysInstallationFolder() + "\\PowerToys.exe") { Arguments = "powertoys://update_now/" });
|
||||
}
|
||||
|
||||
public void RequestUpdateCheckedDate()
|
||||
{
|
||||
GeneralSettingsConfig.CustomActionName = "request_update_state_date";
|
||||
@ -417,5 +529,45 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
|
||||
|
||||
SendRestartAsAdminConfigMSG(customaction.ToString());
|
||||
}
|
||||
|
||||
public void RefreshUpdatingState()
|
||||
{
|
||||
var config = UpdatingSettings.LoadSettings();
|
||||
|
||||
// Retry loading if failed
|
||||
for (int i = 0; i < 3 && config == null; i++)
|
||||
{
|
||||
System.Threading.Thread.Sleep(100);
|
||||
config = UpdatingSettings.LoadSettings();
|
||||
}
|
||||
|
||||
if (config == null || config.ToJsonString() == UpdatingSettingsConfig.ToJsonString())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UpdatingSettingsConfig = config;
|
||||
|
||||
if (PowerToysUpdatingState != config.State)
|
||||
{
|
||||
IsNewVersionDownloading = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool dateChanged = UpdateCheckedDate == UpdatingSettingsConfig.LastCheckedDateLocalized;
|
||||
bool fileDownloaded = string.IsNullOrEmpty(UpdatingSettingsConfig.DownloadedInstallerFilename);
|
||||
IsNewVersionDownloading = !(dateChanged || fileDownloaded);
|
||||
}
|
||||
|
||||
PowerToysUpdatingState = UpdatingSettingsConfig.State;
|
||||
PowerToysNewAvailableVersion = UpdatingSettingsConfig.NewVersion;
|
||||
PowerToysNewAvailableVersionLink = UpdatingSettingsConfig.ReleasePageLink;
|
||||
UpdateCheckedDate = UpdatingSettingsConfig.LastCheckedDateLocalized;
|
||||
|
||||
_isNewVersionChecked = PowerToysUpdatingState == UpdatingSettings.UpdatingState.UpToDate && !IsNewVersionDownloading;
|
||||
NotifyPropertyChanged(nameof(IsNewVersionCheckedAndUpToDate));
|
||||
|
||||
NotifyPropertyChanged(nameof(IsDownloadAllowed));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,24 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Data;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Converters
|
||||
{
|
||||
public sealed class UpdatingStateCannotDownloadToVisibilityConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
return (UpdatingSettings.UpdatingState)value == UpdatingSettings.UpdatingState.ErrorDownloading ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Data;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Converters
|
||||
{
|
||||
public sealed class UpdatingStateReadyToDownloadToVisibilityConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
return (UpdatingSettings.UpdatingState)value == UpdatingSettings.UpdatingState.ReadyToDownload ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Data;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Converters
|
||||
{
|
||||
public sealed class UpdatingStateReadyToInstallToVisibilityConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
return (UpdatingSettings.UpdatingState)value == UpdatingSettings.UpdatingState.ReadyToInstall ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Data;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Converters
|
||||
{
|
||||
public sealed class UpdatingStateUpToDateToVisibilityConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
return (UpdatingSettings.UpdatingState)value == UpdatingSettings.UpdatingState.UpToDate ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
@ -106,6 +106,10 @@
|
||||
<DependentUpon>ShortcutVisualControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Converters\ModuleEnabledToForegroundConverter.cs" />
|
||||
<Compile Include="Converters\UpdatingStateCannotDownloadToVisibilityConverter.cs" />
|
||||
<Compile Include="Converters\UpdatingStateReadyToDownloadToVisibilityConverter.cs" />
|
||||
<Compile Include="Converters\UpdatingStateReadyToInstallToVisibilityConverter.cs" />
|
||||
<Compile Include="Converters\UpdatingStateUpToDateToVisibilityConverter.cs" />
|
||||
<Compile Include="Generated Files\AssemblyInfo.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
|
@ -400,6 +400,9 @@
|
||||
<data name="GeneralPage_CheckForUpdates.Content" xml:space="preserve">
|
||||
<value>Check for updates</value>
|
||||
</data>
|
||||
<data name="GeneralPage_UpdateNow.Content" xml:space="preserve">
|
||||
<value>Update now</value>
|
||||
</data>
|
||||
<data name="GeneralPage_PrivacyStatement_URL.Text" xml:space="preserve">
|
||||
<value>Privacy statement</value>
|
||||
</data>
|
||||
@ -706,10 +709,10 @@
|
||||
<value>Updates</value>
|
||||
</data>
|
||||
<data name="General_Version.Text" xml:space="preserve">
|
||||
<value>Version:</value>
|
||||
<value>Installed version:</value>
|
||||
</data>
|
||||
<data name="General_VersionLastChecked.Text" xml:space="preserve">
|
||||
<value>Last successfully checked: </value>
|
||||
<value>Last checked: </value>
|
||||
</data>
|
||||
<data name="General_Version.AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Version</value>
|
||||
@ -1194,4 +1197,34 @@ From there, simply click on a Markdown file or SVG icon in the File Explorer and
|
||||
<data name="ShortcutGuide_OpenShortcutGuide.Header" xml:space="preserve">
|
||||
<value>Open Shortcut Guide</value>
|
||||
</data>
|
||||
<data name="General_FailedToDownloadTheNewVersion.Text" xml:space="preserve">
|
||||
<value>An error occurred trying to update to</value>
|
||||
</data>
|
||||
<data name="General_InstallNow.Content" xml:space="preserve">
|
||||
<value>Install now</value>
|
||||
</data>
|
||||
<data name="General_ReadMore.Text" xml:space="preserve">
|
||||
<value>Read more</value>
|
||||
</data>
|
||||
<data name="General_NewVersionAvailable.Text" xml:space="preserve">
|
||||
<value>A new version is available: </value>
|
||||
</data>
|
||||
<data name="General_Downloading.Text" xml:space="preserve">
|
||||
<value>Downloading...</value>
|
||||
</data>
|
||||
<data name="General_TryAgainToDownloadAndInstall.Content" xml:space="preserve">
|
||||
<value>Try again to download and install</value>
|
||||
</data>
|
||||
<data name="General_CheckingForUpdates.Text" xml:space="preserve">
|
||||
<value>Checking for updates...</value>
|
||||
</data>
|
||||
<data name="General_NewVersionReadyToInstall.Text" xml:space="preserve">
|
||||
<value>A new version is ready to install:</value>
|
||||
</data>
|
||||
<data name="General_UpToDate.Text" xml:space="preserve">
|
||||
<value>PowerToys is up to date</value>
|
||||
</data>
|
||||
<data name="General_DownloadAndInstall.Content" xml:space="preserve">
|
||||
<value>Download and install</value>
|
||||
</data>
|
||||
</root>
|
@ -6,6 +6,7 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:converters="using:Microsoft.Toolkit.Uwp.UI.Converters"
|
||||
xmlns:localConverters="using:Microsoft.PowerToys.Settings.UI.Converters"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
mc:Ignorable="d"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
|
||||
@ -14,6 +15,10 @@
|
||||
<Page.Resources>
|
||||
<converters:BoolToObjectConverter x:Key="BoolToVisibilityConverter" TrueValue="Collapsed" FalseValue="Visible"/>
|
||||
<converters:BoolToVisibilityConverter x:Key="VisibleIfTrueConverter"/>
|
||||
<localConverters:UpdatingStateUpToDateToVisibilityConverter x:Key="UpdatingStateUpToDateToVisibilityConverter" />
|
||||
<localConverters:UpdatingStateCannotDownloadToVisibilityConverter x:Key="UpdatingStateCannotDownloadToVisibilityConverter" />
|
||||
<localConverters:UpdatingStateReadyToDownloadToVisibilityConverter x:Key="UpdatingStateReadyToDownloadToVisibilityConverter" />
|
||||
<localConverters:UpdatingStateReadyToInstallToVisibilityConverter x:Key="UpdatingStateReadyToInstallToVisibilityConverter" />
|
||||
</Page.Resources>
|
||||
|
||||
<Grid RowSpacing="{StaticResource DefaultRowSpacing}">
|
||||
@ -62,7 +67,7 @@
|
||||
AutomationProperties.HeadingLevel="Level2"
|
||||
Style="{StaticResource SubtitleTextBlockStyle}"/>
|
||||
|
||||
<TextBlock Text="{x:Bind Mode=TwoWay, Path=ViewModel.RunningAsText}"
|
||||
<TextBlock Text="{Binding Mode=TwoWay, Path=RunningAsText}"
|
||||
TextWrapping="Wrap"
|
||||
Margin="{StaticResource SmallTopMargin}"/>
|
||||
|
||||
@ -116,45 +121,176 @@
|
||||
IsOn="{Binding Mode=TwoWay, Path=Startup}"/>
|
||||
|
||||
|
||||
|
||||
<TextBlock x:Uid="General_Updates"
|
||||
Style="{StaticResource SettingsGroupTitleStyle}"/>
|
||||
<StackPanel Orientation="Horizontal"
|
||||
|
||||
<StackPanel Visibility="{Binding PowerToysUpdatingState, Converter={StaticResource UpdatingStateUpToDateToVisibilityConverter}}">
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Margin="{StaticResource SmallTopMargin}"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=General_Version}">
|
||||
<TextBlock x:Name="General_Version_UpToDate"
|
||||
x:Uid="General_Version"
|
||||
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
|
||||
<TextBlock Text="{Binding PowerToysVersion }"
|
||||
Margin="4,0,0,0"
|
||||
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Margin="{StaticResource SmallTopMargin}"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=General_VersionLastChecked}"
|
||||
Visibility="{Binding AutoUpdatesEnabled, Converter={StaticResource VisibleIfTrueConverter}}">
|
||||
|
||||
<TextBlock x:Name="General_VersionLastChecked"
|
||||
x:Uid="General_VersionLastChecked"
|
||||
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
|
||||
|
||||
<TextBlock Text="{Binding UpdateCheckedDate, Mode=OneWay}"
|
||||
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"
|
||||
Margin="6,0" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock x:Name="General_CheckingForUpdates"
|
||||
x:Uid="General_CheckingForUpdates"
|
||||
Margin="{StaticResource SmallTopMargin}"
|
||||
Visibility="{Binding IsNewVersionDownloading, Converter={StaticResource VisibleIfTrueConverter}}"/>
|
||||
|
||||
<TextBlock x:Name="General_UpToDate"
|
||||
x:Uid="General_UpToDate"
|
||||
Margin="{StaticResource SmallTopMargin}"
|
||||
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"
|
||||
Visibility="{Binding IsNewVersionCheckedAndUpToDate, Converter={StaticResource VisibleIfTrueConverter}}"/>
|
||||
|
||||
<Button x:Uid="GeneralPage_CheckForUpdates"
|
||||
Style="{StaticResource AccentButtonStyle}"
|
||||
Foreground="White"
|
||||
Margin="{StaticResource SmallTopMargin}"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=General_Version}">
|
||||
<TextBlock x:Name="General_Version" x:Uid="General_Version" />
|
||||
<HyperlinkButton NavigateUri="https://github.com/microsoft/PowerToys/releases" Margin="4,-6,0,0">
|
||||
<TextBlock Text="{x:Bind ViewModel.PowerToysVersion }" />
|
||||
</HyperlinkButton>
|
||||
<TextBlock Text="{x:Bind ViewModel.LatestAvailableVersion, Mode=OneWay}"
|
||||
Foreground="{ThemeResource SystemControlErrorTextForegroundBrush}"
|
||||
Margin="16,0,0,0" />
|
||||
Command="{Binding CheckForUpdatesEventHandler}"
|
||||
IsEnabled="{Binding IsDownloadAllowed}"
|
||||
/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Margin="{StaticResource SmallBottomMargin}"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=General_VersionLastChecked}"
|
||||
Visibility="{Binding AutoUpdatesEnabled,
|
||||
Converter={StaticResource VisibleIfTrueConverter}}">
|
||||
<TextBlock x:Name="General_VersionLastChecked" x:Uid="General_VersionLastChecked" />
|
||||
<TextBlock Text="{x:Bind ViewModel.UpdateCheckedDate, Mode=OneWay}"
|
||||
Foreground="{ThemeResource ListViewItemForegroundPointerOver}"
|
||||
Margin="6,0" />
|
||||
<StackPanel Visibility="{Binding PowerToysUpdatingState, Converter={StaticResource UpdatingStateReadyToDownloadToVisibilityConverter}}">
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Margin="{StaticResource SmallTopMargin}"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=General_Version}">
|
||||
<TextBlock x:Name="General_Version_ReadyToDownload"
|
||||
x:Uid="General_Version"
|
||||
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
|
||||
<TextBlock Text="{Binding PowerToysVersion }"
|
||||
Margin="4,0,0,0"
|
||||
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Margin="{StaticResource SmallTopMargin}"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=General_Version}">
|
||||
<TextBlock x:Name="General_NewVersionAvailable"
|
||||
x:Uid="General_NewVersionAvailable"
|
||||
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
|
||||
|
||||
<HyperlinkButton NavigateUri="{Binding PowerToysNewAvailableVersionLink }" Margin="4,-6,0,0" IsEnabled="{Binding AutoUpdatesEnabled}">
|
||||
<TextBlock Text="{Binding PowerToysNewAvailableVersion }" />
|
||||
</HyperlinkButton>
|
||||
|
||||
<HyperlinkButton NavigateUri="{Binding PowerToysNewAvailableVersionLink}"
|
||||
Margin="4,-6,0,0"
|
||||
IsEnabled="{Binding AutoUpdatesEnabled}">
|
||||
<TextBlock x:Name="General_ReadMore_ReadyToDownload" x:Uid="General_ReadMore" />
|
||||
</HyperlinkButton>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock x:Name="General_Downloading"
|
||||
x:Uid="General_Downloading"
|
||||
Visibility="{Binding Mode=OneWay, Path=IsNewVersionDownloading, Converter={StaticResource VisibleIfTrueConverter}}"
|
||||
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
|
||||
|
||||
<Button x:Uid="General_DownloadAndInstall"
|
||||
Margin="{StaticResource SmallTopMargin}"
|
||||
Style="{StaticResource AccentButtonStyle}"
|
||||
Foreground="White"
|
||||
Command="{Binding UpdateNowButtonEventHandler}"
|
||||
IsEnabled="{Binding IsDownloadAllowed}"/>
|
||||
</StackPanel>
|
||||
|
||||
<Button x:Uid="GeneralPage_CheckForUpdates"
|
||||
Style="{StaticResource AccentButtonStyle}"
|
||||
Foreground="White"
|
||||
Command="{Binding CheckForUpdatesEventHandler}"
|
||||
IsEnabled="{Binding AutoUpdatesEnabled}"
|
||||
/>
|
||||
<StackPanel Visibility="{Binding PowerToysUpdatingState, Converter={StaticResource UpdatingStateReadyToInstallToVisibilityConverter}}">
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Margin="{StaticResource SmallTopMargin}"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=General_Version}">
|
||||
<TextBlock x:Name="General_Version_ReadyToInstall"
|
||||
x:Uid="General_Version"
|
||||
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
|
||||
<TextBlock Text="{Binding PowerToysVersion }"
|
||||
Margin="4,0,0,0"
|
||||
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Margin="{StaticResource SmallTopMargin}"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=General_Version}">
|
||||
<TextBlock x:Name="General_NewVersionReadyToInstall"
|
||||
x:Uid="General_NewVersionReadyToInstall"
|
||||
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
|
||||
<HyperlinkButton NavigateUri="{Binding PowerToysNewAvailableVersionLink }" Margin="4,-6,0,0" IsEnabled="{Binding AutoUpdatesEnabled}">
|
||||
<TextBlock Text="{Binding PowerToysNewAvailableVersion }" />
|
||||
</HyperlinkButton>
|
||||
|
||||
<HyperlinkButton NavigateUri="{Binding PowerToysNewAvailableVersionLink}"
|
||||
Margin="4,-6,0,0"
|
||||
IsEnabled="{Binding AutoUpdatesEnabled}">
|
||||
<TextBlock x:Name="General_ReadMore_ReadyToInstall" x:Uid="General_ReadMore" />
|
||||
</HyperlinkButton>
|
||||
</StackPanel>
|
||||
|
||||
<Button x:Uid="General_InstallNow"
|
||||
Margin="{StaticResource SmallTopMargin}"
|
||||
Style="{StaticResource AccentButtonStyle}"
|
||||
Foreground="White"
|
||||
Command="{Binding UpdateNowButtonEventHandler}"
|
||||
IsEnabled="{Binding AutoUpdatesEnabled}"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Visibility="{Binding PowerToysUpdatingState, Converter={StaticResource UpdatingStateCannotDownloadToVisibilityConverter}}">
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Margin="{StaticResource SmallTopMargin}"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=General_Version}">
|
||||
<TextBlock x:Name="General_Version_Error"
|
||||
x:Uid="General_Version"
|
||||
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
|
||||
<TextBlock Text="{Binding PowerToysVersion }"
|
||||
Margin="4,0,0,0"
|
||||
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Margin="{StaticResource SmallTopMargin}"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=General_Version}">
|
||||
<TextBlock x:Name="General_FailedToDownloadTheNewVersion"
|
||||
x:Uid="General_FailedToDownloadTheNewVersion"
|
||||
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
|
||||
<HyperlinkButton NavigateUri="{Binding PowerToysNewAvailableVersionLink }" Margin="4,-6,0,0" IsEnabled="{Binding AutoUpdatesEnabled}">
|
||||
<TextBlock Text="{Binding PowerToysNewAvailableVersion }" />
|
||||
</HyperlinkButton>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock x:Name="General_Downloading_TryAgain"
|
||||
x:Uid="General_Downloading"
|
||||
Visibility="{Binding Mode=OneWay, Path=IsNewVersionDownloading, Converter={StaticResource VisibleIfTrueConverter}}"
|
||||
Foreground="{Binding AutoUpdatesEnabled, Converter={StaticResource ModuleEnabledToForegroundConverter}}"/>
|
||||
|
||||
<Button x:Uid="General_TryAgainToDownloadAndInstall"
|
||||
Margin="{StaticResource SmallTopMargin}"
|
||||
Style="{StaticResource AccentButtonStyle}"
|
||||
Foreground="White"
|
||||
Command="{Binding UpdateNowButtonEventHandler}"
|
||||
IsEnabled="{Binding IsDownloadAllowed}"/>
|
||||
</StackPanel>
|
||||
|
||||
<ToggleSwitch x:Uid="GeneralPage_ToggleSwitch_AutoDownloadUpdates"
|
||||
Margin="{StaticResource MediumTopMargin}"
|
||||
Visibility="{Binding Mode=TwoWay, Path=IsAdmin, Converter={StaticResource VisibleIfTrueConverter}}"
|
||||
IsOn="{Binding Mode=TwoWay, Path=AutoDownloadUpdates}"
|
||||
IsEnabled="{Binding AutoUpdatesEnabled}" />
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<RelativePanel x:Name="SidePanel"
|
||||
|
@ -10,6 +10,7 @@ using Microsoft.PowerToys.Settings.UI.Library.Utilities;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.ViewModels;
|
||||
using Windows.ApplicationModel.Resources;
|
||||
using Windows.Data.Json;
|
||||
using Windows.UI.Core;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
@ -38,6 +39,11 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
ResourceLoader loader = ResourceLoader.GetForViewIndependentUse();
|
||||
var settingsUtils = new SettingsUtils();
|
||||
|
||||
Action stateUpdatingAction = async () =>
|
||||
{
|
||||
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, ViewModel.RefreshUpdatingState);
|
||||
};
|
||||
|
||||
ViewModel = new GeneralViewModel(
|
||||
SettingsRepository<GeneralSettings>.GetInstance(settingsUtils),
|
||||
loader.GetString("GeneralSettings_RunningAsAdminText"),
|
||||
@ -47,52 +53,9 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
UpdateUIThemeMethod,
|
||||
ShellPage.SendDefaultIPCMessage,
|
||||
ShellPage.SendRestartAdminIPCMessage,
|
||||
ShellPage.SendCheckForUpdatesIPCMessage);
|
||||
|
||||
ShellPage.ShellHandler.IPCResponseHandleList.Add((JsonObject json) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
string version = json.GetNamedString("version", string.Empty);
|
||||
bool isLatest = json.GetNamedBoolean("isVersionLatest", false);
|
||||
|
||||
if (json.ContainsKey("version"))
|
||||
{
|
||||
ViewModel.RequestUpdateCheckedDate();
|
||||
}
|
||||
|
||||
var str = string.Empty;
|
||||
if (isLatest)
|
||||
{
|
||||
str = ResourceLoader.GetForCurrentView().GetString("GeneralSettings_VersionIsLatest");
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(version))
|
||||
{
|
||||
str = ResourceLoader.GetForCurrentView().GetString("GeneralSettings_NewVersionIsAvailable");
|
||||
if (!string.IsNullOrEmpty(str))
|
||||
{
|
||||
str += ": " + version;
|
||||
}
|
||||
}
|
||||
|
||||
// Using CurrentCulture since this is user-facing
|
||||
if (!string.IsNullOrEmpty(str))
|
||||
{
|
||||
ViewModel.LatestAvailableVersion = string.Format(CultureInfo.CurrentCulture, str);
|
||||
}
|
||||
|
||||
string updateStateDate = json.GetNamedString("updateStateDate", string.Empty);
|
||||
if (!string.IsNullOrEmpty(updateStateDate) && long.TryParse(updateStateDate, out var uTCTime))
|
||||
{
|
||||
var localTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(uTCTime).ToLocalTime();
|
||||
ViewModel.UpdateCheckedDate = localTime.ToString(CultureInfo.CurrentCulture);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError("Exception encountered when reading the version.", e);
|
||||
}
|
||||
});
|
||||
ShellPage.SendCheckForUpdatesIPCMessage,
|
||||
string.Empty,
|
||||
stateUpdatingAction);
|
||||
|
||||
DataContext = ViewModel;
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ void HideUserPrivateInfo(const filesystem::path& dir)
|
||||
HideForFile(dir, it.first);
|
||||
}
|
||||
|
||||
// delete files
|
||||
// Delete files
|
||||
for (auto it : filesToDelete)
|
||||
{
|
||||
auto path = dir;
|
||||
@ -243,6 +243,26 @@ void ReportDotNetInstallationInfo(const filesystem::path& tmpDir)
|
||||
}
|
||||
}
|
||||
|
||||
void ReportBootstrapperLog(const filesystem::path& targetDir)
|
||||
{
|
||||
for (const auto entry : filesystem::directory_iterator{temp_directory_path()})
|
||||
{
|
||||
if (!entry.is_regular_file() || !entry.path().has_filename())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::wstring filename = entry.path().filename().native();
|
||||
if (!filename.starts_with(L"powertoys-bootstrapper-") || !filename.ends_with(L".log"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
std::error_code _;
|
||||
copy(entry.path(), targetDir, _);
|
||||
}
|
||||
}
|
||||
|
||||
int wmain(int argc, wchar_t* argv[], wchar_t*)
|
||||
{
|
||||
// Get path to save zip
|
||||
@ -280,6 +300,7 @@ int wmain(int argc, wchar_t* argv[], wchar_t*)
|
||||
try
|
||||
{
|
||||
copy(settingsRootPath, tmpDir, copy_options::recursive);
|
||||
|
||||
// Remove updates folder contents
|
||||
DeleteFolder(tmpDir / "Updates");
|
||||
}
|
||||
@ -296,7 +317,7 @@ int wmain(int argc, wchar_t* argv[], wchar_t*)
|
||||
ReportWindowsSettings(tmpDir);
|
||||
|
||||
// Write monitors info to the temporary folder
|
||||
reportMonitorInfo(tmpDir);
|
||||
ReportMonitorInfo(tmpDir);
|
||||
|
||||
// Write windows version info to the temporary folder
|
||||
ReportWindowsVersion(tmpDir);
|
||||
@ -310,6 +331,8 @@ int wmain(int argc, wchar_t* argv[], wchar_t*)
|
||||
// Write compatibility tab info to the temporary folder
|
||||
ReportCompatibilityTab(tmpDir);
|
||||
|
||||
ReportBootstrapperLog(tmpDir);
|
||||
|
||||
// Zip folder
|
||||
auto zipPath = path::path(saveZipPath);
|
||||
std::string reportFilename{"PowerToysReport_"};
|
||||
|
@ -246,6 +246,7 @@ void ReportRegistry(const filesystem::path& tmpDir)
|
||||
{
|
||||
registryReport << "ERROR " << result << "\n";
|
||||
}
|
||||
|
||||
registryReport << "\n";
|
||||
}
|
||||
|
||||
@ -288,12 +289,14 @@ void ReportRegistry(const filesystem::path& tmpDir)
|
||||
registryReport << "ERROR " << result << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
RegCloseKey(rootKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
registryReport << "ERROR " << result << "\n";
|
||||
}
|
||||
|
||||
registryReport << "\n";
|
||||
}
|
||||
}
|
||||
|
@ -8,4 +8,4 @@
|
||||
#include <Windows.h>
|
||||
|
||||
void ReportRegistry(const std::filesystem::path& tmpDir);
|
||||
void ReportCompatibilityTab(const std::filesystem::path& tmpDir);
|
||||
void ReportCompatibilityTab(const std::filesystem::path& tmpDir);
|
||||
|
@ -7,7 +7,7 @@ using namespace std;
|
||||
|
||||
namespace
|
||||
{
|
||||
int buildMonitorInfoReport(std::wostream& os)
|
||||
int BuildMonitorInfoReport(std::wostream& os)
|
||||
{
|
||||
struct capture
|
||||
{
|
||||
@ -45,6 +45,7 @@ namespace
|
||||
}
|
||||
return TRUE;
|
||||
};
|
||||
|
||||
capture c;
|
||||
c.os = &os;
|
||||
if (EnumDisplayMonitors(nullptr, nullptr, callback, (LPARAM)&c))
|
||||
@ -60,7 +61,7 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
void reportMonitorInfo(const filesystem::path& tmpDir)
|
||||
void ReportMonitorInfo(const filesystem::path& tmpDir)
|
||||
{
|
||||
auto monitorReportPath = tmpDir;
|
||||
monitorReportPath.append("monitor-report-info.txt");
|
||||
@ -69,7 +70,7 @@ void reportMonitorInfo(const filesystem::path& tmpDir)
|
||||
{
|
||||
wofstream monitorReport(monitorReportPath);
|
||||
monitorReport << "GetSystemMetrics = " << GetSystemMetrics(SM_CMONITORS) << '\n';
|
||||
buildMonitorInfoReport(monitorReport);
|
||||
BuildMonitorInfoReport(monitorReport);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#include <fstream>
|
||||
|
||||
void reportMonitorInfo(const std::filesystem::path& tmpDir);
|
||||
void ReportMonitorInfo(const std::filesystem::path& tmpDir);
|
||||
|
Loading…
Reference in New Issue
Block a user