diff --git a/src/AppVNext.Notifier.ConsoleUwp.Setup/AppVNext.Notifier.ConsoleUwp.Setup.wixproj b/src/AppVNext.Notifier.ConsoleUwp.Setup/AppVNext.Notifier.ConsoleUwp.Setup.wixproj
new file mode 100644
index 0000000..0a66339
--- /dev/null
+++ b/src/AppVNext.Notifier.ConsoleUwp.Setup/AppVNext.Notifier.ConsoleUwp.Setup.wixproj
@@ -0,0 +1,50 @@
+
+
+
+ Debug
+ x86
+ 3.10
+ 6592e67d-a611-4643-b73f-3f1a7c1c5f50
+ 2.0
+ Notifier
+ Package
+ AppVNext.Notifier.ConsoleUwp.Setup
+
+
+ bin\$(Configuration)\
+ obj\$(Configuration)\
+ Debug
+ True
+
+
+ bin\$(Configuration)\
+ obj\$(Configuration)\
+ True
+
+
+
+
+
+
+ AppVNext.Notifier.ConsoleUwp
+ {9ebf043a-3ff8-46cb-a204-3e3bdf35ed49}
+ True
+ True
+ Binaries;Content;Satellites
+ INSTALLFOLDER
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/AppVNext.Notifier.ConsoleUwp.Setup/Product.wxs b/src/AppVNext.Notifier.ConsoleUwp.Setup/Product.wxs
new file mode 100644
index 0000000..50fb2e2
--- /dev/null
+++ b/src/AppVNext.Notifier.ConsoleUwp.Setup/Product.wxs
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/AppVNext.Notifier.ConsoleUwp/App.config b/src/AppVNext.Notifier.ConsoleUwp/App.config
new file mode 100644
index 0000000..ac79024
--- /dev/null
+++ b/src/AppVNext.Notifier.ConsoleUwp/App.config
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/AppVNext.Notifier.ConsoleUwp/AppVNext.Notifier.ConsoleUwp.csproj b/src/AppVNext.Notifier.ConsoleUwp/AppVNext.Notifier.ConsoleUwp.csproj
new file mode 100644
index 0000000..afa789b
--- /dev/null
+++ b/src/AppVNext.Notifier.ConsoleUwp/AppVNext.Notifier.ConsoleUwp.csproj
@@ -0,0 +1,176 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {9EBF043A-3FF8-46CB-A204-3E3BDF35ED49}
+ Exe
+ AppVNext.Notifier.ConsoleUwp
+ notifier
+ v4.6.1
+ 10.0.10240.0
+ 512
+ true
+
+
+
+
+
+ x64
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+ Icon.ico
+
+
+
+ ..\packages\Microsoft.Toolkit.Uwp.Notifications.4.0.0\lib\netstandard1.4\Microsoft.Toolkit.Uwp.Notifications.dll
+
+
+ ..\packages\Microsoft.Win32.Primitives.4.3.0\lib\net46\Microsoft.Win32.Primitives.dll
+
+
+ ..\packages\Microsoft.Win32.Registry.4.5.0\lib\net461\Microsoft.Win32.Registry.dll
+
+
+ ..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll
+
+
+ ..\packages\QueryString.NET.1.0.0\lib\dotnet\QueryString.NETCore.dll
+
+
+
+ ..\packages\System.AppContext.4.3.0\lib\net46\System.AppContext.dll
+
+
+
+ ..\packages\System.Console.4.3.1\lib\net46\System.Console.dll
+
+
+
+ ..\packages\System.Diagnostics.DiagnosticSource.4.5.0\lib\net46\System.Diagnostics.DiagnosticSource.dll
+
+
+ ..\packages\System.Globalization.Calendars.4.3.0\lib\net46\System.Globalization.Calendars.dll
+
+
+ ..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll
+
+
+
+ ..\packages\System.IO.Compression.ZipFile.4.3.0\lib\net46\System.IO.Compression.ZipFile.dll
+
+
+ ..\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll
+
+
+ ..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll
+
+
+ ..\packages\System.Net.Http.4.3.3\lib\net46\System.Net.Http.dll
+
+
+ ..\packages\System.Net.Sockets.4.3.0\lib\net46\System.Net.Sockets.dll
+
+
+
+ ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll
+
+
+ ..\packages\System.Security.AccessControl.4.5.0\lib\net461\System.Security.AccessControl.dll
+
+
+ ..\packages\System.Security.Cryptography.Algorithms.4.3.1\lib\net461\System.Security.Cryptography.Algorithms.dll
+
+
+ ..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll
+
+
+ ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll
+
+
+ ..\packages\System.Security.Cryptography.X509Certificates.4.3.2\lib\net461\System.Security.Cryptography.X509Certificates.dll
+
+
+ ..\packages\System.Security.Principal.Windows.4.5.0\lib\net461\System.Security.Principal.Windows.dll
+
+
+
+
+
+
+
+ 4.0
+
+
+ ..\packages\System.Xml.ReaderWriter.4.3.1\lib\net46\System.Xml.ReaderWriter.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Designer
+
+
+ Designer
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
+
+ {71bc5b4c-e5e3-4c46-933d-a772ca3c0499}
+ AppVNext.Notifier.Common
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
\ No newline at end of file
diff --git a/src/AppVNext.Notifier.ConsoleUwp/DesktopNotificationManagerCompat.cs b/src/AppVNext.Notifier.ConsoleUwp/DesktopNotificationManagerCompat.cs
new file mode 100644
index 0000000..656d776
--- /dev/null
+++ b/src/AppVNext.Notifier.ConsoleUwp/DesktopNotificationManagerCompat.cs
@@ -0,0 +1,398 @@
+// ******************************************************************
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THE CODE 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 CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
+// ******************************************************************
+
+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 DesktopNotifications
+{
+ public class DesktopNotificationManagerCompat
+ {
+ public const string TOAST_ACTIVATED_LAUNCH_ARG = "-ToastActivated";
+
+ private static bool _registeredAumidAndComServer;
+ private static string _aumid;
+ private static bool _registeredActivator;
+
+ ///
+ /// 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.
+ ///
+ /// An AUMID that uniquely identifies your application.
+ public static void RegisterAumidAndComServer(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(exePath);
+
+ _registeredAumidAndComServer = true;
+ }
+
+ private static void RegisterComServer(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 + '"' + " " + TOAST_ACTIVATED_LAUNCH_ARG);
+ }
+
+ ///
+ /// Registers the activator type as a COM server client so that Windows can launch your activator.
+ ///
+ /// Your implementation of NotificationActivator. Must have GUID and ComVisible attributes on class.
+ public static void RegisterActivator()
+ where T : NotificationActivator
+ {
+ // Register type
+ var regService = new RegistrationServices();
+
+ regService.RegisterTypeForComClients(
+ typeof(T),
+ RegistrationClassContext.LocalServer,
+ RegistrationConnectionType.MultipleUse);
+
+ _registeredActivator = true;
+ }
+
+ ///
+ /// Creates a toast notifier. You must have called first (and also if you're a classic Win32 app), or this will throw an exception.
+ ///
+ ///
+ public static ToastNotifier CreateToastNotifier()
+ {
+ EnsureRegistered();
+
+ if (_aumid != null)
+ {
+ // Non-Desktop Bridge
+ return ToastNotificationManager.CreateToastNotifier(_aumid);
+ }
+ else
+ {
+ // Desktop Bridge
+ return ToastNotificationManager.CreateToastNotifier();
+ }
+ }
+
+ ///
+ /// Gets the object. You must have called first (and also if you're a classic Win32 app), or this will throw an exception.
+ ///
+ 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.");
+ }
+ }
+
+ ///
+ /// Gets a boolean representing whether http images can be used within toasts. This is true if running under Desktop Bridge.
+ ///
+ public static bool CanUseHttpImages { get { return DesktopBridgeHelpers.IsRunningAsUwp(); } }
+
+ ///
+ /// Code from https://github.com/qmatteoq/DesktopBridgeHelpers/edit/master/DesktopBridge.Helpers/Helpers.cs
+ ///
+ private class DesktopBridgeHelpers
+ {
+ const long APPMODEL_ERROR_NO_PACKAGE = 15700L;
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
+ 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;
+ }
+ }
+ }
+ }
+
+ ///
+ /// Manages the toast notifications for an app including the ability the clear all toast history and removing individual toasts.
+ ///
+ public sealed class DesktopNotificationHistoryCompat
+ {
+ private string _aumid;
+ private ToastNotificationHistory _history;
+
+ ///
+ /// Do not call this. Instead, call to obtain an instance.
+ ///
+ ///
+ internal DesktopNotificationHistoryCompat(string aumid)
+ {
+ _aumid = aumid;
+ _history = ToastNotificationManager.History;
+ }
+
+ ///
+ /// Removes all notifications sent by this app from action center.
+ ///
+ public void Clear()
+ {
+ if (_aumid != null)
+ {
+ _history.Clear(_aumid);
+ }
+ else
+ {
+ _history.Clear();
+ }
+ }
+
+ ///
+ /// Gets all notifications sent by this app that are currently still in Action Center.
+ ///
+ /// A collection of toasts.
+ public IReadOnlyList GetHistory()
+ {
+ return _aumid != null ? _history.GetHistory(_aumid) : _history.GetHistory();
+ }
+
+ ///
+ /// Removes an individual toast, with the specified tag label, from action center.
+ ///
+ /// The tag label of the toast notification to be removed.
+ public void Remove(string tag)
+ {
+ if (_aumid != null)
+ {
+ _history.Remove(tag, string.Empty, _aumid);
+ }
+ else
+ {
+ _history.Remove(tag);
+ }
+ }
+
+ ///
+ /// Removes a toast notification from the action using the notification's tag and group labels.
+ ///
+ /// The tag label of the toast notification to be removed.
+ /// The group label of the toast notification to be removed.
+ public void Remove(string tag, string group)
+ {
+ if (_aumid != null)
+ {
+ _history.Remove(tag, group, _aumid);
+ }
+ else
+ {
+ _history.Remove(tag, group);
+ }
+ }
+
+ ///
+ /// Removes a group of toast notifications, identified by the specified group label, from action center.
+ ///
+ /// The group label of the toast notifications to be removed.
+ public void RemoveGroup(string group)
+ {
+ if (_aumid != null)
+ {
+ _history.RemoveGroup(group, _aumid);
+ }
+ else
+ {
+ _history.RemoveGroup(group);
+ }
+ }
+ }
+
+ ///
+ /// Apps must implement this activator to handle notification activation.
+ ///
+ public abstract class NotificationActivator : NotificationActivator.INotificationActivationCallback
+ {
+ public void Activate(string appUserModelId, string invokedArgs, NOTIFICATION_USER_INPUT_DATA[] data, uint dataCount)
+ {
+ OnActivated(invokedArgs, new NotificationUserInput(data), appUserModelId);
+ }
+
+ ///
+ /// This method will be called when the user clicks on a foreground or background activation on a toast. Parent app must implement this method.
+ ///
+ /// The arguments from the original notification. This is either the launch argument if the user clicked the body of your toast, or the arguments from a button on your toast.
+ /// Text and selection values that the user entered in your toast.
+ /// Your AUMID.
+ public abstract void OnActivated(string arguments, NotificationUserInput userInput, string appUserModelId);
+
+ // These are the new APIs for Windows 10
+ #region NewAPIs
+ [StructLayout(LayoutKind.Sequential), Serializable]
+ public struct NOTIFICATION_USER_INPUT_DATA
+ {
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string Key;
+
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string Value;
+ }
+
+ [ComImport,
+ Guid("53E31837-6600-4A81-9395-75CFFE746F94"), ComVisible(true),
+ InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ public interface INotificationActivationCallback
+ {
+ void Activate(
+ [In, MarshalAs(UnmanagedType.LPWStr)]
+ string appUserModelId,
+ [In, MarshalAs(UnmanagedType.LPWStr)]
+ string invokedArgs,
+ [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)]
+ NOTIFICATION_USER_INPUT_DATA[] data,
+ [In, MarshalAs(UnmanagedType.U4)]
+ uint dataCount);
+ }
+ #endregion
+ }
+
+ ///
+ /// Text and selection values that the user entered on your notification. The Key is the ID of the input, and the Value is what the user entered.
+ ///
+ public class NotificationUserInput : IReadOnlyDictionary
+ {
+ public NotificationActivator.NOTIFICATION_USER_INPUT_DATA[] Data { get; }
+
+ internal NotificationUserInput(NotificationActivator.NOTIFICATION_USER_INPUT_DATA[] data)
+ {
+ Data = data;
+ }
+
+ public string this[string key] => Data.First(i => i.Key == key).Value;
+
+ public IEnumerable Keys => Data.Select(i => i.Key);
+
+ public IEnumerable Values => Data.Select(i => i.Value);
+
+ public int Count => Data.Length;
+
+ public bool ContainsKey(string key)
+ {
+ return Data.Any(i => i.Key == key);
+ }
+
+ public IEnumerator> GetEnumerator()
+ {
+ return Data?.Select(i => new KeyValuePair(i.Key, i.Value))?.GetEnumerator();
+ }
+
+ public bool TryGetValue(string key, out string value)
+ {
+ foreach (var item in Data)
+ {
+ if (item.Key == key)
+ {
+ value = item.Value;
+ return true;
+ }
+ }
+
+ value = null;
+ return false;
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+ }
+}
diff --git a/src/AppVNext.Notifier.ConsoleUwp/Icon.ico b/src/AppVNext.Notifier.ConsoleUwp/Icon.ico
new file mode 100644
index 0000000..daa2985
Binary files /dev/null and b/src/AppVNext.Notifier.ConsoleUwp/Icon.ico differ
diff --git a/src/AppVNext.Notifier.ConsoleUwp/NotificationEvents.cs b/src/AppVNext.Notifier.ConsoleUwp/NotificationEvents.cs
new file mode 100644
index 0000000..35a620f
--- /dev/null
+++ b/src/AppVNext.Notifier.ConsoleUwp/NotificationEvents.cs
@@ -0,0 +1,80 @@
+using System;
+using Windows.UI.Notifications;
+using static System.Environment;
+using static System.Console;
+using System.Collections.Generic;
+using System.Reflection;
+using AppVNext.Notifier.Common;
+using Microsoft.QueryStringDotNET;
+
+namespace AppVNext.Notifier
+{
+ ///
+ /// Used when the Notification has been activated, dismissed or failed.
+ ///
+ class NotificationEvents
+ {
+ ///
+ /// Triggered when the notification has been activated or clicked on.
+ ///
+ /// ToastNotification sender object.
+ /// Used to get the properties when the notifications has been activated or clicked on.
+ internal void Activated(ToastNotification sender, object e)
+ {
+ var type = e.GetType();
+ var properties = new List(type.GetProperties());
+
+ var results = string.Empty;
+
+ foreach (var property in properties)
+ {
+ if (!string.IsNullOrEmpty(results))
+ {
+ results += $"{results}{Globals.NewLine}";
+ }
+ if (property.GetValue(e, null) is string value && !string.IsNullOrWhiteSpace(value))
+ {
+ results += $"{property.Name}: {value}";
+ }
+ }
+
+ WriteLine($"The user clicked on the toast. {results}");
+ Exit(0);
+ }
+
+ ///
+ /// Triggered when the notification has been dismissed.
+ ///
+ /// ToastNotification sender object.
+ /// Toast dismissed event arguments.
+ internal void Dismissed(ToastNotification sender, ToastDismissedEventArgs e)
+ {
+ switch (e.Reason)
+ {
+ case ToastDismissalReason.ApplicationHidden:
+ WriteLine("The notification has been closed.");
+ Exit((int)DismissalActions.Hidden);
+ break;
+ case ToastDismissalReason.UserCanceled:
+ WriteLine("The user dismissed this toast.");
+ Exit((int)DismissalActions.Dismissed);
+ break;
+ case ToastDismissalReason.TimedOut:
+ WriteLine("The toast has timed out.");
+ Exit((int)DismissalActions.Timeout);
+ break;
+ }
+ }
+
+ ///
+ /// Triggered when the notification failed.
+ ///
+ /// ToastNotification sender object.
+ /// Toast failed event arguments.
+ internal void Failed(ToastNotification sender, ToastFailedEventArgs e)
+ {
+ WriteLine($"An error has occurred. {e.ErrorCode}");
+ Exit(-1);
+ }
+ }
+}
diff --git a/src/AppVNext.Notifier.ConsoleUwp/Notifier.cs b/src/AppVNext.Notifier.ConsoleUwp/Notifier.cs
new file mode 100644
index 0000000..59ceda3
--- /dev/null
+++ b/src/AppVNext.Notifier.ConsoleUwp/Notifier.cs
@@ -0,0 +1,221 @@
+using AppVNext.Notifier.Common;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Windows.UI.Notifications;
+using Microsoft.Toolkit.Uwp.Notifications;
+using Microsoft.QueryStringDotNET;
+using Windows.Data.Xml.Dom;
+using DesktopNotifications;
+using System.IO;
+
+namespace AppVNext.Notifier
+{
+ ///
+ /// Notifier class.
+ ///
+ static class Notifier
+ {
+ ///
+ /// Show toast notification.
+ ///
+ /// Notification arguments object.
+ /// Toast notification object.
+ public static async Task ShowToast(NotificationArguments arguments)
+ {
+ //Set the toast visual
+ var visual = new ToastVisual()
+ {
+ BindingGeneric = new ToastBindingGeneric()
+ {
+ Children =
+ {
+ new AdaptiveText()
+ {
+ Text = arguments.Title
+ },
+ new AdaptiveText()
+ {
+ Text = arguments.Message
+ }
+ }
+ }
+ };
+
+ //Set the logo override
+ var imagePath = Globals.GetImageOrDefault(arguments.PicturePath);
+ var isInternetImage = IsInternetImage(imagePath);
+ var imageSource = isInternetImage ? await DownloadImageToDisk(imagePath) : imagePath;
+
+ visual.BindingGeneric.AppLogoOverride = new ToastGenericAppLogo()
+ {
+ Source = imageSource,
+ HintCrop = ToastGenericAppLogoCrop.Circle
+ };
+
+ //Set a background image
+ if (!string.IsNullOrWhiteSpace(arguments.Image))
+ {
+ isInternetImage = IsInternetImage(arguments.Image);
+ imageSource = isInternetImage ? await DownloadImageToDisk(arguments.Image) : arguments.Image;
+
+ visual.BindingGeneric.Children.Add(new AdaptiveImage()
+ {
+ Source = imageSource
+ });
+ }
+
+ // Construct the actions for the toast (inputs and buttons)
+ var actions = new ToastActionsCustom();
+
+ // Add any inputs
+ if (arguments.Inputs != null)
+ {
+ foreach (var input in arguments.Inputs)
+ {
+ var textBox = new ToastTextBox(input.Id)
+ {
+ PlaceholderContent = input.PlaceHolderText
+ };
+
+ if (!string.IsNullOrWhiteSpace(input.Title))
+ {
+ textBox.Title = input.Title;
+ }
+ actions.Inputs.Add(textBox);
+ }
+ }
+
+ // Add any buttons
+ if (arguments.Buttons != null)
+ {
+ foreach (var button in arguments.Buttons)
+ {
+ actions.Buttons.Add(new ToastButton(button.Text, button.Arguments));
+
+ //Background activation is not needed the COM activator decides whether
+ //to process in background or launch foreground window
+ //actions.Buttons.Add(new ToastButton(button.Text, button.Arguments)
+ //{
+ // ActivationType = ToastActivationType.Background
+ //});
+ }
+ }
+
+ //Set the audio
+ ToastAudio audio = null;
+ if (!string.IsNullOrWhiteSpace(arguments.WindowsSound) || !string.IsNullOrWhiteSpace(arguments.SoundPath))
+ {
+ string sound;
+ if (string.IsNullOrWhiteSpace(arguments.WindowsSound))
+ {
+ sound = "file:///" + arguments.SoundPath;
+ }
+ else
+ {
+ sound = $"ms-winsoundevent:{arguments.WindowsSound}";
+ }
+
+ audio = new ToastAudio()
+ {
+ Src = new Uri(sound),
+ Loop = bool.Parse(arguments.Loop),
+ Silent = arguments.Silent
+ };
+ }
+
+ // Construct the toast content
+ var toastContent = new ToastContent()
+ {
+ Visual = visual,
+ Actions = actions,
+ Audio = audio
+ };
+
+ // Create notification
+ var xmlDocument = new XmlDocument();
+ xmlDocument.LoadXml(toastContent.GetContent());
+
+ var toast = new ToastNotification(xmlDocument);
+
+ // Set the expiration time
+ if (!string.IsNullOrWhiteSpace(arguments.Duration))
+ {
+ switch (arguments.Duration)
+ {
+ case "short":
+ toast.ExpirationTime = DateTime.Now.AddSeconds(5);
+ break;
+ case "long":
+ toast.ExpirationTime = DateTime.Now.AddSeconds(25);
+ break;
+ }
+ }
+
+ //Add event handlers
+ var events = new NotificationEvents();
+ toast.Activated += events.Activated;
+ toast.Dismissed += events.Dismissed;
+ toast.Failed += events.Failed;
+
+ //Show notification
+ DesktopNotificationManagerCompat.CreateToastNotifier().Show(toast);
+
+ return toast;
+ }
+
+ private static bool IsInternetImage(string image)
+ {
+ return image.ToLower().StartsWith("http") || image.ToLower().StartsWith("https");
+ }
+
+ private static bool _hasPerformedCleanup;
+ private static async Task DownloadImageToDisk(string httpImage)
+ {
+ try
+ {
+ if (DesktopNotificationManagerCompat.CanUseHttpImages)
+ {
+ return httpImage;
+ }
+
+ var directory = Directory.CreateDirectory(Path.GetTempPath() + "AppVNextNotifierImages");
+
+ if (!_hasPerformedCleanup)
+ {
+ _hasPerformedCleanup = true;
+
+ foreach (var d in directory.EnumerateDirectories())
+ {
+ if (d.CreationTimeUtc.Date < DateTime.UtcNow.Date.AddDays(-3))
+ {
+ d.Delete(true);
+ }
+ }
+ }
+
+ var dayDirectory = directory.CreateSubdirectory(DateTime.UtcNow.Day.ToString());
+ string imagePath = dayDirectory.FullName + "\\" + (uint)httpImage.GetHashCode();
+
+ if (File.Exists(imagePath))
+ {
+ return imagePath;
+ }
+
+ System.Net.Http.HttpClient c = new System.Net.Http.HttpClient();
+ using (var stream = await c.GetStreamAsync(httpImage))
+ {
+ using (var fileStream = File.OpenWrite(imagePath))
+ {
+ stream.CopyTo(fileStream);
+ }
+ }
+
+ return imagePath;
+ }
+ catch { return ""; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/AppVNext.Notifier.ConsoleUwp/NotifierActivator.cs b/src/AppVNext.Notifier.ConsoleUwp/NotifierActivator.cs
new file mode 100644
index 0000000..0ee5709
--- /dev/null
+++ b/src/AppVNext.Notifier.ConsoleUwp/NotifierActivator.cs
@@ -0,0 +1,59 @@
+// ******************************************************************
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THE CODE 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 CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
+// ******************************************************************
+
+using DesktopNotifications;
+using System;
+using System.Runtime.InteropServices;
+using static System.Environment;
+using static System.Console;
+
+namespace AppVNext.Notifier
+{
+ // This GUID should be unique and match the System.AppUserModel.ToastActivatorCLSID in the installer.
+ [ClassInterface(ClassInterfaceType.None)]
+ [ComSourceInterfaces(typeof(INotificationActivationCallback))]
+ [Guid("69684589-9DC2-46C6-B023-F29BF6B4FA5F"), ComVisible(true)]
+ public class NotifierActivator : NotificationActivator
+ {
+ public override void OnActivated(string arguments, NotificationUserInput userInput, string appUserModelId)
+ {
+ if (arguments?.Length == 0)
+ {
+ WriteLine($"The user clicked on the toast.");
+ }
+ else
+ {
+ WriteLine($"The user clicked on the toast. {arguments}");
+ }
+
+ var inputs = string.Empty;
+ if (userInput?.Data != null)
+ {
+ foreach (var input in userInput)
+ {
+ if (!string.IsNullOrEmpty(inputs))
+ {
+ inputs += "&";
+ }
+ inputs += $"{input.Key}={input.Value}";
+ }
+ }
+
+ if (inputs != string.Empty)
+ {
+ WriteLine($"The user entered the following input values: {inputs}");
+ }
+
+ Exit(0);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/AppVNext.Notifier.ConsoleUwp/Program.cs b/src/AppVNext.Notifier.ConsoleUwp/Program.cs
new file mode 100644
index 0000000..d9b22a8
--- /dev/null
+++ b/src/AppVNext.Notifier.ConsoleUwp/Program.cs
@@ -0,0 +1,97 @@
+using AppVNext.Notifier.Common;
+using DesktopNotifications;
+using Microsoft.QueryStringDotNET;
+using Microsoft.Toolkit.Uwp.Notifications;
+using System;
+using System.IO;
+using System.Linq;
+using System.Net.Http;
+using System.Threading.Tasks;
+using System.Windows;
+using Windows.Data.Xml.Dom;
+using Windows.UI.Notifications;
+using static System.Console;
+
+namespace AppVNext.Notifier
+{
+ ///
+ /// Notifier main program.
+ ///
+ class Program
+ {
+ ///
+ /// Main method.
+ ///
+ /// Arguments for the notification.
+ static void Main(string[] args)
+ {
+ // Register AUMID, COM server, and activator
+ DesktopNotificationManagerCompat.RegisterAumidAndComServer("AppVNextNotifier");
+ DesktopNotificationManagerCompat.RegisterActivator();
+
+ // If launched from a toast notification
+ if (args.Contains(DesktopNotificationManagerCompat.TOAST_ACTIVATED_LAUNCH_ARG))
+ {
+ //TODO: Handle if launched from a toast notification
+ }
+ else
+ {
+ //Initialize application type. TODO: Replace this with dependency injection.
+ Globals.ApplicationType = ApplicationTypes.UwpConsole;
+
+ var arguments = ArgumentManager.ProcessArguments(args);
+
+ if (arguments == null)
+ {
+ WriteLine($"{Globals.HelpForNullMessage}{Globals.HelpForErrors}");
+ ArgumentManager.DisplayHelp();
+ }
+ else
+ {
+ if (arguments.NotificationsCheck)
+ {
+ WriteLine(RegistryHelper.AreNotificationsEnabled(arguments.NotificationCheckAppId));
+ }
+
+ if (arguments.PushNotificationCheck)
+ {
+ WriteLine(RegistryHelper.ArePushNotificationsEnabled());
+ }
+
+ if (arguments.VersionInformation)
+ {
+ WriteLine(Globals.GetVersionInformation());
+ }
+
+ if (arguments.ClearNotifications)
+ {
+ DesktopNotificationManagerCompat.History.Clear();
+ }
+
+ if (string.IsNullOrEmpty(arguments.Errors) && !string.IsNullOrEmpty(arguments.Message))
+ {
+ SendNotification(arguments);
+ while (arguments.Wait) { System.Threading.Thread.Sleep(500); }
+ }
+ else
+ {
+ WriteLine($"{(arguments.Errors ?? string.Empty)}");
+ }
+ }
+ }
+ }
+
+ ///
+ /// Send notification.
+ ///
+ /// Notification arguments object.
+ private static void SendNotification(NotificationArguments arguments)
+ {
+ //if (arguments.ApplicationId == Globals.DefaultApplicationId)
+ //{
+ // ShortcutHelper.CreateShortcutIfNeeded(arguments.ApplicationId, arguments.ApplicationName);
+ //}
+ var toast = Notifier.ShowToast(arguments);
+ }
+ }
+}
diff --git a/src/AppVNext.Notifier.ConsoleUwp/Properties/AssemblyInfo.cs b/src/AppVNext.Notifier.ConsoleUwp/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..98042fc
--- /dev/null
+++ b/src/AppVNext.Notifier.ConsoleUwp/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("App vNext UWP Notifier")]
+[assembly: AssemblyDescription("Command line tool to send Windows Toast Notifications.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("App vNext")]
+[assembly: AssemblyProduct("UWP Notifier")]
+[assembly: AssemblyCopyright("Copyright © 2018")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("9ebf043a-3ff8-46cb-a204-3e3bdf35ed49")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/src/AppVNext.Notifier.ConsoleUwp/packages.config b/src/AppVNext.Notifier.ConsoleUwp/packages.config
new file mode 100644
index 0000000..b0dcc2a
--- /dev/null
+++ b/src/AppVNext.Notifier.ConsoleUwp/packages.config
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/AppVNext.Notifier.ConsoleUwp/sound.mp3 b/src/AppVNext.Notifier.ConsoleUwp/sound.mp3
new file mode 100644
index 0000000..800c655
Binary files /dev/null and b/src/AppVNext.Notifier.ConsoleUwp/sound.mp3 differ
diff --git a/src/AppVNext.Notifier.sln b/src/AppVNext.Notifier.sln
index d10490e..f69c08a 100644
--- a/src/AppVNext.Notifier.sln
+++ b/src/AppVNext.Notifier.sln
@@ -9,12 +9,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppVNext.Notifier.Common",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppVNext.Notifier.Uwp", "AppVNext.Notifier.Uwp\AppVNext.Notifier.Uwp.csproj", "{0D1A6417-F76C-4562-A12B-B3E0AB90F294}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppVNext.Notifier.Uwp.Tasks", "AppVNext.Notifier.Uwp.Tasks\AppVNext.Notifier.Uwp.Tasks.csproj", "{796A3452-8359-494E-8AB8-946CE61FED18}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppVNext.Notifier.ConsoleUwp", "AppVNext.Notifier.ConsoleUwp\AppVNext.Notifier.ConsoleUwp.csproj", "{9EBF043A-3FF8-46CB-A204-3E3BDF35ED49}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleApp1", "ConsoleApp1\ConsoleApp1.csproj", "{8AD9E6C1-54B5-4548-AC66-19510A6C6FED}"
+Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "AppVNext.Notifier.ConsoleUwp.Setup", "AppVNext.Notifier.ConsoleUwp.Setup\AppVNext.Notifier.ConsoleUwp.Setup.wixproj", "{6592E67D-A611-4643-B73F-3F1A7C1C5F50}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ All|Any CPU = All|Any CPU
+ All|ARM = All|ARM
+ All|x64 = All|x64
+ All|x86 = All|x86
Debug|Any CPU = Debug|Any CPU
Debug|ARM = Debug|ARM
Debug|x64 = Debug|x64
@@ -25,6 +29,14 @@ Global
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {A4C223A8-6D90-4015-B417-64D01F9F1C9B}.All|Any CPU.ActiveCfg = Release|Any CPU
+ {A4C223A8-6D90-4015-B417-64D01F9F1C9B}.All|Any CPU.Build.0 = Release|Any CPU
+ {A4C223A8-6D90-4015-B417-64D01F9F1C9B}.All|ARM.ActiveCfg = Release|Any CPU
+ {A4C223A8-6D90-4015-B417-64D01F9F1C9B}.All|ARM.Build.0 = Release|Any CPU
+ {A4C223A8-6D90-4015-B417-64D01F9F1C9B}.All|x64.ActiveCfg = Release|Any CPU
+ {A4C223A8-6D90-4015-B417-64D01F9F1C9B}.All|x64.Build.0 = Release|Any CPU
+ {A4C223A8-6D90-4015-B417-64D01F9F1C9B}.All|x86.ActiveCfg = Release|Any CPU
+ {A4C223A8-6D90-4015-B417-64D01F9F1C9B}.All|x86.Build.0 = Release|Any CPU
{A4C223A8-6D90-4015-B417-64D01F9F1C9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A4C223A8-6D90-4015-B417-64D01F9F1C9B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A4C223A8-6D90-4015-B417-64D01F9F1C9B}.Debug|ARM.ActiveCfg = Debug|Any CPU
@@ -41,6 +53,14 @@ Global
{A4C223A8-6D90-4015-B417-64D01F9F1C9B}.Release|x64.Build.0 = Release|Any CPU
{A4C223A8-6D90-4015-B417-64D01F9F1C9B}.Release|x86.ActiveCfg = Release|Any CPU
{A4C223A8-6D90-4015-B417-64D01F9F1C9B}.Release|x86.Build.0 = Release|Any CPU
+ {71BC5B4C-E5E3-4C46-933D-A772CA3C0499}.All|Any CPU.ActiveCfg = Release|Any CPU
+ {71BC5B4C-E5E3-4C46-933D-A772CA3C0499}.All|Any CPU.Build.0 = Release|Any CPU
+ {71BC5B4C-E5E3-4C46-933D-A772CA3C0499}.All|ARM.ActiveCfg = Release|Any CPU
+ {71BC5B4C-E5E3-4C46-933D-A772CA3C0499}.All|ARM.Build.0 = Release|Any CPU
+ {71BC5B4C-E5E3-4C46-933D-A772CA3C0499}.All|x64.ActiveCfg = Release|Any CPU
+ {71BC5B4C-E5E3-4C46-933D-A772CA3C0499}.All|x64.Build.0 = Release|Any CPU
+ {71BC5B4C-E5E3-4C46-933D-A772CA3C0499}.All|x86.ActiveCfg = Release|Any CPU
+ {71BC5B4C-E5E3-4C46-933D-A772CA3C0499}.All|x86.Build.0 = Release|Any CPU
{71BC5B4C-E5E3-4C46-933D-A772CA3C0499}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{71BC5B4C-E5E3-4C46-933D-A772CA3C0499}.Debug|Any CPU.Build.0 = Debug|Any CPU
{71BC5B4C-E5E3-4C46-933D-A772CA3C0499}.Debug|ARM.ActiveCfg = Debug|Any CPU
@@ -57,6 +77,18 @@ Global
{71BC5B4C-E5E3-4C46-933D-A772CA3C0499}.Release|x64.Build.0 = Release|Any CPU
{71BC5B4C-E5E3-4C46-933D-A772CA3C0499}.Release|x86.ActiveCfg = Release|Any CPU
{71BC5B4C-E5E3-4C46-933D-A772CA3C0499}.Release|x86.Build.0 = Release|Any CPU
+ {0D1A6417-F76C-4562-A12B-B3E0AB90F294}.All|Any CPU.ActiveCfg = Release|x64
+ {0D1A6417-F76C-4562-A12B-B3E0AB90F294}.All|Any CPU.Build.0 = Release|x64
+ {0D1A6417-F76C-4562-A12B-B3E0AB90F294}.All|Any CPU.Deploy.0 = Release|x64
+ {0D1A6417-F76C-4562-A12B-B3E0AB90F294}.All|ARM.ActiveCfg = Release|ARM
+ {0D1A6417-F76C-4562-A12B-B3E0AB90F294}.All|ARM.Build.0 = Release|ARM
+ {0D1A6417-F76C-4562-A12B-B3E0AB90F294}.All|ARM.Deploy.0 = Release|ARM
+ {0D1A6417-F76C-4562-A12B-B3E0AB90F294}.All|x64.ActiveCfg = Release|x64
+ {0D1A6417-F76C-4562-A12B-B3E0AB90F294}.All|x64.Build.0 = Release|x64
+ {0D1A6417-F76C-4562-A12B-B3E0AB90F294}.All|x64.Deploy.0 = Release|x64
+ {0D1A6417-F76C-4562-A12B-B3E0AB90F294}.All|x86.ActiveCfg = Release|x86
+ {0D1A6417-F76C-4562-A12B-B3E0AB90F294}.All|x86.Build.0 = Release|x86
+ {0D1A6417-F76C-4562-A12B-B3E0AB90F294}.All|x86.Deploy.0 = Release|x86
{0D1A6417-F76C-4562-A12B-B3E0AB90F294}.Debug|Any CPU.ActiveCfg = Debug|x86
{0D1A6417-F76C-4562-A12B-B3E0AB90F294}.Debug|ARM.ActiveCfg = Debug|ARM
{0D1A6417-F76C-4562-A12B-B3E0AB90F294}.Debug|ARM.Build.0 = Debug|ARM
@@ -77,38 +109,48 @@ Global
{0D1A6417-F76C-4562-A12B-B3E0AB90F294}.Release|x86.ActiveCfg = Release|x86
{0D1A6417-F76C-4562-A12B-B3E0AB90F294}.Release|x86.Build.0 = Release|x86
{0D1A6417-F76C-4562-A12B-B3E0AB90F294}.Release|x86.Deploy.0 = Release|x86
- {796A3452-8359-494E-8AB8-946CE61FED18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {796A3452-8359-494E-8AB8-946CE61FED18}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {796A3452-8359-494E-8AB8-946CE61FED18}.Debug|ARM.ActiveCfg = Debug|ARM
- {796A3452-8359-494E-8AB8-946CE61FED18}.Debug|ARM.Build.0 = Debug|ARM
- {796A3452-8359-494E-8AB8-946CE61FED18}.Debug|x64.ActiveCfg = Debug|x64
- {796A3452-8359-494E-8AB8-946CE61FED18}.Debug|x64.Build.0 = Debug|x64
- {796A3452-8359-494E-8AB8-946CE61FED18}.Debug|x86.ActiveCfg = Debug|x86
- {796A3452-8359-494E-8AB8-946CE61FED18}.Debug|x86.Build.0 = Debug|x86
- {796A3452-8359-494E-8AB8-946CE61FED18}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {796A3452-8359-494E-8AB8-946CE61FED18}.Release|Any CPU.Build.0 = Release|Any CPU
- {796A3452-8359-494E-8AB8-946CE61FED18}.Release|ARM.ActiveCfg = Release|ARM
- {796A3452-8359-494E-8AB8-946CE61FED18}.Release|ARM.Build.0 = Release|ARM
- {796A3452-8359-494E-8AB8-946CE61FED18}.Release|x64.ActiveCfg = Release|x64
- {796A3452-8359-494E-8AB8-946CE61FED18}.Release|x64.Build.0 = Release|x64
- {796A3452-8359-494E-8AB8-946CE61FED18}.Release|x86.ActiveCfg = Release|x86
- {796A3452-8359-494E-8AB8-946CE61FED18}.Release|x86.Build.0 = Release|x86
- {8AD9E6C1-54B5-4548-AC66-19510A6C6FED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {8AD9E6C1-54B5-4548-AC66-19510A6C6FED}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {8AD9E6C1-54B5-4548-AC66-19510A6C6FED}.Debug|ARM.ActiveCfg = Debug|Any CPU
- {8AD9E6C1-54B5-4548-AC66-19510A6C6FED}.Debug|ARM.Build.0 = Debug|Any CPU
- {8AD9E6C1-54B5-4548-AC66-19510A6C6FED}.Debug|x64.ActiveCfg = Debug|Any CPU
- {8AD9E6C1-54B5-4548-AC66-19510A6C6FED}.Debug|x64.Build.0 = Debug|Any CPU
- {8AD9E6C1-54B5-4548-AC66-19510A6C6FED}.Debug|x86.ActiveCfg = Debug|Any CPU
- {8AD9E6C1-54B5-4548-AC66-19510A6C6FED}.Debug|x86.Build.0 = Debug|Any CPU
- {8AD9E6C1-54B5-4548-AC66-19510A6C6FED}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {8AD9E6C1-54B5-4548-AC66-19510A6C6FED}.Release|Any CPU.Build.0 = Release|Any CPU
- {8AD9E6C1-54B5-4548-AC66-19510A6C6FED}.Release|ARM.ActiveCfg = Release|Any CPU
- {8AD9E6C1-54B5-4548-AC66-19510A6C6FED}.Release|ARM.Build.0 = Release|Any CPU
- {8AD9E6C1-54B5-4548-AC66-19510A6C6FED}.Release|x64.ActiveCfg = Release|Any CPU
- {8AD9E6C1-54B5-4548-AC66-19510A6C6FED}.Release|x64.Build.0 = Release|Any CPU
- {8AD9E6C1-54B5-4548-AC66-19510A6C6FED}.Release|x86.ActiveCfg = Release|Any CPU
- {8AD9E6C1-54B5-4548-AC66-19510A6C6FED}.Release|x86.Build.0 = Release|Any CPU
+ {9EBF043A-3FF8-46CB-A204-3E3BDF35ED49}.All|Any CPU.ActiveCfg = Release|Any CPU
+ {9EBF043A-3FF8-46CB-A204-3E3BDF35ED49}.All|Any CPU.Build.0 = Release|Any CPU
+ {9EBF043A-3FF8-46CB-A204-3E3BDF35ED49}.All|ARM.ActiveCfg = Release|Any CPU
+ {9EBF043A-3FF8-46CB-A204-3E3BDF35ED49}.All|ARM.Build.0 = Release|Any CPU
+ {9EBF043A-3FF8-46CB-A204-3E3BDF35ED49}.All|x64.ActiveCfg = Release|Any CPU
+ {9EBF043A-3FF8-46CB-A204-3E3BDF35ED49}.All|x64.Build.0 = Release|Any CPU
+ {9EBF043A-3FF8-46CB-A204-3E3BDF35ED49}.All|x86.ActiveCfg = Release|Any CPU
+ {9EBF043A-3FF8-46CB-A204-3E3BDF35ED49}.All|x86.Build.0 = Release|Any CPU
+ {9EBF043A-3FF8-46CB-A204-3E3BDF35ED49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9EBF043A-3FF8-46CB-A204-3E3BDF35ED49}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9EBF043A-3FF8-46CB-A204-3E3BDF35ED49}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {9EBF043A-3FF8-46CB-A204-3E3BDF35ED49}.Debug|ARM.Build.0 = Debug|Any CPU
+ {9EBF043A-3FF8-46CB-A204-3E3BDF35ED49}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {9EBF043A-3FF8-46CB-A204-3E3BDF35ED49}.Debug|x64.Build.0 = Debug|Any CPU
+ {9EBF043A-3FF8-46CB-A204-3E3BDF35ED49}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {9EBF043A-3FF8-46CB-A204-3E3BDF35ED49}.Debug|x86.Build.0 = Debug|Any CPU
+ {9EBF043A-3FF8-46CB-A204-3E3BDF35ED49}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9EBF043A-3FF8-46CB-A204-3E3BDF35ED49}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9EBF043A-3FF8-46CB-A204-3E3BDF35ED49}.Release|ARM.ActiveCfg = Release|Any CPU
+ {9EBF043A-3FF8-46CB-A204-3E3BDF35ED49}.Release|ARM.Build.0 = Release|Any CPU
+ {9EBF043A-3FF8-46CB-A204-3E3BDF35ED49}.Release|x64.ActiveCfg = Release|Any CPU
+ {9EBF043A-3FF8-46CB-A204-3E3BDF35ED49}.Release|x64.Build.0 = Release|Any CPU
+ {9EBF043A-3FF8-46CB-A204-3E3BDF35ED49}.Release|x86.ActiveCfg = Release|Any CPU
+ {9EBF043A-3FF8-46CB-A204-3E3BDF35ED49}.Release|x86.Build.0 = Release|Any CPU
+ {6592E67D-A611-4643-B73F-3F1A7C1C5F50}.All|Any CPU.ActiveCfg = Release|x86
+ {6592E67D-A611-4643-B73F-3F1A7C1C5F50}.All|Any CPU.Build.0 = Release|x86
+ {6592E67D-A611-4643-B73F-3F1A7C1C5F50}.All|ARM.ActiveCfg = Release|x86
+ {6592E67D-A611-4643-B73F-3F1A7C1C5F50}.All|ARM.Build.0 = Release|x86
+ {6592E67D-A611-4643-B73F-3F1A7C1C5F50}.All|x64.ActiveCfg = Release|x86
+ {6592E67D-A611-4643-B73F-3F1A7C1C5F50}.All|x64.Build.0 = Release|x86
+ {6592E67D-A611-4643-B73F-3F1A7C1C5F50}.All|x86.ActiveCfg = Release|x86
+ {6592E67D-A611-4643-B73F-3F1A7C1C5F50}.All|x86.Build.0 = Release|x86
+ {6592E67D-A611-4643-B73F-3F1A7C1C5F50}.Debug|Any CPU.ActiveCfg = Debug|x86
+ {6592E67D-A611-4643-B73F-3F1A7C1C5F50}.Debug|ARM.ActiveCfg = Debug|x86
+ {6592E67D-A611-4643-B73F-3F1A7C1C5F50}.Debug|x64.ActiveCfg = Debug|x86
+ {6592E67D-A611-4643-B73F-3F1A7C1C5F50}.Debug|x86.ActiveCfg = Debug|x86
+ {6592E67D-A611-4643-B73F-3F1A7C1C5F50}.Debug|x86.Build.0 = Debug|x86
+ {6592E67D-A611-4643-B73F-3F1A7C1C5F50}.Release|Any CPU.ActiveCfg = Release|x86
+ {6592E67D-A611-4643-B73F-3F1A7C1C5F50}.Release|ARM.ActiveCfg = Release|x86
+ {6592E67D-A611-4643-B73F-3F1A7C1C5F50}.Release|x64.ActiveCfg = Release|x86
+ {6592E67D-A611-4643-B73F-3F1A7C1C5F50}.Release|x86.ActiveCfg = Release|x86
+ {6592E67D-A611-4643-B73F-3F1A7C1C5F50}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE