Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
// 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;
using static Microsoft.Toolkit.Uwp.Notifications.NotificationActivator;

namespace Microsoft.Toolkit.Uwp.Notifications
{
Expand All @@ -23,12 +21,19 @@ public class DesktopNotificationManagerCompat
/// </summary>
public const string ToastActivatedLaunchArg = "-ToastActivated";

private const int CLASS_E_NOAGGREGATION = -2147221232;
private const int E_NOINTERFACE = -2147467262;
private const int CLSCTX_LOCAL_SERVER = 4;
private const int REGCLS_MULTIPLEUSE = 1;
private const int S_OK = 0;
private static readonly Guid IUnknownGuid = new Guid("00000000-0000-0000-C000-000000000046");

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
/// If you're not using MSIX or sparse packages, 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>
Expand Down Expand Up @@ -73,24 +78,85 @@ private static void RegisterComServer<T>(string exePath)
key.SetValue(null, '"' + exePath + '"' + " " + ToastActivatedLaunchArg);
}

/*
* RegisterActivator code and all internal dependencies is from FrecherxDachs.
* See entry #2 in ThirdPartyNotices.txt in root repository directory for full license. */

/// <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
where T : NotificationActivator, new()
{
// Register type
var regService = new RegistrationServices();

regService.RegisterTypeForComClients(
typeof(T),
RegistrationClassContext.LocalServer,
RegistrationConnectionType.MultipleUse);
// 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(
uuid,
new NotificationActivatorClassFactory<T>(),
CLSCTX_LOCAL_SERVER,
REGCLS_MULTIPLEUSE,
out cookie);

_registeredActivator = true;
}

[ComImport]
[Guid("00000001-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IClassFactory
{
[PreserveSig]
int CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject);

[PreserveSig]
int LockServer(bool fLock);
}

private class NotificationActivatorClassFactory<T> : IClassFactory
where T : NotificationActivator, new()
{
public int CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject)
{
ppvObject = IntPtr.Zero;

if (pUnkOuter != IntPtr.Zero)
{
Marshal.ThrowExceptionForHR(CLASS_E_NOAGGREGATION);
}

if (riid == typeof(T).GUID || riid == IUnknownGuid)
{
// Create the instance of the .NET object
ppvObject = Marshal.GetComInterfaceForObject(
new T(),
typeof(INotificationActivationCallback));
}
else
{
// The object that ppvObject points to does not support the
// interface identified by riid.
Marshal.ThrowExceptionForHR(E_NOINTERFACE);
}

return S_OK;
}

public int LockServer(bool fLock)
{
return S_OK;
}
}

[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);

/// <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>
Expand Down Expand Up @@ -151,7 +217,7 @@ private static void EnsureRegistered()
}

/// <summary>
/// Gets a value indicating whether http images can be used within toasts. This is true if running under Desktop Bridge.
/// Gets a value indicating whether http images can be used within toasts. This is true if running with package identity (MSIX or sparse package).
/// </summary>
public static bool CanUseHttpImages
{
Expand Down Expand Up @@ -206,4 +272,4 @@ private static bool IsWindows7OrLower
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="MSBuild.Sdk.Extras">

<PropertyGroup>
<TargetFrameworks>netstandard1.4;uap10.0;native;net461</TargetFrameworks>
<TargetFrameworks>netstandard1.4;uap10.0;native;net461;netcoreapp3.0</TargetFrameworks>
<DefineConstants>$(DefineConstants);NETFX_CORE</DefineConstants>
<Title>Windows Community Toolkit Notifications</Title>
<Description>
Expand All @@ -14,6 +14,35 @@
<PackageTags>notifications win10 windows 10 tile tiles toast toasts badge xml uwp c# csharp c++</PackageTags>
<ExtrasImplicitPlatformPackageIsPrivate Condition=" '$(TargetFramework)' == 'native' ">true</ExtrasImplicitPlatformPackageIsPrivate>
</PropertyGroup>

<Choose>

<!--Desktop Win32 apps-->
<When Condition="'$(TargetFramework)'=='net461' or '$(TargetFramework)'=='netcoreapp3.0'">
<ItemGroup>
<!--Reference Windows SDK NuGet of correct target platform version-->
<PackageReference Include="Microsoft.Windows.SDK.Contracts" Version="10.0.17763.1000" />
</ItemGroup>
<PropertyGroup>
<!--Define the WINDOWS_UWP conditional symbol, since the Windows.Data.Xml and the Windows.UI.Notification namespaces are available-->
<DefineConstants>$(DefineConstants);WINDOWS_UWP</DefineConstants>
</PropertyGroup>
</When>

<!--Non-desktop apps (UWP, libraries, ASP.NET servers)-->
<Otherwise>
<ItemGroup>
<!--Remove the DesktopNotificationManager code-->
<Compile Remove="DesktopNotificationManager\**\*" />
</ItemGroup>
</Otherwise>

</Choose>

<!--NET Core desktop apps also need the Registry NuGet package-->
<ItemGroup Condition="'$(TargetFramework)'=='netcoreapp3.0'">
<PackageReference Include="Microsoft.Win32.Registry" Version="4.7.0" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'native' ">
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform" Version="$(ExtrasUwpMetaPackageVersion)" PrivateAssets="all" IsImplicitlyDefined="true" />
Expand All @@ -27,20 +56,6 @@
<PackageReference Include="System.ValueTuple" Version="4.4.0" />
</ItemGroup>

<ItemGroup Condition="!('$(TargetFramework)'=='net461')">
<Compile Remove="DesktopNotificationManager\**\*" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)'=='net461'">
<Reference Include="System" />
<Reference Include="System.Runtime" />
<Reference Include="Windows">
<HintPath Condition="Exists('$(MSBuildProgramFiles32)\Windows Kits\10\UnionMetadata\$(TargetPlatformVersion)\Windows.winmd')">$(MSBuildProgramFiles32)\Windows Kits\10\UnionMetadata\$(TargetPlatformVersion)\Windows.winmd</HintPath>
<IsWinMDFile>true</IsWinMDFile>
<Private>False</Private>
</Reference>
</ItemGroup>

<PropertyGroup Condition="'$(TargetFramework)' == 'native'">
<OutputType>winmdobj</OutputType>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
Expand Down
27 changes: 27 additions & 0 deletions ThirdPartyNotices.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Do Not Translate or Localize
This project incorporates components from the projects listed below. The original copyright notices and the licenses under which the .NET Foundation received such components are set forth below. The .NET Foundation reserves all rights not expressly granted herein, whether by implication, estoppel or otherwise.

1. PedroLamas/DeferredEvents version 1.0.4 (https://github.com/PedroLamas/DeferredEvents)
2. MichaeIDietrich/UwpNotificationNetCoreTest commit 5c1a4a3 (https://github.com/MichaeIDietrich/UwpNotificationNetCoreTest), used in DesktopNotificationManagerCompat.cs to support .NET Core 3.0.

%% PedroLamas/DeferredEvents NOTICES AND INFORMATION BEGIN HERE
=========================================
Expand All @@ -30,3 +31,29 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
=========================================
END OF PedroLamas/DeferredEvents NOTICES AND INFORMATION

%% MichaeIDietrich/UwpNotificationNetCoreTest NOTICES AND INFORMATION BEGIN HERE
=========================================
The MIT License (MIT)

Copyright (c) 2020 Michael Dietrich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
=========================================
END OF FrecherxDachs/UwpNotificationNetCoreTest NOTICES AND INFORMATION