Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Directory.Build.targets
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<Choose>
<When Condition="'$(TargetFramework)' == 'uap10.0' or '$(TargetFramework)' == 'uap10.0.16299' or '$(TargetFramework)' == 'native'">
<When Condition="'$(TargetFramework)' == 'uap10.0' or '$(TargetFramework)' == 'uap10.0.16299' or '$(TargetFramework)' == 'native' or '$(TargetFramework)' == 'net461'">
<!-- UAP versions for uap10.0 where TPMV isn't implied -->
<PropertyGroup>
<TargetPlatformVersion>10.0.$(DefaultTargetPlatformVersion).0</TargetPlatformVersion>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Collections.Generic;
using Windows.UI.Notifications;

namespace Microsoft.Toolkit.Uwp.Notifications
{
/// <summary>
/// Manages the toast notifications for an app including the ability the clear all toast history and removing individual toasts.
/// </summary>
public sealed class DesktopNotificationHistoryCompat
{
private string _aumid;
private ToastNotificationHistory _history;

/// <summary>
/// Initializes a new instance of the <see cref="DesktopNotificationHistoryCompat"/> class.
/// Do not call this. Instead, call <see cref="DesktopNotificationManagerCompat.History"/> to obtain an instance.
/// </summary>
/// <param name="aumid">An AUMID that uniquely identifies your application.</param>
internal DesktopNotificationHistoryCompat(string aumid)
{
_aumid = aumid;
_history = ToastNotificationManager.History;
}

/// <summary>
/// Removes all notifications sent by this app from action center.
/// </summary>
public void Clear()
{
if (_aumid != null)
{
_history.Clear(_aumid);
}
else
{
_history.Clear();
}
}

/// <summary>
/// Gets all notifications sent by this app that are currently still in Action Center.
/// </summary>
/// <returns>A collection of toasts.</returns>
public IReadOnlyList<ToastNotification> GetHistory()
{
return _aumid != null ? _history.GetHistory(_aumid) : _history.GetHistory();
}

/// <summary>
/// Removes an individual toast, with the specified tag label, from action center.
/// </summary>
/// <param name="tag">The tag label of the toast notification to be removed.</param>
public void Remove(string tag)
{
if (_aumid != null)
{
_history.Remove(tag, string.Empty, _aumid);
}
else
{
_history.Remove(tag);
}
}

/// <summary>
/// Removes a toast notification from the action using the notification's tag and group labels.
/// </summary>
/// <param name="tag">The tag label of the toast notification to be removed.</param>
/// <param name="group">The group label of the toast notification to be removed.</param>
public void Remove(string tag, string group)
{
if (_aumid != null)
{
_history.Remove(tag, group, _aumid);
}
else
{
_history.Remove(tag, group);
}
}

/// <summary>
/// Removes a group of toast notifications, identified by the specified group label, from action center.
/// </summary>
/// <param name="group">The group label of the toast notifications to be removed.</param>
public void RemoveGroup(string group)
{
if (_aumid != null)
{
_history.RemoveGroup(group, _aumid);
}
else
{
_history.RemoveGroup(group);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Windows.UI.Notifications;

namespace Microsoft.Toolkit.Uwp.Notifications
{
/// <summary>
/// Helper for .NET Framework applications to display toast notifications and respond to toast events
/// </summary>
public class DesktopNotificationManagerCompat
{
/// <summary>
/// A constant that is used as the launch arg when your EXE is launched from a toast notification.
/// </summary>
public const string ToastActivatedLaunchArg = "-ToastActivated";

private static bool _registeredAumidAndComServer;
private static string _aumid;
private static bool _registeredActivator;

/// <summary>
/// If not running under the Desktop Bridge, you must call this method to register your AUMID with the Compat library and to
/// register your COM CLSID and EXE in LocalServer32 registry. Feel free to call this regardless, and we will no-op if running
/// under Desktop Bridge. Call this upon application startup, before calling any other APIs.
/// </summary>
/// <typeparam name="T">Your implementation of NotificationActivator. Must have GUID and ComVisible attributes on class.</typeparam>
/// <param name="aumid">An AUMID that uniquely identifies your application.</param>
public static void RegisterAumidAndComServer<T>(string aumid)
where T : NotificationActivator
{
if (string.IsNullOrWhiteSpace(aumid))
{
throw new ArgumentException("You must provide an AUMID.", nameof(aumid));
}

// If running as Desktop Bridge
if (DesktopBridgeHelpers.IsRunningAsUwp())
{
// Clear the AUMID since Desktop Bridge doesn't use it, and then we're done.
// Desktop Bridge apps are registered with platform through their manifest.
// Their LocalServer32 key is also registered through their manifest.
_aumid = null;
_registeredAumidAndComServer = true;
return;
}

_aumid = aumid;

string exePath = Process.GetCurrentProcess().MainModule.FileName;
RegisterComServer<T>(exePath);

_registeredAumidAndComServer = true;
}

private static void RegisterComServer<T>(string exePath)
where T : NotificationActivator
{
// We register the EXE to start up when the notification is activated
string regString = string.Format("SOFTWARE\\Classes\\CLSID\\{{{0}}}\\LocalServer32", typeof(T).GUID);
var key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(regString);

// Include a flag so we know this was a toast activation and should wait for COM to process
// We also wrap EXE path in quotes for extra security
key.SetValue(null, '"' + exePath + '"' + " " + ToastActivatedLaunchArg);
}

/// <summary>
/// Registers the activator type as a COM server client so that Windows can launch your activator.
/// </summary>
/// <typeparam name="T">Your implementation of NotificationActivator. Must have GUID and ComVisible attributes on class.</typeparam>
public static void RegisterActivator<T>()
where T : NotificationActivator
{
// Register type
var regService = new RegistrationServices();

regService.RegisterTypeForComClients(
typeof(T),
RegistrationClassContext.LocalServer,
RegistrationConnectionType.MultipleUse);

_registeredActivator = true;
}

/// <summary>
/// Creates a toast notifier. You must have called <see cref="RegisterActivator{T}"/> first (and also <see cref="RegisterAumidAndComServer(string)"/> if you're a classic Win32 app), or this will throw an exception.
/// </summary>
/// <returns><see cref="ToastNotifier"/></returns>
public static ToastNotifier CreateToastNotifier()
{
EnsureRegistered();

if (_aumid != null)
{
// Non-Desktop Bridge
return ToastNotificationManager.CreateToastNotifier(_aumid);
}
else
{
// Desktop Bridge
return ToastNotificationManager.CreateToastNotifier();
}
}

/// <summary>
/// Gets the <see cref="DesktopNotificationHistoryCompat"/> object. You must have called <see cref="RegisterActivator{T}"/> first (and also <see cref="RegisterAumidAndComServer(string)"/> if you're a classic Win32 app), or this will throw an exception.
/// </summary>
public static DesktopNotificationHistoryCompat History
{
get
{
EnsureRegistered();

return new DesktopNotificationHistoryCompat(_aumid);
}
}

private static void EnsureRegistered()
{
// If not registered AUMID yet
if (!_registeredAumidAndComServer)
{
// Check if Desktop Bridge
if (DesktopBridgeHelpers.IsRunningAsUwp())
{
// Implicitly registered, all good!
_registeredAumidAndComServer = true;
}
else
{
// Otherwise, incorrect usage
throw new Exception("You must call RegisterAumidAndComServer first.");
}
}

// If not registered activator yet
if (!_registeredActivator)
{
// Incorrect usage
throw new Exception("You must call RegisterActivator first.");
}
}

/// <summary>
/// Gets a value indicating whether http images can be used within toasts. This is true if running under Desktop Bridge.
/// </summary>
public static bool CanUseHttpImages
{
get { return DesktopBridgeHelpers.IsRunningAsUwp(); }
}

/// <summary>
/// Code from https://github.com/qmatteoq/DesktopBridgeHelpers/edit/master/DesktopBridge.Helpers/Helpers.cs
/// </summary>
private class DesktopBridgeHelpers
{
private const long APPMODEL_ERROR_NO_PACKAGE = 15700L;

[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int GetCurrentPackageFullName(ref int packageFullNameLength, StringBuilder packageFullName);

private static bool? _isRunningAsUwp;

public static bool IsRunningAsUwp()
{
if (_isRunningAsUwp == null)
{
if (IsWindows7OrLower)
{
_isRunningAsUwp = false;
}
else
{
int length = 0;
StringBuilder sb = new StringBuilder(0);
int result = GetCurrentPackageFullName(ref length, sb);

sb = new StringBuilder(length);
result = GetCurrentPackageFullName(ref length, sb);

_isRunningAsUwp = result != APPMODEL_ERROR_NO_PACKAGE;
}
}

return _isRunningAsUwp.Value;
}

private static bool IsWindows7OrLower
{
get
{
int versionMajor = Environment.OSVersion.Version.Major;
int versionMinor = Environment.OSVersion.Version.Minor;
double version = versionMajor + ((double)versionMinor / 10);
return version <= 6.1;
}
}
}
}
}
Loading