/// <summary> /// Registers a <see cref="Verb"/> in a registry key. /// </summary> /// <param name="verbKey">The registry key to write the new data to.</param> /// <param name="target">The application being integrated.</param> /// <param name="verb">The verb to register.</param> /// <param name="iconStore">Stores icon files downloaded from the web as local files.</param> /// <param name="machineWide">Assume <paramref name="verbKey"/> is effective machine-wide instead of just for the current user.</param> /// <exception cref="OperationCanceledException">The user canceled the task.</exception> /// <exception cref="IOException">A problem occurred while writing to the filesystem or registry.</exception> /// <exception cref="WebException">A problem occurred while downloading additional data (such as icons).</exception> /// <exception cref="UnauthorizedAccessException">Write access to the filesystem or registry is not permitted.</exception> public static void Register(RegistryKey verbKey, FeedTarget target, Verb verb, IIconStore iconStore, bool machineWide) { string?description = verb.Descriptions.GetBestLanguage(CultureInfo.CurrentUICulture); verbKey.SetOrDelete("", description); verbKey.SetOrDelete("MUIVerb", description); verbKey.SetOrDelete("MultiSelectModel", verb.SingleElementOnly ? "Single" : null); if (verb.Extended) { verbKey.SetValue("Extended", ""); } else { verbKey.DeleteValue("Extended", throwOnMissingValue: false); } var icon = target.Feed.GetBestIcon(Icon.MimeTypeIco, verb.Command) ?? target.Feed.Icons.GetIcon(Icon.MimeTypeIco); verbKey.SetOrDelete("Icon", icon?.To(iconStore.GetFresh)); using var commandKey = verbKey.CreateSubKeyChecked("command"); commandKey.SetValue("", GetLaunchCommandLine(target, verb, iconStore, machineWide)); }
/// <inheritdoc/> public override void Apply(AppEntry appEntry, Feed feed, IIconStore iconStore, bool machineWide) { #region Sanity checks if (appEntry == null) { throw new ArgumentNullException(nameof(appEntry)); } if (iconStore == null) { throw new ArgumentNullException(nameof(iconStore)); } #endregion ValidateName(); var target = new FeedTarget(appEntry.InterfaceUri, feed); if (WindowsUtils.IsWindows) { Windows.AppAlias.Create(target, Command, Name, iconStore, machineWide); } else if (UnixUtils.IsUnix) { Unix.AppAlias.Create(target, Command, Name, iconStore, machineWide); } }
/// <summary> /// Generates a command-line string for launching a <see cref="Verb"/>. /// </summary> /// <param name="target">The application being integrated.</param> /// <param name="verb">The verb to get to launch command for.</param> /// <param name="iconStore">Stores icon files downloaded from the web as local files.</param> /// <param name="machineWide">Store the stub in a machine-wide directory instead of just for the current user.</param> /// <exception cref="IOException">A problem occurred while writing to the filesystem.</exception> /// <exception cref="WebException">A problem occurred while downloading additional data (such as icons).</exception> /// <exception cref="InvalidOperationException">Write access to the filesystem is not permitted.</exception> internal static string GetLaunchCommandLine(FeedTarget target, Verb verb, IIconStore iconStore, bool machineWide) { IEnumerable <string> GetCommandLine() { try { return(new StubBuilder(iconStore).GetRunCommandLine(target, verb.Command, machineWide)); } #region Error handling catch (InvalidOperationException ex) { // Wrap exception since only certain exception types are allowed throw new IOException(ex.Message, ex); } #endregion } if (verb.Arguments.Count == 0) { string arguments = string.IsNullOrEmpty(verb.ArgumentsLiteral) ? "\"%V\"" : verb.ArgumentsLiteral; return(GetCommandLine().JoinEscapeArguments() + " " + arguments); } return(GetCommandLine() .Concat(verb.Arguments.Select(x => x.Value)) .JoinEscapeArguments() .Replace("${item}", "\"%V\"")); }
/// <summary> /// Creates an application alias in the current system. /// </summary> /// <param name="target">The application being integrated.</param> /// <param name="command">The command within <paramref name="target"/> the alias shall point to; can be <c>null</c>.</param> /// <param name="aliasName">The name of the alias to be created.</param> /// <param name="machineWide">Create the alias machine-wide instead of just for the current user.</param> /// <param name="iconStore">Stores icon files downloaded from the web as local files.</param> /// <exception cref="OperationCanceledException">The user canceled the task.</exception> /// <exception cref="IOException">A problem occurred while writing to the filesystem or registry.</exception> /// <exception cref="WebException">A problem occurred while downloading additional data (such as icons).</exception> /// <exception cref="UnauthorizedAccessException">Write access to the filesystem or registry is not permitted.</exception> public static void Create(FeedTarget target, string?command, string aliasName, IIconStore iconStore, bool machineWide) { #region Sanity checks if (string.IsNullOrEmpty(aliasName)) { throw new ArgumentNullException(nameof(aliasName)); } if (iconStore == null) { throw new ArgumentNullException(nameof(iconStore)); } #endregion #if NETFRAMEWORK string stubDirPath = GetStubDir(machineWide); PathEnv.AddDir(stubDirPath, machineWide); string stubFilePath = Path.Combine(stubDirPath, aliasName + ".exe"); new StubBuilder(iconStore).BuildRunStub(stubFilePath, target, command); if (machineWide || WindowsUtils.IsWindows7) { var hive = machineWide ? Registry.LocalMachine : Registry.CurrentUser; using var appPathsKey = hive.CreateSubKeyChecked(RegKeyAppPaths); using var exeKey = appPathsKey.CreateSubKeyChecked(aliasName + ".exe"); exeKey.SetValue("", stubFilePath); } #else throw new PlatformNotSupportedException("Generating Windows aliases is not supported by the .NET Core version of Zero Install."); #endif }
/// <summary> /// Creates a new Windows shortcut. /// </summary> /// <param name="path">The location to place the shortcut at.</param> /// <param name="target">The target the shortcut shall point to.</param> /// <param name="command">The command within <paramref name="target"/> the shortcut shall point to; can be <c>null</c>.</param> /// <param name="iconStore">Stores icon files downloaded from the web as local files.</param> private static void Create(string path, FeedTarget target, string?command, IIconStore iconStore) { if (string.IsNullOrEmpty(command)) { command = Command.NameRun; } var entryPoint = target.Feed.GetEntryPoint(command); bool needsTerminal = (entryPoint != null && entryPoint.NeedsTerminal); string targetPath = Path.Combine(Locations.InstallBase, needsTerminal ? "0install.exe" : "0install-win.exe"); string arguments = "run "; if (!needsTerminal) { arguments += "--no-wait "; } if (command != Command.NameRun) { arguments += "--command " + command.EscapeArgument() + " "; } arguments += target.Uri.ToStringRfc().EscapeArgument(); var icon = target.Feed.GetIcon(Icon.MimeTypeIco, command); Create(path, targetPath, arguments, iconLocation: (icon == null) ? null : iconStore.GetPath(icon), description: target.Feed.GetBestSummary(CultureInfo.CurrentUICulture, command)); }
/// <summary> /// Creates a new tile manager. /// </summary> /// <param name="feedManager">Provides access to remote and local <see cref="Feed"/>s. Handles downloading, signature verification and caching.</param> /// <param name="catalogManager">Provides access to remote and local <see cref="Catalog"/>s. Handles downloading, signature verification and caching.</param> /// <param name="iconStore">The icon store used by newly created <see cref="IAppTile"/>s to retrieve application icons.</param> /// <param name="tileListMyApps">The <see cref="IAppTileList"/> used to represent the "my apps" <see cref="AppList"/>.</param> /// <param name="tileListCatalog">The <see cref="IAppTileList"/> used to represent the merged <see cref="Catalog"/>.</param> /// <param name="machineWide">Apply operations machine-wide instead of just for the current user.</param> public AppTileManagement(IFeedManager feedManager, ICatalogManager catalogManager, IIconStore iconStore, IAppTileList tileListMyApps, IAppTileList tileListCatalog, bool machineWide) { _feedManager = feedManager ?? throw new ArgumentNullException(nameof(feedManager)); _catalogManager = catalogManager ?? throw new ArgumentNullException(nameof(catalogManager)); _iconStore = iconStore ?? throw new ArgumentNullException(nameof(iconStore)); _tileListMyApps = tileListMyApps ?? throw new ArgumentNullException(nameof(tileListMyApps)); _tileListCatalog = tileListCatalog ?? throw new ArgumentNullException(nameof(tileListCatalog)); _machineWide = machineWide; }
/// <summary> /// Creates a new Windows shortcut in the quick launch bar. /// </summary> /// <param name="quickLaunch">Information about the shortcut to be created.</param> /// <param name="target">The target the shortcut shall point to.</param> /// <param name="iconStore">Stores icon files downloaded from the web as local files.</param> public static void Create(QuickLaunch quickLaunch, FeedTarget target, IIconStore iconStore) { #region Sanity checks if (quickLaunch == null) { throw new ArgumentNullException(nameof(quickLaunch)); } if (iconStore == null) { throw new ArgumentNullException(nameof(iconStore)); } #endregion string filePath = GetQuickLaunchPath(quickLaunch.Name); Create(filePath, target, quickLaunch.Command, iconStore); }
/// <summary> /// Creates a new Windows shortcut in the start menu or on the start page. /// </summary> /// <param name="menuEntry">Information about the shortcut to be created.</param> /// <param name="target">The target the shortcut shall point to.</param> /// <param name="iconStore">Stores icon files downloaded from the web as local files.</param> /// <param name="machineWide">Create the shortcut machine-wide instead of just for the current user.</param> public static void Create(MenuEntry menuEntry, FeedTarget target, IIconStore iconStore, bool machineWide) { #region Sanity checks if (menuEntry == null) { throw new ArgumentNullException(nameof(menuEntry)); } if (iconStore == null) { throw new ArgumentNullException(nameof(iconStore)); } #endregion string filePath = GetStartMenuPath(menuEntry.Category, menuEntry.Name, machineWide); Create(filePath, target, menuEntry.Command, iconStore); }
/// <summary> /// Adds an entry to the list of uninstallable applications. /// </summary> /// <param name="target">The application being added.</param> /// <param name="machineWide">Apply the registration machine-wide instead of just for the current user.</param> /// <param name="iconStore">Stores icon files downloaded from the web as local files.</param> /// <exception cref="OperationCanceledException">The user canceled the task.</exception> /// <exception cref="IOException">A problem occurred while writing to the filesystem or registry.</exception> /// <exception cref="WebException">A problem occurred while downloading additional data (such as icons).</exception> /// <exception cref="UnauthorizedAccessException">Write access to the filesystem or registry is not permitted.</exception> public static void Register(FeedTarget target, IIconStore iconStore, bool machineWide) { string[] uninstallCommand = { Path.Combine(Locations.InstallBase, "0install-win.exe"), "remove", target.Uri.ToStringRfc() }; if (machineWide) { uninstallCommand = uninstallCommand.Append("--machine"); } Register( target.Uri.PrettyEscape(), uninstallCommand, target.Feed.Name + " (Zero Install)", target.Feed.Homepage, GetIconPath(target.Feed, iconStore), machineWide: machineWide); }
/// <summary> /// Creates a new Windows shortcut in the "Send to" menu. /// </summary> /// <param name="sendTo">Information about the shortcut to be created.</param> /// <param name="target">The target the shortcut shall point to.</param> /// <param name="iconStore">Stores icon files downloaded from the web as local files.</param> public static void Create(SendTo sendTo, FeedTarget target, IIconStore iconStore) { #region Sanity checks if (sendTo == null) { throw new ArgumentNullException(nameof(sendTo)); } if (iconStore == null) { throw new ArgumentNullException(nameof(iconStore)); } #endregion string filePath = GetSendToPath(sendTo.Name); Create(filePath, target, sendTo.Command, iconStore); }
/// <summary> /// Creates a new Windows shortcut in the "Startup" menu. /// </summary> /// <param name="autoStart">Information about the shortcut to be created.</param> /// <param name="target">The target the shortcut shall point to.</param> /// <param name="iconStore">Stores icon files downloaded from the web as local files.</param> /// <param name="machineWide">Create the shortcut machine-wide instead of just for the current user.</param> public static void Create(AutoStart autoStart, FeedTarget target, IIconStore iconStore, bool machineWide) { #region Sanity checks if (autoStart == null) { throw new ArgumentNullException(nameof(autoStart)); } if (iconStore == null) { throw new ArgumentNullException(nameof(iconStore)); } #endregion string filePath = GetStartupPath(autoStart.Name, machineWide); Create(filePath, targetPath: StubBuilder.GetRunStub(target, autoStart.Command, iconStore)); }
/// <summary> /// Creates a new Windows shortcut on the desktop. /// </summary> /// <param name="desktopIcon">Information about the shortcut to be created.</param> /// <param name="target">The target the shortcut shall point to.</param> /// <param name="iconStore">Stores icon files downloaded from the web as local files.</param> /// <param name="machineWide">Create the shortcut machine-wide instead of just for the current user.</param> public static void Create(DesktopIcon desktopIcon, FeedTarget target, IIconStore iconStore, bool machineWide) { #region Sanity checks if (desktopIcon == null) { throw new ArgumentNullException(nameof(desktopIcon)); } if (iconStore == null) { throw new ArgumentNullException(nameof(iconStore)); } #endregion string filePath = GetDesktopPath(desktopIcon.Name, machineWide); Create(filePath, target, desktopIcon.Command, iconStore); }
/// <summary> /// Creates an application alias in the current system. /// </summary> /// <param name="target">The application being integrated.</param> /// <param name="command">The command within <paramref name="target"/> the alias shall point to; can be <c>null</c>.</param> /// <param name="aliasName">The name of the alias to be created.</param> /// <param name="iconStore">Stores icon files downloaded from the web as local files.</param> /// <param name="machineWide">Create the alias machine-wide instead of just for the current user.</param> /// <exception cref="OperationCanceledException">The user canceled the task.</exception> /// <exception cref="IOException">A problem occurred while writing to the filesystem.</exception> /// <exception cref="WebException">A problem occurred while downloading additional data (such as icons).</exception> /// <exception cref="UnauthorizedAccessException">Write access to the filesystem is not permitted.</exception> public static void Create(FeedTarget target, string?command, string aliasName, IIconStore iconStore, bool machineWide) { #region Sanity checks if (string.IsNullOrEmpty(aliasName)) { throw new ArgumentNullException(nameof(aliasName)); } if (iconStore == null) { throw new ArgumentNullException(nameof(iconStore)); } #endregion // TODO: Find directory in search PATH // TODO: Write file }
/// <inheritdoc/> public override void Apply(AppEntry appEntry, Feed feed, IIconStore iconStore, bool machineWide) { #region Sanity checks if (appEntry == null) { throw new ArgumentNullException(nameof(appEntry)); } if (iconStore == null) { throw new ArgumentNullException(nameof(iconStore)); } #endregion var target = new FeedTarget(appEntry.InterfaceUri, feed); if (WindowsUtils.IsWindows && !machineWide) { Windows.Shortcut.Create(this, target, iconStore); } }
/// <inheritdoc/> public override void Apply(AppEntry appEntry, Feed feed, IIconStore iconStore, bool machineWide) { #region Sanity checks if (appEntry == null) { throw new ArgumentNullException(nameof(appEntry)); } #endregion if (!string.IsNullOrEmpty(ID)) { // Trigger exceptions in case invalid capabilities are referenced appEntry.LookupCapability <Model.Capabilities.FileType>(Capability); } if (!string.IsNullOrEmpty(ApplyFlagPath)) { FileUtils.Touch(ApplyFlagPath); } }
/// <inheritdoc/> public override void Apply(AppEntry appEntry, Feed feed, IIconStore iconStore, bool machineWide) { #region Sanity checks if (appEntry == null) { throw new ArgumentNullException(nameof(appEntry)); } if (iconStore == null) { throw new ArgumentNullException(nameof(iconStore)); } #endregion var capability = appEntry.LookupCapability <Model.Capabilities.UrlProtocol>(Capability); var target = new FeedTarget(appEntry.InterfaceUri, feed); if (WindowsUtils.IsWindows) { Windows.UrlProtocol.Register(target, capability, iconStore, machineWide, accessPoint: true); } }
/// <summary> /// Exports all specified icons. /// </summary> /// <param name="icons">The icons to export.</param> /// <param name="iconStore">The icon store to export the icons from.</param> /// <exception cref="OperationCanceledException">The user canceled the task.</exception> /// <exception cref="IOException">A problem occurred while reading or writing a file.</exception> /// <exception cref="UnauthorizedAccessException">Read or access to a file is not permitted.</exception> /// <exception cref="WebException">A problem occurred while downloading icons.</exception> public void ExportIcons(IEnumerable <Icon> icons, IIconStore iconStore) { #region Sanity checks if (icons == null) { throw new ArgumentNullException(nameof(icons)); } if (iconStore == null) { throw new ArgumentNullException(nameof(iconStore)); } #endregion foreach (var icon in icons) { File.Copy( iconStore.GetFresh(icon), Path.Combine(_contentDir, IconStore.GetFileName(icon)), overwrite: true); } }
/// <summary> /// Creates a new Windows shortcut. /// </summary> /// <param name="path">The location to place the shortcut at.</param> /// <param name="target">The target the shortcut shall point to.</param> /// <param name="command">The command within <paramref name="target"/> the shortcut shall point to; can be <c>null</c>.</param> /// <param name="iconStore">Stores icon files downloaded from the web as local files.</param> private static void Create(string path, FeedTarget target, string?command, IIconStore iconStore) { if (string.IsNullOrEmpty(command)) { command = Command.NameRun; } var entryPoint = target.Feed.GetEntryPoint(command); bool needsTerminal = entryPoint is { NeedsTerminal : true }; string targetPath = Path.Combine(Locations.InstallBase, needsTerminal ? "0install.exe" : "0install-win.exe"); string arguments = "run "; if (!needsTerminal) { arguments += "--no-wait "; } if (command != Command.NameRun) { arguments += "--command " + command.EscapeArgument() + " "; } arguments += target.Uri.ToStringRfc().EscapeArgument(); var icon = target.Feed.GetBestIcon(Icon.MimeTypeIco, command); string dirPath = Path.GetDirectoryName(path) !; if (!Directory.Exists(dirPath)) { Directory.CreateDirectory(dirPath); } Create(path, targetPath, arguments, iconLocation: icon?.To(iconStore.GetFresh), description: target.Feed.GetBestSummary(CultureInfo.CurrentUICulture, command), appId: entryPoint?.AppId ?? GuessAppExePath(target.Feed, entryPoint)); }
/// <summary> /// Builds a stub EXE in a well-known location. Future calls with the same arguments will return the same EXE. /// </summary> /// <param name="target">The application to be launched via the stub.</param> /// <param name="command">The command argument to be passed to the the "0install run" command; can be <c>null</c>.</param> /// <param name="machineWide">Store the stub in a machine-wide directory instead of just for the current user.</param> /// <param name="iconStore">Stores icon files downloaded from the web as local files.</param> /// <returns>The path to the generated stub EXE.</returns> /// <exception cref="OperationCanceledException">The user canceled the task.</exception> /// <exception cref="InvalidOperationException">There was a compilation error while generating the stub EXE.</exception> /// <exception cref="IOException">A problem occurred while writing to the filesystem.</exception> /// <exception cref="WebException">A problem occurred while downloading additional data (such as icons).</exception> /// <exception cref="InvalidOperationException">Write access to the filesystem is not permitted.</exception> public static string GetRunStub(FeedTarget target, string?command, IIconStore iconStore, bool machineWide = false) { #region Sanity checks if (iconStore == null) { throw new ArgumentNullException(nameof(iconStore)); } #endregion var entryPoint = target.Feed.GetEntryPoint(command); string exeName = (entryPoint != null) ? entryPoint.BinaryName ?? entryPoint.Command : FeedUri.Escape(target.Feed.Name); bool needsTerminal = (entryPoint != null && entryPoint.NeedsTerminal); string hash = (target.Uri + "#" + command).Hash(SHA256.Create()); string path = Path.Combine( IntegrationManager.GetDir(machineWide, "stubs", hash), exeName + ".exe"); CreateOrUpdateRunStub(target, path, command, needsTerminal, iconStore); return(path); }
/// <summary> /// Creates a new Windows shortcut in the "Startup" menu. /// </summary> /// <param name="autoStart">Information about the shortcut to be created.</param> /// <param name="target">The target the shortcut shall point to.</param> /// <param name="iconStore">Stores icon files downloaded from the web as local files.</param> /// <param name="machineWide">Create the shortcut machine-wide instead of just for the current user.</param> public static void Create(AutoStart autoStart, FeedTarget target, IIconStore iconStore, bool machineWide) { #region Sanity checks if (autoStart == null) { throw new ArgumentNullException(nameof(autoStart)); } if (iconStore == null) { throw new ArgumentNullException(nameof(iconStore)); } #endregion string filePath = GetStartupPath(autoStart.Name, machineWide); if (WindowsUtils.IsWindows) { var commandLine = new StubBuilder(iconStore).GetRunCommandLine(target, autoStart.Command, machineWide); Create(filePath, commandLine.First(), commandLine.Skip(1).JoinEscapeArguments()); } else { Create(filePath, target, autoStart.Command, iconStore); } }
/// <inheritdoc/> public override void Apply(AppEntry appEntry, Feed feed, IIconStore iconStore, bool machineWide) { #region Sanity checks if (appEntry == null) { throw new ArgumentNullException(nameof(appEntry)); } if (iconStore == null) { throw new ArgumentNullException(nameof(iconStore)); } #endregion var capability = appEntry.LookupCapability <Model.Capabilities.ContextMenu>(Capability); var target = new FeedTarget(appEntry.InterfaceUri, feed); if (WindowsUtils.IsWindows) { Windows.ContextMenu.Apply(target, capability, iconStore, machineWide); } else if (UnixUtils.IsUnix) { Unix.ContextMenu.Apply(target, capability, iconStore, machineWide); } }
/// <inheritdoc/> public override void Apply(AppEntry appEntry, Feed feed, IIconStore iconStore, bool machineWide) { #region Sanity checks if (appEntry == null) { throw new ArgumentNullException(nameof(appEntry)); } if (iconStore == null) { throw new ArgumentNullException(nameof(iconStore)); } #endregion var target = new FeedTarget(appEntry.InterfaceUri, feed); if (WindowsUtils.IsWindows) { Windows.UninstallEntry.Register(target, iconStore, machineWide); } var capabilities = appEntry.CapabilityLists.CompatibleCapabilities().ToList(); foreach (var capability in capabilities) { switch (capability) { case Model.Capabilities.FileType fileType: if (WindowsUtils.IsWindows) { Windows.FileType.Register(target, fileType, iconStore, machineWide); } else if (UnixUtils.IsUnix) { Unix.FileType.Register(target, fileType, iconStore, machineWide); } break; case Model.Capabilities.UrlProtocol urlProtocol: if (WindowsUtils.IsWindows) { Windows.UrlProtocol.Register(target, urlProtocol, iconStore, machineWide); } else if (UnixUtils.IsUnix) { Unix.UrlProtocol.Register(target, urlProtocol, iconStore, machineWide); } break; case Model.Capabilities.AutoPlay autoPlay: if (WindowsUtils.IsWindows) { Windows.AutoPlay.Register(target, autoPlay, iconStore, machineWide); } break; case AppRegistration appRegistration: if ((WindowsUtils.IsWindows && machineWide) || WindowsUtils.IsWindows8) { Windows.AppRegistration.Register(target, appRegistration, capabilities.OfType <VerbCapability>(), iconStore, machineWide); } break; case Model.Capabilities.DefaultProgram defaultProgram: if (WindowsUtils.IsWindows && machineWide) { Windows.DefaultProgram.Register(target, defaultProgram, iconStore); } else if (UnixUtils.IsUnix) { Unix.DefaultProgram.Register(target, defaultProgram, iconStore, machineWide); } break; case ComServer comServer: if (WindowsUtils.IsWindows) { Windows.ComServer.Register(target, comServer, iconStore, machineWide); } break; } } }
/// <summary> /// Registers a file type in the current system. /// </summary> /// <param name="target">The application being integrated.</param> /// <param name="fileType">The file type to register.</param> /// <param name="machineWide">Register the file type machine-wide instead of just for the current user.</param> /// <param name="iconStore">Stores icon files downloaded from the web as local files.</param> /// <param name="accessPoint">Indicates that the file associations shall become default handlers for their respective types.</param> /// <exception cref="OperationCanceledException">The user canceled the task.</exception> /// <exception cref="IOException">A problem occurred while writing to the filesystem or registry.</exception> /// <exception cref="WebException">A problem occurred while downloading additional data (such as icons).</exception> /// <exception cref="UnauthorizedAccessException">Write access to the filesystem or registry is not permitted.</exception> public static void Register(FeedTarget target, Model.Capabilities.FileType fileType, IIconStore iconStore, bool machineWide, bool accessPoint = false) { #region Sanity checks if (fileType == null) { throw new ArgumentNullException(nameof(fileType)); } if (iconStore == null) { throw new ArgumentNullException(nameof(iconStore)); } #endregion using var classesKey = RegistryClasses.OpenHive(machineWide); // Register ProgID using (var progIDKey = classesKey.CreateSubKeyChecked(RegistryClasses.Prefix + fileType.ID)) { progIDKey.SetValue("", fileType.Descriptions.GetBestLanguage(CultureInfo.CurrentUICulture) ?? fileType.ID); progIDKey.SetValue(accessPoint ? RegistryClasses.PurposeFlagAccessPoint : RegistryClasses.PurposeFlagCapability, ""); RegistryClasses.Register(progIDKey, target, fileType, iconStore, machineWide); } foreach (var extension in fileType.Extensions.Except(x => string.IsNullOrEmpty(x.Value))) { // Register extensions using (var extensionKey = classesKey.CreateSubKeyChecked(extension.Value)) { extensionKey.SetOrDelete(RegValueContentType, extension.MimeType); extensionKey.SetOrDelete(RegValuePerceivedType, extension.PerceivedType); using (var openWithKey = extensionKey.CreateSubKeyChecked(RegSubKeyOpenWith)) openWithKey.SetValue(RegistryClasses.Prefix + fileType.ID, ""); if (accessPoint) { if (!machineWide && WindowsUtils.IsWindowsVista) { // Windows Vista and later store per-user file extension overrides using var overridesKey = Registry.CurrentUser.OpenSubKeyChecked(RegKeyOverrides, writable: true); using var extensionOverrideKey = overridesKey.CreateSubKeyChecked(extension.Value); // Only mess with this part of the registry when necessary bool alreadySet; using (var userChoiceKey = extensionOverrideKey.OpenSubKey("UserChoice", writable: false)) { if (userChoiceKey == null) { alreadySet = false; } else { alreadySet = ((userChoiceKey.GetValue("Progid") ?? "").ToString() == RegistryClasses.Prefix + fileType.ID); } } if (!alreadySet) { // Must delete and recreate instead of direct modification due to wicked ACLs extensionOverrideKey.DeleteSubKeyTree("UserChoice", throwOnMissingSubKey: false); try { using var userChoiceKey = extensionOverrideKey.CreateSubKeyChecked("UserChoice"); userChoiceKey.SetValue("Progid", RegistryClasses.Prefix + fileType.ID); } catch (UnauthorizedAccessException ex) { // Windows may try to prevent modifications to this key Log.Debug(ex); } } } else { extensionKey.SetValue("", RegistryClasses.Prefix + fileType.ID); } } } // Register MIME types if (!string.IsNullOrEmpty(extension.MimeType)) { using var mimeKey = classesKey.CreateSubKeyChecked($@"{RegSubKeyMimeType}\{extension.MimeType}"); mimeKey.SetValue(RegValueExtension, extension.Value); } } }
/// <summary> /// Registers an application as a candidate for a default program for some service in the current system. This can only be applied machine-wide, not per user. /// </summary> /// <param name="target">The application being integrated.</param> /// <param name="defaultProgram">The default program information to be registered.</param> /// <param name="iconStore">Stores icon files downloaded from the web as local files.</param> /// <param name="accessPoint">Indicates that the program should be set as the current default for the service it provides.</param> /// <exception cref="OperationCanceledException">The user canceled the task.</exception> /// <exception cref="IOException">A problem occurred while writing to the filesystem or registry.</exception> /// <exception cref="WebException">A problem occurred while downloading additional data (such as icons).</exception> /// <exception cref="UnauthorizedAccessException">Write access to the filesystem or registry is not permitted.</exception> public static void Register(FeedTarget target, Model.Capabilities.DefaultProgram defaultProgram, IIconStore iconStore, bool accessPoint = false) { #region Sanity checks if (defaultProgram == null) { throw new ArgumentNullException(nameof(defaultProgram)); } if (iconStore == null) { throw new ArgumentNullException(nameof(iconStore)); } #endregion using var serviceKey = Registry.LocalMachine.CreateSubKeyChecked($@"{RegKeyMachineClients}\{defaultProgram.Service}"); using (var appKey = serviceKey.CreateSubKeyChecked(defaultProgram.ID)) { appKey.SetValue("", target.Feed.Name); appKey.SetValue(accessPoint ? RegistryClasses.PurposeFlagAccessPoint : RegistryClasses.PurposeFlagCapability, ""); RegistryClasses.Register(appKey, target, defaultProgram, iconStore, machineWide: true); // Set callbacks for Windows SPAD using (var installInfoKey = appKey.CreateSubKeyChecked(RegSubKeyInstallInfo)) { string exePath = Path.Combine(Locations.InstallBase, "0install-win.exe"); installInfoKey.SetValue(RegValueReinstallCommand, new[] { exePath, "integrate", "--machine", "--batch", "--add", "defaults", target.Uri.ToStringRfc() }.JoinEscapeArguments()); installInfoKey.SetValue(RegValueShowIconsCommand, new[] { exePath, "integrate", "--machine", "--batch", "--add", MenuEntry.TagName, "--add", DesktopIcon.TagName, target.Uri.ToStringRfc() }.JoinEscapeArguments()); installInfoKey.SetValue(RegValueHideIconsCommand, new[] { exePath, "integrate", "--machine", "--batch", "--remove", MenuEntry.TagName, "--remove", DesktopIcon.TagName, target.Uri.ToStringRfc() }.JoinEscapeArguments()); installInfoKey.SetValue(RegValueIconsVisible, 0, RegistryValueKind.DWord); } if (defaultProgram.Service == Model.Capabilities.DefaultProgram.ServiceMail) { var mailToProtocol = new Model.Capabilities.UrlProtocol { Verbs = { new Verb { Name = Verb.NameOpen } } }; using var mailToKey = appKey.CreateSubKeyChecked(@"Protocols\mailto"); RegistryClasses.Register(mailToKey, target, mailToProtocol, iconStore, machineWide: true); } } if (accessPoint) { serviceKey.SetValue("", defaultProgram.ID); } }
/// <summary> /// Registers a URL protocol in the current system. /// </summary> /// <param name="target">The application being integrated.</param> /// <param name="urlProtocol">The URL protocol to register.</param> /// <param name="machineWide">Register the URL protocol machine-wide instead of just for the current user.</param> /// <param name="iconStore">Stores icon files downloaded from the web as local files.</param> /// <param name="accessPoint">Indicates that the handler shall become the default handler for the protocol.</param> /// <exception cref="OperationCanceledException">The user canceled the task.</exception> /// <exception cref="IOException">A problem occurred while writing to the filesystem.</exception> /// <exception cref="WebException">A problem occurred while downloading additional data (such as icons).</exception> /// <exception cref="UnauthorizedAccessException">Write access to the filesystem is not permitted.</exception> /// <exception cref="InvalidDataException">The data in <paramref name="urlProtocol"/> is invalid.</exception> public static void Register(FeedTarget target, Model.Capabilities.UrlProtocol urlProtocol, IIconStore iconStore, bool machineWide, bool accessPoint = false) { #region Sanity checks if (urlProtocol == null) { throw new ArgumentNullException(nameof(urlProtocol)); } if (iconStore == null) { throw new ArgumentNullException(nameof(iconStore)); } #endregion if (string.IsNullOrEmpty(urlProtocol.ID)) { throw new InvalidDataException("Missing ID"); } // TODO: Implement }
/// <summary> /// Applies this access point to the current machine. /// </summary> /// <param name="appEntry">The application being integrated.</param> /// <param name="feed">The feed providing additional metadata, icons, etc. for the application.</param> /// <param name="iconStore">Stores icon files downloaded from the web as local files.</param> /// <param name="machineWide">Apply the configuration machine-wide instead of just for the current user.</param> /// <exception cref="KeyNotFoundException">An <see cref="AccessPoint"/> reference to a <see cref="Capability"/> is invalid.</exception> /// <exception cref="OperationCanceledException">The user canceled the task.</exception> /// <exception cref="IOException">A problem occurred while writing to the filesystem or registry.</exception> /// <exception cref="WebException">A problem occurred while downloading additional data (such as icons).</exception> /// <exception cref="UnauthorizedAccessException">Write access to the filesystem or registry is not permitted.</exception> /// <exception cref="InvalidDataException">The access point's data or a referenced <see cref="Capability"/>'s data are invalid.</exception> public abstract void Apply(AppEntry appEntry, Feed feed, IIconStore iconStore, bool machineWide);
private static string?GetIconPath(Feed feed, IIconStore iconStore) { var icon = feed.Icons.GetIcon(Icon.MimeTypeIco); return(icon?.To(iconStore.GetFresh)); }
/// <summary> /// Registers a URL protocol in the current system. /// </summary> /// <param name="target">The application being integrated.</param> /// <param name="urlProtocol">The URL protocol to register.</param> /// <param name="machineWide">Register the URL protocol machine-wide instead of just for the current user.</param> /// <param name="iconStore">Stores icon files downloaded from the web as local files.</param> /// <param name="accessPoint">Indicates that the handler shall become the default handler for the protocol.</param> /// <exception cref="OperationCanceledException">The user canceled the task.</exception> /// <exception cref="IOException">A problem occurred while writing to the filesystem or registry.</exception> /// <exception cref="WebException">A problem occurred while downloading additional data (such as icons).</exception> /// <exception cref="UnauthorizedAccessException">Write access to the filesystem or registry is not permitted.</exception> public static void Register(FeedTarget target, Model.Capabilities.UrlProtocol urlProtocol, IIconStore iconStore, bool machineWide, bool accessPoint = false) { #region Sanity checks if (urlProtocol == null) { throw new ArgumentNullException(nameof(urlProtocol)); } if (iconStore == null) { throw new ArgumentNullException(nameof(iconStore)); } #endregion using var classesKey = RegistryClasses.OpenHive(machineWide); if (urlProtocol.KnownPrefixes.Count == 0) { if (accessPoint) { // Can only be registered invasively by registering protocol ProgID (will replace existing and become default) using var progIDKey = classesKey.CreateSubKeyChecked(urlProtocol.ID); progIDKey.SetValue("", urlProtocol.Descriptions.GetBestLanguage(CultureInfo.CurrentUICulture) ?? urlProtocol.ID); RegistryClasses.Register(progIDKey, target, urlProtocol, iconStore, machineWide); progIDKey.SetValue(ProtocolIndicator, ""); } } else { // Can be registered non-invasively by registering custom ProgID (without becoming default) using (var progIDKey = classesKey.CreateSubKeyChecked(RegistryClasses.Prefix + urlProtocol.ID)) { progIDKey.SetValue("", urlProtocol.Descriptions.GetBestLanguage(CultureInfo.CurrentUICulture) ?? urlProtocol.ID); progIDKey.SetValue(accessPoint ? RegistryClasses.PurposeFlagAccessPoint : RegistryClasses.PurposeFlagCapability, ""); RegistryClasses.Register(progIDKey, target, urlProtocol, iconStore, machineWide); progIDKey.SetValue(ProtocolIndicator, ""); } if (accessPoint) { foreach (var prefix in urlProtocol.KnownPrefixes) { if (WindowsUtils.IsWindowsVista && !machineWide) { using var userChoiceKey = Registry.CurrentUser.CreateSubKeyChecked($@"{RegKeyUserVistaUrlAssoc}\{prefix.Value}\UserChoice"); userChoiceKey.SetValue("ProgID", RegistryClasses.Prefix + urlProtocol.ID); } else { // Setting default invasively by registering protocol ProgID using var progIDKey = classesKey.CreateSubKeyChecked(prefix.Value); RegistryClasses.Register(progIDKey, target, urlProtocol, iconStore, machineWide); progIDKey.SetValue(ProtocolIndicator, ""); } } } } }
/// <summary> /// Registers a <see cref="Verb"/> in a registry key. /// </summary> /// <param name="verbKey">The registry key to write the new data to.</param> /// <param name="target">The application being integrated.</param> /// <param name="verb">The verb to register.</param> /// <param name="iconStore">Stores icon files downloaded from the web as local files.</param> /// <param name="machineWide">Assume <paramref name="verbKey"/> is effective machine-wide instead of just for the current user.</param> /// <exception cref="OperationCanceledException">The user canceled the task.</exception> /// <exception cref="IOException">A problem occurred while writing to the filesystem or registry.</exception> /// <exception cref="WebException">A problem occurred while downloading additional data (such as icons).</exception> /// <exception cref="UnauthorizedAccessException">Write access to the filesystem or registry is not permitted.</exception> /// <exception cref="InvalidDataException">The data in <paramref name="verb"/> is invalid.</exception> public static void Register(RegistryKey verbKey, FeedTarget target, Verb verb, IIconStore iconStore, bool machineWide) { string?description = verb.Descriptions.GetBestLanguage(CultureInfo.CurrentUICulture); if (!string.IsNullOrEmpty(description)) { verbKey.SetValue("", description); verbKey.SetValue("MUIVerb", description); } if (verb.Extended) { verbKey.SetValue("Extended", ""); } var icon = target.Feed.GetIcon(Icon.MimeTypeIco, verb.Command); if (icon != null) { verbKey.SetValue("Icon", iconStore.GetPath(icon)); } using var commandKey = verbKey.CreateSubKeyChecked("command"); commandKey.SetValue("", GetLaunchCommandLine(target, verb, iconStore, machineWide)); }
/// <summary> /// Registers a <see cref="VerbCapability"/> in a registry key. /// </summary> /// <param name="registryKey">The registry key to write the new data to.</param> /// <param name="target">The application being integrated.</param> /// <param name="capability">The capability to register.</param> /// <param name="iconStore">Stores icon files downloaded from the web as local files.</param> /// <param name="machineWide">Assume <paramref name="registryKey"/> is effective machine-wide instead of just for the current user.</param> /// <exception cref="OperationCanceledException">The user canceled the task.</exception> /// <exception cref="IOException">A problem occurred while writing to the filesystem or registry.</exception> /// <exception cref="WebException">A problem occurred while downloading additional data (such as icons).</exception> /// <exception cref="UnauthorizedAccessException">Write access to the filesystem or registry is not permitted.</exception> public static void Register(RegistryKey registryKey, FeedTarget target, VerbCapability capability, IIconStore iconStore, bool machineWide) { #region Sanity checks if (capability == null) { throw new ArgumentNullException(nameof(capability)); } if (iconStore == null) { throw new ArgumentNullException(nameof(iconStore)); } #endregion if ((capability.GetIcon(Icon.MimeTypeIco) ?? target.Feed.Icons.GetIcon(Icon.MimeTypeIco)) is {} icon) { using var iconKey = registryKey.CreateSubKeyChecked("DefaultIcon"); iconKey.SetValue("", iconStore.GetFresh(icon) + ",0"); } foreach (var verb in capability.Verbs) { using var verbKey = registryKey.CreateSubKeyChecked($@"shell\{verb.Name}"); Register(verbKey, target, verb, iconStore, machineWide); } // Prevent conflicts with existing entries registryKey.DeleteSubKeyTree(@"shell\ddeexec", throwOnMissingSubKey: false); }