mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-01-18 14:41:21 +08:00
notifications: add support for unpackaged apps and protocol activation
This commit is contained in:
parent
b90f1fc237
commit
c543b7585a
@ -192,6 +192,13 @@
|
|||||||
|
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<DirectoryRef Id="INSTALLFOLDER" FileSource="$(var.BinX64Dir)">
|
<DirectoryRef Id="INSTALLFOLDER" FileSource="$(var.BinX64Dir)">
|
||||||
|
<Component Id="powertoys_toast_clsid" Win64="yes">
|
||||||
|
<RegistryKey Root="HKCU" Key="Software\Classes\CLSID\{DD5CACDA-7C2E-4997-A62A-04A597B58F76}">
|
||||||
|
<RegistryValue Type="string" Value="PowerToys Toast Notifications Background Activator" />
|
||||||
|
<RegistryValue Type="string" Key="LocalServer32" Value="[INSTALLFOLDER]PowerToys.exe -ToastActivated" />
|
||||||
|
<RegistryValue Type="string" Key="LocalServer32" Name="ThreadingModel" Value="Apartment" />
|
||||||
|
</RegistryKey>
|
||||||
|
</Component>
|
||||||
<Component Id="powertoys_exe" Guid="A2C66D91-3485-4D00-B04D-91844E6B345B" Win64="yes">
|
<Component Id="powertoys_exe" Guid="A2C66D91-3485-4D00-B04D-91844E6B345B" Win64="yes">
|
||||||
<File Id="PowerToys.exe" KeyPath="yes" Checksum="yes">
|
<File Id="PowerToys.exe" KeyPath="yes" Checksum="yes">
|
||||||
<Shortcut Id="ApplicationStartMenuShortcut"
|
<Shortcut Id="ApplicationStartMenuShortcut"
|
||||||
@ -201,7 +208,10 @@
|
|||||||
WorkingDirectory="INSTALLFOLDER"
|
WorkingDirectory="INSTALLFOLDER"
|
||||||
Icon="powertoys.ico"
|
Icon="powertoys.ico"
|
||||||
IconIndex="0"
|
IconIndex="0"
|
||||||
Advertise="yes" />
|
Advertise="yes">
|
||||||
|
<ShortcutProperty Key="System.AppUserModel.ID" Value="Microsoft.PowerToysWin32"/>
|
||||||
|
<ShortcutProperty Key="System.AppUserModel.ToastActivatorCLSID" Value="{DD5CACDA-7C2E-4997-A62A-04A597B58F76}"/>
|
||||||
|
</Shortcut>
|
||||||
</File>
|
</File>
|
||||||
|
|
||||||
<RemoveFolder Id="DeleteShortcutFolder" Directory="ApplicationProgramsFolder" On="uninstall" />
|
<RemoveFolder Id="DeleteShortcutFolder" Directory="ApplicationProgramsFolder" On="uninstall" />
|
||||||
@ -209,6 +219,9 @@
|
|||||||
<Component Id="settings_exe" Guid="A5A461A9-7097-4CBA-9D39-3DBBB6B7B80C" Win64="yes">
|
<Component Id="settings_exe" Guid="A5A461A9-7097-4CBA-9D39-3DBBB6B7B80C" Win64="yes">
|
||||||
<File Id="PowerToysSettings.exe" KeyPath="yes" Checksum="yes" />
|
<File Id="PowerToysSettings.exe" KeyPath="yes" Checksum="yes" />
|
||||||
</Component>
|
</Component>
|
||||||
|
<Component Id="notifications_dll" Guid="23B25EE4-BCA2-45DF-BBCD-82FBDF01C5AB" Win64="yes">
|
||||||
|
<File Id="Notifications.dll" KeyPath="yes" Checksum="yes" />
|
||||||
|
</Component>
|
||||||
<Component Id="License_rtf" Guid="3E5AE43B-CFB4-449B-A346-94CAAFF3312E" Win64="yes">
|
<Component Id="License_rtf" Guid="3E5AE43B-CFB4-449B-A346-94CAAFF3312E" Win64="yes">
|
||||||
<File Source="$(var.RepoDir)\License.rtf" Id="License.rtf" KeyPath="yes" />
|
<File Source="$(var.RepoDir)\License.rtf" Id="License.rtf" KeyPath="yes" />
|
||||||
</Component>
|
</Component>
|
||||||
@ -292,6 +305,8 @@
|
|||||||
<Fragment>
|
<Fragment>
|
||||||
<ComponentGroup Id="CoreComponents" Directory="INSTALLFOLDER">
|
<ComponentGroup Id="CoreComponents" Directory="INSTALLFOLDER">
|
||||||
<ComponentRef Id="powertoys_exe" />
|
<ComponentRef Id="powertoys_exe" />
|
||||||
|
<ComponentRef Id="notifications_dll" />
|
||||||
|
<ComponentRef Id="powertoys_toast_clsid" />
|
||||||
<ComponentRef Id="License_rtf" />
|
<ComponentRef Id="License_rtf" />
|
||||||
<ComponentRef Id="PowerToysSvgs" />
|
<ComponentRef Id="PowerToysSvgs" />
|
||||||
<ComponentRef Id="Module_ShortcutGuide" />
|
<ComponentRef Id="Module_ShortcutGuide" />
|
||||||
|
60
src/common/com_object_factory.h
Normal file
60
src/common/com_object_factory.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Unknwn.h>
|
||||||
|
#include <winrt/base.h>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class com_object_factory : public IClassFactory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HRESULT __stdcall QueryInterface(const IID & riid, void** ppv) override
|
||||||
|
{
|
||||||
|
static const QITAB qit[] = {
|
||||||
|
QITABENT(com_object_factory, IClassFactory),
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
return QISearch(this, qit, riid, ppv);
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG __stdcall AddRef() override
|
||||||
|
{
|
||||||
|
return ++_refCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG __stdcall Release() override
|
||||||
|
{
|
||||||
|
LONG refCount = --_refCount;
|
||||||
|
return refCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT __stdcall CreateInstance(IUnknown* punkOuter, const IID & riid, void** ppv)
|
||||||
|
{
|
||||||
|
*ppv = nullptr;
|
||||||
|
HRESULT hr;
|
||||||
|
if (punkOuter)
|
||||||
|
{
|
||||||
|
hr = CLASS_E_NOAGGREGATION;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
T* psrm = new (std::nothrow) T();
|
||||||
|
HRESULT hr = psrm ? S_OK : E_OUTOFMEMORY;
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = psrm->QueryInterface(riid, ppv);
|
||||||
|
psrm->Release();
|
||||||
|
}
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT __stdcall LockServer(BOOL)
|
||||||
|
{
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::atomic<long> _refCount;
|
||||||
|
};
|
@ -119,3 +119,11 @@ struct on_scope_exit
|
|||||||
_f();
|
_f();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class... Ts>
|
||||||
|
struct overloaded : Ts...
|
||||||
|
{
|
||||||
|
using Ts::operator()...;
|
||||||
|
};
|
||||||
|
template<class... Ts>
|
||||||
|
overloaded(Ts...)->overloaded<Ts...>;
|
||||||
|
@ -105,6 +105,7 @@
|
|||||||
<ClInclude Include="d2d_text.h" />
|
<ClInclude Include="d2d_text.h" />
|
||||||
<ClInclude Include="d2d_window.h" />
|
<ClInclude Include="d2d_window.h" />
|
||||||
<ClInclude Include="dpi_aware.h" />
|
<ClInclude Include="dpi_aware.h" />
|
||||||
|
<ClInclude Include="com_object_factory.h" />
|
||||||
<ClInclude Include="notifications.h" />
|
<ClInclude Include="notifications.h" />
|
||||||
<ClInclude Include="window_helpers.h" />
|
<ClInclude Include="window_helpers.h" />
|
||||||
<ClInclude Include="icon_helpers.h" />
|
<ClInclude Include="icon_helpers.h" />
|
||||||
|
@ -87,6 +87,9 @@
|
|||||||
<ClInclude Include="notifications.h">
|
<ClInclude Include="notifications.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="com_object_factory.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="d2d_svg.cpp">
|
<ClCompile Include="d2d_svg.cpp">
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "com_object_factory.h"
|
||||||
#include "notifications.h"
|
#include "notifications.h"
|
||||||
|
|
||||||
#include <unknwn.h>
|
#include <unknwn.h>
|
||||||
@ -9,6 +12,13 @@
|
|||||||
#include <winrt/Windows.UI.Notifications.h>
|
#include <winrt/Windows.UI.Notifications.h>
|
||||||
#include <winrt/Windows.ApplicationModel.Background.h>
|
#include <winrt/Windows.ApplicationModel.Background.h>
|
||||||
|
|
||||||
|
#include "winstore.h"
|
||||||
|
|
||||||
|
#include <winerror.h>
|
||||||
|
#include <NotificationActivationCallback.h>
|
||||||
|
|
||||||
|
#include "notifications_winrt/handler_functions.h"
|
||||||
|
|
||||||
using namespace winrt::Windows::ApplicationModel::Background;
|
using namespace winrt::Windows::ApplicationModel::Background;
|
||||||
using winrt::Windows::Data::Xml::Dom::XmlDocument;
|
using winrt::Windows::Data::Xml::Dom::XmlDocument;
|
||||||
using winrt::Windows::UI::Notifications::ToastNotification;
|
using winrt::Windows::UI::Notifications::ToastNotification;
|
||||||
@ -19,10 +29,94 @@ namespace
|
|||||||
constexpr std::wstring_view TASK_NAME = L"PowerToysBackgroundNotificationsHandler";
|
constexpr std::wstring_view TASK_NAME = L"PowerToysBackgroundNotificationsHandler";
|
||||||
constexpr std::wstring_view TASK_ENTRYPOINT = L"PowerToysNotifications.BackgroundHandler";
|
constexpr std::wstring_view TASK_ENTRYPOINT = L"PowerToysNotifications.BackgroundHandler";
|
||||||
constexpr std::wstring_view APPLICATION_ID = L"PowerToys";
|
constexpr std::wstring_view APPLICATION_ID = L"PowerToys";
|
||||||
|
|
||||||
|
constexpr std::wstring_view WIN32_AUMID = L"Microsoft.PowerToysWin32";
|
||||||
|
}
|
||||||
|
|
||||||
|
static DWORD loop_thread_id()
|
||||||
|
{
|
||||||
|
static const DWORD thread_id = GetCurrentThreadId();
|
||||||
|
return thread_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
class DECLSPEC_UUID("DD5CACDA-7C2E-4997-A62A-04A597B58F76") NotificationActivator : public INotificationActivationCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HRESULT __stdcall QueryInterface(_In_ REFIID iid, _Outptr_ void** resultInterface) override
|
||||||
|
{
|
||||||
|
static const QITAB qit[] = {
|
||||||
|
QITABENT(NotificationActivator, INotificationActivationCallback),
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
return QISearch(this, qit, iid, resultInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG __stdcall AddRef() override
|
||||||
|
{
|
||||||
|
return ++_refCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG __stdcall Release() override
|
||||||
|
{
|
||||||
|
LONG refCount = --_refCount;
|
||||||
|
if (refCount == 0)
|
||||||
|
{
|
||||||
|
PostThreadMessage(loop_thread_id(), WM_QUIT, 0, 0);
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
return refCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual HRESULT STDMETHODCALLTYPE Activate(
|
||||||
|
LPCWSTR appUserModelId,
|
||||||
|
LPCWSTR invokedArgs,
|
||||||
|
const NOTIFICATION_USER_INPUT_DATA*,
|
||||||
|
ULONG) override
|
||||||
|
{
|
||||||
|
auto lib = LoadLibraryW(L"Notifications.dll");
|
||||||
|
if (!lib)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
auto dispatcher = reinterpret_cast<decltype(dispatch_to_backround_handler)*>(GetProcAddress(lib, "dispatch_to_backround_handler"));
|
||||||
|
if (!dispatcher)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatcher(invokedArgs);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::atomic<long> _refCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
void notifications::run_desktop_app_activator_loop()
|
||||||
|
{
|
||||||
|
com_object_factory<NotificationActivator> factory;
|
||||||
|
|
||||||
|
(void)loop_thread_id();
|
||||||
|
|
||||||
|
DWORD token;
|
||||||
|
auto res = CoRegisterClassObject(__uuidof(NotificationActivator), &factory, CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &token);
|
||||||
|
if (!SUCCEEDED(res))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
run_message_loop();
|
||||||
|
CoRevokeClassObject(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
void notifications::register_background_toast_handler()
|
void notifications::register_background_toast_handler()
|
||||||
{
|
{
|
||||||
|
if (!winstore::running_as_packaged())
|
||||||
|
{
|
||||||
|
// The WIX installer will have us registered via the registry
|
||||||
|
return;
|
||||||
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Re-request access to clean up from previous PowerToys installations
|
// Re-request access to clean up from previous PowerToys installations
|
||||||
@ -54,36 +148,89 @@ void notifications::register_background_toast_handler()
|
|||||||
void notifications::show_toast(std::wstring_view message)
|
void notifications::show_toast(std::wstring_view message)
|
||||||
{
|
{
|
||||||
// The toast won't be actually activated in the background, since it doesn't have any buttons
|
// The toast won't be actually activated in the background, since it doesn't have any buttons
|
||||||
show_toast_background_activated(message, {}, {});
|
show_toast_with_activations(message, {}, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
void notifications::show_toast_background_activated(std::wstring_view message, std::wstring_view background_handler_id, std::vector<std::wstring_view> button_labels)
|
inline void xml_escape(std::wstring data)
|
||||||
|
{
|
||||||
|
std::wstring buffer;
|
||||||
|
buffer.reserve(data.size());
|
||||||
|
for (size_t pos = 0; pos != data.size(); ++pos)
|
||||||
|
{
|
||||||
|
switch (data[pos])
|
||||||
|
{
|
||||||
|
case L'&':
|
||||||
|
buffer.append(L"&");
|
||||||
|
break;
|
||||||
|
case L'\"':
|
||||||
|
buffer.append(L""");
|
||||||
|
break;
|
||||||
|
case L'\'':
|
||||||
|
buffer.append(L"'");
|
||||||
|
break;
|
||||||
|
case L'<':
|
||||||
|
buffer.append(L"<");
|
||||||
|
break;
|
||||||
|
case L'>':
|
||||||
|
buffer.append(L">");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
buffer.append(&data[pos], 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data.swap(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void notifications::show_toast_with_activations(std::wstring_view message, std::wstring_view background_handler_id, std::vector<button_t> buttons)
|
||||||
{
|
{
|
||||||
// DO NOT LOCALIZE any string in this function, because they're XML tags and a subject to
|
// 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
|
// https://docs.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/toast-xml-schema
|
||||||
|
|
||||||
std::wstring toast_xml;
|
std::wstring toast_xml;
|
||||||
toast_xml.reserve(1024);
|
toast_xml.reserve(1024);
|
||||||
toast_xml += LR"(<?xml version="1.0"?><toast><visual><binding template="ToastGeneric"><text>PowerToys</text><text>)";
|
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 += title;
|
||||||
|
toast_xml += L"</text><text>";
|
||||||
toast_xml += message;
|
toast_xml += message;
|
||||||
toast_xml += L"</text></binding></visual><actions>";
|
toast_xml += L"</text></binding></visual><actions>";
|
||||||
|
|
||||||
for (size_t i = 0; i < size(button_labels); ++i)
|
for (size_t i = 0; i < size(buttons); ++i)
|
||||||
{
|
{
|
||||||
toast_xml += LR"(<action activationType="background" arguments=")";
|
std::visit(overloaded{
|
||||||
toast_xml += L"button_id=" + std::to_wstring(i); // pass the button ID
|
[&](const link_button& b) {
|
||||||
toast_xml += L"&handler=";
|
toast_xml += LR"(<action activationType="protocol" arguments=")";
|
||||||
toast_xml += background_handler_id;
|
toast_xml += b.url;
|
||||||
toast_xml += LR"(" content=")";
|
toast_xml += LR"(" content=")";
|
||||||
toast_xml += button_labels[i];
|
toast_xml += b.label;
|
||||||
toast_xml += LR"("/>)";
|
toast_xml += LR"("/>)";
|
||||||
|
},
|
||||||
|
[&](const background_activated_button& b) {
|
||||||
|
toast_xml += LR"(<action activationType="background" arguments=")";
|
||||||
|
toast_xml += L"button_id=" + std::to_wstring(i); // pass the button ID
|
||||||
|
toast_xml += L"&handler=";
|
||||||
|
toast_xml += background_handler_id;
|
||||||
|
toast_xml += LR"(" content=")";
|
||||||
|
toast_xml += b.label;
|
||||||
|
toast_xml += LR"("/>)";
|
||||||
|
},
|
||||||
|
},
|
||||||
|
buttons[i]);
|
||||||
}
|
}
|
||||||
toast_xml += L"</actions></toast>";
|
toast_xml += L"</actions></toast>";
|
||||||
|
|
||||||
XmlDocument toast_xml_doc;
|
XmlDocument toast_xml_doc;
|
||||||
|
xml_escape(toast_xml);
|
||||||
toast_xml_doc.LoadXml(toast_xml);
|
toast_xml_doc.LoadXml(toast_xml);
|
||||||
ToastNotification notification{ toast_xml_doc };
|
ToastNotification notification{ toast_xml_doc };
|
||||||
|
|
||||||
const auto notifier = ToastNotificationManager::ToastNotificationManager::CreateToastNotifier();
|
const auto notifier = winstore::running_as_packaged() ? ToastNotificationManager::ToastNotificationManager::CreateToastNotifier() :
|
||||||
|
ToastNotificationManager::ToastNotificationManager::CreateToastNotifier(WIN32_AUMID);
|
||||||
notifier.Show(notification);
|
notifier.Show(notification);
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,29 @@
|
|||||||
|
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
namespace notifications
|
namespace notifications
|
||||||
{
|
{
|
||||||
|
constexpr inline const wchar_t TOAST_ACTIVATED_LAUNCH_ARG[] = L"-ToastActivated";
|
||||||
|
|
||||||
void register_background_toast_handler();
|
void register_background_toast_handler();
|
||||||
|
|
||||||
// Make sure your plaintext_message argument is properly XML-escaped
|
void run_desktop_app_activator_loop();
|
||||||
|
|
||||||
|
struct link_button
|
||||||
|
{
|
||||||
|
std::wstring_view label;
|
||||||
|
std::wstring_view url;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct background_activated_button
|
||||||
|
{
|
||||||
|
std::wstring_view label;
|
||||||
|
};
|
||||||
|
|
||||||
|
using button_t = std::variant<link_button, background_activated_button>;
|
||||||
|
|
||||||
void show_toast(std::wstring_view plaintext_message);
|
void show_toast(std::wstring_view plaintext_message);
|
||||||
void show_toast_background_activated(std::wstring_view plaintext_message, std::wstring_view background_handler_id, std::vector<std::wstring_view> plaintext_button_labels);
|
void show_toast_with_activations(std::wstring_view plaintext_message, std::wstring_view background_handler_id, std::vector<button_t> buttons);
|
||||||
}
|
}
|
||||||
|
@ -3,3 +3,4 @@ DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE
|
|||||||
DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE
|
DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE
|
||||||
DllRegisterServer PRIVATE
|
DllRegisterServer PRIVATE
|
||||||
DllUnregisterServer PRIVATE
|
DllUnregisterServer PRIVATE
|
||||||
|
dispatch_to_backround_handler PRIVATE
|
@ -8,7 +8,6 @@ namespace winrt::PowerToysNotifications::implementation
|
|||||||
{
|
{
|
||||||
using Windows::ApplicationModel::Background::IBackgroundTaskInstance;
|
using Windows::ApplicationModel::Background::IBackgroundTaskInstance;
|
||||||
using Windows::UI::Notifications::ToastNotificationActionTriggerDetail;
|
using Windows::UI::Notifications::ToastNotificationActionTriggerDetail;
|
||||||
using Windows::Foundation::WwwFormUrlDecoder;
|
|
||||||
|
|
||||||
void BackgroundHandler::Run(IBackgroundTaskInstance bti)
|
void BackgroundHandler::Run(IBackgroundTaskInstance bti)
|
||||||
{
|
{
|
||||||
@ -18,10 +17,6 @@ namespace winrt::PowerToysNotifications::implementation
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WwwFormUrlDecoder decoder{details.Argument()};
|
dispatch_to_backround_handler(details.Argument());
|
||||||
|
|
||||||
const size_t button_id = std::stoi(decoder.GetFirstValueByName(L"button_id").c_str());
|
|
||||||
auto handler = decoder.GetFirstValueByName(L"handler");
|
|
||||||
dispatch_to_backround_handler(std::move(handler), std::move(bti), button_id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,19 +2,26 @@
|
|||||||
|
|
||||||
#include "handler_functions.h"
|
#include "handler_functions.h"
|
||||||
|
|
||||||
using handler_function_t = void (*)(IBackgroundTaskInstance, const size_t button_id);
|
#include <winrt/Windows.System.h>
|
||||||
|
|
||||||
|
using handler_function_t = void (*)(const size_t button_id);
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
const std::unordered_map<std::wstring_view, handler_function_t> handlers_map;
|
const std::unordered_map<std::wstring_view, handler_function_t> handlers_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dispatch_to_backround_handler(std::wstring_view background_handler_id, IBackgroundTaskInstance bti, const size_t button_id)
|
void dispatch_to_backround_handler(std::wstring_view argument)
|
||||||
{
|
{
|
||||||
const auto found_handler = handlers_map.find(background_handler_id);
|
winrt::Windows::Foundation::WwwFormUrlDecoder decoder{ argument };
|
||||||
|
|
||||||
|
const size_t button_id = std::stoi(decoder.GetFirstValueByName(L"button_id").c_str());
|
||||||
|
auto handler = decoder.GetFirstValueByName(L"handler");
|
||||||
|
|
||||||
|
const auto found_handler = handlers_map.find(handler);
|
||||||
if (found_handler == end(handlers_map))
|
if (found_handler == end(handlers_map))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
found_handler->second(std::move(bti), button_id);
|
found_handler->second(button_id);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
using winrt::Windows::ApplicationModel::Background::IBackgroundTaskInstance;
|
#include <string_view>
|
||||||
|
|
||||||
void dispatch_to_backround_handler(std::wstring_view background_handler_id, IBackgroundTaskInstance bti, const size_t button_id);
|
void dispatch_to_backround_handler(std::wstring_view argument);
|
||||||
|
@ -120,10 +120,7 @@ int runner(bool isProcessElevated)
|
|||||||
int result = -1;
|
int result = -1;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (winstore::running_as_packaged())
|
notifications::register_background_toast_handler();
|
||||||
{
|
|
||||||
notifications::register_background_toast_handler();
|
|
||||||
}
|
|
||||||
|
|
||||||
chdir_current_executable();
|
chdir_current_executable();
|
||||||
// Load Powertyos DLLS
|
// Load Powertyos DLLS
|
||||||
@ -165,8 +162,46 @@ int runner(bool isProcessElevated)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the PT runner is launched as part of some action and manually by a user, e.g. being activated as a COM server
|
||||||
|
// for background toast notification handling, we should execute corresponding code flow instead of the main code flow.
|
||||||
|
enum class SpecialMode
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Win32ToastNotificationCOMServer
|
||||||
|
};
|
||||||
|
|
||||||
|
SpecialMode should_run_in_special_mode()
|
||||||
|
{
|
||||||
|
int nArgs;
|
||||||
|
LPWSTR* szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
|
||||||
|
for (size_t i = 1; i < nArgs; ++i)
|
||||||
|
{
|
||||||
|
if (!wcscmp(notifications::TOAST_ACTIVATED_LAUNCH_ARG, szArglist[i]))
|
||||||
|
return SpecialMode::Win32ToastNotificationCOMServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SpecialMode::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
int win32_toast_notification_COM_server_mode()
|
||||||
|
{
|
||||||
|
notifications::run_desktop_app_activator_loop();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
|
||||||
{
|
{
|
||||||
|
winrt::init_apartment();
|
||||||
|
|
||||||
|
switch (should_run_in_special_mode())
|
||||||
|
{
|
||||||
|
case SpecialMode::Win32ToastNotificationCOMServer:
|
||||||
|
return win32_toast_notification_COM_server_mode();
|
||||||
|
case SpecialMode::None:
|
||||||
|
// continue as usual
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
wil::unique_mutex_nothrow msi_mutex;
|
wil::unique_mutex_nothrow msi_mutex;
|
||||||
wil::unique_mutex_nothrow msix_mutex;
|
wil::unique_mutex_nothrow msix_mutex;
|
||||||
|
|
||||||
@ -235,12 +270,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||||||
int result = 0;
|
int result = 0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
winrt::init_apartment();
|
|
||||||
|
|
||||||
if (winstore::running_as_packaged())
|
if (winstore::running_as_packaged())
|
||||||
{
|
{
|
||||||
notifications::register_background_toast_handler();
|
|
||||||
|
|
||||||
std::thread{ [] {
|
std::thread{ [] {
|
||||||
start_msi_uninstallation_sequence();
|
start_msi_uninstallation_sequence();
|
||||||
} }.detach();
|
} }.detach();
|
||||||
|
Loading…
Reference in New Issue
Block a user