Autoupdate: implement updating bootstrapper utility (#5204)

This commit is contained in:
Andrey Nekrasov
2020-07-27 19:53:29 +03:00
committed by GitHub
parent 5a48376a77
commit 3796a5ef97
34 changed files with 1016 additions and 296 deletions

View File

@@ -3,6 +3,7 @@
#include "common.h"
#include "com_object_factory.h"
#include "notifications.h"
#include "winstore.h"
#include <unknwn.h>
#include <winrt/base.h>
@@ -11,35 +12,37 @@
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.UI.Notifications.h>
#include <winrt/Windows.ApplicationModel.Background.h>
#include "winstore.h"
#include <wil/com.h>
#include <propvarutil.h>
#include <propkey.h>
#include <Shobjidl.h>
#include <winerror.h>
#include <NotificationActivationCallback.h>
#include "notifications_winrt/handler_functions.h"
#include <filesystem>
using namespace winrt::Windows::ApplicationModel::Background;
using winrt::Windows::Data::Xml::Dom::XmlDocument;
using winrt::Windows::UI::Notifications::ToastNotification;
using winrt::Windows::UI::Notifications::ToastNotificationManager;
namespace fs = std::filesystem;
namespace
{
constexpr std::wstring_view TASK_NAME = L"PowerToysBackgroundNotificationsHandler";
constexpr std::wstring_view TASK_ENTRYPOINT = L"PowerToysNotifications.BackgroundHandler";
constexpr std::wstring_view APPLICATION_ID = L"PowerToys";
constexpr std::wstring_view PACKAGED_APPLICATION_ID = L"PowerToys";
constexpr std::wstring_view APPIDS_REGISTRY = LR"(Software\Classes\AppUserModelId\)";
constexpr std::wstring_view WIN32_AUMID = L"Microsoft.PowerToysWin32";
std::wstring APPLICATION_ID;
}
namespace localized_strings
namespace localized_strings
{
constexpr std::wstring_view SNOOZE_BUTTON = L"Snooze";
constexpr std::wstring_view PT_UPDATE = L"PowerToys update";
constexpr std::wstring_view DOWNLOAD_IN_PROGRESS = L"Downloading...";
constexpr std::wstring_view DOWNLOAD_COMPLETE = L"Download complete";
}
static DWORD loop_thread_id()
@@ -119,6 +122,74 @@ void notifications::run_desktop_app_activator_loop()
CoRevokeClassObject(token);
}
bool notifications::register_application_id(const std::wstring_view appName, const std::wstring_view iconPath)
{
std::wstring aumidPath{ APPIDS_REGISTRY };
aumidPath += APPLICATION_ID;
wil::unique_hkey aumidKey;
if (FAILED(RegCreateKeyW(HKEY_CURRENT_USER, aumidPath.c_str(), &aumidKey)))
{
return false;
}
if (FAILED(RegSetKeyValueW(aumidKey.get(),
nullptr,
L"DisplayName",
REG_SZ,
appName.data(),
static_cast<DWORD>((size(appName) + 1) * sizeof(wchar_t)))))
{
return false;
}
if (FAILED(RegSetKeyValueW(aumidKey.get(),
nullptr,
L"IconUri",
REG_SZ,
iconPath.data(),
static_cast<DWORD>((size(iconPath) + 1) * sizeof(wchar_t)))))
{
return false;
}
const std::wstring_view iconColor = L"FFDDDDDD";
if (FAILED(RegSetKeyValueW(aumidKey.get(),
nullptr,
L"IconBackgroundColor",
REG_SZ,
iconColor.data(),
static_cast<DWORD>((size(iconColor) + 1) * sizeof(wchar_t)))))
{
return false;
}
return true;
}
void notifications::unregister_application_id()
{
std::wstring aumidPath{ APPIDS_REGISTRY };
aumidPath += APPLICATION_ID;
wil::unique_hkey registryRoot;
RegOpenKeyW(HKEY_CURRENT_USER, aumidPath.c_str(), &registryRoot);
if (!registryRoot)
{
return;
}
RegDeleteTreeW(registryRoot.get(), nullptr);
registryRoot.reset();
RegOpenKeyW(HKEY_CURRENT_USER, APPIDS_REGISTRY.data(), &registryRoot);
if (!registryRoot)
{
return;
}
RegDeleteKeyW(registryRoot.get(), APPLICATION_ID.data());
}
void notifications::set_application_id(const std::wstring_view appID)
{
APPLICATION_ID = appID;
SetCurrentProcessExplicitAppUserModelID(APPLICATION_ID.c_str());
}
void notifications::register_background_toast_handler()
{
if (!winstore::running_as_packaged())
@@ -133,7 +204,7 @@ void notifications::register_background_toast_handler()
BackgroundExecutionManager::RequestAccessAsync().get();
BackgroundTaskBuilder builder;
ToastNotificationActionTrigger trigger{ APPLICATION_ID };
ToastNotificationActionTrigger trigger{ PACKAGED_APPLICATION_ID };
builder.SetTrigger(trigger);
builder.TaskEntryPoint(TASK_ENTRYPOINT);
builder.Name(TASK_NAME);
@@ -154,10 +225,10 @@ void notifications::register_background_toast_handler()
}
}
void notifications::show_toast(std::wstring message, toast_params params)
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
show_toast_with_activations(std::move(message), {}, {}, std::move(params));
show_toast_with_activations(std::move(message), std::move(title), {}, {}, std::move(params));
}
inline void xml_escape(std::wstring data)
@@ -191,34 +262,26 @@ inline void xml_escape(std::wstring data)
data.swap(buffer);
}
void notifications::show_toast_with_activations(std::wstring message, std::wstring_view background_handler_id, std::vector<action_t> actions, toast_params params)
void notifications::show_toast_with_activations(std::wstring message,
std::wstring title,
std::wstring_view background_handler_id,
std::vector<action_t> actions,
toast_params params)
{
// DO NOT LOCALIZE any string in this function, because they're XML tags and a subject to
// https://docs.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/toast-xml-schema
std::wstring toast_xml;
toast_xml.reserve(2048);
std::wstring title{ L"PowerToys" };
if (winstore::running_as_packaged())
{
title += L" (Experimental)";
}
toast_xml += LR"(<?xml version="1.0"?><toast><visual><binding template="ToastGeneric"><text>)";
toast_xml += LR"(<?xml version="1.0"?><toast><visual><binding template="ToastGeneric"><text id="1">)";
toast_xml += title;
toast_xml += L"</text><text>";
toast_xml += LR"(</text><text id="2">)";
toast_xml += message;
toast_xml += L"</text>";
if (params.progress)
if (params.progress_bar.has_value())
{
toast_xml += LR"(<progress title=")";
toast_xml += localized_strings::PT_UPDATE;
if (params.subtitle)
{
toast_xml += L" ";
toast_xml += *params.subtitle;
}
toast_xml += LR"(" value="{progressValue}" valueStringOverride="{progressValueString}" status="{progressStatus}"/>)";
toast_xml += LR"(<progress title="{progressTitle}" value="{progressValue}" valueStringOverride="{progressValueString}" status="" />)";
}
toast_xml += L"</binding></visual><actions>";
for (size_t i = 0; i < size(actions); ++i)
@@ -310,19 +373,19 @@ void notifications::show_toast_with_activations(std::wstring message, std::wstri
toast_xml_doc.LoadXml(toast_xml);
ToastNotification notification{ toast_xml_doc };
if (params.progress)
if (params.progress_bar.has_value())
{
float progress = std::clamp(params.progress.value(), 0.0f, 1.0f);
float progress = std::clamp(params.progress_bar->progress, 0.0f, 1.0f);
winrt::Windows::Foundation::Collections::StringMap map;
map.Insert(L"progressValue", std::to_wstring(progress));
map.Insert(L"progressValueString", std::to_wstring(static_cast<int>(progress * 100)) + std::wstring(L"%"));
map.Insert(L"progressStatus", localized_strings::DOWNLOAD_IN_PROGRESS);
map.Insert(L"progressTitle", params.progress_bar->progress_title);
winrt::Windows::UI::Notifications::NotificationData data(map);
notification.Data(data);
}
const auto notifier = winstore::running_as_packaged() ? ToastNotificationManager::ToastNotificationManager::CreateToastNotifier() :
ToastNotificationManager::ToastNotificationManager::CreateToastNotifier(WIN32_AUMID);
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)
@@ -343,29 +406,18 @@ void notifications::show_toast_with_activations(std::wstring message, std::wstri
notifier.Show(notification);
}
void notifications::update_progress_bar_toast(std::wstring plaintext_message, toast_params params)
void notifications::update_progress_bar_toast(std::wstring_view tag, progress_bar_params params)
{
if (!params.progress.has_value())
{
return;
}
const auto notifier = winstore::running_as_packaged() ?
ToastNotificationManager::ToastNotificationManager::CreateToastNotifier() :
ToastNotificationManager::ToastNotificationManager::CreateToastNotifier(APPLICATION_ID);
const auto notifier = winstore::running_as_packaged() ? ToastNotificationManager::ToastNotificationManager::CreateToastNotifier() :
ToastNotificationManager::ToastNotificationManager::CreateToastNotifier(WIN32_AUMID);
float progress = std::clamp(params.progress.value(), 0.0f, 1.0f);
float progress = std::clamp(params.progress, 0.0f, 1.0f);
winrt::Windows::Foundation::Collections::StringMap map;
map.Insert(L"progressValue", std::to_wstring(progress));
map.Insert(L"progressValueString", std::to_wstring(static_cast<int>(progress * 100)) + std::wstring(L"%"));
map.Insert(L"progressStatus", progress < 1 ? localized_strings::DOWNLOAD_IN_PROGRESS : localized_strings::DOWNLOAD_COMPLETE);
map.Insert(L"progressTitle", params.progress_title);
winrt::Windows::UI::Notifications::NotificationData data(map);
std::wstring tag = L"";
if (params.tag.has_value() && params.tag->length() < 64)
{
tag = *params.tag;
}
winrt::Windows::UI::Notifications::NotificationUpdateResult res = notifier.Update(data, tag);
}