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>
        /// 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>
        /// <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 Initialize()
        {
            // If containerized
            if (DesktopBridgeHelpers.IsContainerized())
            {
                // No need to do anything additional, already registered through manifest
                return;
            }

            Win32AppInfo win32AppInfo = null;

            // If sparse
            if (DesktopBridgeHelpers.HasIdentity())
            {
                _win32Aumid = new ManifestHelper().GetAumidFromPackageManifest();
            }
            else
            {
                win32AppInfo = Win32AppInfo.Get();
                _win32Aumid  = win32AppInfo.Aumid;
            }

            // Create and register activator
            var activatorType = CreateAndRegisterActivator();

            // Register via registry
            using (var rootKey = Registry.CurrentUser.CreateSubKey(GetRegistrySubKey()))
            {
                // If they don't have identity, we need to specify the display assets
                if (!DesktopBridgeHelpers.HasIdentity())
                {
                    // Set the display name and icon uri
                    rootKey.SetValue("DisplayName", win32AppInfo.DisplayName);

                    if (win32AppInfo.IconPath != null)
                    {
                        rootKey.SetValue("IconUri", win32AppInfo.IconPath);
                    }
                    else
                    {
                        if (rootKey.GetValue("IconUri") != null)
                        {
                            rootKey.DeleteValue("IconUri");
                        }
                    }

                    // Background color only appears in the settings page, format is
                    // hex without leading #, like "FFDDDDDD"
                    rootKey.SetValue("IconBackgroundColor", "FFDDDDDD");

                    // Additionally, we need to read whether they've sent a notification before
                    _hasSentNotification = rootKey.GetValue(REG_HAS_SENT_NOTIFICATION) != null;
                }

                rootKey.SetValue("CustomActivator", string.Format("{{{0}}}", activatorType.GUID));
            }
        }
 private void PreprocessScheduledToast(ScheduledToastNotification notification)
 {
     // For apps that don't have identity...
     if (!DesktopBridgeHelpers.HasIdentity())
     {
         // If tag is specified
         if (!string.IsNullOrEmpty(notification.Tag))
         {
             // If group isn't specified, we have to add a group since otherwise can't remove without a group
             notification.Group = ToastNotificationManagerCompat.DEFAULT_GROUP;
         }
     }
 }
        /// <summary>
        /// Updates the existing toast notification that has the specified tag.
        /// </summary>
        /// <param name="data">An object that contains the updated info.</param>
        /// <param name="tag">The identifier of the toast notification to update.</param>
        /// <returns>A value that indicates the result of the update (failure, success, etc).</returns>
        public NotificationUpdateResult Update(NotificationData data, string tag)
        {
#if WIN32
            // For apps that don't have identity...
            if (!DesktopBridgeHelpers.HasIdentity())
            {
                // If group isn't specified, we have to add a group since otherwise can't remove without a group
                return(Update(data, tag, ToastNotificationManagerCompat.DEFAULT_GROUP));
            }
#endif

            return(_notifier.Update(data, tag));
        }
Beispiel #6
0
        private static Type CreateActivatorType()
        {
            // https://stackoverflow.com/questions/24069352/c-sharp-typebuilder-generate-class-with-function-dynamically
            // For .NET Core we use https://stackoverflow.com/questions/36937276/is-there-any-replace-of-assemblybuilder-definedynamicassembly-in-net-core
            AssemblyName    aName    = new AssemblyName("DynamicComActivator");
            AssemblyBuilder aBuilder = AssemblyBuilder.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Run);

            // For a single-module assembly, the module name is usually the assembly name plus an extension.
            ModuleBuilder mb = aBuilder.DefineDynamicModule(aName.Name);

            // Create class which extends NotificationActivator
            TypeBuilder tb = mb.DefineType(
                name: "MyNotificationActivator",
                attr: TypeAttributes.Public,
                parent: typeof(Internal.InternalNotificationActivator),
                interfaces: new Type[0]);

            if (DesktopBridgeHelpers.IsContainerized())
            {
                _clsid = new ManifestHelper().GetClsidFromPackageManifest();
            }
            else
            {
                _clsid = Win32AppInfo.GenerateGuid(_win32Aumid);
            }

            tb.SetCustomAttribute(new CustomAttributeBuilder(
                                      con: typeof(GuidAttribute).GetConstructor(new Type[] { typeof(string) }),
                                      constructorArgs: new object[] { _clsid }));

            tb.SetCustomAttribute(new CustomAttributeBuilder(
                                      con: typeof(ComVisibleAttribute).GetConstructor(new Type[] { typeof(bool) }),
                                      constructorArgs: new object[] { true }));

            tb.SetCustomAttribute(new CustomAttributeBuilder(
#pragma warning disable CS0618 // Type or member is obsolete
                                      con: typeof(ComSourceInterfacesAttribute).GetConstructor(new Type[] { typeof(Type) }),
#pragma warning restore CS0618 // Type or member is obsolete
                                      constructorArgs: new object[] { typeof(Internal.InternalNotificationActivator.INotificationActivationCallback) }));

            tb.SetCustomAttribute(new CustomAttributeBuilder(
                                      con: typeof(ClassInterfaceAttribute).GetConstructor(new Type[] { typeof(ClassInterfaceType) }),
                                      constructorArgs: new object[] { ClassInterfaceType.None }));

            return(tb.CreateType());
        }
Beispiel #7
0
        private static void RegisterActivator(Type activatorType)
        {
            if (!DesktopBridgeHelpers.IsContainerized())
            {
                string exePath = Process.GetCurrentProcess().MainModule.FileName;
                RegisterComServer(activatorType, exePath);
            }

            // 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;

            NativeMethods.CoRegisterClassObject(
                uuid,
                new NotificationActivatorClassFactory(activatorType),
                CLSCTX_LOCAL_SERVER,
                REGCLS_MULTIPLEUSE,
                out _);
        }
Beispiel #8
0
        internal static void SetHasSentToastNotification()
        {
            // For plain Win32 apps, record that we've sent a notification
            if (!_hasSentNotification && !DesktopBridgeHelpers.HasIdentity())
            {
                _hasSentNotification = true;

                try
                {
                    using (var rootKey = Registry.CurrentUser.CreateSubKey(GetRegistrySubKey()))
                    {
                        rootKey.SetValue(REG_HAS_SENT_NOTIFICATION, 1);
                    }
                }
                catch
                {
                }
            }
        }
Beispiel #9
0
        /// <summary>
        /// Creates a toast notifier.
        /// </summary>
        /// <returns><see cref="ToastNotifierCompat"/>An instance of the toast notifier.</returns>
        public static ToastNotifierCompat CreateToastNotifier()
        {
#if WIN32
            if (_initializeEx != null)
            {
                throw _initializeEx;
            }

            if (DesktopBridgeHelpers.HasIdentity())
            {
                return(new ToastNotifierCompat(ToastNotificationManager.CreateToastNotifier()));
            }
            else
            {
                return(new ToastNotifierCompat(ToastNotificationManager.CreateToastNotifier(_win32Aumid)));
            }
#else
            return(new ToastNotifierCompat(ToastNotificationManager.CreateToastNotifier()));
#endif
        }
Beispiel #10
0
        internal static void PreRegisterIdentityLessApp()
        {
            // For plain Win32 apps, we first have to have send a toast notification once before using scheduled toasts.
            if (!_hasSentNotification && !DesktopBridgeHelpers.HasIdentity())
            {
                const string tag = "toolkit1stNotif";

                // Show the toast
                new ToastContentBuilder()
                .AddText("New notification")
                .Show(toast =>
                {
                    // We'll hide the popup and set the toast to expire in case removing doesn't work
                    toast.SuppressPopup  = true;
                    toast.Tag            = tag;
                    toast.ExpirationTime = DateTime.Now.AddSeconds(15);
                });

                // And then remove it
                ToastNotificationManagerCompat.History.Remove(tag);
            }
        }
Beispiel #11
0
        /// <summary>
        /// If you're not using MSIX, call this when your app is being uninstalled to properly clean up all notifications and notification-related resources. Note that this must be called from your app's main EXE (the one that you used notifications for) and not a separate uninstall EXE. If called from a MSIX app, this method no-ops.
        /// </summary>
        public static void Uninstall()
        {
            if (DesktopBridgeHelpers.IsContainerized())
            {
                // Packaged containerized apps automatically clean everything up already
                return;
            }

            if (!DesktopBridgeHelpers.HasIdentity())
            {
                try
                {
                    // Remove all scheduled notifications (do this first before clearing current notifications)
                    var notifier = CreateToastNotifier();
                    foreach (var scheduled in notifier.GetScheduledToastNotifications())
                    {
                        try
                        {
                            notifier.RemoveFromSchedule(scheduled);
                        }
                        catch
                        {
                        }
                    }
                }
                catch
                {
                }

                try
                {
                    // Clear all current notifications
                    History.Clear();
                }
                catch
                {
                }
            }

            try
            {
                // Remove registry key
                if (_win32Aumid != null)
                {
                    Registry.CurrentUser.DeleteSubKey(GetRegistrySubKey());
                }
            }
            catch
            {
            }

            try
            {
                if (_clsid != null)
                {
                    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
            {
            }

            try
            {
                // Delete any of the app files
                var appDataFolderPath = Win32AppInfo.GetAppDataFolderPath(_win32Aumid);
                if (Directory.Exists(appDataFolderPath))
                {
                    Directory.Delete(appDataFolderPath, recursive: true);
                }
            }
            catch
            {
            }
        }