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 static void CleanUpOldAumid(string oldAumid) { try { // Remove all scheduled notifications (do this first before clearing current notifications) var notifier = ToastNotificationManager.CreateToastNotifier(oldAumid); foreach (var scheduled in notifier.GetScheduledToastNotifications()) { try { notifier.RemoveFromSchedule(scheduled); } catch { } } } catch { } try { // Clear all current notifications ToastNotificationManager.History.Clear(oldAumid); } catch { } try { // Remove registry key Registry.CurrentUser.DeleteSubKey(GetRegistrySubKey(oldAumid)); } catch { } try { // Delete any of the app files var appDataFolderPath = Win32AppInfo.GetAppDataFolderPath(oldAumid); if (Directory.Exists(appDataFolderPath)) { Directory.Delete(appDataFolderPath, recursive: true); } } catch { } }
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()); }
/// <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 { } }