diff --git a/dev/PushNotifications/PushNotificationChannel.cpp b/dev/PushNotifications/PushNotificationChannel.cpp index 2c1c166271..2b36467e98 100644 --- a/dev/PushNotifications/PushNotificationChannel.cpp +++ b/dev/PushNotifications/PushNotificationChannel.cpp @@ -12,7 +12,7 @@ #include "externs.h" #include "PushNotificationTelemetry.h" #include - +#include "PushNotificationUtility.h" namespace winrt::Windows { @@ -89,15 +89,34 @@ namespace winrt::Microsoft::Windows::PushNotifications::implementation { if (IsPackagedAppScenario()) { - return m_channel.PushNotificationReceived([weak_self = get_weak(), handler](auto&&, auto&& args) + if (m_channel) + { + return m_channel.PushNotificationReceived([weak_self = get_weak(), handler](auto&&, auto&& args) + { + if (auto strong = weak_self.get()) + { + auto pushArgs = winrt::make(args); + pushArgs.Handled(true); + handler(*strong, pushArgs); + }; + }); + } + else { - if (auto strong = weak_self.get()) + // The channelUri is directly obtained when we request Channel from UDK using RemoteId + auto lock = m_lock.lock_exclusive(); + + if (!m_foregroundHandlerCount) { - auto pushArgs = winrt::make(args); - pushArgs.Handled(true); - handler(*strong, pushArgs); - }; - }); + auto appUserModelId = GetAppUserModelId(); + + THROW_IF_FAILED(PushNotifications_RegisterNotificationSinkForFullTrustApplication(appUserModelId.get(), this)); + } + + ++m_foregroundHandlerCount; + + return m_foregroundHandlers.add(handler); + } } else { @@ -120,7 +139,24 @@ namespace winrt::Microsoft::Windows::PushNotifications::implementation { if (IsPackagedAppScenario()) { - m_channel.PushNotificationReceived(token); + if (m_channel) + { + m_channel.PushNotificationReceived(token); + } + else + { + auto lock = m_lock.lock_exclusive(); + + if (m_foregroundHandlerCount == 1) + { + auto appUserModelId = GetAppUserModelId(); + + THROW_IF_FAILED(PushNotifications_UnregisterNotificationSinkForFullTrustApplication(appUserModelId.get())); + } + + m_foregroundHandlers.remove(token); + --m_foregroundHandlerCount; + } } else { @@ -148,6 +184,20 @@ namespace winrt::Microsoft::Windows::PushNotifications::implementation } CATCH_RETURN() + HRESULT __stdcall PushNotificationChannel::OnRawNotificationReceived(unsigned int payloadLength, _In_ byte* payload, _In_ HSTRING /*correlationVector */) noexcept try + { + BOOL foregroundHandled = true; + THROW_IF_FAILED(InvokeAll(payloadLength, payload, &foregroundHandled)); + + if (!foregroundHandled) + { + ProtocolLaunchHelper(payloadLength, payload); + } + + return S_OK; + } + CATCH_RETURN(); + bool PushNotificationChannel::IsBackgroundTaskBuilderAvailable() { return winrt::Windows::ApiInformation::IsMethodPresent(L"Windows.ApplicationModel.Background.BackgroundTaskBuilder", L"SetTaskEntryPointClsid"); diff --git a/dev/PushNotifications/PushNotificationChannel.h b/dev/PushNotifications/PushNotificationChannel.h index cb02cb6e68..1a1595acd1 100644 --- a/dev/PushNotifications/PushNotificationChannel.h +++ b/dev/PushNotifications/PushNotificationChannel.h @@ -5,6 +5,7 @@ #include "Microsoft.Windows.PushNotifications.PushNotificationChannel.g.h" #include #include "winrt/Windows.Networking.PushNotifications.h" +#include #include "externs.h" namespace winrt::Microsoft::Windows::PushNotifications::implementation @@ -13,7 +14,7 @@ namespace winrt::Microsoft::Windows::PushNotifications::implementation winrt::Microsoft::Windows::PushNotifications::PushNotificationChannel, winrt::Microsoft::Windows::PushNotifications::PushNotificationReceivedEventArgs> PushNotificationEventHandler; - struct PushNotificationChannel : PushNotificationChannelT + struct PushNotificationChannel : PushNotificationChannelT { PushNotificationChannel(winrt::Windows::Networking::PushNotifications::PushNotificationChannel const& channel); @@ -29,6 +30,9 @@ namespace winrt::Microsoft::Windows::PushNotifications::implementation // IWpnForegroundSink HRESULT __stdcall InvokeAll(_In_ ULONG length, _In_ byte* payload, _Out_ BOOL* foregroundHandled) noexcept; + // INotificationHandler + HRESULT __stdcall OnRawNotificationReceived(unsigned int payloadLength, _In_ byte* payload, _In_ HSTRING /*correlationVector */) noexcept; + private: bool IsPackagedAppScenario(); bool IsBackgroundTaskBuilderAvailable(); diff --git a/dev/PushNotifications/PushNotificationUtility.cpp b/dev/PushNotifications/PushNotificationUtility.cpp new file mode 100644 index 0000000000..081800b8fe --- /dev/null +++ b/dev/PushNotifications/PushNotificationUtility.cpp @@ -0,0 +1,69 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. +#include "pch.h" +#include "externs.h" +#include "PushNotificationUtility.h" + +wil::unique_cotaskmem_string GetAppUserModelId() +{ + wchar_t appId[APPLICATION_USER_MODEL_ID_MAX_LENGTH] = {}; + UINT32 appIdSize{ ARRAYSIZE(appId) }; + + THROW_IF_FAILED(::GetCurrentApplicationUserModelId(&appIdSize, appId)); + + return wil::make_unique_string(appId); +} + +std::wstring Utf8BytesToWideString(unsigned int payloadLength, _In_reads_(payloadLength) byte* payload) +{ + int size = MultiByteToWideChar( + CP_UTF8, + 0, + reinterpret_cast(payload), + payloadLength, + nullptr, + 0); + THROW_LAST_ERROR_IF(size == 0); + + std::wstring payloadAsWideString(size, 0); + size = MultiByteToWideChar( + CP_UTF8, + 0, + reinterpret_cast(payload), + payloadLength, + &payloadAsWideString[0], + size); + THROW_LAST_ERROR_IF(size == 0); + + return payloadAsWideString; +} + +void ProtocolLaunchHelper(unsigned int payloadLength, _In_reads_(payloadLength) byte* payload) +{ + // Command line format: ----WindowsAppRuntimePushServer:-Payload:"" + std::wstring commandLine = L"----WindowsAppRuntimePushServer:-Payload:\""; + + // Escape special characters to follow command line standards for any app activation type in AppLifecycle + // (See AppInstance.cpp and Serialize() from other activation types) + std::wstring payloadAsWideString = Utf8BytesToWideString(payloadLength, payload); + auto payloadAsEscapedUriFormat = winrt::Windows::Foundation::Uri::EscapeComponent(payloadAsWideString.c_str()); + + commandLine.append(payloadAsEscapedUriFormat); + commandLine.append(L"\""); + + wil::unique_cotaskmem_string processName; + THROW_IF_FAILED(GetCurrentProcessPath(processName)); + + SHELLEXECUTEINFO shellExecuteInfo{}; + shellExecuteInfo.cbSize = sizeof(SHELLEXECUTEINFO); + shellExecuteInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_DOENVSUBST; + shellExecuteInfo.lpFile = processName.get(); + shellExecuteInfo.lpParameters = commandLine.c_str(); + + shellExecuteInfo.nShow = SW_NORMAL; + + if (!ShellExecuteEx(&shellExecuteInfo)) + { + THROW_IF_WIN32_ERROR(GetLastError()); + } +} diff --git a/dev/PushNotifications/PushNotificationUtility.h b/dev/PushNotifications/PushNotificationUtility.h new file mode 100644 index 0000000000..69475daa1d --- /dev/null +++ b/dev/PushNotifications/PushNotificationUtility.h @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE in the project root for license information. + +#pragma once +#include "pch.h" + +const std::wstring ConvertByteArrayToWideString(unsigned int payloadLength, _In_reads_(payloadLength) byte* payload); +void ProtocolLaunchHelper(unsigned int payloadLength, _In_reads_(payloadLength) byte* payload); +wil::unique_cotaskmem_string GetAppUserModelId(); diff --git a/dev/PushNotifications/PushNotifications.vcxitems b/dev/PushNotifications/PushNotifications.vcxitems index 118587af45..acf9dce25e 100644 --- a/dev/PushNotifications/PushNotifications.vcxitems +++ b/dev/PushNotifications/PushNotifications.vcxitems @@ -23,6 +23,7 @@ + @@ -36,6 +37,10 @@ + + + + \ No newline at end of file diff --git a/dev/PushNotifications/PushNotificationsLongRunningTask/PushNotificationsLongRunningTask.vcxproj b/dev/PushNotifications/PushNotificationsLongRunningTask/PushNotificationsLongRunningTask.vcxproj index 7f1a18296a..af3d8fe24b 100644 --- a/dev/PushNotifications/PushNotificationsLongRunningTask/PushNotificationsLongRunningTask.vcxproj +++ b/dev/PushNotifications/PushNotificationsLongRunningTask/PushNotificationsLongRunningTask.vcxproj @@ -123,7 +123,7 @@ WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) true stdcpp17 - %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory);$(OutDir)..\PushNotificationsLongRunningTask.ProxyStub;$(OutDir)..\WindowsAppSDK_BootstrapDLL + %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory);$(OutDir)..\PushNotificationsLongRunningTask.ProxyStub;$(OutDir)\..\WindowsAppRuntime_DLL;$(OutDir)..\WindowsAppSDK_BootstrapDLL Windows @@ -141,7 +141,7 @@ true stdcpp17 Guard - %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory);$(OutDir)..\PushNotificationsLongRunningTask.ProxyStub;$(OutDir)..\WindowsAppSDK_BootstrapDLL + %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory);$(OutDir)..\PushNotificationsLongRunningTask.ProxyStub;$(OutDir)\..\WindowsAppRuntime_DLL;$(OutDir)..\WindowsAppSDK_BootstrapDLL Windows @@ -158,7 +158,7 @@ _DEBUG;_WINDOWS;%(PreprocessorDefinitions) true stdcpp17 - %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory);$(OutDir)..\PushNotificationsLongRunningTask.ProxyStub;$(OutDir)..\WindowsAppSDK_BootstrapDLL + %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory);$(OutDir)..\PushNotificationsLongRunningTask.ProxyStub;$(OutDir)\..\WindowsAppRuntime_DLL;$(OutDir)..\WindowsAppSDK_BootstrapDLL Windows @@ -176,7 +176,7 @@ true stdcpp17 Guard - %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory);$(OutDir)..\PushNotificationsLongRunningTask.ProxyStub;$(OutDir)..\WindowsAppSDK_BootstrapDLL + %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory);$(OutDir)..\PushNotificationsLongRunningTask.ProxyStub;$(OutDir)\..\WindowsAppRuntime_DLL;$(OutDir)..\WindowsAppSDK_BootstrapDLL Windows @@ -193,7 +193,7 @@ _DEBUG;_WINDOWS;%(PreprocessorDefinitions) true stdcpp20 - %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory);$(OutDir)..\PushNotificationsLongRunningTask.ProxyStub;$(OutDir)..\WindowsAppSDK_BootstrapDLL + %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory);$(OutDir)..\PushNotificationsLongRunningTask.ProxyStub;$(OutDir)\..\WindowsAppRuntime_DLL;$(OutDir)..\WindowsAppSDK_BootstrapDLL Windows @@ -211,7 +211,7 @@ true Guard stdcpp20 - %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory);$(OutDir)..\PushNotificationsLongRunningTask.ProxyStub;$(OutDir)..\WindowsAppSDK_BootstrapDLL + %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory);$(OutDir)..\PushNotificationsLongRunningTask.ProxyStub;$(OutDir)\..\WindowsAppRuntime_DLL;$(OutDir)..\WindowsAppSDK_BootstrapDLL Windows diff --git a/dev/PushNotifications/externs.h b/dev/PushNotifications/externs.h index 090418cb8b..2217362df3 100644 --- a/dev/PushNotifications/externs.h +++ b/dev/PushNotifications/externs.h @@ -20,4 +20,3 @@ inline HRESULT GetCurrentProcessPath(wil::unique_cotaskmem_string& processName) { return wil::GetModuleFileNameExW(GetCurrentProcess(), nullptr, processName); }; - diff --git a/test/TestApps/PushNotificationsDemoApp/main.cpp b/test/TestApps/PushNotificationsDemoApp/main.cpp index ccdf58a866..2ad3518336 100644 --- a/test/TestApps/PushNotificationsDemoApp/main.cpp +++ b/test/TestApps/PushNotificationsDemoApp/main.cpp @@ -18,7 +18,7 @@ winrt::Windows::Foundation::IAsyncOperation RequestChan // To obtain an AAD RemoteIdentifier for your app, // follow the instructions on https://docs.microsoft.com/azure/active-directory/develop/quickstart-register-app auto channelOperation = PushNotificationManager::CreateChannelAsync( - winrt::guid("ccd2ae3f-764f-4ae3-be45-9804761b28b2")); + winrt::guid("0160ee84-0c53-4851-9ff2-d7f5a87ed914")); // Setup the inprogress event handler channelOperation.Progress(