예제 #1
0
        /// <summary>
        /// Gets the class of the given file extension, optionally creating it if it does not exist.
        /// </summary>
        /// <param name="classesKey">The classes key (HKEY_CLASSES_ROOT).</param>
        /// <param name="fileExtension">The file extension, with a leading dot.</param>
        /// <param name="createIfMissing">if set to <c>true</c> then if no class exists, one will be created.</param>
        /// <returns></returns>
        /// <exception cref="InvalidOperationException">Thrown if the extension is invalid.</exception>
        public static string Get(IRegistryKey classesKey, string fileExtension, bool createIfMissing)
        {
            //  Make sure that we have a file extension, a string which starts with a dot and
            //  has at least one character following it.
            if (string.IsNullOrEmpty(fileExtension) ||
                fileExtension.StartsWith(".") == false ||
                fileExtension.Length < 2)
            {
                throw new InvalidOperationException($@"'{fileExtension}' does not appear to be a valid file extension class.");
            }

            //  We will need the extension with no leading dot later.
            var extension = fileExtension.Substring(1);

            //  Open or create the file extension key.
            using (var fileExtensionClassKey =
                       classesKey.CreateSubKey(fileExtension, RegistryKeyPermissionCheck.ReadWriteSubTree))
            {
                //  Get the class, which is the 'default' value. If we've got a value, we're done.
                var fileExtensionClassName = fileExtensionClassKey.GetValue(null) as string;
                if (!string.IsNullOrEmpty(fileExtensionClassName))
                {
                    return(fileExtensionClassName);
                }

                //  We don't have a class for the extension. If we are *not* creating missing ones, we're done.
                if (!createIfMissing)
                {
                    return(null);
                }

                //  There is no file extension class name, so we'll have to create one. Set the desired class name.
                fileExtensionClassName = $"{extension}.1"; // e.g. 'dllfile', 'mytypefile'

                //  If the desired class name exists, we're going to have to bail out (we could try and find another
                //  name, but that starts to get difficult for users to reason about).
                using (var fileExtensionClassNameKey = classesKey.OpenSubKey(fileExtensionClassName))
                {
                    if (fileExtensionClassNameKey != null)
                    {
                        var applicationName = fileExtensionClassNameKey.GetValue(null) as string;
                        throw new InvalidOperationException(
                                  $@"Unable to create a new class '{fileExtensionClassName}' for extension '{fileExtension}'. That class is already in use by application '{applicationName}'.");
                    }
                }

                //  Create the file extension class name key, point the file extension to it, set a sensible name for the application and we're done.
                using (var fileExtensionClassNameKey = classesKey.CreateSubKey(fileExtensionClassName, RegistryKeyPermissionCheck.ReadWriteSubTree))
                {
                    fileExtensionClassKey.SetValue(null, fileExtensionClassName);
                    fileExtensionClassNameKey.SetValue(null, $"{extension} Application");
                    return(fileExtensionClassName);
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Sets the icon handler default icon, enabling an icon handler extension.
        /// </summary>
        /// <param name="classesKey">The classes key.</param>
        /// <param name="className">Name of the class.</param>
        private static void SetIconHandlerDefaultIcon(IRegistryKey classesKey, string className)
        {
            //  Open the class.
            using (var classKey = classesKey.OpenSubKey(className))
            {
                //  Check we have the class.
                if (classKey == null)
                {
                    throw new InvalidOperationException("Cannot open class " + className);
                }

                //  Open the default icon.
                using (var defaultIconKey = classKey.OpenSubKey(KeyName_DefaultIcon, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.ReadKey | RegistryRights.WriteKey))
                {
                    //  Check we have the key.
                    if (defaultIconKey == null)
                    {
                        // if not, we create the key.
                        var tempDefaultIconKey = classesKey.CreateSubKey(className + @"\" + KeyName_DefaultIcon, RegistryKeyPermissionCheck.ReadWriteSubTree);
                        tempDefaultIconKey.SetValue(null, "%1");
                    }
                    else
                    {
                        //  Get the default icon.
                        var defaultIcon = defaultIconKey.GetValue(null, string.Empty).ToString();

                        //  Save the default icon.
                        defaultIconKey.SetValue(ValueName_DefaultIconBackup, defaultIcon);
                        defaultIconKey.SetValue(null, "%1");
                    }
                }
            }
        }
예제 #3
0
        public IRegistryKey CreateKey(string keyPath, RegistryKeyPermissionCheck permissionCheck = default)
        {
            IRegistryKey cleanUpKey = null;

            if (!keyPath.Contains(RegistryPathDelimiter))
            {
                throw new ArgumentException("Can not create a root key itself", nameof(keyPath));
            }
            try
            {
                IRegistryKey root        = GetCorrespondingRoot(keyPath);
                string       openKeyName = keyPath.MustEndWith(RegistryPathDelimiter).Remove(root.Name.MustEndWith(RegistryPathDelimiter));
                cleanUpKey = root;
                if (openKeyName.IsNullOrWhitespace())
                {
                    throw new ArgumentException("Can not create a root key itself", nameof(keyPath));
                }
                IRegistryKey key = root.CreateSubKey(openKeyName, permissionCheck);
                return(key);
            }
            finally
            {
                cleanUpKey?.Dispose();
            }
        }
        private IRegistryKey?OpenKey(string rootName, string keyPath, bool writing = false)
        {
            IRegistryKey root = GetRootKey(rootName, this.registry);

            return(writing
                ? root.CreateSubKey(keyPath)
                : root.OpenSubKey(keyPath));
        }
예제 #5
0
        /// <summary>
        ///     Copy a registry key.  The parentKey must be writeable.
        /// </summary>
        /// <param name="parentKey"></param>
        /// <param name="keyNameToCopy"></param>
        /// <param name="newKeyName"></param>
        /// <returns></returns>
        public bool CopyKey(IRegistryKey parentKey, string keyNameToCopy, string newKeyName)
        {
            //Create new key
            var destinationKey = parentKey.CreateSubKey(newKeyName);

            //Open the sourceKey we are copying from
            var sourceKey = parentKey.OpenSubKey(keyNameToCopy);

            RecurseCopyKey(sourceKey, destinationKey);

            return(true);
        }
예제 #6
0
        private static void AddValue(IRegistryKey baseKey, bool policy, object value)
        {
            if (string.IsNullOrEmpty(value.ToString()))
            {
                return;
            }
            const string zoneKeyTemplate = @"SOFTWARE\{0}Microsoft\Windows\CurrentVersion\Internet Settings\Zones\1";
            var          zoneKey         = string.Format(zoneKeyTemplate, policy ? @"Policies\" : "");
            var          key             = baseKey.CreateSubKey(zoneKey);

            key.SetValue("2500", value, RegistryValueKind.DWord);
        }
예제 #7
0
        private void RecurseCopyKey(IRegistryKey sourceKey, IRegistryKey destinationKey)
        {
            //copy all the values
            foreach (var valueName in sourceKey.GetValueNames())
            {
                var objValue = sourceKey.GetValue(valueName);
                var valKind  = sourceKey.GetValueKind(valueName);
                destinationKey.SetValue(valueName, objValue, valKind);
            }

            //For Each subKey
            //Create a new subKey in destinationKey
            //Call myself
            foreach (var sourceSubKeyName in sourceKey.GetSubKeyNames())
            {
                var sourceSubKey = sourceKey.OpenSubKey(sourceSubKeyName);
                var destSubKey   = destinationKey.CreateSubKey(sourceSubKeyName);
                RecurseCopyKey(sourceSubKey, destSubKey);
            }
        }
        /// <summary>
        /// Saves the active changes to the current theme.
        ///
        /// This is needed to be performed before enabling high-contrast because when high-contrast is de-activated it
        /// loads the settings (such as the wallpaper) from the last used .theme file, rather than the applied settings.
        ///
        /// These means, any unsaved theme customisations will be lost.
        ///
        /// Theme files are described in https://docs.microsoft.com/en-us/windows/desktop/controls/themesfileformat-overview
        /// </summary>
        /// <param name="currentThemeFile">
        /// The current theme file used by the OS. This will be used as a base to create a new theme file, and currently
        /// applied settings will be added to it.</param>
        /// <param name="saveAs">The file to write the saved theme to.</param>
        private async Task SaveCurrentTheme(string currentThemeFile, string saveAs)
        {
            this.logger.LogInformation($"Saving current theme, using {currentThemeFile}.");

            bool isValid = false;
            Dictionary <string, string>?themeData = null;

            try
            {
                // Read the .theme file that's currently being used.
                Ini themeReader = new();
                await themeReader.ReadFile(currentThemeFile);

                themeData = themeReader.ReadData();
                isValid   = themeData.ContainsKey("MasterThemeSelector.MTSM");
            }
            catch (IOException e)
            {
                this.logger.LogInformation(e, $"Unable to read {currentThemeFile}.");
            }

            if (!isValid || themeData is null)
            {
                string defaultTheme = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows),
                                                   "resources\\Themes\\aero.theme");
                if (currentThemeFile != defaultTheme)
                {
                    // OBSERVATION: this code is re-entrant; also note that if the aero.theme file is corrupt...this might reenter infinitely until the stack was full
                    await this.SaveCurrentTheme(defaultTheme, saveAs);
                }
                return;
            }
            else if (themeData.ContainsKey("VisualStyles.HighContrast"))
            {
                // Only save the current theme if it is not high-contrast.
                return;
            }

            using IRegistryKey hKeyCurrentUser =
                      this.registry.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default);

            // Wallpaper
            using IRegistryKey desktopKey = hKeyCurrentUser.OpenSubKey(@"Control Panel\Desktop", false);

            themeData["Theme.DisplayName"] = "morphic";

            themeData["Control Panel\\Desktop.Wallpaper"] =
                desktopKey.GetValue("WallPaper")?.ToString() ?? string.Empty;
            themeData["Control Panel\\Desktop.TileWallpaper"] =
                desktopKey.GetValue("TileWallPaper")?.ToString() ?? string.Empty;
            themeData["Control Panel\\Desktop.WallpaperStyle"] =
                desktopKey.GetValue("WallPaperStyle")?.ToString() ?? string.Empty;

            using IRegistryKey wallpapersKey =
                      hKeyCurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Explorer\Wallpapers");
            string?backgroundType = wallpapersKey.GetValue("backgroundType")?.ToString();

            if (backgroundType != "2")
            {
                // It's not a slide-show, remove the entire section.
                themeData.Keys.Where(k => k.StartsWith("Slideshow"))
                .ToList()
                .ForEach(k => themeData.Remove(k));
            }

            // Colours
            using IRegistryKey colorsKey = hKeyCurrentUser.OpenSubKey(@"Control Panel\Colors");
            foreach (string valueName in colorsKey.GetValueNames())
            {
                if (colorsKey.GetValue(valueName, null) is string value)
                {
                    themeData[$"Control Panel\\Colors.{valueName}"] = value;
                }
            }

            // if the directory for the saveAs file doesn't exist, create it now
            var saveAsPath = Path.GetDirectoryName(saveAs);

            if (Directory.Exists(saveAsPath) == false)
            {
                Directory.CreateDirectory(saveAsPath);
            }

            Ini writer = new();
            await writer.ReadFile(currentThemeFile);

            writer.WriteData(themeData !);
            await writer.WriteFile(saveAs);

            // Make windows use this theme file when restoring high-contrast.
            using IRegistryKey highContrastKey =
                      hKeyCurrentUser.CreateSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\HighContrast");
            highContrastKey.SetValue("Pre-High Contrast Scheme", saveAs);
        }