Merge latest master: 4/22/20
@ -46,6 +46,7 @@ build:
|
||||
include:
|
||||
- 'PowerToys.exe'
|
||||
- 'PowerToysSettings.exe'
|
||||
- 'action_runner.exe'
|
||||
- 'modules\FancyZonesEditor.exe'
|
||||
- 'modules\fancyzones.dll'
|
||||
- 'modules\shortcut_guide.dll'
|
||||
|
@ -158,7 +158,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "action_runner", "src\action
|
||||
{17DA04DF-E393-4397-9CF0-84DABE11032E} = {17DA04DF-E393-4397-9CF0-84DABE11032E}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msi_to_msix_upgrade_lib", "src\common\msi_to_msix_upgrade_lib\msi_to_msix_upgrade_lib.vcxproj", "{17DA04DF-E393-4397-9CF0-84DABE11032E}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "updating", "src\common\updating\updating.vcxproj", "{17DA04DF-E393-4397-9CF0-84DABE11032E}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "keyboardmanager", "keyboardmanager", "{38BDB927-829B-4C65-9CD9-93FB05D66D65}"
|
||||
EndProject
|
||||
|
@ -13,7 +13,7 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline
|
||||
|
||||
### Via Github with MSI [Recommended]
|
||||
|
||||
Install from the [Microsoft PowerToys GitHub releases page][github-release-link]. Click on `Assets` to show the files available in the release and then click on `PowerToysSetup-0.16.0-x64.msi` to download the PowerToys installer.
|
||||
Install from the [Microsoft PowerToys GitHub releases page][github-release-link]. Click on `Assets` to show the files available in the release and then click on `PowerToysSetup-0.16.1-x64.msi` to download the PowerToys installer.
|
||||
|
||||
This is our preferred method.
|
||||
|
||||
|
13
community.md
Normal file
@ -0,0 +1,13 @@
|
||||
# Community
|
||||
|
||||
The PowerToys team is extremely grateful to have the support of an amazing active community. The work you do is incredibly important. PowerToys wouldn’t be near what it is without your help filing bugs, updating documentation, guiding the design, or writing features. We want to say thanks and to recognize your work. This is a living document dedicated to highlighting the high impact community members and their contributions.
|
||||
|
||||
## High impact community members
|
||||
|
||||
### [@Niels9001](https://github.com/niels9001/) - [Niels Laute](https://nielslaute.com/)
|
||||
|
||||
Niels has helped drive large sums of our update toward a new [consistent and modern UX](https://github.com/microsoft/PowerToys/issues/891). This includes the [launcher work](https://github.com/microsoft/PowerToys/issues/44) and [icon design](https://github.com/microsoft/PowerToys/issues/1118).
|
||||
|
||||
### [@riverar](https://github.com/riverar) - [Rafael Rivera](https://withinrafael.com/)
|
||||
|
||||
Rafael has helped do the [upgrade from CppWinRT 1.x to 2.0](https://github.com/microsoft/PowerToys/issues/1907). He directly provided feedback to the CppWinRT team for bugs from this migration as well.
|
6551
doc/images/Logo/AI/PowerToys_UWP_Assets.ai
Normal file
BIN
doc/images/Logo/ICO/PowerToys.ico
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
doc/images/Logo/ICO/PowerToys_14.ico
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
doc/images/Logo/PNG/PowerToysAppList.targetsize-14-in-16.png
Normal file
After Width: | Height: | Size: 454 B |
BIN
doc/images/Logo/PNG/PowerToysAppList.targetsize-16.png
Normal file
After Width: | Height: | Size: 336 B |
BIN
doc/images/Logo/PNG/PowerToysAppList.targetsize-20.png
Normal file
After Width: | Height: | Size: 514 B |
BIN
doc/images/Logo/PNG/PowerToysAppList.targetsize-24.png
Normal file
After Width: | Height: | Size: 637 B |
BIN
doc/images/Logo/PNG/PowerToysAppList.targetsize-256.png
Normal file
After Width: | Height: | Size: 7.1 KiB |
BIN
doc/images/Logo/PNG/PowerToysAppList.targetsize-30.png
Normal file
After Width: | Height: | Size: 728 B |
BIN
doc/images/Logo/PNG/PowerToysAppList.targetsize-32.png
Normal file
After Width: | Height: | Size: 724 B |
BIN
doc/images/Logo/PNG/PowerToysAppList.targetsize-36.png
Normal file
After Width: | Height: | Size: 812 B |
BIN
doc/images/Logo/PNG/PowerToysAppList.targetsize-40.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
doc/images/Logo/PNG/PowerToysAppList.targetsize-48.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
doc/images/Logo/PNG/PowerToysAppList.targetsize-60.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
doc/images/Logo/PNG/PowerToysAppList.targetsize-64.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
doc/images/Logo/PNG/PowerToysAppList.targetsize-72.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
doc/images/Logo/PNG/PowerToysAppList.targetsize-80.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
doc/images/Logo/PNG/PowerToysAppList.targetsize-96.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
@ -39,6 +39,8 @@
|
||||
<ComponentGroupRef Id="CoreComponents" />
|
||||
<ComponentGroupRef Id="ResourcesComponents" />
|
||||
</Feature>
|
||||
<SetProperty Id="ARPINSTALLLOCATION" Value="[INSTALLFOLDER]" After="CostFinalize" />
|
||||
|
||||
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLFOLDER" />
|
||||
<UI>
|
||||
<UIRef Id="WixUI_PTInstallDir"/>
|
||||
@ -71,6 +73,9 @@
|
||||
<RegistrySearch Id="ExistingImageResizerPath" Root="HKCU" Key="Software\Classes\CLSID\{51B4D7E5-7568-4234-B4BB-47FB3C016A69}\InprocServer32" Type="raw"/>
|
||||
</Property>
|
||||
|
||||
<InstallUISequence>
|
||||
<Custom Action="DetectPrevInstallPath" After="CostFinalize" />
|
||||
</InstallUISequence>
|
||||
<InstallExecuteSequence>
|
||||
<Custom Action="SetRegisterPowerToysSchTaskParam" Before="RegisterPowerToysSchTask" />
|
||||
<Custom Action="RegisterPowerToysSchTask" After="InstallFiles">
|
||||
@ -163,6 +168,13 @@
|
||||
DllEntry="TelemetryLogRepairFailCA"
|
||||
/>
|
||||
|
||||
<CustomAction Id="DetectPrevInstallPath"
|
||||
Return="check"
|
||||
Impersonate="yes"
|
||||
BinaryKey="PTCustomActions"
|
||||
DllEntry="DetectPrevInstallPathCA"
|
||||
/>
|
||||
|
||||
<!-- Close 'PowerToys.exe' before uninstall-->
|
||||
<Property Id="MSIRESTARTMANAGERCONTROL" Value="Disable" />
|
||||
<!-- Restart explorer.exe if we detect existing PowerRenameExt.dll or ImageResizerExt.dll installation -->
|
||||
@ -233,7 +245,7 @@
|
||||
</Shortcut>
|
||||
</File>
|
||||
|
||||
<RegistryKey Root="HKCR" Key="powertoys" Action="createAndRemoveOnUninstall">
|
||||
<RegistryKey Root="HKCR" Key="powertoys">
|
||||
<RegistryValue Type="string" Name="URL Protocol" Value=""/>
|
||||
<RegistryValue Type="string" Value="URL:PowerToys custom internal URI protocol"/>
|
||||
<RegistryKey Key="DefaultIcon">
|
||||
@ -253,6 +265,9 @@
|
||||
<Component Id="notifications_dll" Guid="23B25EE4-BCA2-45DF-BBCD-82FBDF01C5AB" Win64="yes">
|
||||
<File Id="Notifications.dll" KeyPath="yes" Checksum="yes" />
|
||||
</Component>
|
||||
<Component Id="action_runner_exe" Guid="626ABB17-16F0-4007-9A58-6998724A5E14" Win64="yes">
|
||||
<File Id="action_runner.exe" KeyPath="yes" Checksum="yes" />
|
||||
</Component>
|
||||
<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>
|
||||
@ -507,6 +522,7 @@
|
||||
<ComponentGroup Id="CoreComponents" Directory="INSTALLFOLDER">
|
||||
<ComponentRef Id="powertoys_exe" />
|
||||
<ComponentRef Id="notifications_dll" />
|
||||
<ComponentRef Id="action_runner_exe" />
|
||||
<ComponentRef Id="powertoys_toast_clsid" />
|
||||
<ComponentRef Id="License_rtf" />
|
||||
<ComponentRef Id="PowerToysSvgs" />
|
||||
|
@ -1,17 +1,5 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
#define SECURITY_WIN32
|
||||
#include <Security.h>
|
||||
#pragma comment(lib, "Secur32.lib")
|
||||
#include <Lmcons.h>
|
||||
|
||||
#include <comdef.h>
|
||||
#include <taskschd.h>
|
||||
#pragma comment(lib, "taskschd.lib")
|
||||
#pragma comment(lib, "comsupp.lib")
|
||||
|
||||
#include <iostream>
|
||||
#include <strutil.h>
|
||||
#include <ProjectTelemetry.h>
|
||||
|
||||
using namespace std;
|
||||
@ -26,6 +14,9 @@ TRACELOGGING_DEFINE_PROVIDER(
|
||||
const DWORD USERNAME_DOMAIN_LEN = DNLEN + UNLEN + 2; // Domain Name + '\' + User Name + '\0'
|
||||
const DWORD USERNAME_LEN = UNLEN + 1; // User Name + '\0'
|
||||
|
||||
static const wchar_t* POWERTOYS_EXE_COMPONENT = L"{A2C66D91-3485-4D00-B04D-91844E6B345B}";
|
||||
static const wchar_t* POWERTOYS_UPGRADE_CODE = L"{42B84BF7-5FBF-473B-9C8B-049DC16F7708}";
|
||||
|
||||
// Creates a Scheduled Task to run at logon for the current user.
|
||||
// The path of the executable to run should be passed as the CustomActionData (Value).
|
||||
// Based on the Task Scheduler Logon Trigger Example:
|
||||
@ -48,6 +39,8 @@ UINT __stdcall CreateScheduledTaskCA(MSIHANDLE hInstall)
|
||||
ITriggerCollection* pTriggerCollection = NULL;
|
||||
IRegisteredTask* pRegisteredTask = NULL;
|
||||
|
||||
LPWSTR wszExecutablePath = NULL;
|
||||
|
||||
hr = WcaInitialize(hInstall, "CreateScheduledTaskCA");
|
||||
ExitOnFailure(hr, "Failed to initialize");
|
||||
|
||||
@ -77,7 +70,6 @@ UINT __stdcall CreateScheduledTaskCA(MSIHANDLE hInstall)
|
||||
wstrTaskName += username;
|
||||
|
||||
// Get the executable path passed to the custom action.
|
||||
LPWSTR wszExecutablePath = NULL;
|
||||
hr = WcaGetProperty(L"CustomActionData", &wszExecutablePath);
|
||||
ExitOnFailure(hr, "Failed to get the executable path from CustomActionData.");
|
||||
|
||||
@ -571,6 +563,73 @@ LExit:
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
std::optional<std::wstring> getMsiPackageInstalledPath(const wchar_t* product_upgrade_code, const wchar_t* file_component)
|
||||
{
|
||||
constexpr size_t guid_length = 39;
|
||||
wchar_t product_ID[guid_length];
|
||||
if (const bool found = ERROR_SUCCESS == MsiEnumRelatedProductsW(product_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[256];
|
||||
DWORD path_size = 256;
|
||||
MsiGetComponentPathW(product_ID, file_component, path, &path_size);
|
||||
if (!path_size)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
PathCchRemoveFileSpec(path, path_size);
|
||||
return path;
|
||||
}
|
||||
|
||||
UINT __stdcall DetectPrevInstallPathCA(MSIHANDLE hInstall)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
UINT er = ERROR_SUCCESS;
|
||||
hr = WcaInitialize(hInstall, "DetectPrevInstallPathCA");
|
||||
|
||||
try
|
||||
{
|
||||
if (auto install_path = getMsiPackageInstalledPath(POWERTOYS_UPGRADE_CODE, POWERTOYS_EXE_COMPONENT))
|
||||
{
|
||||
MsiSetPropertyW(hInstall, L"INSTALLFOLDER", install_path->data());
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
|
||||
}
|
||||
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
|
||||
return WcaFinalize(er);
|
||||
}
|
||||
|
||||
// DllMain - Initialize and cleanup WiX custom action utils.
|
||||
extern "C" BOOL WINAPI DllMain(__in HINSTANCE hInst, __in ULONG ulReason, __in LPVOID)
|
||||
{
|
||||
|
@ -2,6 +2,7 @@ LIBRARY "PowerToysSetupCustomActions"
|
||||
|
||||
EXPORTS
|
||||
CreateScheduledTaskCA
|
||||
DetectPrevInstallPathCA
|
||||
RemoveScheduledTasksCA
|
||||
TelemetryLogInstallSuccessCA
|
||||
TelemetryLogInstallCancelCA
|
||||
|
@ -55,11 +55,13 @@
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>msi.lib;dutil.lib;wcautil.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Pathcch.lib;comsupp.lib;taskschd.lib;Secur32.lib;msi.lib;dutil.lib;wcautil.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(WIX)sdk\$(WixPlatformToolset)\lib\x64;$(SolutionDir)\packages\WiX.3.11.2\tools\sdk\vs2017\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<ModuleDefinitionFile>CustomAction.def</ModuleDefinitionFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
@ -76,11 +78,13 @@
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>msi.lib;dutil.lib;wcautil.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Pathcch.lib;comsupp.lib;taskschd.lib;Secur32.lib;msi.lib;dutil.lib;wcautil.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(WIX)sdk\$(WixPlatformToolset)\lib\x64;$(SolutionDir)\packages\WiX.3.11.2\tools\sdk\vs2017\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<ModuleDefinitionFile>CustomAction.def</ModuleDefinitionFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -1,13 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
// Windows Header Files:
|
||||
#include <windows.h>
|
||||
#include <strsafe.h>
|
||||
#include <msiquery.h>
|
||||
#include <Msi.h>
|
||||
|
||||
// WiX Header Files:
|
||||
#include <wcautil.h>
|
||||
|
||||
#define SECURITY_WIN32
|
||||
#include <Security.h>
|
||||
#include <Lmcons.h>
|
||||
|
||||
// TODO: reference additional headers your program requires here
|
||||
#include <comdef.h>
|
||||
#include <taskschd.h>
|
||||
#include <iostream>
|
||||
#include <strutil.h>
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <pathcch.h>
|
||||
|
@ -4,19 +4,24 @@
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include <common/msi_to_msix_upgrade_lib/msi_to_msix_upgrade.h>
|
||||
#include <common/common.h>
|
||||
#include <common/updating/updating.h>
|
||||
|
||||
#include <winrt/Windows.ApplicationModel.h>
|
||||
#include <winrt/Windows.Storage.h>
|
||||
#include <Msi.h>
|
||||
|
||||
#include "../runner/tray_icon.h"
|
||||
#include "../runner/action_runner_utils.h"
|
||||
|
||||
int uninstall_msi_action()
|
||||
{
|
||||
const auto package_path = get_msi_package_path();
|
||||
const auto package_path = updating::get_msi_package_path();
|
||||
if (package_path.empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (!uninstall_msi_version(package_path))
|
||||
if (!updating::uninstall_msi_version(package_path))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@ -33,6 +38,90 @@ int uninstall_msi_action()
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
std::optional<fs::path> copy_self_to_temp_dir()
|
||||
{
|
||||
std::error_code error;
|
||||
auto dst_path = fs::temp_directory_path() / "action_runner.exe";
|
||||
fs::copy_file(get_module_filename(), dst_path, fs::copy_options::overwrite_existing, error);
|
||||
if (error)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
return std::move(dst_path);
|
||||
}
|
||||
|
||||
bool install_new_version_stage_1(const bool must_restart = false)
|
||||
{
|
||||
std::optional<fs::path> installer;
|
||||
for (auto path : fs::directory_iterator{ updating::get_pending_updates_path() })
|
||||
{
|
||||
if (path.path().native().find(updating::installer_filename_pattern) != std::wstring::npos)
|
||||
{
|
||||
installer.emplace(std::move(path));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!installer)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (auto copy_in_temp = copy_self_to_temp_dir())
|
||||
{
|
||||
// detect if PT was running
|
||||
const auto pt_main_window = FindWindowW(pt_tray_icon_window_class, nullptr);
|
||||
const bool launch_powertoys = must_restart || pt_main_window != nullptr;
|
||||
if (pt_main_window != nullptr)
|
||||
{
|
||||
SendMessageW(pt_main_window, WM_CLOSE, 0, 0);
|
||||
}
|
||||
|
||||
std::wstring arguments{ UPDATE_NOW_LAUNCH_STAGE2_CMDARG };
|
||||
arguments += L" \"";
|
||||
arguments += installer->c_str();
|
||||
arguments += L"\" \"";
|
||||
arguments += get_module_folderpath();
|
||||
arguments += L"\" ";
|
||||
arguments += launch_powertoys ? UPDATE_STAGE2_RESTART_PT_CMDARG : UPDATE_STAGE2_DONT_START_PT_CMDARG;
|
||||
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 install_new_version_stage_2(std::wstring_view installer_path, std::wstring_view install_path, const bool launch_powertoys)
|
||||
{
|
||||
if (MsiInstallProductW(installer_path.data(), nullptr) != ERROR_SUCCESS)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::error_code _;
|
||||
fs::remove(installer_path, _);
|
||||
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;
|
||||
@ -47,6 +136,19 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
|
||||
{
|
||||
return uninstall_msi_action();
|
||||
}
|
||||
else if (action == UPDATE_NOW_LAUNCH_STAGE1_CMDARG)
|
||||
{
|
||||
return !install_new_version_stage_1();
|
||||
}
|
||||
else if (action == UPDATE_NOW_LAUNCH_STAGE1_START_PT_CMDARG)
|
||||
{
|
||||
return !install_new_version_stage_1(true);
|
||||
}
|
||||
else if (action == UPDATE_NOW_LAUNCH_STAGE2_CMDARG)
|
||||
{
|
||||
using namespace std::string_view_literals;
|
||||
return !install_new_version_stage_2(args[2], args[3], args[4] == std::wstring_view{ UPDATE_STAGE2_RESTART_PT_CMDARG });
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -157,12 +157,12 @@
|
||||
<ProjectReference Include="..\common\common.vcxproj">
|
||||
<Project>{74485049-c722-400f-abe5-86ac52d929b3}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\common\msi_to_msix_upgrade_lib\msi_to_msix_upgrade_lib.vcxproj">
|
||||
<ProjectReference Include="..\common\updating\updating.vcxproj">
|
||||
<Project>{17da04df-e393-4397-9cf0-84dabe11032e}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\runner\msi_to_msix_upgrade.h" />
|
||||
<ClInclude Include="..\runner\updating.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
@ -166,6 +166,7 @@
|
||||
<ClCompile Include="start_visible.cpp" />
|
||||
<ClCompile Include="tasklist_positions.cpp" />
|
||||
<ClCompile Include="common.cpp" />
|
||||
<ClCompile Include="version.cpp" />
|
||||
<ClCompile Include="VersionHelper.cpp" />
|
||||
<ClCompile Include="windows_colors.cpp" />
|
||||
<ClCompile Include="window_helpers.cpp" />
|
||||
|
@ -171,6 +171,9 @@
|
||||
<ClCompile Include="keyboard_layout.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="version.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
|
@ -1,157 +0,0 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "version.h"
|
||||
|
||||
#include "msi_to_msix_upgrade.h"
|
||||
|
||||
#include <msi.h>
|
||||
#include <common/common.h>
|
||||
#include <common/json.h>
|
||||
|
||||
#include <common/winstore.h>
|
||||
#include <common/notifications.h>
|
||||
#include <MsiQuery.h>
|
||||
|
||||
#include <winrt/Windows.Web.Http.h>
|
||||
#include <winrt/Windows.Web.Http.Headers.h>
|
||||
#include <winrt/Windows.Management.Deployment.h>
|
||||
|
||||
#include "VersionHelper.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
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* USER_AGENT = L"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)";
|
||||
const wchar_t* LATEST_RELEASE_ENDPOINT = L"https://api.github.com/repos/microsoft/PowerToys/releases/latest";
|
||||
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";
|
||||
}
|
||||
|
||||
namespace localized_strings
|
||||
{
|
||||
const wchar_t* OFFER_UNINSTALL_MSI = L"We've detected a previous installation of PowerToys. Would you like to remove it?";
|
||||
const wchar_t* OFFER_UNINSTALL_MSI_TITLE = L"PowerToys: uninstall previous version?";
|
||||
const wchar_t* UNINSTALLATION_SUCCESS = L"Previous version of PowerToys was uninstalled successfully.";
|
||||
const wchar_t* UNINSTALLATION_UNKNOWN_ERROR = L"Error: please uninstall the previous version of PowerToys manually.";
|
||||
}
|
||||
|
||||
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 auto selection = SHMessageBoxCheckW(nullptr, localized_strings::OFFER_UNINSTALL_MSI, localized_strings::OFFER_UNINSTALL_MSI_TITLE, MB_ICONQUESTION | MB_YESNO, IDNO, DONT_SHOW_AGAIN_RECORD_REGISTRY_PATH);
|
||||
return selection == IDYES;
|
||||
}
|
||||
|
||||
bool uninstall_msi_version(const std::wstring& package_path)
|
||||
{
|
||||
const auto uninstall_result = MsiInstallProductW(package_path.c_str(), L"REMOVE=ALL");
|
||||
if (ERROR_SUCCESS == uninstall_result)
|
||||
{
|
||||
notifications::show_toast(localized_strings::UNINSTALLATION_SUCCESS);
|
||||
return true;
|
||||
}
|
||||
else if (auto system_message = get_last_error_message(uninstall_result); system_message.has_value())
|
||||
{
|
||||
try
|
||||
{
|
||||
notifications::show_toast(*system_message);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
notifications::show_toast(localized_strings::UNINSTALLATION_UNKNOWN_ERROR);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::future<std::optional<new_version_download_info>> check_for_new_github_release_async()
|
||||
{
|
||||
try
|
||||
{
|
||||
winrt::Windows::Web::Http::HttpClient client;
|
||||
auto headers = client.DefaultRequestHeaders();
|
||||
headers.UserAgent().TryParseAdd(USER_AGENT);
|
||||
|
||||
auto response = co_await client.GetAsync(winrt::Windows::Foundation::Uri{ LATEST_RELEASE_ENDPOINT });
|
||||
(void)response.EnsureSuccessStatusCode();
|
||||
const auto body = co_await response.Content().ReadAsStringAsync();
|
||||
auto json_body = json::JsonValue::Parse(body).GetObjectW();
|
||||
auto new_version = json_body.GetNamedString(L"tag_name");
|
||||
winrt::Windows::Foundation::Uri release_page_uri{ json_body.GetNamedString(L"html_url") };
|
||||
|
||||
VersionHelper github_version(winrt::to_string(new_version));
|
||||
VersionHelper current_version(VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION);
|
||||
|
||||
if (github_version > current_version)
|
||||
{
|
||||
co_return new_version_download_info{ std::move(release_page_uri), new_version.c_str() };
|
||||
}
|
||||
else
|
||||
{
|
||||
co_return std::nullopt;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
co_return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
std::future<bool> uninstall_previous_msix_version_async()
|
||||
{
|
||||
winrt::Windows::Management::Deployment::PackageManager package_manager;
|
||||
|
||||
try
|
||||
{
|
||||
auto packages = package_manager.FindPackagesForUser({}, MSIX_PACKAGE_NAME, MSIX_PACKAGE_PUBLISHER);
|
||||
VersionHelper current_version(VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION);
|
||||
|
||||
for (auto package : packages)
|
||||
{
|
||||
VersionHelper msix_version(package.Id().Version().Major, package.Id().Version().Minor, package.Id().Version().Revision);
|
||||
|
||||
if (msix_version < current_version)
|
||||
{
|
||||
co_await package_manager.RemovePackageAsync(package.Id().FullName());
|
||||
co_return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
co_return false;
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <future>
|
||||
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
|
||||
std::wstring get_msi_package_path();
|
||||
bool uninstall_msi_version(const std::wstring& package_path);
|
||||
bool offer_msi_uninstallation();
|
||||
|
||||
std::future<bool> uninstall_previous_msix_version_async();
|
||||
|
||||
struct new_version_download_info
|
||||
{
|
||||
winrt::Windows::Foundation::Uri release_page_uri;
|
||||
std::wstring version_string;
|
||||
};
|
||||
std::future<std::optional<new_version_download_info>> check_for_new_github_release_async();
|
@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef PCH_H
|
||||
#define PCH_H
|
||||
|
||||
#pragma warning (disable: 5205)
|
||||
#include <winrt/base.h>
|
||||
#pragma warning (default: 5205)
|
||||
#include <Windows.h>
|
||||
#include <MsiQuery.h>
|
||||
#include <Shlwapi.h>
|
||||
|
||||
#endif //PCH_H
|
17
src/common/updating/pch.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef PCH_H
|
||||
#define PCH_H
|
||||
|
||||
#pragma warning(disable : 5205)
|
||||
#include <winrt/base.h>
|
||||
#pragma warning(default : 5205)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <MsiQuery.h>
|
||||
#include <Shlwapi.h>
|
||||
#include <Shobjidl.h>
|
||||
#include <Knownfolders.h>
|
||||
#include <ShlObj_core.h>
|
||||
|
||||
#endif //PCH_H
|
244
src/common/updating/updating.cpp
Normal file
@ -0,0 +1,244 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "version.h"
|
||||
|
||||
#include "updating.h"
|
||||
|
||||
#include <msi.h>
|
||||
#include <common/common.h>
|
||||
#include <common/json.h>
|
||||
#include <common/version.h>
|
||||
#include <common/settings_helpers.h>
|
||||
#include <common/winstore.h>
|
||||
#include <common/notifications.h>
|
||||
|
||||
#include <winrt/Windows.Web.Http.h>
|
||||
#include <winrt/Windows.Web.Http.Headers.h>
|
||||
#include <winrt/Windows.Storage.Streams.h>
|
||||
#include <winrt/Windows.Management.Deployment.h>
|
||||
#include <winrt/Windows.Networking.Connectivity.h>
|
||||
|
||||
#include "VersionHelper.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
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 USER_AGENT[] = L"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)";
|
||||
const wchar_t LATEST_RELEASE_ENDPOINT[] = L"https://api.github.com/repos/microsoft/PowerToys/releases/latest";
|
||||
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";
|
||||
}
|
||||
|
||||
namespace localized_strings
|
||||
{
|
||||
const wchar_t OFFER_UNINSTALL_MSI[] = L"We've detected a previous installation of PowerToys. Would you like to remove it?";
|
||||
const wchar_t OFFER_UNINSTALL_MSI_TITLE[] = L"PowerToys: uninstall previous version?";
|
||||
const wchar_t UNINSTALLATION_SUCCESS[] = L"Previous version of PowerToys was uninstalled successfully.";
|
||||
const wchar_t UNINSTALLATION_UNKNOWN_ERROR[] = L"Error: please uninstall the previous version of PowerToys manually.";
|
||||
|
||||
const wchar_t GITHUB_NEW_VERSION_READY_TO_INSTALL[] = L"An update to PowerToys is ready to install.";
|
||||
const wchar_t GITHUB_NEW_VERSION_UPDATE_NOW[] = L"Update now";
|
||||
const wchar_t GITHUB_NEW_VERSION_UPDATE_AFTER_RESTART[] = L"At next launch";
|
||||
|
||||
const wchar_t GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT[] = L"An update to PowerToys is available. Visit our GitHub page to get ";
|
||||
const wchar_t GITHUB_NEW_VERSION_AGREE[] = L"Visit";
|
||||
const wchar_t GITHUB_NEW_VERSION_UPDATE_SNOOZE_1D[] = L"1 day";
|
||||
const wchar_t GITHUB_NEW_VERSION_UPDATE_SNOOZE_5D[] = L"5 days";
|
||||
}
|
||||
namespace updating
|
||||
{
|
||||
inline winrt::Windows::Web::Http::HttpClient create_http_client()
|
||||
{
|
||||
winrt::Windows::Web::Http::HttpClient client;
|
||||
auto headers = client.DefaultRequestHeaders();
|
||||
headers.UserAgent().TryParseAdd(USER_AGENT);
|
||||
return client;
|
||||
}
|
||||
|
||||
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 auto selection = SHMessageBoxCheckW(nullptr, localized_strings::OFFER_UNINSTALL_MSI, localized_strings::OFFER_UNINSTALL_MSI_TITLE, MB_ICONQUESTION | MB_YESNO, IDNO, DONT_SHOW_AGAIN_RECORD_REGISTRY_PATH);
|
||||
return selection == IDYES;
|
||||
}
|
||||
|
||||
bool uninstall_msi_version(const std::wstring& package_path)
|
||||
{
|
||||
const auto uninstall_result = MsiInstallProductW(package_path.c_str(), L"REMOVE=ALL");
|
||||
if (ERROR_SUCCESS == uninstall_result)
|
||||
{
|
||||
notifications::show_toast(localized_strings::UNINSTALLATION_SUCCESS);
|
||||
return true;
|
||||
}
|
||||
else if (auto system_message = get_last_error_message(uninstall_result); system_message.has_value())
|
||||
{
|
||||
try
|
||||
{
|
||||
notifications::show_toast(*system_message);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
notifications::show_toast(localized_strings::UNINSTALLATION_UNKNOWN_ERROR);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::future<std::optional<new_version_download_info>> get_new_github_version_info_async()
|
||||
{
|
||||
try
|
||||
{
|
||||
auto client = create_http_client();
|
||||
auto response = co_await client.GetAsync(winrt::Windows::Foundation::Uri{ LATEST_RELEASE_ENDPOINT });
|
||||
(void)response.EnsureSuccessStatusCode();
|
||||
const auto body = co_await response.Content().ReadAsStringAsync();
|
||||
auto json_body = json::JsonValue::Parse(body).GetObjectW();
|
||||
auto new_version = json_body.GetNamedString(L"tag_name");
|
||||
winrt::Windows::Foundation::Uri release_page_uri{ json_body.GetNamedString(L"html_url") };
|
||||
|
||||
VersionHelper github_version(winrt::to_string(new_version));
|
||||
VersionHelper current_version(VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION);
|
||||
|
||||
if (github_version > current_version)
|
||||
{
|
||||
const std::wstring_view required_asset_extension = winstore::running_as_packaged() ? L".msix" : L".msi";
|
||||
const std::wstring_view required_architecture = get_architecture_string(get_current_architecture());
|
||||
constexpr const std::wstring_view required_filename_pattern = updating::installer_filename_pattern;
|
||||
for (auto asset_elem : json_body.GetNamedArray(L"assets"))
|
||||
{
|
||||
auto asset{ asset_elem.GetObjectW() };
|
||||
std::wstring filename_lower = asset.GetNamedString(L"name", {}).c_str();
|
||||
std::transform(begin(filename_lower), end(filename_lower), begin(filename_lower), ::towlower);
|
||||
|
||||
const bool extension_matched = filename_lower.ends_with(required_asset_extension);
|
||||
const bool architecture_matched = filename_lower.find(required_architecture) != std::wstring::npos;
|
||||
const bool filename_matched = filename_lower.find(required_filename_pattern) != std::wstring::npos;
|
||||
if (extension_matched && architecture_matched && filename_matched)
|
||||
{
|
||||
winrt::Windows::Foundation::Uri msi_download_url{ asset.GetNamedString(L"browser_download_url") };
|
||||
co_return new_version_download_info{ std::move(release_page_uri), new_version.c_str(), std::move(msi_download_url), std::move(filename_lower) };
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
co_return std::nullopt;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
co_return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
std::future<bool> uninstall_previous_msix_version_async()
|
||||
{
|
||||
winrt::Windows::Management::Deployment::PackageManager package_manager;
|
||||
|
||||
try
|
||||
{
|
||||
auto packages = package_manager.FindPackagesForUser({}, MSIX_PACKAGE_NAME, MSIX_PACKAGE_PUBLISHER);
|
||||
VersionHelper current_version(VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION);
|
||||
|
||||
for (auto package : packages)
|
||||
{
|
||||
VersionHelper msix_version(package.Id().Version().Major, package.Id().Version().Minor, package.Id().Version().Revision);
|
||||
|
||||
if (msix_version < current_version)
|
||||
{
|
||||
co_await package_manager.RemovePackageAsync(package.Id().FullName());
|
||||
co_return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
co_return false;
|
||||
}
|
||||
|
||||
bool could_be_costly_connection()
|
||||
{
|
||||
using namespace winrt::Windows::Networking::Connectivity;
|
||||
ConnectionProfile internetConnectionProfile = NetworkInformation::GetInternetConnectionProfile();
|
||||
return internetConnectionProfile.IsWwanConnectionProfile();
|
||||
}
|
||||
|
||||
std::filesystem::path get_pending_updates_path()
|
||||
{
|
||||
auto path_str{ PTSettingsHelper::get_root_save_folder_location() };
|
||||
path_str += L"\\Updates";
|
||||
return { std::move(path_str) };
|
||||
}
|
||||
|
||||
std::future<void> try_autoupdate(const bool download_updates_automatically)
|
||||
{
|
||||
const auto new_version = co_await get_new_github_version_info_async();
|
||||
if (!new_version)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
using namespace localized_strings;
|
||||
namespace storage = winrt::Windows::Storage;
|
||||
|
||||
if (download_updates_automatically && !could_be_costly_connection())
|
||||
{
|
||||
auto client = create_http_client();
|
||||
auto response = co_await client.GetAsync(new_version->msi_download_url);
|
||||
(void)response.EnsureSuccessStatusCode();
|
||||
|
||||
auto download_dst = get_pending_updates_path();
|
||||
std::error_code _;
|
||||
std::filesystem::create_directories(download_dst, _);
|
||||
download_dst /= new_version->msi_filename;
|
||||
auto msi_installer_file_stream = co_await storage::Streams::FileRandomAccessStream::OpenAsync(download_dst.c_str(), storage::FileAccessMode::ReadWrite, storage::StorageOpenOptions::AllowReadersAndWriters, storage::Streams::FileOpenDisposition::CreateAlways);
|
||||
co_await response.Content().WriteToStreamAsync(msi_installer_file_stream);
|
||||
notifications::toast_params toast_params{ L"PTUpdateReadyTag", false };
|
||||
std::wstring new_version_ready{ GITHUB_NEW_VERSION_READY_TO_INSTALL };
|
||||
new_version_ready += L" ";
|
||||
new_version_ready += new_version->version_string;
|
||||
notifications::show_toast_with_activations(std::move(new_version_ready), {}, { notifications::link_button{ GITHUB_NEW_VERSION_UPDATE_NOW, L"powertoys://update_now/" }, notifications::link_button{ GITHUB_NEW_VERSION_UPDATE_AFTER_RESTART, L"powertoys://schedule_update/" }, notifications::snooze_button{ { { GITHUB_NEW_VERSION_UPDATE_SNOOZE_1D, 24 * 60 }, { GITHUB_NEW_VERSION_UPDATE_SNOOZE_5D, 120 * 60 } } } }, std::move(toast_params));
|
||||
}
|
||||
else
|
||||
{
|
||||
notifications::toast_params toast_params{ L"PTUpdateNotifyTag", false };
|
||||
std::wstring contents = GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT;
|
||||
contents += new_version->version_string;
|
||||
contents += L'.';
|
||||
notifications::show_toast_with_activations(std::move(contents), {}, { notifications::link_button{ GITHUB_NEW_VERSION_AGREE, new_version->release_page_uri.ToString().c_str() } }, std::move(toast_params));
|
||||
}
|
||||
}
|
||||
}
|
31
src/common/updating/updating.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <future>
|
||||
#include <filesystem>
|
||||
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
|
||||
namespace updating
|
||||
{
|
||||
std::wstring get_msi_package_path();
|
||||
bool uninstall_msi_version(const std::wstring& package_path);
|
||||
bool offer_msi_uninstallation();
|
||||
|
||||
std::future<bool> uninstall_previous_msix_version_async();
|
||||
|
||||
struct new_version_download_info
|
||||
{
|
||||
winrt::Windows::Foundation::Uri release_page_uri;
|
||||
std::wstring version_string;
|
||||
winrt::Windows::Foundation::Uri msi_download_url;
|
||||
std::wstring msi_filename;
|
||||
};
|
||||
|
||||
std::future<std::optional<new_version_download_info>> get_new_github_version_info_async();
|
||||
std::future<void> try_autoupdate(const bool download_updates_automatically);
|
||||
std::filesystem::path get_pending_updates_path();
|
||||
|
||||
constexpr inline std::wstring_view installer_filename_pattern = L"powertoyssetup";
|
||||
}
|
@ -22,8 +22,9 @@
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<ProjectGuid>{17DA04DF-E393-4397-9CF0-84DABE11032E}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>msitomsixupgradelib</RootNamespace>
|
||||
<RootNamespace>updating</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>updating</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
@ -171,11 +172,11 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="msi_to_msix_upgrade.h" />
|
||||
<ClInclude Include="updating.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="msi_to_msix_upgrade.cpp" />
|
||||
<ClCompile Include="updating.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
@ -18,7 +18,7 @@
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="msi_to_msix_upgrade.h">
|
||||
<ClInclude Include="updating.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
@ -26,7 +26,7 @@
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="msi_to_msix_upgrade.cpp">
|
||||
<ClCompile Include="updating.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
21
src/common/version.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
#include "pch.h"
|
||||
#include "version.h"
|
||||
|
||||
version_architecture get_current_architecture()
|
||||
{
|
||||
// TODO: detect ARM build with #ifdef
|
||||
return version_architecture::x64;
|
||||
}
|
||||
|
||||
const wchar_t* get_architecture_string(const version_architecture v)
|
||||
{
|
||||
switch (v)
|
||||
{
|
||||
case version_architecture::x64:
|
||||
return L"x64";
|
||||
case version_architecture::arm:
|
||||
return L"arm";
|
||||
default:
|
||||
throw std::runtime_error("unknown architecture");
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
#define STRINGIZE2(s) #s
|
||||
#define STRINGIZE(s) STRINGIZE2(s)
|
||||
|
||||
|
||||
#include "Generated Files\version_gen.h"
|
||||
|
||||
#define FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, 0
|
||||
@ -14,3 +14,12 @@
|
||||
#define COMPANY_NAME "Microsoft Corporation"
|
||||
|
||||
#define COPYRIGHT_NOTE "Copyright (C) 2019 Microsoft Corporation"
|
||||
|
||||
enum class version_architecture
|
||||
{
|
||||
x64,
|
||||
arm
|
||||
};
|
||||
|
||||
version_architecture get_current_architecture();
|
||||
const wchar_t* get_architecture_string(const version_architecture);
|
@ -9,6 +9,7 @@
|
||||
#include "lib/JsonHelpers.h"
|
||||
#include "lib/ZoneSet.h"
|
||||
#include "trace.h"
|
||||
#include "VirtualDesktopUtils.h"
|
||||
|
||||
#include <functional>
|
||||
#include <common/common.h>
|
||||
@ -349,17 +350,28 @@ FancyZones::VirtualDesktopInitialize() noexcept
|
||||
IFACEMETHODIMP_(void)
|
||||
FancyZones::WindowCreated(HWND window) noexcept
|
||||
{
|
||||
std::shared_lock readLock(m_lock);
|
||||
if (m_settings->GetSettings()->appLastZone_moveWindows && IsInterestingWindow(window))
|
||||
{
|
||||
for (const auto& [monitor, zoneWindow] : m_zoneWindowMap)
|
||||
{
|
||||
// WindowCreated is also invoked when a virtual desktop switch occurs, we need a way
|
||||
// to figure out when that happens to avoid moving windows that should not be moved.
|
||||
GUID windowDesktopId{};
|
||||
GUID zoneWindowDesktopId{};
|
||||
if (VirtualDesktopUtils::GetWindowDesktopId(window, &windowDesktopId) &&
|
||||
VirtualDesktopUtils::GetZoneWindowDesktopId(zoneWindow.get(), &zoneWindowDesktopId) &&
|
||||
(windowDesktopId != zoneWindowDesktopId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
const auto activeZoneSet = zoneWindow->ActiveZoneSet();
|
||||
if (activeZoneSet)
|
||||
{
|
||||
const auto& fancyZonesData = JSONHelpers::FancyZonesDataInstance();
|
||||
|
||||
wil::unique_cotaskmem_string guidString;
|
||||
if (SUCCEEDED_LOG(StringFromCLSID(activeZoneSet->Id(), &guidString)))
|
||||
if (SUCCEEDED(StringFromCLSID(activeZoneSet->Id(), &guidString)))
|
||||
{
|
||||
int zoneIndex = fancyZonesData.GetAppLastZoneIndex(window, zoneWindow->UniqueId(), guidString.get());
|
||||
if (zoneIndex != -1)
|
||||
|
@ -103,6 +103,7 @@
|
||||
<ClInclude Include="Settings.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
<ClInclude Include="util.h" />
|
||||
<ClInclude Include="VirtualDesktopUtils.h" />
|
||||
<ClInclude Include="Zone.h" />
|
||||
<ClInclude Include="ZoneSet.h" />
|
||||
<ClInclude Include="ZoneWindow.h" />
|
||||
@ -117,6 +118,7 @@
|
||||
<ClCompile Include="Settings.cpp" />
|
||||
<ClCompile Include="trace.cpp" />
|
||||
<ClCompile Include="util.cpp" />
|
||||
<ClCompile Include="VirtualDesktopUtils.cpp" />
|
||||
<ClCompile Include="Zone.cpp" />
|
||||
<ClCompile Include="ZoneSet.cpp" />
|
||||
<ClCompile Include="ZoneWindow.cpp" />
|
||||
|
@ -48,6 +48,9 @@
|
||||
<ClInclude Include="JsonHelpers.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VirtualDesktopUtils.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp">
|
||||
@ -77,6 +80,9 @@
|
||||
<ClCompile Include="util.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VirtualDesktopUtils.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="fancyzones.rc">
|
||||
|
49
src/modules/fancyzones/lib/VirtualDesktopUtils.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "VirtualDesktopUtils.h"
|
||||
|
||||
namespace VirtualDesktopUtils
|
||||
{
|
||||
const CLSID CLSID_ImmersiveShell = { 0xC2F03A33, 0x21F5, 0x47FA, 0xB4, 0xBB, 0x15, 0x63, 0x62, 0xA2, 0xF2, 0x39 };
|
||||
const wchar_t GUID_EmptyGUID[] = L"{00000000-0000-0000-0000-000000000000}";
|
||||
|
||||
IServiceProvider* GetServiceProvider()
|
||||
{
|
||||
IServiceProvider* provider{ nullptr };
|
||||
if (FAILED(CoCreateInstance(CLSID_ImmersiveShell, nullptr, CLSCTX_LOCAL_SERVER, __uuidof(provider), (PVOID*)&provider)))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
|
||||
IVirtualDesktopManager* GetVirtualDesktopManager()
|
||||
{
|
||||
IVirtualDesktopManager* manager{ nullptr };
|
||||
IServiceProvider* serviceProvider = GetServiceProvider();
|
||||
if (serviceProvider == nullptr || FAILED(serviceProvider->QueryService(__uuidof(manager), &manager)))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return manager;
|
||||
}
|
||||
|
||||
bool GetWindowDesktopId(HWND topLevelWindow, GUID* desktopId)
|
||||
{
|
||||
static IVirtualDesktopManager* virtualDesktopManager = GetVirtualDesktopManager();
|
||||
return (virtualDesktopManager != nullptr) &&
|
||||
SUCCEEDED(virtualDesktopManager->GetWindowDesktopId(topLevelWindow, desktopId));
|
||||
}
|
||||
|
||||
bool GetZoneWindowDesktopId(IZoneWindow* zoneWindow, GUID* desktopId)
|
||||
{
|
||||
// Format: <device-id>_<resolution>_<virtual-desktop-id>
|
||||
std::wstring uniqueId = zoneWindow->UniqueId();
|
||||
std::wstring virtualDesktopId = uniqueId.substr(uniqueId.rfind('_') + 1);
|
||||
if (virtualDesktopId == GUID_EmptyGUID)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return SUCCEEDED(CLSIDFromString(virtualDesktopId.c_str(), desktopId));
|
||||
}
|
||||
}
|
9
src/modules/fancyzones/lib/VirtualDesktopUtils.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "ZoneWindow.h"
|
||||
|
||||
namespace VirtualDesktopUtils
|
||||
{
|
||||
bool GetWindowDesktopId(HWND topLevelWindow, GUID* desktopId);
|
||||
bool GetZoneWindowDesktopId(IZoneWindow* zoneWindow, GUID* desktopId);
|
||||
}
|
@ -7,6 +7,7 @@ namespace ZoneWindowUtils
|
||||
const std::wstring& GetActiveZoneSetTmpPath();
|
||||
const std::wstring& GetAppliedZoneSetTmpPath();
|
||||
const std::wstring& GetCustomZoneSetsTmpPath();
|
||||
|
||||
std::wstring GenerateUniqueId(HMONITOR monitor, PCWSTR deviceId, PCWSTR virtualDesktopId);
|
||||
}
|
||||
|
||||
|
28
src/runner/action_runner_utils.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "action_runner_utils.h"
|
||||
|
||||
#include <common/common.h>
|
||||
#include <common/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"\\action_runner.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;
|
||||
}
|
15
src/runner/action_runner_utils.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
|
||||
SHELLEXECUTEINFOW launch_action_runner(const wchar_t* cmdline);
|
||||
|
||||
const inline wchar_t* UPDATE_NOW_LAUNCH_STAGE1_START_PT_CMDARG = L"-update_now_and_start_pt";
|
||||
const inline wchar_t* UPDATE_NOW_LAUNCH_STAGE1_CMDARG = L"-update_now";
|
||||
|
||||
const inline wchar_t* UPDATE_NOW_LAUNCH_STAGE2_CMDARG = L"-update_now_stage_2";
|
||||
const inline wchar_t* UPDATE_STAGE2_RESTART_PT_CMDARG = L"restart";
|
||||
const inline wchar_t* UPDATE_STAGE2_DONT_START_PT_CMDARG = L"dont_start";
|
||||
|
||||
const inline wchar_t* UPDATE_REPORT_SUCCESS = L"-report_update_success";
|
@ -10,8 +10,10 @@
|
||||
|
||||
#include "trace.h"
|
||||
|
||||
// TODO: would be nice to get rid of these globals, since they're basically cached json settings
|
||||
static std::wstring settings_theme = L"system";
|
||||
static bool run_as_elevated = false;
|
||||
static bool download_updates_automatically = true;
|
||||
|
||||
// TODO: add resource.rc for settings project and localize
|
||||
namespace localized_strings
|
||||
@ -40,6 +42,7 @@ json::JsonObject GeneralSettings::to_json()
|
||||
|
||||
result.SetNamedValue(L"is_elevated", json::value(isElevated));
|
||||
result.SetNamedValue(L"run_elevated", json::value(isRunElevated));
|
||||
result.SetNamedValue(L"download_updates_automatically", json::value(downloadUpdatesAutomatically));
|
||||
result.SetNamedValue(L"is_admin", json::value(isAdmin));
|
||||
result.SetNamedValue(L"theme", json::value(theme));
|
||||
result.SetNamedValue(L"system_theme", json::value(systemTheme));
|
||||
@ -57,19 +60,22 @@ json::JsonObject load_general_settings()
|
||||
settings_theme = L"system";
|
||||
}
|
||||
run_as_elevated = loaded.GetNamedBoolean(L"run_elevated", false);
|
||||
download_updates_automatically = loaded.GetNamedBoolean(L"download_updates_automatically", true);
|
||||
|
||||
return loaded;
|
||||
}
|
||||
|
||||
GeneralSettings get_settings()
|
||||
GeneralSettings get_general_settings()
|
||||
{
|
||||
GeneralSettings settings{
|
||||
.isPackaged = winstore::running_as_packaged(),
|
||||
.isElevated = is_process_elevated(),
|
||||
.isRunElevated = run_as_elevated,
|
||||
.isAdmin = check_user_is_admin(),
|
||||
.downloadUpdatesAutomatically = download_updates_automatically,
|
||||
.theme = settings_theme,
|
||||
.systemTheme = WindowsColors::is_dark_mode() ? L"dark" : L"light",
|
||||
.powerToysVersion = get_product_version(),
|
||||
.powerToysVersion = get_product_version()
|
||||
};
|
||||
|
||||
if (winstore::running_as_packaged())
|
||||
@ -107,16 +113,12 @@ GeneralSettings get_settings()
|
||||
return settings;
|
||||
}
|
||||
|
||||
json::JsonObject get_general_settings()
|
||||
{
|
||||
auto settings = get_settings();
|
||||
return settings.to_json();
|
||||
}
|
||||
|
||||
void apply_general_settings(const json::JsonObject& general_configs)
|
||||
{
|
||||
run_as_elevated = general_configs.GetNamedBoolean(L"run_elevated", false);
|
||||
|
||||
download_updates_automatically = general_configs.GetNamedBoolean(L"download_updates_automatically", true);
|
||||
|
||||
if (json::has(general_configs, L"startup", json::JsonValueType::Boolean))
|
||||
{
|
||||
const bool startup = general_configs.GetNamedBoolean(L"startup");
|
||||
@ -192,7 +194,7 @@ void apply_general_settings(const json::JsonObject& general_configs)
|
||||
settings_theme = general_configs.GetNamedString(L"theme");
|
||||
}
|
||||
|
||||
GeneralSettings save_settings = get_settings();
|
||||
GeneralSettings save_settings = get_general_settings();
|
||||
PTSettingsHelper::save_general_settings(save_settings.to_json());
|
||||
Trace::SettingsChanged(save_settings);
|
||||
}
|
||||
@ -217,7 +219,9 @@ void start_initial_powertoys()
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...) { }
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
|
||||
if (powertoys_to_disable.empty())
|
||||
{
|
||||
|
@ -11,6 +11,7 @@ struct GeneralSettings
|
||||
bool isElevated;
|
||||
bool isRunElevated;
|
||||
bool isAdmin;
|
||||
bool downloadUpdatesAutomatically;
|
||||
std::wstring theme;
|
||||
std::wstring systemTheme;
|
||||
std::wstring powerToysVersion;
|
||||
@ -19,6 +20,6 @@ struct GeneralSettings
|
||||
};
|
||||
|
||||
json::JsonObject load_general_settings();
|
||||
json::JsonObject get_general_settings();
|
||||
GeneralSettings get_general_settings();
|
||||
void apply_general_settings(const json::JsonObject& general_configs);
|
||||
void start_initial_powertoys();
|
||||
|
@ -13,12 +13,14 @@
|
||||
#include <common/common.h>
|
||||
#include <common/dpi_aware.h>
|
||||
|
||||
#include <common/msi_to_msix_upgrade_lib/msi_to_msix_upgrade.h>
|
||||
#include <common/winstore.h>
|
||||
#include <common/notifications.h>
|
||||
#include <common/timeutil.h>
|
||||
|
||||
#include <common/updating/updating.h>
|
||||
|
||||
#include "update_state.h"
|
||||
#include "update_utils.h"
|
||||
#include "action_runner_utils.h"
|
||||
|
||||
#include <winrt/Windows.System.h>
|
||||
|
||||
@ -33,9 +35,6 @@ namespace localized_strings
|
||||
{
|
||||
const wchar_t MSI_VERSION_IS_ALREADY_RUNNING[] = L"An older version of PowerToys is already running.";
|
||||
const wchar_t OLDER_MSIX_UNINSTALLED[] = L"An older MSIX version of PowerToys was uninstalled.";
|
||||
|
||||
const wchar_t GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT[] = L"An update to PowerToys is available. Visit our GitHub page to get ";
|
||||
const wchar_t GITHUB_NEW_VERSION_AGREE[] = L"Visit";
|
||||
}
|
||||
|
||||
namespace
|
||||
@ -78,78 +77,6 @@ wil::unique_mutex_nothrow create_msix_mutex()
|
||||
return create_runner_mutex(true);
|
||||
}
|
||||
|
||||
bool start_msi_uninstallation_sequence()
|
||||
{
|
||||
const auto package_path = get_msi_package_path();
|
||||
|
||||
if (package_path.empty())
|
||||
{
|
||||
// No MSI version detected
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!offer_msi_uninstallation())
|
||||
{
|
||||
// User declined to uninstall or opted for "Don't show again"
|
||||
return false;
|
||||
}
|
||||
|
||||
std::wstring action_runner_path{ winrt::Windows::ApplicationModel::Package::Current().InstalledLocation().Path() };
|
||||
action_runner_path += L"\\action_runner.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 = L"-uninstall_msi";
|
||||
ShellExecuteExW(&sei);
|
||||
WaitForSingleObject(sei.hProcess, INFINITE);
|
||||
DWORD exit_code = 0;
|
||||
GetExitCodeProcess(sei.hProcess, &exit_code);
|
||||
CloseHandle(sei.hProcess);
|
||||
return exit_code == 0;
|
||||
}
|
||||
|
||||
std::future<void> check_github_updates()
|
||||
{
|
||||
const auto new_version = co_await check_for_new_github_release_async();
|
||||
if (!new_version)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
using namespace localized_strings;
|
||||
|
||||
std::wstring contents = GITHUB_NEW_VERSION_AVAILABLE_OFFER_VISIT;
|
||||
contents += new_version->version_string;
|
||||
contents += L'.';
|
||||
notifications::show_toast_with_activations(std::move(contents), {}, { notifications::link_button{ GITHUB_NEW_VERSION_AGREE, new_version->release_page_uri.ToString().c_str() } });
|
||||
}
|
||||
|
||||
void github_update_checking_worker()
|
||||
{
|
||||
const int64_t update_check_period_minutes = 60 * 24;
|
||||
|
||||
auto state = UpdateState::load();
|
||||
for (;;)
|
||||
{
|
||||
int64_t sleep_minutes_till_next_update = 0;
|
||||
if (state.github_update_last_checked_date.has_value())
|
||||
{
|
||||
int64_t last_checked_minutes_ago = timeutil::diff::in_minutes(timeutil::now(), *state.github_update_last_checked_date);
|
||||
if (last_checked_minutes_ago < 0)
|
||||
{
|
||||
last_checked_minutes_ago = update_check_period_minutes;
|
||||
}
|
||||
sleep_minutes_till_next_update = max(0, update_check_period_minutes - last_checked_minutes_ago);
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::minutes(sleep_minutes_till_next_update));
|
||||
|
||||
check_github_updates().get();
|
||||
state.github_update_last_checked_date.emplace(timeutil::now());
|
||||
state.save();
|
||||
}
|
||||
}
|
||||
|
||||
void open_menu_from_another_instance()
|
||||
{
|
||||
HWND hwnd_main = FindWindow(L"PToyTrayIconWindow", NULL);
|
||||
@ -172,7 +99,7 @@ int runner(bool isProcessElevated)
|
||||
try
|
||||
{
|
||||
std::thread{ [] {
|
||||
github_update_checking_worker();
|
||||
github_update_worker();
|
||||
} }.detach();
|
||||
|
||||
if (winstore::running_as_packaged())
|
||||
@ -183,13 +110,12 @@ int runner(bool isProcessElevated)
|
||||
}
|
||||
else
|
||||
{
|
||||
std::thread{[] {
|
||||
if(uninstall_previous_msix_version_async().get())
|
||||
std::thread{ [] {
|
||||
if (updating::uninstall_previous_msix_version_async().get())
|
||||
{
|
||||
notifications::show_toast(localized_strings::OLDER_MSIX_UNINSTALLED);
|
||||
}
|
||||
}}.detach();
|
||||
|
||||
} }.detach();
|
||||
}
|
||||
|
||||
notifications::register_background_toast_handler();
|
||||
@ -244,7 +170,8 @@ enum class SpecialMode
|
||||
{
|
||||
None,
|
||||
Win32ToastNotificationCOMServer,
|
||||
ToastNotificationHandler
|
||||
ToastNotificationHandler,
|
||||
ReportSuccessfulUpdate
|
||||
};
|
||||
|
||||
SpecialMode should_run_in_special_mode(const int n_cmd_args, LPWSTR* cmd_arg_list)
|
||||
@ -259,6 +186,10 @@ SpecialMode should_run_in_special_mode(const int n_cmd_args, LPWSTR* cmd_arg_lis
|
||||
{
|
||||
return SpecialMode::ToastNotificationHandler;
|
||||
}
|
||||
else if (n_cmd_args == 2 && !wcscmp(UPDATE_REPORT_SUCCESS, cmd_arg_list[i]))
|
||||
{
|
||||
return SpecialMode::ReportSuccessfulUpdate;
|
||||
}
|
||||
}
|
||||
|
||||
return SpecialMode::None;
|
||||
@ -282,6 +213,19 @@ toast_notification_handler_result toast_notification_handler(const std::wstring_
|
||||
{
|
||||
return disable_cant_drag_elevated_warning() ? toast_notification_handler_result::exit_success : toast_notification_handler_result::exit_error;
|
||||
}
|
||||
else if (param == L"update_now/")
|
||||
{
|
||||
launch_action_runner(UPDATE_NOW_LAUNCH_STAGE1_CMDARG);
|
||||
return toast_notification_handler_result::exit_success;
|
||||
}
|
||||
else if (param == L"schedule_update/")
|
||||
{
|
||||
UpdateState::store([](UpdateState& state) {
|
||||
state.pending_update = true;
|
||||
});
|
||||
|
||||
return toast_notification_handler_result::exit_success;
|
||||
}
|
||||
else
|
||||
{
|
||||
return toast_notification_handler_result::exit_error;
|
||||
@ -292,6 +236,11 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
{
|
||||
winrt::init_apartment();
|
||||
|
||||
if (launch_pending_update())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int n_cmd_args = 0;
|
||||
LPWSTR* cmd_arg_list = CommandLineToArgvW(GetCommandLineW(), &n_cmd_args);
|
||||
switch (should_run_in_special_mode(n_cmd_args, cmd_arg_list))
|
||||
@ -306,6 +255,10 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
case toast_notification_handler_result::exit_success:
|
||||
return 0;
|
||||
}
|
||||
case SpecialMode::ReportSuccessfulUpdate:
|
||||
notifications::show_toast(GET_RESOURCE_STRING(IDS_AUTOUPDATE_SUCCESS));
|
||||
break;
|
||||
|
||||
case SpecialMode::None:
|
||||
// continue as usual
|
||||
break;
|
||||
|
@ -6,6 +6,7 @@
|
||||
#define IDS_COULDNOT_RESTART_NONELEVATED 105
|
||||
#define IDS_COULDNOT_RESTART_ELEVATED 106
|
||||
#define IDS_ANOTHER_INSTANCE_RUNNING 107
|
||||
#define IDS_AUTOUPDATE_SUCCESS 108
|
||||
|
||||
#define ID_EXIT_MENU_COMMAND 40001
|
||||
#define ID_SETTINGS_MENU_COMMAND 40002
|
||||
|
@ -10,6 +10,7 @@
|
||||
|