Skip to content

Commit

Permalink
Implement Unregister APIs for PushNotificationManager
Browse files Browse the repository at this point in the history
  • Loading branch information
sharath2727 committed Feb 24, 2022
1 parent d6097f7 commit ae2a024
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 44 deletions.
176 changes: 133 additions & 43 deletions dev/PushNotifications/PushNotificationManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ constexpr std::wstring_view expectedPushServerArgs = L"----WindowsAppRuntimePush

static wil::unique_event g_waitHandleForArgs;
static winrt::guid g_comServerClsid{ GUID_NULL };
static bool registering{ false };

wil::unique_event& GetWaitHandleForArgs()
{
Expand Down Expand Up @@ -202,9 +203,17 @@ namespace winrt::Microsoft::Windows::PushNotifications::implementation
// Need to recreate the Foreground sinks since channel creation removes the old sink
RegisterForegroundSinkHelper();

auto channel{ winrt::make<PushNotificationChannel>(channelInfo) };
// { };

{
auto lock{ m_lock.lock_exclusive() };
m_channel = channel;
}

PushNotificationTelemetry::ChannelRequestedByApi(S_OK, remoteId);
co_return winrt::make<PushNotificationCreateChannelResult>(
winrt::make<PushNotificationChannel>(channelInfo),
channel,
S_OK,
PushNotificationChannelStatus::CompletedSuccess);
}
Expand Down Expand Up @@ -266,7 +275,6 @@ namespace winrt::Microsoft::Windows::PushNotifications::implementation

void PushNotificationManager::Register()
{
static bool registering{ false };
{
auto lock{ m_lock.lock_exclusive() };
THROW_HR_IF_MSG(E_FAIL, registering, "Registration is in progress!");
Expand Down Expand Up @@ -346,11 +354,9 @@ namespace winrt::Microsoft::Windows::PushNotifications::implementation
}
else
{
std::wstring processName;
{
auto lock{ m_lock.lock_shared() };
processName = m_processName.get();
THROW_HR_IF(E_INVALIDARG, m_lrpRegistration);
THROW_HR_IF(E_INVALIDARG, m_singletonForegroundRegistration && m_singletonBackgroundRegistration);
}

auto scopeExitToCleanRegistrations{ wil::scope_exit([&]()
Expand All @@ -359,35 +365,36 @@ namespace winrt::Microsoft::Windows::PushNotifications::implementation
auto lock { m_lock.lock_exclusive() };

m_comActivatorRegistration.reset();
m_lrpRegistration = false;
m_singletonBackgroundRegistration = false;
m_singletonForegroundRegistration = false;
registering = false;
}

auto notificationsLongRunningPlatform{ PushNotificationHelpers::GetNotificationPlatform() };
if (AppModel::Identity::IsPackagedProcess())
{
auto appUserModelId{ PushNotificationHelpers::GetAppUserModelId() };
LOG_IF_FAILED(PushNotifications_UnregisterNotificationSinkForFullTrustApplication(appUserModelId.get()));
}
else
{
LOG_IF_FAILED(notificationsLongRunningPlatform->UnregisterForegroundActivator(processName.c_str()));
}
LOG_IF_FAILED(notificationsLongRunningPlatform->UnregisterFullTrustApplication(processName.c_str()));
}
) };

LOG_IF_FAILED(notificationsLongRunningPlatform->UnregisterForegroundActivator(m_processName.get()));

LOG_IF_FAILED(notificationsLongRunningPlatform->UnregisterFullTrustApplication(m_processName.get()));
}) };

auto notificationPlatform{ PushNotificationHelpers::GetNotificationPlatform() };
wil::unique_cotaskmem_string unpackagedAppUserModelId;
// Apps treated as unpackaged need to call RegisterFullTrustApplication and register with the LRP
THROW_IF_FAILED(notificationPlatform->RegisterFullTrustApplication(processName.c_str(), GUID_NULL, &unpackagedAppUserModelId));
THROW_IF_FAILED(notificationPlatform->RegisterFullTrustApplication(m_processName.get(), GUID_NULL, &unpackagedAppUserModelId));

// Register a sink for the application to receive foreground raw notifications
RegisterForegroundSinkHelper();
{
auto lock{ m_lock.lock_exclusive() };
m_lrpRegistration = true;
m_singletonForegroundRegistration = true;
}

// Register a sink for the application to receive foreground raw notifications
RegisterForegroundSinkHelper();
// m_registeredClsid is set to GUID_NULL for unpackaged applications
THROW_IF_FAILED(notificationPlatform->RegisterLongRunningActivatorWithClsid(m_processName.get(), m_registeredClsid));
{
auto lock{ m_lock.lock_exclusive() };
m_singletonBackgroundRegistration = true;
}

// Register a COM object for the PushNotificationLongRunningProcess to CoCreate in background activation scenarios
if (AppModel::Identity::IsPackagedProcess())
Expand Down Expand Up @@ -418,22 +425,54 @@ namespace winrt::Microsoft::Windows::PushNotifications::implementation

void PushNotificationManager::Unregister()
{
try
{
auto lock{ m_lock.lock_exclusive() };

// Check for COM flag, a valid cookie
if (AppModel::Identity::IsPackagedProcess())
THROW_HR_IF_MSG(E_FAIL, registering, "Register or Unregister currently in progress!");
registering = true;
}

auto scope_exit = wil::scope_exit(
[&] {
auto lock{ m_lock.lock_exclusive() };
registering = false;
});

try
{
if (PushNotificationHelpers::IsPackagedAppScenario())
{
THROW_HR_IF_MSG(HRESULT_FROM_WIN32(ERROR_NOT_FOUND), !m_comActivatorRegistration, "ComActivator not registered.");
m_comActivatorRegistration.reset();
{
auto lock{ m_lock.lock_exclusive() };
THROW_HR_IF_MSG(E_FAIL, !m_comActivatorRegistration, "No active COM registration");
// m_comActivatorRegistration handles multiple unregistrations
m_comActivatorRegistration.reset();
}

auto appUserModelId{ PushNotificationHelpers::GetAppUserModelId() };
THROW_IF_FAILED(PushNotifications_UnregisterNotificationSinkForFullTrustApplication(appUserModelId.get()));
}
else if (!AppModel::Identity::IsPackagedProcess())
else
{
auto coInitialize{ wil::CoInitializeEx() };
auto notificationPlatform{ PushNotificationHelpers::GetNotificationPlatform() };
if (AppModel::Identity::IsPackagedProcess())
{
auto lock{ m_lock.lock_exclusive() };
THROW_HR_IF_MSG(E_FAIL, !m_comActivatorRegistration, "No active COM registration");
m_comActivatorRegistration.reset();
}

{
auto lock{ m_lock.lock_exclusive() };
THROW_HR_IF_MSG(E_FAIL, !m_singletonForegroundRegistration, "No foreground sink registered");
}

LOG_IF_FAILED(notificationPlatform->UnregisterForegroundActivator(m_processName.get()));
auto notificationsLongRunningPlatform{ PushNotificationHelpers::GetNotificationPlatform() };
// Unregister foreground sink with the Long Running Process Singelton
THROW_IF_FAILED(notificationsLongRunningPlatform->UnregisterForegroundActivator(m_processName.get()));

{
auto lock{ m_lock.lock_exclusive() };
m_singletonForegroundRegistration = false;
}
}
}
catch (...)
Expand All @@ -447,44 +486,95 @@ namespace winrt::Microsoft::Windows::PushNotifications::implementation

void PushNotificationManager::UnregisterAll()
{
try
bool unregisterCompleted{ false };
{
auto lock{ m_lock.lock_exclusive() };
unregisterCompleted = (!m_singletonForegroundRegistration || !m_comActivatorRegistration);
}

if (!unregisterCompleted)
{
Unregister();
}

{
auto lock{ m_lock.lock_exclusive() };
THROW_HR_IF_MSG(E_FAIL, registering, "Register or Unregister currently in progress!");
registering = true;
}

auto scope_exit = wil::scope_exit(
[&] {
auto lock{ m_lock.lock_exclusive() };
registering = false;
});

try
{
try
{
bool channelExists{ false };
{
auto lock{ m_lock.lock_exclusive() };
channelExists = (m_channel != nullptr) ? true : false;
}

if (channelExists)
{
auto lock{ m_lock.lock_exclusive() };
m_channel.Close();
}
}
catch (...)
{
LOG_IF_FAILED(wil::ResultFromCaughtException());
}


if (PushNotificationHelpers::IsPackagedAppScenario())
{
THROW_HR_IF_NULL_MSG(HRESULT_FROM_WIN32(ERROR_NOT_FOUND), m_pushTriggerRegistration, "PushTrigger not registered.");
{
auto lock{ m_lock.lock_exclusive() };
THROW_HR_IF_NULL(E_FAIL, m_pushTriggerRegistration);

m_pushTriggerRegistration.Unregister(true);
m_pushTriggerRegistration = nullptr;
m_pushTriggerRegistration.Unregister(true);
m_pushTriggerRegistration = nullptr;
}
}
else if (!AppModel::Identity::IsPackagedProcess())
else
{
THROW_HR_IF_MSG(HRESULT_FROM_WIN32(ERROR_NOT_FOUND), !m_lrpRegistration, "Not registered with the PushNotificationsLongRunningProcess.");
auto notificationsLongRunningPlatform{ PushNotificationHelpers::GetNotificationPlatform() };

auto coInitialize{ wil::CoInitializeEx() };
{
auto lock{ m_lock.lock_exclusive() };
THROW_HR_IF(E_FAIL, !m_singletonBackgroundRegistration);
}

auto notificationPlatform{ PushNotificationHelpers::GetNotificationPlatform() };
// Removes the Long Running Singleton sink registered with platform for both packaged and unpackaged applications
THROW_IF_FAILED(notificationsLongRunningPlatform->UnregisterLongRunningActivator(m_processName.get()));

LOG_IF_FAILED(notificationPlatform->UnregisterLongRunningActivator(m_processName.get()));
THROW_IF_FAILED(notificationsLongRunningPlatform->UnregisterFullTrustApplication(m_processName.get()));

m_lrpRegistration = false;
{
auto lock{ m_lock.lock_exclusive() };
m_singletonBackgroundRegistration = false;
}
}
}
catch (...)
{
PushNotificationTelemetry::ActivatorUnregisteredByApi(wil::ResultFromCaughtException());
throw;
}

PushNotificationTelemetry::ActivatorUnregisteredByApi(S_OK);
}

winrt::event_token PushNotificationManager::PushReceived(TypedEventHandler<winrt::Microsoft::Windows::PushNotifications::PushNotificationManager, winrt::Microsoft::Windows::PushNotifications::PushNotificationReceivedEventArgs> handler)
{
{
auto lock{ m_lock.lock_shared() };
THROW_HR_IF_MSG(HRESULT_FROM_WIN32(ERROR_NOT_FOUND), m_comActivatorRegistration || m_lrpRegistration, "Must register event handlers before calling Register().");
THROW_HR_IF_MSG(HRESULT_FROM_WIN32(ERROR_NOT_FOUND), m_comActivatorRegistration || m_singletonBackgroundRegistration, "Must register event handlers before calling Register().");
}

auto lock{ m_lock.lock_exclusive() };
Expand Down
4 changes: 3 additions & 1 deletion dev/PushNotifications/PushNotificationManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,12 @@ namespace winrt::Microsoft::Windows::PushNotifications::implementation
winrt::event<PushNotificationEventHandler> m_foregroundHandlers;
winrt::Windows::ApplicationModel::Background::IBackgroundTaskRegistration m_pushTriggerRegistration{ nullptr };
wil::unique_com_class_object_cookie m_comActivatorRegistration;
bool m_lrpRegistration{ false }; // Defines if the app is registered with the PushNotificationsLongRunningProcess
bool m_singletonBackgroundRegistration{ false }; // Defines if the long running process singleton has registered a sink with the platform for a given app
bool m_singletonForegroundRegistration{ false }; // Defines if the app has registered a foreground sink with the Long running process singleton
wil::srwlock m_lock;
wil::unique_cotaskmem_string m_processName;
winrt::guid m_registeredClsid{ GUID_NULL };
winrt::Microsoft::Windows::PushNotifications::PushNotificationChannel m_channel{ nullptr };
};
}

Expand Down

0 comments on commit ae2a024

Please sign in to comment.