Dev/yuyoyuppe/autoupdate polishing (#11693)

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

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

* [Updating] Use PowerToys.Update for update procedures

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

* [Installer] Remove Winstore, redundant strings

* [Settings] Remove deprecated 'packaged' setting
This commit is contained in:
Andrey Nekrasov 2021-06-14 12:55:59 +03:00 committed by GitHub
parent 5b804a1ff6
commit cdd06d7e98
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
58 changed files with 914 additions and 1154 deletions

View file

@ -65,6 +65,7 @@ build:
to: 'Build_Output'
include:
- 'PowerToys.ActionRunner.exe'
- 'PowerToys.Update.exe'
- 'BackgroundActivatorDLL.dll'
- 'Notifications.dll'
- 'os-detection.dll'

View file

@ -272,8 +272,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "interop", "interop", "{5A78
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "log", "log", "{E4E03FE0-94FD-47C7-88C5-F17D0AA549D3}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WinStore", "src\common\WinStore\Winstore.vcxproj", "{C502A854-53AC-4EBB-8DC0-E4AF2191E4F6}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "COMUtils", "src\common\COMUtils\COMUtils.vcxproj", "{7319089E-46D6-4400-BC65-E39BDF1416EE}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Display", "src\common\Display\Display.vcxproj", "{CABA8DFB-823B-4BF2-93AC-3F31984150D9}"
@ -288,8 +286,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "utils", "utils", "{B39DC643
src\common\utils\EventLocker.h = src\common\utils\EventLocker.h
src\common\utils\EventWaiter.h = src\common\utils\EventWaiter.h
src\common\utils\exec.h = src\common\utils\exec.h
src\common\utils\HttpClient.h = src\common\utils\HttpClient.h
src\common\utils\json.h = src\common\utils\json.h
src\common\utils\logger_helper.h = src\common\utils\logger_helper.h
src\common\utils\MsiUtils.h = src\common\utils\MsiUtils.h
src\common\utils\os-detect.h = src\common\utils\os-detect.h
src\common\utils\process_path.h = src\common\utils\process_path.h
src\common\utils\ProcessWaiter.h = src\common\utils\ProcessWaiter.h
@ -345,6 +345,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ShortcutGuideModuleInterfac
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ShortcutGuide", "src\modules\ShortcutGuide\ShortcutGuide\ShortcutGuide.vcxproj", "{2EDB3EB4-FA92-4BFF-B2D8-566584837231}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerToys.Update", "src\Update\PowerToys.Update.vcxproj", "{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.PowerToys.Run.Plugin.WindowsSettings", "src\modules\launcher\Plugins\Microsoft.PowerToys.Run.Plugin.WindowsSettings\Microsoft.PowerToys.Run.Plugin.WindowsSettings.csproj", "{5043CECE-E6A7-4867-9CBE-02D27D83747A}"
EndProject
Global
@ -623,10 +625,6 @@ Global
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Debug|x64.Build.0 = Debug|x64
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Release|x64.ActiveCfg = Release|x64
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF}.Release|x64.Build.0 = Release|x64
{C502A854-53AC-4EBB-8DC0-E4AF2191E4F6}.Debug|x64.ActiveCfg = Debug|x64
{C502A854-53AC-4EBB-8DC0-E4AF2191E4F6}.Debug|x64.Build.0 = Debug|x64
{C502A854-53AC-4EBB-8DC0-E4AF2191E4F6}.Release|x64.ActiveCfg = Release|x64
{C502A854-53AC-4EBB-8DC0-E4AF2191E4F6}.Release|x64.Build.0 = Release|x64
{7319089E-46D6-4400-BC65-E39BDF1416EE}.Debug|x64.ActiveCfg = Debug|x64
{7319089E-46D6-4400-BC65-E39BDF1416EE}.Debug|x64.Build.0 = Debug|x64
{7319089E-46D6-4400-BC65-E39BDF1416EE}.Release|x64.ActiveCfg = Release|x64
@ -679,22 +677,22 @@ Global
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Debug|x64.Build.0 = Debug|x64
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Release|x64.ActiveCfg = Release|x64
{62173D9A-6724-4C00-A1C8-FB646480A9EC}.Release|x64.Build.0 = Release|x64
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Debug|x64.ActiveCfg = Debug|x64
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Debug|x64.Build.0 = Debug|x64
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Release|x64.ActiveCfg = Release|x64
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Release|x64.Build.0 = Release|x64
{D940E07F-532C-4FF3-883F-790DA014F19A}.Debug|x64.ActiveCfg = Debug|x64
{D940E07F-532C-4FF3-883F-790DA014F19A}.Debug|x64.Build.0 = Debug|x64
{D940E07F-532C-4FF3-883F-790DA014F19A}.Release|x64.ActiveCfg = Release|x64
{D940E07F-532C-4FF3-883F-790DA014F19A}.Release|x64.Build.0 = Release|x64
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Debug|x64.ActiveCfg = Debug|x64
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Debug|x64.Build.0 = Debug|x64
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Release|x64.ActiveCfg = Release|x64
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4}.Release|x64.Build.0 = Release|x64
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Debug|x64.ActiveCfg = Debug|x64
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Debug|x64.Build.0 = Debug|x64
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Release|x64.ActiveCfg = Release|x64
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A}.Release|x64.Build.0 = Release|x64
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Debug|x64.ActiveCfg = Debug|x64
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Debug|x64.Build.0 = Debug|x64
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Release|x64.ActiveCfg = Release|x64
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1}.Release|x64.Build.0 = Release|x64
{D940E07F-532C-4FF3-883F-790DA014F19A}.Debug|x64.ActiveCfg = Debug|x64
{D940E07F-532C-4FF3-883F-790DA014F19A}.Debug|x64.Build.0 = Debug|x64
{D940E07F-532C-4FF3-883F-790DA014F19A}.Release|x64.ActiveCfg = Release|x64
{D940E07F-532C-4FF3-883F-790DA014F19A}.Release|x64.Build.0 = Release|x64
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Debug|x64.ActiveCfg = Debug|x64
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Debug|x64.Build.0 = Debug|x64
{2D604C07-51FC-46BB-9EB7-75AECC7F5E81}.Release|x64.ActiveCfg = Release|x64
@ -703,6 +701,10 @@ Global
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Debug|x64.Build.0 = Debug|x64
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Release|x64.ActiveCfg = Release|x64
{2EDB3EB4-FA92-4BFF-B2D8-566584837231}.Release|x64.Build.0 = Release|x64
{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}.Debug|x64.ActiveCfg = Debug|x64
{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}.Debug|x64.Build.0 = Debug|x64
{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}.Release|x64.ActiveCfg = Release|x64
{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}.Release|x64.Build.0 = Release|x64
{5043CECE-E6A7-4867-9CBE-02D27D83747A}.Debug|x64.ActiveCfg = Debug|x64
{5043CECE-E6A7-4867-9CBE-02D27D83747A}.Debug|x64.Build.0 = Debug|x64
{5043CECE-E6A7-4867-9CBE-02D27D83747A}.Release|x64.ActiveCfg = Release|x64
@ -789,7 +791,6 @@ Global
{CC6E41AC-8174-4E8A-8D22-85DD7F4851DF} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{5A7818A8-109C-4E1C-850D-1A654E234B0E} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{E4E03FE0-94FD-47C7-88C5-F17D0AA549D3} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{C502A854-53AC-4EBB-8DC0-E4AF2191E4F6} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{7319089E-46D6-4400-BC65-E39BDF1416EE} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{CABA8DFB-823B-4BF2-93AC-3F31984150D9} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{98537082-0FDB-40DE-ABD8-0DC5A4269BAB} = {1AFB6476-670D-4E80-A464-657E01DFF482}
@ -806,8 +807,8 @@ Global
{23D2070D-E4AD-4ADD-85A7-083D9C76AD49} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
{62173D9A-6724-4C00-A1C8-FB646480A9EC} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
{127F38E0-40AA-4594-B955-5616BF206882} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A} = {127F38E0-40AA-4594-B955-5616BF206882}
{BB23A474-5058-4F75-8FA3-5FE3DE53CDF4} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{5E7360A8-D048-4ED3-8F09-0BFD64C5529A} = {127F38E0-40AA-4594-B955-5616BF206882}
{3E424AD2-19E5-4AE6-B833-F53963EB5FC1} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
{D940E07F-532C-4FF3-883F-790DA014F19A} = {127F38E0-40AA-4594-B955-5616BF206882}
{106CBECA-0701-4FC3-838C-9DF816A19AE2} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}

View file

@ -3,8 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30320.27
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Updating", "..\..\src\common\updating\updating.vcxproj", "{17DA04DF-E393-4397-9CF0-84DABE11032E}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bootstrapper", "bootstrapper\bootstrapper.vcxproj", "{D194E3AA-F824-4CA9-9A58-034DD6B7D022}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spdlog", "..\..\src\logging\logging.vcxproj", "{7E1E3F13-2BD6-3F75-A6A7-873A2B55C60F}"
@ -13,20 +11,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Version", "..\..\src\common
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SetttingsAPI", "..\..\src\common\SettingsAPI\SetttingsAPI.vcxproj", "{6955446D-23F7-4023-9BB3-8657F904AF99}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Notifications", "..\..\src\common\notifications\notifications.vcxproj", "{1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WinStore", "..\..\src\common\WinStore\Winstore.vcxproj", "{C502A854-53AC-4EBB-8DC0-E4AF2191E4F6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{17DA04DF-E393-4397-9CF0-84DABE11032E}.Debug|x64.ActiveCfg = Debug|x64
{17DA04DF-E393-4397-9CF0-84DABE11032E}.Debug|x64.Build.0 = Debug|x64
{17DA04DF-E393-4397-9CF0-84DABE11032E}.Release|x64.ActiveCfg = Release|x64
{17DA04DF-E393-4397-9CF0-84DABE11032E}.Release|x64.Build.0 = Release|x64
{D194E3AA-F824-4CA9-9A58-034DD6B7D022}.Debug|x64.ActiveCfg = Debug|x64
{D194E3AA-F824-4CA9-9A58-034DD6B7D022}.Debug|x64.Build.0 = Debug|x64
{D194E3AA-F824-4CA9-9A58-034DD6B7D022}.Release|x64.ActiveCfg = Release|x64
@ -43,14 +33,6 @@ Global
{6955446D-23F7-4023-9BB3-8657F904AF99}.Debug|x64.Build.0 = Debug|x64
{6955446D-23F7-4023-9BB3-8657F904AF99}.Release|x64.ActiveCfg = Release|x64
{6955446D-23F7-4023-9BB3-8657F904AF99}.Release|x64.Build.0 = Release|x64
{1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}.Debug|x64.ActiveCfg = Debug|x64
{1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}.Debug|x64.Build.0 = Debug|x64
{1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}.Release|x64.ActiveCfg = Release|x64
{1D5BE09D-78C0-4FD7-AF00-AE7C1AF7C525}.Release|x64.Build.0 = Release|x64
{C502A854-53AC-4EBB-8DC0-E4AF2191E4F6}.Debug|x64.ActiveCfg = Debug|x64
{C502A854-53AC-4EBB-8DC0-E4AF2191E4F6}.Debug|x64.Build.0 = Debug|x64
{C502A854-53AC-4EBB-8DC0-E4AF2191E4F6}.Release|x64.ActiveCfg = Release|x64
{C502A854-53AC-4EBB-8DC0-E4AF2191E4F6}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View file

@ -1,11 +1,10 @@
#include "pch.h"
#include "dotnet_installation.h"
#include "http_client.h"
#include "utils/exec.h"
#include "utils/winapi_error.h"
#include "DotnetInstallation.h"
#include <common/utils/exec.h>
#include <common/utils/HttpClient.h>
#include <common/utils/winapi_error.h>
namespace fs = std::filesystem;
namespace updating

View file

@ -67,30 +67,9 @@
<data name="DOTNET_CORE_DOWNLOAD_FAILURE_TITLE" xml:space="preserve">
<value>PowerToys installation error</value>
</data>
<data name="GITHUB_NEW_VERSION_AVAILABLE" xml:space="preserve">
<value>An update to PowerToys is available.</value>
</data>
<data name="GITHUB_NEW_VERSION_UPDATE_NOW" xml:space="preserve">
<value>Update now</value>
</data>
<data name="UNINSTALLATION_UNKNOWN_ERROR" xml:space="preserve">
<value>Error: please uninstall the previous version of PowerToys manually.</value>
</data>
<data name="GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT" xml:space="preserve">
<value>An update to PowerToys is available. Visit our GitHub page to update.</value>
</data>
<data name="GITHUB_NEW_VERSION_MORE_INFO" xml:space="preserve">
<value>More info...</value>
</data>
<data name="TOAST_TITLE" xml:space="preserve">
<value>PowerToys Update</value>
</data>
<data name="OFFER_UNINSTALL_MSI" xml:space="preserve">
<value>We've detected a previous installation of PowerToys. Would you like to remove it?</value>
</data>
<data name="OFFER_UNINSTALL_MSI_TITLE" xml:space="preserve">
<value>PowerToys: uninstall previous version?</value>
</data>
<data name="INSTALLER_EXTRACT_ERROR" xml:space="preserve">
<value>Couldn't extract MSI installer.</value>
</data>

View file

@ -2,23 +2,21 @@
#include "Generated Files/resource.h"
#include "RcResource.h"
#include <common/updating/dotnet_installation.h>
#include <common/updating/installer.h>
#include <common/updating/notifications.h>
#include <common/version/helper.h>
#include <common/version/version.h>
#include <common/utils/appMutex.h>
#include <common/utils/elevation.h>
#include <common/utils/MsiUtils.h>
#include <common/utils/os-detect.h>
#include <common/utils/processApi.h>
#include <common/utils/resources.h>
#include <common/utils/window.h>
#include <common/utils/winapi_error.h>
#include <common/SettingsAPI/settings_helpers.h>
#include <runner/action_runner_utils.h>
#include "DotnetInstallation.h"
#include "progressbar_window.h"
auto Strings = create_notifications_strings();
static bool g_Silent = false;
#define STR_HELPER(x) #x
@ -95,7 +93,7 @@ void CleanupSettingsFromOlderVersions()
spdlog::info("Old log settings file wasn't found");
}
}
catch(...)
catch (...)
{
spdlog::error("Failed to cleanup old log settings");
}
@ -106,9 +104,9 @@ void ShowMessageBoxError(const wchar_t* message)
if (!g_Silent)
{
MessageBoxW(nullptr,
message,
GET_RESOURCE_STRING(IDS_BOOTSTRAPPER_PROGRESS_TITLE).c_str(),
MB_OK | MB_ICONERROR);
message,
GET_RESOURCE_STRING(IDS_BOOTSTRAPPER_PROGRESS_TITLE).c_str(),
MB_OK | MB_ICONERROR);
}
}
@ -117,6 +115,46 @@ void ShowMessageBoxError(const UINT messageId)
ShowMessageBoxError(GET_RESOURCE_STRING(messageId).c_str());
}
bool uninstall_msi_version(const std::wstring& package_path)
{
const auto uninstall_result = MsiInstallProductW(package_path.c_str(), L"REMOVE=ALL");
return ERROR_SUCCESS == uninstall_result;
}
std::optional<VersionHelper> get_installed_powertoys_version()
{
auto installed_path = GetMsiPackageInstalledPath();
if (!installed_path)
{
return std::nullopt;
}
*installed_path += L"\\PowerToys.exe";
// Get the version information for the file requested
const DWORD fvSize = GetFileVersionInfoSizeW(installed_path->c_str(), nullptr);
if (!fvSize)
{
return std::nullopt;
}
auto pbVersionInfo = std::make_unique<BYTE[]>(fvSize);
if (!GetFileVersionInfoW(installed_path->c_str(), 0, fvSize, pbVersionInfo.get()))
{
return std::nullopt;
}
VS_FIXEDFILEINFO* fileInfo = nullptr;
UINT fileInfoLen = 0;
if (!VerQueryValueW(pbVersionInfo.get(), L"\\", reinterpret_cast<LPVOID*>(&fileInfo), &fileInfoLen))
{
return std::nullopt;
}
return VersionHelper{ (fileInfo->dwFileVersionMS >> 16) & 0xffff,
(fileInfo->dwFileVersionMS >> 0) & 0xffff,
(fileInfo->dwFileVersionLS >> 16) & 0xffff };
}
int Bootstrapper(HINSTANCE hInstance)
{
winrt::init_apartment();
@ -133,17 +171,17 @@ int Bootstrapper(HINSTANCE hInstance)
cxxopts::Options options{ "PowerToysBootstrapper" };
// clang-format off
options.add_options()
("h,help", "Show help")
("no_full_ui", "Use reduced UI for MSI")
("s,silent", "Suppress all UI, notifications and does not start PowerToys")
("no_start_pt", "Do not launch PowerToys after the installation is complete")
("start_pt", "Always launch PowerToys after the installation is complete")
("skip_dotnet_install", "Skip dotnet 3.X installation even if it's not detected")
("log_level", "Log level. Possible values: off|debug|error", cxxopts::value<std::string>()->default_value("off"))
("log_dir", "Log directory", cxxopts::value<std::string>()->default_value("."))
("install_dir", "Installation directory", cxxopts::value<std::string>()->default_value(defaultInstallDir))
("extract_msi", "Extract MSI to the working directory and exit. Use only if you must access MSI directly.");
options.add_options()
("h,help", "Show help")
("no_full_ui", "Use reduced UI for MSI")
("s,silent", "Suppress all UI, notifications and does not start PowerToys")
("no_start_pt", "Do not launch PowerToys after the installation is complete")
("start_pt", "Always launch PowerToys after the installation is complete")
("skip_dotnet_install", "Skip dotnet 3.X installation even if it's not detected")
("log_level", "Log level. Possible values: off|debug|error", cxxopts::value<std::string>()->default_value("off"))
("log_dir", "Log directory", cxxopts::value<std::string>()->default_value("."))
("install_dir", "Installation directory", cxxopts::value<std::string>()->default_value(defaultInstallDir))
("extract_msi", "Extract MSI to the working directory and exit. Use only if you must access MSI directly.");
// clang-format on
cxxopts::ParseResult cmdArgs;
@ -234,15 +272,15 @@ int Bootstrapper(HINSTANCE hInstance)
const VersionHelper myVersion(VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION);
// Do not support installing on Windows < 1903
if (updating::is_1809_or_older())
if (!Is19H1OrHigher())
{
ShowMessageBoxError(IDS_OLD_WINDOWS_ERROR);
spdlog::error("PowerToys {} requires at least Windows 1903 to run.", myVersion.toString());
return 1;
ShowMessageBoxError(IDS_OLD_WINDOWS_ERROR);
spdlog::error("PowerToys {} requires at least Windows 1903 to run.", myVersion.toString());
return 1;
}
// Check if there's a newer version installed
const auto installedVersion = updating::get_installed_powertoys_version();
const auto installedVersion = get_installed_powertoys_version();
if (installedVersion && *installedVersion >= myVersion)
{
spdlog::error(L"Detected a newer version {} vs {}", (*installedVersion).toWstring(), myVersion.toWstring());
@ -341,7 +379,7 @@ int Bootstrapper(HINSTANCE hInstance)
});
spdlog::debug("Acquiring existing MSI package path if exists");
const auto package_path = updating::get_msi_package_path();
const auto package_path = GetMsiPackagePath();
if (!package_path.empty())
{
spdlog::debug(L"Existing MSI package path found: {}", package_path);
@ -351,7 +389,7 @@ int Bootstrapper(HINSTANCE hInstance)
spdlog::debug("Existing MSI package path not found");
}
if (!package_path.empty() && !updating::uninstall_msi_version(package_path, Strings))
if (!package_path.empty() && !uninstall_msi_version(package_path))
{
spdlog::error("Couldn't install the existing MSI package ({})", GetLastError());
ShowMessageBoxError(IDS_UNINSTALL_PREVIOUS_VERSION_ERROR);
@ -401,7 +439,7 @@ int Bootstrapper(HINSTANCE hInstance)
spdlog::error("Unknown exception during dotnet installation");
ShowMessageBoxError(IDS_DOTNET_INSTALL_ERROR);
}
// At this point, there's no reason to show progress bar window, since MSI installers have their own
CloseProgressBarDialog();
@ -419,7 +457,7 @@ int Bootstrapper(HINSTANCE hInstance)
if ((!noStartPT && !g_Silent) || startPT)
{
spdlog::debug("Starting the newly installed PowerToys.exe");
auto newPTPath = updating::get_msi_package_installed_path();
auto newPTPath = GetMsiPackageInstalledPath();
if (!newPTPath)
{
spdlog::error("Couldn't determine new MSI package install location ({})", GetLastError());
@ -448,7 +486,7 @@ int WINAPI WinMain(HINSTANCE hi, HINSTANCE, LPSTR, int)
std::string messageA{ "Unhandled std exception encountered\n" };
messageA.append(ex.what());
spdlog::error(messageA.c_str());
spdlog::error(messageA.c_str());
std::wstring messageW{};
std::copy(messageA.begin(), messageA.end(), messageW.begin());

View file

@ -24,7 +24,9 @@
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{D194E3AA-F824-4CA9-9A58-034DD6B7D022}</ProjectGuid>
<RootNamespace>bootstrapper</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
<OverrideWindowsTargetPlatformVersion>true</OverrideWindowsTargetPlatformVersion>
<TargetPlatformVersion>10.0.18362.0</TargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
<ProjectName>bootstrapper</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
@ -71,7 +73,7 @@
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
@ -88,12 +90,12 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>WindowsApp.lib;Msi.lib;Shlwapi.lib;Comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>WindowsApp.lib;Msi.lib;Shlwapi.lib;Comctl32.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
@ -106,11 +108,12 @@
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>WindowsApp.lib;Msi.lib;Shlwapi.lib;Comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>WindowsApp.lib;Msi.lib;Shlwapi.lib;Comctl32.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="bootstrapper.cpp" />
<ClCompile Include="DotnetInstallation.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
@ -119,6 +122,7 @@
<ClCompile Include="RcResource.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="DotnetInstallation.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="progressbar_window.h" />
</ItemGroup>
@ -133,8 +137,11 @@
<Image Include="..\runner\svgs\icon.ico" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\common\updating\updating.vcxproj">
<Project>{17da04df-e393-4397-9cf0-84dabe11032e}</Project>
<ProjectReference Include="..\..\..\src\common\SettingsAPI\SetttingsAPI.vcxproj">
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\src\common\version\version.vcxproj">
<Project>{cc6e41ac-8174-4e8a-8d22-85dd7f4851df}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\src\logging\logging.vcxproj">
<Project>{7e1e3f13-2bd6-3f75-a6a7-873a2b55c60f}</Project>

View file

@ -6,6 +6,7 @@
#include <shellapi.h>
#include <commctrl.h>
#include <charconv>
#include <string_view>
#include <optional>
#include <fstream>
@ -22,8 +23,10 @@
#include <spdlog/sinks/null_sink.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#pragma warning(push, 0)
#include <winrt/base.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#pragma warning(pop)
#include <cxxopts.hpp>

View file

@ -1,6 +1,5 @@
#include "pch.h"
#include <common/updating/notifications.h>
#include <common/utils/window.h>
#include "progressbar_window.h"

View file

@ -359,6 +359,9 @@
<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="PowerToys_Update_exe" Guid="446D0AD4-AA8F-45BA-BDAC-6C620DF77AFF" Win64="yes">
<File Id="PowerToys.Update.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" />
</Component>
@ -869,6 +872,7 @@
<ComponentRef Id="PowerToysStartMenuShortcut"/>
<ComponentRef Id="BackgroundActivator_dll" />
<ComponentRef Id="PowerToys_ActionRunner_exe" />
<ComponentRef Id="PowerToys_Update_exe" />
<ComponentRef Id="powertoys_toast_clsid" />
<ComponentRef Id="License_rtf" />
<ComponentRef Id="Notice_md" />

View file

@ -2,6 +2,7 @@
#include <ProjectTelemetry.h>
#include "../../src/common/utils/MsiUtils.h"
#include "../../src/common/updating/installer.h"
#include "../../src/common/version/version.h"
@ -582,7 +583,7 @@ UINT __stdcall DetectPrevInstallPathCA(MSIHANDLE hInstall)
try
{
if (auto install_path = updating::get_msi_package_installed_path())
if (auto install_path = GetMsiPackageInstalledPath())
{
MsiSetPropertyW(hInstall, L"INSTALLFOLDER", install_path->data());
}

View file

@ -56,7 +56,7 @@
</ClCompile>
<Link>
<AdditionalLibraryDirectories>$(WIX)sdk\$(WixPlatformToolset)\lib\x64;$(SolutionDir)\packages\WiX.3.11.2\tools\sdk\vs2017\lib\x64;..\..\$(PlatformShortName)\$(Configuration)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>msi.lib;wcautil.lib;Psapi.lib;Pathcch.lib;comsupp.lib;taskschd.lib;Secur32.lib;msi.lib;dutil.lib;wcautil.lib;Version.lib;ApplicationUpdate.lib;Notifications.lib;winstore.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>msi.lib;wcautil.lib;Psapi.lib;Pathcch.lib;comsupp.lib;taskschd.lib;Secur32.lib;msi.lib;dutil.lib;wcautil.lib;Version.lib;ApplicationUpdate.lib;Notifications.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

View file

@ -64,28 +64,7 @@
<data name="DOTNET_CORE_DOWNLOAD_FAILURE_TITLE" xml:space="preserve">
<value>PowerToys installation error</value>
</data>
<data name="GITHUB_NEW_VERSION_AVAILABLE" xml:space="preserve">
<value>An update to PowerToys is available.</value>
</data>
<data name="GITHUB_NEW_VERSION_UPDATE_NOW" xml:space="preserve">
<value>Update now</value>
</data>
<data name="UNINSTALLATION_UNKNOWN_ERROR" xml:space="preserve">
<value>Error: please uninstall the previous version of PowerToys manually.</value>
</data>
<data name="GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT" xml:space="preserve">
<value>An update to PowerToys is available. Visit our GitHub page to update.</value>
</data>
<data name="GITHUB_NEW_VERSION_MORE_INFO" xml:space="preserve">
<value>More info...</value>
</data>
<data name="TOAST_TITLE" xml:space="preserve">
<value>PowerToys Update</value>
</data>
<data name="OFFER_UNINSTALL_MSI" xml:space="preserve">
<value>We've detected a previous installation of PowerToys. Would you like to remove it?</value>
</data>
<data name="OFFER_UNINSTALL_MSI_TITLE" xml:space="preserve">
<value>PowerToys: uninstall previous version?</value>
</data>
</root>

View file

@ -11,12 +11,6 @@
#include <filesystem>
#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>
#include <common/utils/elevation.h>
#include <common/utils/process_path.h>
#include <common/utils/resources.h>
@ -28,214 +22,14 @@
#include <winrt/Windows.ApplicationModel.h>
#include <winrt/Windows.Storage.h>
#include <Msi.h>
#include "../runner/tray_icon.h"
#include "../runner/action_runner_utils.h"
auto Strings = create_notifications_strings();
#include "../runner/ActionRunnerUtils.h"
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;
}
// Launch PowerToys again, since it's been terminated by the MSI uninstaller
std::wstring runner_path{ winrt::Windows::ApplicationModel::Package::Current().InstalledLocation().Path() };
runner_path += L"\\PowerToys.exe";
SHELLEXECUTEINFOW sei{ sizeof(sei) };
sei.fMask = { SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC };
sei.lpFile = runner_path.c_str();
sei.nShow = SW_SHOWNORMAL;
ShellExecuteExW(&sei);
return 0;
}
namespace fs = std::filesystem;
std::optional<fs::path> CopySelfToTempDir()
{
std::error_code error;
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);
}
std::optional<fs::path> ObtainInstallerPath()
{
using namespace updating;
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 = CopySelfToTempDir())
{
// Detect if PT was running
const auto pt_main_window = FindWindowW(pt_tray_icon_window_class, 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 };
arguments += L" \"";
arguments += installer->c_str();
arguments += L"\" \"";
arguments += get_module_folderpath();
arguments += L"\" ";
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();
sei.nShow = SW_SHOWNORMAL;
sei.lpParameters = arguments.c_str();
return ShellExecuteExW(&sei) == TRUE;
}
else
{
return false;
}
}
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);
bool success = true;
if (installer_path.ends_with(L".msi"))
{
success = MsiInstallProductW(installer_path.data(), nullptr) == ERROR_SUCCESS;
}
else
{
// If it's not .msi, then it's our .exe installer
SHELLEXECUTEINFOW sei{ sizeof(sei) };
sei.fMask = { SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NO_CONSOLE };
sei.lpFile = installer_path.c_str();
sei.nShow = SW_SHOWNORMAL;
std::wstring parameters = L"--no_full_ui";
if (launch_powertoys)
{
// .exe installer launches the main app by default
launch_powertoys = false;
}
else
{
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);
}
}
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 };
new_pt_path += L"\\PowerToys.exe";
SHELLEXECUTEINFOW sei{ sizeof(sei) };
sei.fMask = { SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC };
sei.lpFile = new_pt_path.c_str();
sei.nShow = SW_SHOWNORMAL;
sei.lpParameters = UPDATE_REPORT_SUCCESS;
return ShellExecuteExW(&sei) == TRUE;
}
return true;
}
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
int nArgs = 0;
@ -312,37 +106,6 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
}
}
}
else if (action == UNINSTALL_MSI)
{
return UninstallMsiAction();
}
else if (action == UPDATE_NOW_LAUNCH_STAGE1)
{
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_STAGE2)
{
using namespace std::string_view_literals;
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;
}

View file

@ -41,15 +41,9 @@
<ProjectReference Include="..\common\logger\logger.vcxproj">
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
</ProjectReference>
<ProjectReference Include="..\common\notifications\notifications.vcxproj">
<Project>{1d5be09d-78c0-4fd7-af00-ae7c1af7c525}</Project>
</ProjectReference>
<ProjectReference Include="..\common\SettingsAPI\SetttingsAPI.vcxproj">
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
</ProjectReference>
<ProjectReference Include="..\common\updating\updating.vcxproj">
<Project>{17da04df-e393-4397-9cf0-84dabe11032e}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="resource.h" />

View file

@ -0,0 +1,14 @@
{
"Projects": [
{
"LanguageSet": "Azure_Languages",
"LocItems": [
{
"SourceFile": "src\\Update\\Resources.resx",
"CopyOption": "LangIDOnName",
"OutputPath": "src\\Update"
}
]
}
]
}

View file

@ -0,0 +1,36 @@
#include <windows.h>
#include "resource.h"
#include "../common/version/version.h"
1 VERSIONINFO
FILEVERSION FILE_VERSION
PRODUCTVERSION PRODUCT_VERSION
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#ifdef _DEBUG
FILEFLAGS VS_FF_DEBUG
#else
FILEFLAGS 0x0L
#endif
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset
BEGIN
VALUE "CompanyName", COMPANY_NAME
VALUE "FileDescription", FILE_DESCRIPTION
VALUE "FileVersion", FILE_VERSION_STRING
VALUE "InternalName", INTERNAL_NAME
VALUE "LegalCopyright", COPYRIGHT_NOTE
VALUE "OriginalFilename", ORIGINAL_FILENAME
VALUE "ProductName", PRODUCT_NAME
VALUE "ProductVersion", PRODUCT_VERSION_STRING
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset
END
END

View file

@ -0,0 +1,255 @@
// 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"
#include <Windows.h>
#include <shellapi.h>
#include <filesystem>
#include <string_view>
#include <common/updating/updating.h>
#include <common/updating/updateState.h>
#include <common/updating/installer.h>
#include <common/utils/elevation.h>
#include <common/utils/HttpClient.h>
#include <common/utils/process_path.h>
#include <common/utils/resources.h>
#include <common/utils/timeutil.h>
#include <common/SettingsAPI/settings_helpers.h>
#include <common/logger/logger.h>
#include <winrt/Windows.ApplicationModel.h>
#include <winrt/Windows.Storage.h>
#include <Msi.h>
#include "../runner/tray_icon.h"
#include "../runner/UpdateUtils.h"
using namespace cmdArg;
namespace fs = std::filesystem;
std::optional<fs::path> CopySelfToTempDir()
{
std::error_code error;
auto dst_path = fs::temp_directory_path() / "PowerToys.Update.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);
}
std::optional<fs::path> ObtainInstallerPath()
{
using namespace updating;
auto state = UpdateState::read();
if (state.state == UpdateState::readyToDownload || state.state == UpdateState::errorDownloading)
{
const auto new_version_info = get_github_version_info_async().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 = CopySelfToTempDir())
{
// Detect if PT was running
const auto pt_main_window = FindWindowW(pt_tray_icon_window_class, 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 };
arguments += L" \"";
arguments += installer->c_str();
arguments += L"\" \"";
arguments += get_module_folderpath();
arguments += L"\" ";
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();
sei.nShow = SW_SHOWNORMAL;
sei.lpParameters = arguments.c_str();
return ShellExecuteExW(&sei) == TRUE;
}
else
{
return false;
}
}
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);
bool success = true;
if (installer_path.ends_with(L".msi"))
{
success = MsiInstallProductW(installer_path.data(), nullptr) == ERROR_SUCCESS;
}
else
{
// If it's not .msi, then it's our .exe installer
SHELLEXECUTEINFOW sei{ sizeof(sei) };
sei.fMask = { SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NO_CONSOLE };
sei.lpFile = installer_path.c_str();
sei.nShow = SW_SHOWNORMAL;
std::wstring parameters = L"--no_full_ui";
if (launch_powertoys)
{
// .exe installer launches the main app by default
launch_powertoys = false;
}
else
{
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);
}
}
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 };
new_pt_path += L"\\PowerToys.exe";
SHELLEXECUTEINFOW sei{ sizeof(sei) };
sei.fMask = { SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC };
sei.lpFile = new_pt_path.c_str();
sei.nShow = SW_SHOWNORMAL;
sei.lpParameters = UPDATE_REPORT_SUCCESS;
return ShellExecuteExW(&sei) == TRUE;
}
return true;
}
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
int nArgs = 0;
LPWSTR* args = CommandLineToArgvW(GetCommandLineW(), &nArgs);
if (!args || nArgs < 2)
{
return 1;
}
std::wstring_view action{ args[1] };
std::filesystem::path logFilePath(PTSettingsHelper::get_root_save_folder_location());
logFilePath.append(LogSettings::updateLogPath);
Logger::init(LogSettings::updateLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location());
if (action == UPDATE_NOW_LAUNCH_STAGE1)
{
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_STAGE2)
{
using namespace std::string_view_literals;
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;
}

View file

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<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 PowerToys.Update.base.rc PowerToys.Update.rc" />
</Target>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{44CE9AE1-4390-42C5-BACC-0FD6B40AA203}</ProjectGuid>
<RootNamespace>Update</RootNamespace>
<ProjectName>PowerToys.Update</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="..\..\deps\expected.props" />
<PropertyGroup>
<ConfigurationType>Application</ConfigurationType>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup>
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup>
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>WindowsApp.lib;Msi.lib;Shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="PowerToys.Update.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\common\logger\logger.vcxproj">
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
</ProjectReference>
<ProjectReference Include="..\common\notifications\notifications.vcxproj">
<Project>{1d5be09d-78c0-4fd7-af00-ae7c1af7c525}</Project>
</ProjectReference>
<ProjectReference Include="..\common\SettingsAPI\SetttingsAPI.vcxproj">
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
</ProjectReference>
<ProjectReference Include="..\common\updating\updating.vcxproj">
<Project>{17da04df-e393-4397-9cf0-84dabe11032e}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<None Include="PowerToys.Update.base.rc" />
<ResourceCompile Include="Generated Files\PowerToys.Update.rc" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="..\..\deps\spdlog.props" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<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>

82
src/Update/Resources.resx Normal file
View file

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="DOTNET_CORE_DOWNLOAD_FAILURE" xml:space="preserve">
<value>Couldn't download .NET Core Desktop Runtime 3.1, please install it manually.</value>
</data>
<data name="DOTNET_CORE_DOWNLOAD_FAILURE_TITLE" xml:space="preserve">
<value>PowerToys installation error</value>
</data>
<data name="GITHUB_NEW_VERSION_AVAILABLE" xml:space="preserve">
<value>An update to PowerToys is available.</value>
</data>
<data name="GITHUB_NEW_VERSION_UPDATE_NOW" xml:space="preserve">
<value>Update now</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_MORE_INFO" xml:space="preserve">
<value>More info...</value>
</data>
<data name="TOAST_TITLE" xml:space="preserve">
<value>PowerToys Update</value>
</data>
</root>

View file

@ -0,0 +1,11 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by PowerToys.Update.rc
//////////////////////////////
// Non-localizable
#define FILE_DESCRIPTION "PowerToys Update"
#define INTERNAL_NAME "PowerToys.Update"
#define ORIGINAL_FILENAME "PowerToys.Update.exe"

View file

@ -1,54 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<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')" />
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{C502A854-53AC-4EBB-8DC0-E4AF2191E4F6}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>WinStore</RootNamespace>
<ProjectName>WinStore</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</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'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="winstore.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="winstore.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<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>

View file

@ -1,70 +0,0 @@
#include "winstore.h"
#include <Windows.h>
#include <appmodel.h>
using winrt::Windows::ApplicationModel::StartupTask;
namespace
{
const wchar_t* STARTUP_TASKID = L"PowerToysStartupTaskID";
}
namespace winstore
{
bool running_as_packaged()
{
UINT32 length = 0;
const auto rc = GetPackageFamilyName(GetCurrentProcess(), &length, nullptr);
return rc != APPMODEL_ERROR_NO_PACKAGE;
}
std::future<StartupTaskState> get_startup_task_status_async()
{
const auto startupTask = co_await StartupTask::GetAsync(STARTUP_TASKID);
co_return startupTask.State();
}
std::future<void> switch_startup_task_state_async(const bool enabled)
{
const auto startupTask = co_await StartupTask::GetAsync(STARTUP_TASKID);
enum class action
{
none,
enable,
disable,
} action_to_try = action::none;
switch (startupTask.State())
{
case StartupTaskState::Disabled:
if (enabled)
{
action_to_try = action::enable;
}
break;
case StartupTaskState::Enabled:
if (!enabled)
{
action_to_try = action::disable;
}
break;
}
try
{
switch (action_to_try)
{
case action::enable:
co_await startupTask.RequestEnableAsync();
break;
case action::disable:
startupTask.Disable();
break;
}
}
catch (...)
{
// We can't handle the error, in case we don't have a permission to change startup task state
}
}
}

View file

@ -1,16 +0,0 @@
#pragma once
#include <future>
#include <winrt/base.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.ApplicationModel.h>
namespace winstore
{
using winrt::Windows::ApplicationModel::StartupTaskState;
bool running_as_packaged();
std::future<void> switch_startup_task_state_async(const bool enabled);
std::future<StartupTaskState> get_startup_task_status_async();
}

View file

@ -11,6 +11,8 @@ struct LogSettings
inline const static std::wstring runnerLogPath = L"RunnerLogs\\runner-log.txt";
inline const static std::string actionRunnerLoggerName = "action-runner";
inline const static std::wstring actionRunnerLogPath = L"RunnerLogs\\action-runner-log.txt";
inline const static std::string updateLoggerName = "update";
inline const static std::wstring updateLogPath = L"UpdateLogs\\update-log.txt";
inline const static std::string launcherLoggerName = "launcher";
inline const static std::wstring launcherLogPath = L"LogsModuleInterface\\launcher-log.txt";
inline const static std::wstring awakeLogPath = L"Logs\\awake-log.txt";

View file

@ -3,7 +3,6 @@
#include "notifications.h"
#include "utils/com_object_factory.h"
#include "utils/window.h"
#include "winstore/winstore.h"
#include <unknwn.h>
#include <winrt/base.h>
@ -201,41 +200,6 @@ void notifications::override_application_id(const std::wstring_view appID)
SetCurrentProcessExplicitAppUserModelID(APPLICATION_ID.c_str());
}
void notifications::register_background_toast_handler()
{
if (!winstore::running_as_packaged())
{
// The WIX installer will have us registered via the registry
return;
}
try
{
// Re-request access to clean up from previous PowerToys installations
BackgroundExecutionManager::RemoveAccess();
BackgroundExecutionManager::RequestAccessAsync().get();
BackgroundTaskBuilder builder;
ToastNotificationActionTrigger trigger{ PACKAGED_APPLICATION_ID };
builder.SetTrigger(trigger);
builder.TaskEntryPoint(TASK_ENTRYPOINT);
builder.Name(TASK_NAME);
const auto tasks = BackgroundTaskRegistration::AllTasks();
const bool already_registered = std::any_of(begin(tasks), end(tasks), [=](const auto& task) {
return task.Value().Name() == TASK_NAME;
});
if (already_registered)
{
return;
}
(void)builder.Register();
}
catch (...)
{
// Couldn't register the background task, nothing we can do
}
}
void notifications::show_toast(std::wstring message, std::wstring title, toast_params params)
{
// The toast won't be actually activated in the background, since it doesn't have any buttons
@ -402,8 +366,8 @@ void notifications::show_toast_with_activations(std::wstring message,
NotificationData data{ map };
notification.Data(std::move(data));
const auto notifier = winstore::running_as_packaged() ? ToastNotificationManager::ToastNotificationManager::CreateToastNotifier() :
ToastNotificationManager::ToastNotificationManager::CreateToastNotifier(APPLICATION_ID);
const auto notifier =
ToastNotificationManager::ToastNotificationManager::CreateToastNotifier(APPLICATION_ID);
// Set a tag-related params if it has a valid length
if (params.tag.has_value() && params.tag->length() < 64)
@ -431,9 +395,8 @@ void notifications::show_toast_with_activations(std::wstring message,
void notifications::update_toast_progress_bar(std::wstring_view tag, progress_bar_params params)
{
const auto notifier = winstore::running_as_packaged() ?
ToastNotificationManager::ToastNotificationManager::CreateToastNotifier() :
ToastNotificationManager::ToastNotificationManager::CreateToastNotifier(APPLICATION_ID);
const auto notifier =
ToastNotificationManager::ToastNotificationManager::CreateToastNotifier(APPLICATION_ID);
float progress = std::clamp(params.progress, 0.0f, 1.0f);
winrt::Windows::Foundation::Collections::StringMap map;
@ -468,8 +431,7 @@ void notifications::remove_toasts_by_tag(std::wstring_view tag)
void notifications::remove_all_scheduled_toasts()
{
const auto notifier = winstore::running_as_packaged() ? ToastNotificationManager::ToastNotificationManager::CreateToastNotifier() :
ToastNotificationManager::ToastNotificationManager::CreateToastNotifier(APPLICATION_ID);
const auto notifier = ToastNotificationManager::ToastNotificationManager::CreateToastNotifier(APPLICATION_ID);
try
{

View file

@ -12,7 +12,6 @@ namespace notifications
constexpr inline const wchar_t UPDATING_PROCESS_TOAST_TAG[] = L"PTUpdateNotifyTag";
void override_application_id(const std::wstring_view appID);
void register_background_toast_handler();
void run_desktop_app_activator_loop();
bool register_application_id(const std::wstring_view appName, const std::wstring_view iconPath);

View file

@ -39,11 +39,6 @@
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WinStore\Winstore.vcxproj">
<Project>{c502a854-53ac-4ebb-8dc0-e4af2191e4f6}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200729.8\build\native\Microsoft.Windows.CppWinRT.targets')" />

View file

@ -1,72 +0,0 @@
#include "pch.h"
#include "http_client.h"
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Web.Http.Headers.h>
#include <winrt/Windows.Storage.Streams.h>
namespace http
{
using namespace winrt::Windows::Web::Http;
namespace storage = winrt::Windows::Storage;
const wchar_t USER_AGENT[] = L"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)";
HttpClient::HttpClient()
{
auto headers = m_client.DefaultRequestHeaders();
headers.UserAgent().TryParseAdd(USER_AGENT);
}
std::future<std::wstring> HttpClient::request(const winrt::Windows::Foundation::Uri& url)
{
auto response = co_await m_client.GetAsync(url);
(void)response.EnsureSuccessStatusCode();
auto body = co_await response.Content().ReadAsStringAsync();
co_return std::wstring(body);
}
std::future<void> HttpClient::download(const winrt::Windows::Foundation::Uri& url, const std::wstring& dstFilePath)
{
auto response = co_await m_client.GetAsync(url);
(void)response.EnsureSuccessStatusCode();
auto file_stream = co_await storage::Streams::FileRandomAccessStream::OpenAsync(dstFilePath.c_str(), storage::FileAccessMode::ReadWrite, storage::StorageOpenOptions::AllowReadersAndWriters, storage::Streams::FileOpenDisposition::CreateAlways);
co_await response.Content().WriteToStreamAsync(file_stream);
file_stream.Close();
}
std::future<void> HttpClient::download(const winrt::Windows::Foundation::Uri& url, const std::wstring& dstFilePath, const std::function<void(float)>& progressUpdateCallback)
{
auto response = co_await m_client.GetAsync(url, HttpCompletionOption::ResponseHeadersRead);
response.EnsureSuccessStatusCode();
uint64_t totalBytes = response.Content().Headers().ContentLength().GetUInt64();
auto contentStream = co_await response.Content().ReadAsInputStreamAsync();
uint64_t totalBytesRead = 0;
storage::Streams::Buffer buffer(8192);
auto fileStream = co_await storage::Streams::FileRandomAccessStream::OpenAsync(dstFilePath.c_str(), storage::FileAccessMode::ReadWrite, storage::StorageOpenOptions::AllowReadersAndWriters, storage::Streams::FileOpenDisposition::CreateAlways);
co_await contentStream.ReadAsync(buffer, buffer.Capacity(), storage::Streams::InputStreamOptions::None);
while (buffer.Length() > 0)
{
co_await fileStream.WriteAsync(buffer);
totalBytesRead += buffer.Length();
if (progressUpdateCallback)
{
float percentage = (float)totalBytesRead / totalBytes;
progressUpdateCallback(percentage);
}
co_await contentStream.ReadAsync(buffer, buffer.Capacity(), storage::Streams::InputStreamOptions::None);
}
if (progressUpdateCallback)
{
progressUpdateCallback(1);
}
fileStream.Close();
contentStream.Close();
}
}

View file

@ -1,19 +0,0 @@
#pragma once
#include <future>
#include <winrt/Windows.Web.Http.h>
namespace http
{
class HttpClient
{
public:
HttpClient();
std::future<std::wstring> request(const winrt::Windows::Foundation::Uri& url);
std::future<void> download(const winrt::Windows::Foundation::Uri& url, const std::wstring& dstFle);
std::future<void> download(const winrt::Windows::Foundation::Uri& url, const std::wstring& dstFle, const std::function<void(float)>& progressUpdateCallback);
private:
winrt::Windows::Web::Http::HttpClient m_client;
};
}

View file

@ -2,171 +2,22 @@
#include "installer.h"
#include <common/version/version.h>
#include <common/notifications/notifications.h>
#include <common/utils/MsiUtils.h>
#include <common/utils/os-detect.h>
#include "utils/winapi_error.h"
namespace // Strings in this namespace should not be localized
{
const wchar_t POWER_TOYS_UPGRADE_CODE[] = L"{42B84BF7-5FBF-473B-9C8B-049DC16F7708}";
const wchar_t DONT_SHOW_AGAIN_RECORD_REGISTRY_PATH[] = L"delete_previous_powertoys_confirm";
const wchar_t TOAST_TITLE[] = L"PowerToys";
const wchar_t MSIX_PACKAGE_NAME[] = L"Microsoft.PowerToys";
const wchar_t MSIX_PACKAGE_PUBLISHER[] = L"CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US";
const wchar_t POWERTOYS_EXE_COMPONENT[] = L"{A2C66D91-3485-4D00-B04D-91844E6B345B}";
}
namespace updating
{
std::wstring get_msi_package_path()
{
std::wstring package_path;
wchar_t GUID_product_string[39];
if (const bool found = ERROR_SUCCESS == MsiEnumRelatedProductsW(POWER_TOYS_UPGRADE_CODE, 0, 0, GUID_product_string); !found)
{
return package_path;
}
if (const bool installed = INSTALLSTATE_DEFAULT == MsiQueryProductStateW(GUID_product_string); !installed)
{
return package_path;
}
DWORD package_path_size = 0;
if (const bool has_package_path = ERROR_SUCCESS == MsiGetProductInfoW(GUID_product_string, INSTALLPROPERTY_LOCALPACKAGE, nullptr, &package_path_size); !has_package_path)
{
return package_path;
}
package_path = std::wstring(++package_path_size, L'\0');
if (const bool got_package_path = ERROR_SUCCESS == MsiGetProductInfoW(GUID_product_string, INSTALLPROPERTY_LOCALPACKAGE, package_path.data(), &package_path_size); !got_package_path)
{
package_path = {};
return package_path;
}
package_path.resize(size(package_path) - 1); // trim additional \0 which we got from MsiGetProductInfoW
return package_path;
}
bool offer_msi_uninstallation(const notifications::strings& strings)
{
const auto selection = SHMessageBoxCheckW(nullptr,
strings.OFFER_UNINSTALL_MSI.c_str(),
strings.OFFER_UNINSTALL_MSI_TITLE.c_str(),
MB_ICONQUESTION | MB_YESNO,
IDNO,
DONT_SHOW_AGAIN_RECORD_REGISTRY_PATH);
return selection == IDYES;
}
bool uninstall_msi_version(const std::wstring& package_path, const notifications::strings& strings)
{
const auto uninstall_result = MsiInstallProductW(package_path.c_str(), L"REMOVE=ALL");
if (ERROR_SUCCESS == uninstall_result)
{
return true;
}
else if (auto system_message = get_last_error_message(uninstall_result); system_message.has_value())
{
try
{
::notifications::show_toast(*system_message, TOAST_TITLE);
}
catch (...)
{
MessageBoxW(nullptr, strings.UNINSTALLATION_UNKNOWN_ERROR.c_str(), strings.NOTIFICATION_TITLE.c_str(), MB_OK | MB_ICONERROR);
}
}
return false;
}
std::optional<std::wstring> get_msi_package_installed_path()
{
constexpr size_t guid_length = 39;
wchar_t product_ID[guid_length];
if (const bool found = ERROR_SUCCESS == MsiEnumRelatedProductsW(POWER_TOYS_UPGRADE_CODE, 0, 0, product_ID); !found)
{
return std::nullopt;
}
if (const bool installed = INSTALLSTATE_DEFAULT == MsiQueryProductStateW(product_ID); !installed)
{
return std::nullopt;
}
DWORD buf_size = MAX_PATH;
wchar_t buf[MAX_PATH];
if (ERROR_SUCCESS == MsiGetProductInfoW(product_ID, INSTALLPROPERTY_INSTALLLOCATION, buf, &buf_size) && buf_size)
{
return buf;
}
DWORD package_path_size = 0;
if (ERROR_SUCCESS != MsiGetProductInfoW(product_ID, INSTALLPROPERTY_LOCALPACKAGE, nullptr, &package_path_size))
{
return std::nullopt;
}
std::wstring package_path(++package_path_size, L'\0');
if (ERROR_SUCCESS != MsiGetProductInfoW(product_ID, INSTALLPROPERTY_LOCALPACKAGE, package_path.data(), &package_path_size))
{
return std::nullopt;
}
package_path.resize(size(package_path) - 1); // trim additional \0 which we got from MsiGetProductInfoW
wchar_t path[MAX_PATH];
DWORD path_size = MAX_PATH;
MsiGetComponentPathW(product_ID, POWERTOYS_EXE_COMPONENT, path, &path_size);
if (!path_size)
{
return std::nullopt;
}
PathCchRemoveFileSpec(path, path_size);
return path;
}
std::optional<VersionHelper> get_installed_powertoys_version()
{
auto installed_path = get_msi_package_installed_path();
if (!installed_path)
{
return std::nullopt;
}
*installed_path += L"\\PowerToys.exe";
// Get the version information for the file requested
const DWORD fvSize = GetFileVersionInfoSizeW(installed_path->c_str(), nullptr);
if (!fvSize)
{
return std::nullopt;
}
auto pbVersionInfo = std::make_unique<BYTE[]>(fvSize);
if (!GetFileVersionInfoW(installed_path->c_str(), 0, fvSize, pbVersionInfo.get()))
{
return std::nullopt;
}
VS_FIXEDFILEINFO* fileInfo = nullptr;
UINT fileInfoLen = 0;
if (!VerQueryValueW(pbVersionInfo.get(), L"\\", reinterpret_cast<LPVOID*>(&fileInfo), &fileInfoLen))
{
return std::nullopt;
}
return VersionHelper{ (fileInfo->dwFileVersionMS >> 16) & 0xffff,
(fileInfo->dwFileVersionMS >> 0) & 0xffff,
(fileInfo->dwFileVersionLS >> 16) & 0xffff };
}
std::future<bool> uninstall_previous_msix_version_async()
{
winrt::Windows::Management::Deployment::PackageManager package_manager;
@ -192,9 +43,4 @@ namespace updating
}
co_return false;
}
bool is_1809_or_older()
{
return !Is19H1OrHigher();
}
}

View file

@ -4,18 +4,9 @@
#include <optional>
#include <future>
#include "notifications.h"
#include <common/version/helper.h>
namespace updating
{
std::wstring get_msi_package_path();
bool uninstall_msi_version(const std::wstring& package_path, const notifications::strings&);
bool offer_msi_uninstallation(const notifications::strings&);
std::optional<std::wstring> get_msi_package_installed_path();
std::optional<VersionHelper> get_installed_powertoys_version();
std::future<bool> uninstall_previous_msix_version_async();
bool is_1809_or_older();
}

View file

@ -1,61 +0,0 @@
#include "pch.h"
#include "notifications.h"
#include <common/notifications/notifications.h>
#include "updating.h"
#include <common/version/helper.h>
#include <common/version/version.h>
namespace updating
{
namespace notifications
{
using namespace ::notifications;
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" -> ";
current_version_to_next_version += info.version.toWstring();
return current_version_to_next_version;
}
void show_new_version_available(const new_version_download_info& info, 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;
contents += L'\n';
contents += current_version_to_next_version(info);
show_toast_with_activations(std::move(contents),
strings.NOTIFICATION_TITLE,
{},
{ link_button{ strings.GITHUB_NEW_VERSION_UPDATE_NOW,
L"powertoys://update_now/" },
link_button{ strings.GITHUB_NEW_VERSION_MORE_INFO,
L"powertoys://open_settings/" } },
std::move(toast_params));
}
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::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,
{},
std::move(actions),
std::move(toast_params));
}
}
}

View file

@ -1,40 +0,0 @@
#pragma once
#include <string>
namespace updating
{
struct new_version_download_info;
namespace notifications
{
struct strings
{
std::wstring GITHUB_NEW_VERSION_AVAILABLE;
std::wstring GITHUB_NEW_VERSION_MORE_INFO;
std::wstring GITHUB_NEW_VERSION_UPDATE_NOW;
std::wstring OFFER_UNINSTALL_MSI;
std::wstring OFFER_UNINSTALL_MSI_TITLE;
std::wstring NOTIFICATION_TITLE;
std::wstring UNINSTALLATION_UNKNOWN_ERROR;
};
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 \
{ \
.GITHUB_NEW_VERSION_AVAILABLE = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_AVAILABLE), \
.GITHUB_NEW_VERSION_MORE_INFO = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_MORE_INFO), \
.GITHUB_NEW_VERSION_UPDATE_NOW = GET_RESOURCE_STRING(IDS_GITHUB_NEW_VERSION_UPDATE_NOW), \
.OFFER_UNINSTALL_MSI = GET_RESOURCE_STRING(IDS_OFFER_UNINSTALL_MSI), \
.OFFER_UNINSTALL_MSI_TITLE = GET_RESOURCE_STRING(IDS_OFFER_UNINSTALL_MSI_TITLE), \
.NOTIFICATION_TITLE = GET_RESOURCE_STRING(IDS_TOAST_TITLE), \
.UNINSTALLATION_UNKNOWN_ERROR = GET_RESOURCE_STRING(IDS_UNINSTALLATION_UNKNOWN_ERROR) \
}

View file

@ -1,13 +1,11 @@
#include "pch.h"
#include <common/utils/HttpClient.h>
#include <common/version/version.h>
#include <common/version/helper.h>
#include "http_client.h"
#include "notifications.h"
#include "updating.h"
#include <common/notifications/notifications.h>
#include <common/SettingsAPI/settings_helpers.h>
#include <common/utils/json.h>
@ -76,7 +74,7 @@ namespace updating
throw std::runtime_error("Release object doesn't have the required asset");
}
std::future<nonstd::expected<github_version_info, std::wstring>> get_github_version_info_async(const notifications::strings& strings, const bool prerelease)
std::future<nonstd::expected<github_version_info, std::wstring>> get_github_version_info_async(const bool prerelease)
{
// 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)

View file

@ -8,7 +8,6 @@
#include <winrt/Windows.Foundation.h>
#include <expected.hpp>
#include "notifications.h"
#include <common/version/helper.h>
namespace updating
@ -28,7 +27,7 @@ namespace updating
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<nonstd::expected<github_version_info, std::wstring>> get_github_version_info_async(const notifications::strings& strings, const bool prerelease = false);
std::future<nonstd::expected<github_version_info, std::wstring>> get_github_version_info_async(const bool prerelease = false);
// non-localized
constexpr inline std::wstring_view INSTALLER_FILENAME_PATTERN = L"powertoyssetup";

View file

@ -35,20 +35,13 @@
</Lib>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="dotnet_installation.h" />
<ClInclude Include="http_client.h" />
<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>
<ItemGroup>
<ClCompile Include="dotnet_installation.cpp" />
<ClCompile Include="http_client.cpp" />
<ClCompile Include="installer.cpp" />
<ClCompile Include="notifications.cpp" />
<ClCompile Include="updating.cpp" />
<ClCompile Include="updateState.cpp" />
<ClCompile Include="pch.cpp">
@ -56,9 +49,6 @@
</ClCompile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\notifications\notifications.vcxproj">
<Project>{1d5be09d-78c0-4fd7-af00-ae7c1af7c525}</Project>
</ProjectReference>
<ProjectReference Include="..\SettingsAPI\SetttingsAPI.vcxproj">
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
</ProjectReference>

View file

@ -21,21 +21,15 @@
<ClInclude Include="updating.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="http_client.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="dotnet_installation.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="notifications.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="installer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="winstore.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="updateState.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
@ -44,18 +38,12 @@
<ClCompile Include="updating.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="http_client.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="dotnet_installation.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="notifications.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="installer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="updateState.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

View file

@ -0,0 +1,79 @@
#pragma once
#include <future>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Storage.Streams.h>
#include <winrt/Windows.Web.Http.h>
#include <winrt/Windows.Web.Http.Headers.h>
namespace http
{
using namespace winrt::Windows::Web::Http;
namespace storage = winrt::Windows::Storage;
const inline wchar_t USER_AGENT[] = L"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)";
class HttpClient
{
public:
HttpClient()
{
auto headers = m_client.DefaultRequestHeaders();
headers.UserAgent().TryParseAdd(USER_AGENT);
}
std::future<std::wstring> request(const winrt::Windows::Foundation::Uri& url)
{
auto response = co_await m_client.GetAsync(url);
(void)response.EnsureSuccessStatusCode();
auto body = co_await response.Content().ReadAsStringAsync();
co_return std::wstring(body);
}
std::future<void> download(const winrt::Windows::Foundation::Uri& url, const std::wstring& dstFilePath)
{
auto response = co_await m_client.GetAsync(url);
(void)response.EnsureSuccessStatusCode();
auto file_stream = co_await storage::Streams::FileRandomAccessStream::OpenAsync(dstFilePath.c_str(), storage::FileAccessMode::ReadWrite, storage::StorageOpenOptions::AllowReadersAndWriters, storage::Streams::FileOpenDisposition::CreateAlways);
co_await response.Content().WriteToStreamAsync(file_stream);
file_stream.Close();
}
std::future<void> download(const winrt::Windows::Foundation::Uri& url, const std::wstring& dstFilePath, const std::function<void(float)>& progressUpdateCallback)
{
auto response = co_await m_client.GetAsync(url, HttpCompletionOption::ResponseHeadersRead);
response.EnsureSuccessStatusCode();
uint64_t totalBytes = response.Content().Headers().ContentLength().GetUInt64();
auto contentStream = co_await response.Content().ReadAsInputStreamAsync();
uint64_t totalBytesRead = 0;
storage::Streams::Buffer buffer(8192);
auto fileStream = co_await storage::Streams::FileRandomAccessStream::OpenAsync(dstFilePath.c_str(), storage::FileAccessMode::ReadWrite, storage::StorageOpenOptions::AllowReadersAndWriters, storage::Streams::FileOpenDisposition::CreateAlways);
co_await contentStream.ReadAsync(buffer, buffer.Capacity(), storage::Streams::InputStreamOptions::None);
while (buffer.Length() > 0)
{
co_await fileStream.WriteAsync(buffer);
totalBytesRead += buffer.Length();
if (progressUpdateCallback)
{
float percentage = (float)totalBytesRead / totalBytes;
progressUpdateCallback(percentage);
}
co_await contentStream.ReadAsync(buffer, buffer.Capacity(), storage::Streams::InputStreamOptions::None);
}
if (progressUpdateCallback)
{
progressUpdateCallback(1);
}
fileStream.Close();
contentStream.Close();
}
private:
winrt::Windows::Web::Http::HttpClient m_client;
};
}

View file

@ -0,0 +1,95 @@
#pragma once
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <Windows.h>
#include <pathcch.h>
#include <Msi.h>
#include <optional>
#include <string>
namespace // Strings in this namespace should not be localized
{
const inline wchar_t POWER_TOYS_UPGRADE_CODE[] = L"{42B84BF7-5FBF-473B-9C8B-049DC16F7708}";
const inline wchar_t POWERTOYS_EXE_COMPONENT[] = L"{A2C66D91-3485-4D00-B04D-91844E6B345B}";
}
std::optional<std::wstring> GetMsiPackageInstalledPath()
{
constexpr size_t guid_length = 39;
wchar_t product_ID[guid_length];
if (const bool found = ERROR_SUCCESS == MsiEnumRelatedProductsW(POWER_TOYS_UPGRADE_CODE, 0, 0, product_ID); !found)
{
return std::nullopt;
}
if (const bool installed = INSTALLSTATE_DEFAULT == MsiQueryProductStateW(product_ID); !installed)
{
return std::nullopt;
}
DWORD buf_size = MAX_PATH;
wchar_t buf[MAX_PATH];
if (ERROR_SUCCESS == MsiGetProductInfoW(product_ID, INSTALLPROPERTY_INSTALLLOCATION, buf, &buf_size) && buf_size)
{
return buf;
}
DWORD package_path_size = 0;
if (ERROR_SUCCESS != MsiGetProductInfoW(product_ID, INSTALLPROPERTY_LOCALPACKAGE, nullptr, &package_path_size))
{
return std::nullopt;
}
std::wstring package_path(++package_path_size, L'\0');
if (ERROR_SUCCESS != MsiGetProductInfoW(product_ID, INSTALLPROPERTY_LOCALPACKAGE, package_path.data(), &package_path_size))
{
return std::nullopt;
}
package_path.resize(size(package_path) - 1); // trim additional \0 which we got from MsiGetProductInfoW
wchar_t path[MAX_PATH];
DWORD path_size = MAX_PATH;
MsiGetComponentPathW(product_ID, POWERTOYS_EXE_COMPONENT, path, &path_size);
if (!path_size)
{
return std::nullopt;
}
PathCchRemoveFileSpec(path, path_size);
return path;
}
std::wstring GetMsiPackagePath()
{
std::wstring package_path;
wchar_t GUID_product_string[39];
if (const bool found = ERROR_SUCCESS == MsiEnumRelatedProductsW(POWER_TOYS_UPGRADE_CODE, 0, 0, GUID_product_string); !found)
{
return package_path;
}
if (const bool installed = INSTALLSTATE_DEFAULT == MsiQueryProductStateW(GUID_product_string); !installed)
{
return package_path;
}
DWORD package_path_size = 0;
if (const bool has_package_path = ERROR_SUCCESS == MsiGetProductInfoW(GUID_product_string, INSTALLPROPERTY_LOCALPACKAGE, nullptr, &package_path_size); !has_package_path)
{
return package_path;
}
package_path = std::wstring(++package_path_size, L'\0');
if (const bool got_package_path = ERROR_SUCCESS == MsiGetProductInfoW(GUID_product_string, INSTALLPROPERTY_LOCALPACKAGE, package_path.data(), &package_path_size); !got_package_path)
{
package_path = {};
return package_path;
}
package_path.resize(size(package_path) - 1); // trim additional \0 which we got from MsiGetProductInfoW
return package_path;
}

View file

@ -5,6 +5,9 @@
#include <shellapi.h>
#include <sddl.h>
#include <winrt/base.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <string>
#include <common/logger/logger.h>
#include <common/utils/winapi_error.h>

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -13,10 +13,6 @@ namespace Microsoft.PowerToys.Settings.UI.Library
{
public class GeneralSettings : ISettingsConfig
{
// Gets or sets a value indicating whether packaged.
[JsonPropertyName("packaged")]
public bool Packaged { get; set; }
// Gets or sets a value indicating whether run powertoys on start-up.
[JsonPropertyName("startup")]
public bool Startup { get; set; }
@ -57,7 +53,6 @@ namespace Microsoft.PowerToys.Settings.UI.Library
[SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Any error from calling interop code should not prevent the program from loading.")]
public GeneralSettings()
{
Packaged = false;
Startup = false;
IsAdmin = false;
IsElevated = false;

View file

@ -112,7 +112,6 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
}
}
private bool _packaged;
private bool _startup;
private bool _isElevated;
private bool _runElevated;
@ -130,24 +129,6 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
private bool _isNewVersionDownloading;
private bool _isNewVersionChecked;
// Gets or sets a value indicating whether packaged.
public bool Packaged
{
get
{
return _packaged;
}
set
{
if (_packaged != value)
{
_packaged = value;
NotifyPropertyChanged();
}
}
}
// Gets or sets a value indicating whether run powertoys on start-up.
public bool Startup
{

View file

@ -61,7 +61,6 @@ namespace ViewModelTests
// Verify that the old settings persisted
Assert.AreEqual(originalGeneralSettings.AutoDownloadUpdates, viewModel.AutoDownloadUpdates);
Assert.AreEqual(originalGeneralSettings.Packaged, viewModel.Packaged);
Assert.AreEqual(originalGeneralSettings.PowertoysVersion, viewModel.PowerToysVersion);
Assert.AreEqual(originalGeneralSettings.RunElevated, viewModel.RunElevated);
Assert.AreEqual(originalGeneralSettings.Startup, viewModel.Startup);