diff --git a/Directory.Build.targets b/Directory.Build.targets
index ab132c6cf4c..2101233710b 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -1,19 +1,21 @@
- true
+ true
-
+
+
true
$(MSBuildThisFileDirectory)toolkit.snk
-
-
+
+
+
diff --git a/Microsoft.Toolkit.Uwp.Notifications/Microsoft.Toolkit.Uwp.Notifications.csproj b/Microsoft.Toolkit.Uwp.Notifications/Microsoft.Toolkit.Uwp.Notifications.csproj
index 64b54d1d3c1..c980f7c4205 100644
--- a/Microsoft.Toolkit.Uwp.Notifications/Microsoft.Toolkit.Uwp.Notifications.csproj
+++ b/Microsoft.Toolkit.Uwp.Notifications/Microsoft.Toolkit.Uwp.Notifications.csproj
@@ -1,22 +1,10 @@
-
-
- netstandard1.4;uap10.0;net461;netcoreapp3.1
+ netstandard1.4;uap10.0.19041;net461;netcoreapp3.1;net5.0;net5.0-windows10.0.17763.0;native
$(DefineConstants);NETFX_CORE
- Windows Community Toolkit Notifications
-
- Generate tile, toast, and badge notifications for Windows 10 via code, with the help of IntelliSense.
- Adds Support for adaptive tiles and adaptive/interactive toasts for Windows 10. It is part of the Windows Community Toolkit.
- Supports C# and C++ UWP project types.
- Also works with C# portable class libraries and non-UWP C# projects like server projects.
- This project contains outputs for netstandard1.4, uap10.0 and native for WinRT.
-
- notifications win10 windows 10 tile tiles toast toasts badge xml uwp c# csharp c++
true
- 10240
- 10.0.10240.0
+ Microsoft.Toolkit.Uwp.Notifications.nuspec
@@ -27,16 +15,17 @@
-
-
- $(DefineConstants);WINDOWS_UWP;WIN32
-
+
+
+
+ $(DefineConstants);WINDOWS_UWP;WIN32
+
-
+
@@ -54,6 +43,12 @@
+
+
+ 10.0.19041.0
+ 16299
+ 10.0.16299.0
+
winmdobj
@@ -63,8 +58,9 @@
native
UAP,Version=v10.0
uap10.0
- 10.0.19041.0
- 10.0.10240.0
+ 10.0.19041.0
+ 10240
+ 10.0.10240.0
$(DefineConstants);NETFX_CORE;WINDOWS_UWP;WINRT
false
.NETCore
@@ -76,5 +72,12 @@
UAP$(TargetPlatformMinVersion.Replace('.', '_'))
true
+
+
+
+
+ buildOutput=bin\$(Configuration);version=$(Version)
+
+
diff --git a/Microsoft.Toolkit.Uwp.Notifications/Microsoft.Toolkit.Uwp.Notifications.nuspec b/Microsoft.Toolkit.Uwp.Notifications/Microsoft.Toolkit.Uwp.Notifications.nuspec
new file mode 100644
index 00000000000..7778144f3cb
--- /dev/null
+++ b/Microsoft.Toolkit.Uwp.Notifications/Microsoft.Toolkit.Uwp.Notifications.nuspec
@@ -0,0 +1,84 @@
+
+
+
+ Microsoft.Toolkit.Uwp.Notifications
+ $version$
+ Windows Community Toolkit Notifications
+ Microsoft.Toolkit,dotnetfoundation
+ true
+ https://github.com/windows-toolkit/WindowsCommunityToolkit/blob/master/license.md
+ https://github.com/windows-toolkit/WindowsCommunityToolkit
+ https://raw.githubusercontent.com/windows-toolkit/WindowsCommunityToolkit/master/build/nuget.png
+ The official way to send toast notifications on Windows 10 via code rather than XML, with the help of IntelliSense. Supports all C# app types, including WPF, UWP, WinForms, and Console, even without packaging your app as MSIX. Also supports C++ UWP apps.
+
+ Additionally, generate notification payloads from your ASP.NET web server to send as push notifications, or generate notification payloads from class libraries.
+
+ For UWP/MSIX apps, you can also generate tile and badge notifications.
+ https://github.com/windows-toolkit/WindowsCommunityToolkit/releases
+ (c) .NET Foundation and Contributors. All rights reserved.
+ notifications win10 windows 10 tile tiles toast toasts badge xml uwp c# csharp c++ wpf winforms
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Microsoft.Toolkit.Uwp.Notifications/Toasts/Compat/Desktop/DesktopBridgeHelpers.cs b/Microsoft.Toolkit.Uwp.Notifications/Toasts/Compat/Desktop/DesktopBridgeHelpers.cs
index 6134db08869..500d0418cd2 100644
--- a/Microsoft.Toolkit.Uwp.Notifications/Toasts/Compat/Desktop/DesktopBridgeHelpers.cs
+++ b/Microsoft.Toolkit.Uwp.Notifications/Toasts/Compat/Desktop/DesktopBridgeHelpers.cs
@@ -20,9 +20,6 @@ internal 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? _hasIdentity;
public static bool HasIdentity()
@@ -37,10 +34,10 @@ public static bool HasIdentity()
{
int length = 0;
var sb = new StringBuilder(0);
- GetCurrentPackageFullName(ref length, sb);
+ NativeMethods.GetCurrentPackageFullName(ref length, sb);
sb = new StringBuilder(length);
- int error = GetCurrentPackageFullName(ref length, sb);
+ int error = NativeMethods.GetCurrentPackageFullName(ref length, sb);
_hasIdentity = error != APPMODEL_ERROR_NO_PACKAGE;
}
diff --git a/Microsoft.Toolkit.Uwp.Notifications/Toasts/Compat/Desktop/DesktopNotificationManagerCompat.cs b/Microsoft.Toolkit.Uwp.Notifications/Toasts/Compat/Desktop/DesktopNotificationManagerCompat.cs
index 38359aa56dc..164c50e8672 100644
--- a/Microsoft.Toolkit.Uwp.Notifications/Toasts/Compat/Desktop/DesktopNotificationManagerCompat.cs
+++ b/Microsoft.Toolkit.Uwp.Notifications/Toasts/Compat/Desktop/DesktopNotificationManagerCompat.cs
@@ -50,7 +50,7 @@ public static void RegisterAumidAndComServer(string aumid)
}
// If running as Desktop Bridge
- if (DesktopBridgeHelpers.IsRunningAsUwp())
+ if (DesktopBridgeHelpers.HasIdentity())
{
// 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.
@@ -94,7 +94,7 @@ public static void RegisterActivator()
// Big thanks to FrecherxDachs for figuring out the following code which works in .NET Core 3: https://github.com/FrecherxDachs/UwpNotificationNetCoreTest
var uuid = typeof(T).GUID;
uint cookie;
- CoRegisterClassObject(
+ NativeMethods.CoRegisterClassObject(
uuid,
new NotificationActivatorClassFactory(),
CLSCTX_LOCAL_SERVER,
@@ -151,14 +151,6 @@ public int LockServer(bool fLock)
}
}
- [DllImport("ole32.dll")]
- private static extern int CoRegisterClassObject(
- [MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
- [MarshalAs(UnmanagedType.IUnknown)] object pUnk,
- uint dwClsContext,
- uint flags,
- out uint lpdwRegister);
-
///
/// Creates a toast notifier. You must have called first (and also if you're a classic Win32 app), or this will throw an exception.
///
@@ -198,7 +190,7 @@ private static void EnsureRegistered()
if (!_registeredAumidAndComServer)
{
// Check if Desktop Bridge
- if (DesktopBridgeHelpers.IsRunningAsUwp())
+ if (DesktopBridgeHelpers.HasIdentity())
{
// Implicitly registered, all good!
_registeredAumidAndComServer = true;
@@ -223,55 +215,7 @@ private static void EnsureRegistered()
///
public static bool CanUseHttpImages
{
- get { return DesktopBridgeHelpers.IsRunningAsUwp(); }
- }
-
- ///
- /// Code from https://github.com/qmatteoq/DesktopBridgeHelpers/tree/master/DesktopBridge.Helpers/Helpers.cs
- ///
- 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;
- var sb = new StringBuilder(0);
- GetCurrentPackageFullName(ref length, sb);
-
- sb = new StringBuilder(length);
- int error = GetCurrentPackageFullName(ref length, sb);
-
- _isRunningAsUwp = error != 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;
- }
- }
+ get { return DesktopBridgeHelpers.HasIdentity(); }
}
}
}
diff --git a/Microsoft.Toolkit.Uwp.Notifications/Toasts/Compat/Desktop/Native/NativeMethods.cs b/Microsoft.Toolkit.Uwp.Notifications/Toasts/Compat/Desktop/Native/NativeMethods.cs
new file mode 100644
index 00000000000..2de3b811bb7
--- /dev/null
+++ b/Microsoft.Toolkit.Uwp.Notifications/Toasts/Compat/Desktop/Native/NativeMethods.cs
@@ -0,0 +1,32 @@
+// 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.
+
+#if WIN32
+
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace Microsoft.Toolkit.Uwp.Notifications
+{
+ internal class NativeMethods
+ {
+ [DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool DeleteObject([In] IntPtr hObject);
+
+ [DllImport("ole32.dll")]
+ internal static extern int CoRegisterClassObject(
+ [MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
+ [MarshalAs(UnmanagedType.IUnknown)] object pUnk,
+ uint dwClsContext,
+ uint flags,
+ out uint lpdwRegister);
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
+ internal static extern int GetCurrentPackageFullName(ref int packageFullNameLength, StringBuilder packageFullName);
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/Microsoft.Toolkit.Uwp.Notifications/Toasts/Compat/Desktop/Win32AppInfo.cs b/Microsoft.Toolkit.Uwp.Notifications/Toasts/Compat/Desktop/Win32AppInfo.cs
index 44a5a3f2344..b4fabd2d43d 100644
--- a/Microsoft.Toolkit.Uwp.Notifications/Toasts/Compat/Desktop/Win32AppInfo.cs
+++ b/Microsoft.Toolkit.Uwp.Notifications/Toasts/Compat/Desktop/Win32AppInfo.cs
@@ -84,7 +84,7 @@ public static Win32AppInfo Get()
{
}
- DeleteObject(nativeHBitmap);
+ NativeMethods.DeleteObject(nativeHBitmap);
}
}
catch
@@ -231,10 +231,6 @@ private static bool IsAlphaBitmap(Bitmap bmp, out BitmapData bmpData)
return false;
}
- [DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
- [return: MarshalAs(UnmanagedType.Bool)]
- private static extern bool DeleteObject([In] IntPtr hObject);
-
///
/// From https://stackoverflow.com/a/41622689/1454643
/// Generates Guid based on String. Key assumption for this algorithm is that name is unique (across where it it's being used)
diff --git a/Microsoft.Toolkit.Uwp.Notifications/Toasts/Compat/ToastNotificationManagerCompat.cs b/Microsoft.Toolkit.Uwp.Notifications/Toasts/Compat/ToastNotificationManagerCompat.cs
index 74d45d901ac..758746a7624 100644
--- a/Microsoft.Toolkit.Uwp.Notifications/Toasts/Compat/ToastNotificationManagerCompat.cs
+++ b/Microsoft.Toolkit.Uwp.Notifications/Toasts/Compat/ToastNotificationManagerCompat.cs
@@ -59,7 +59,7 @@ public static event OnActivated OnActivated
}
catch (Exception ex)
{
- _initializeEx = ex;
+ _initializeEx = new InvalidOperationException("Failed to register notification activator", ex);
}
}
@@ -108,7 +108,7 @@ internal static void OnActivatedInternal(string args, Internal.InternalNotificat
private static string _win32Aumid;
private static string _clsid;
- private static Exception _initializeEx;
+ private static InvalidOperationException _initializeEx;
static ToastNotificationManagerCompat()
{
@@ -119,7 +119,7 @@ static ToastNotificationManagerCompat()
catch (Exception ex)
{
// We catch the exception so that things like subscribing to the event handler doesn't crash app
- _initializeEx = ex;
+ _initializeEx = new InvalidOperationException("Failed initializing notifications", ex);
}
}
@@ -251,7 +251,7 @@ private static void RegisterActivator(Type activatorType)
// Big thanks to FrecherxDachs for figuring out the following code which works in .NET Core 3: https://github.com/FrecherxDachs/UwpNotificationNetCoreTest
var uuid = activatorType.GUID;
- CoRegisterClassObject(
+ NativeMethods.CoRegisterClassObject(
uuid,
new NotificationActivatorClassFactory(activatorType),
CLSCTX_LOCAL_SERVER,
@@ -262,12 +262,36 @@ private static void RegisterActivator(Type activatorType)
private static void RegisterComServer(Type activatorType, string exePath)
{
// We register the EXE to start up when the notification is activated
- string regString = string.Format("SOFTWARE\\Classes\\CLSID\\{{{0}}}\\LocalServer32", activatorType.GUID);
- var key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(regString);
+ string regString = string.Format("SOFTWARE\\Classes\\CLSID\\{{{0}}}", activatorType.GUID);
+ using (var key = Registry.CurrentUser.CreateSubKey(regString + "\\LocalServer32"))
+ {
+ // 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 + '"' + " " + TOAST_ACTIVATED_LAUNCH_ARG);
+ }
+
+ if (IsElevated)
+ {
+ //// For elevated apps, we need to ensure they'll activate in existing running process by adding
+ //// some values in local machine
+ using (var key = Registry.LocalMachine.CreateSubKey(regString))
+ {
+ // Same as above, except also including AppId to link to our AppId entry below
+ using (var localServer32 = key.CreateSubKey("LocalServer32"))
+ {
+ localServer32.SetValue(null, '"' + exePath + '"' + " " + TOAST_ACTIVATED_LAUNCH_ARG);
+ }
- // 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 + '"' + " " + TOAST_ACTIVATED_LAUNCH_ARG);
+ key.SetValue("AppId", "{" + activatorType.GUID + "}");
+ }
+
+ // This tells COM to match any client, so Action Center will activate our elevated process.
+ // More info: https://docs.microsoft.com/windows/win32/com/runas
+ using (var key = Registry.LocalMachine.CreateSubKey(string.Format("SOFTWARE\\Classes\\AppID\\{{{0}}}", activatorType.GUID)))
+ {
+ key.SetValue("RunAs", "Interactive User");
+ }
+ }
}
///
@@ -332,13 +356,13 @@ public int LockServer(bool fLock)
}
}
- [DllImport("ole32.dll")]
- private static extern int CoRegisterClassObject(
- [MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
- [MarshalAs(UnmanagedType.IUnknown)] object pUnk,
- uint dwClsContext,
- uint flags,
- out uint lpdwRegister);
+ private static bool IsElevated
+ {
+ get
+ {
+ return new System.Security.Principal.WindowsPrincipal(System.Security.Principal.WindowsIdentity.GetCurrent()).IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator);
+ }
+ }
#endif
///
@@ -460,7 +484,32 @@ public static void Uninstall()
{
if (_clsid != null)
{
- Registry.CurrentUser.DeleteSubKey(string.Format("SOFTWARE\\Classes\\CLSID\\{{{0}}}\\LocalServer32", _clsid));
+ try
+ {
+ Registry.CurrentUser.DeleteSubKeyTree(string.Format("SOFTWARE\\Classes\\CLSID\\{{{0}}}", _clsid));
+ }
+ catch
+ {
+ }
+
+ if (IsElevated)
+ {
+ try
+ {
+ Registry.LocalMachine.DeleteSubKeyTree(string.Format("SOFTWARE\\Classes\\CLSID\\{{{0}}}", _clsid));
+ }
+ catch
+ {
+ }
+
+ try
+ {
+ Registry.LocalMachine.DeleteSubKeyTree(string.Format("SOFTWARE\\Classes\\AppID\\{{{0}}}", _clsid));
+ }
+ catch
+ {
+ }
+ }
}
}
catch
diff --git a/global.json b/global.json
index 80d84a257c6..a3d78890e48 100644
--- a/global.json
+++ b/global.json
@@ -1,5 +1,5 @@
{
"msbuild-sdks": {
- "MSBuild.Sdk.Extras": "2.0.54"
+ "MSBuild.Sdk.Extras": "3.0.22"
}
}
\ No newline at end of file