Работа с реестром на C#

Приветствую всех, сегодня поговорим об одной интересной теме, работа с реестром.

Реестр Windows или системный реестр (Windows Registry) — иерархически построенная база данных параметров и настроек в большинстве операционных систем Microsoft Windows.
Реестр содержит информацию и настройки для аппаратного обеспечения, программного обеспечения, профилей пользователей, пред установки. Большинство изменений в Панели
управления, ассоциации файлов, системные политики, список установленного ПО фиксируются в реестре.

Windows хранит море информации о системе, настройках программ, пользователях и множество других данных в специальном хранилище— реестре. Существует возможность улучшить работу программ путем изменения параметров, содержащихся в реестре. В Интернете можно найти целый класс программ, называемых твикерами, в которых собраны различные полезные и интересные настройки, которые можно поменять в реестре, чтобы изменить функциональность программ. Не представляет труда самому написать такой
твикер при помощи управляемого кода.

Разделы реестра

  • HKEY_CLASSES_ROOT – содержит информацию о ассоциациях расширения файлов и зарегистрированных COM объектах.
  • HKEY_CURRENT_USER – содержит настройки для текущего пользователя.
  • HKEY_LOCAL_MACHINE – содержит настройки локального компьютера.
  • HKEY_USERS – содержит настройки пользователя по умолчанию.
  • HKEY_CURRENT_CONFIG – содержит информацию о настройках, которые не являются специфическими для пользователя.
  • HKEY_PERFORMANCE_DATA – содержит информацию о производительности программных компонентов.
  • HKEY_DYN_DATA – содержит динамические изменяемые данные реестра, на данный момент является устаревшим.

Пространство имен для работы с реестром using Microsoft.Win32;

Registry — это статический класс, предоставляющий эксклюзивный доступ к ключам реестра для простых операций.

Registry — этот класс предоставляет набор стандартных корневых разделов, находящихся в реестре компьютеров, работающих под управлением Windows. Реестр является средством хранения сведений о приложениях, пользователях и стандартных системных параметрах. Например, приложения используют реестр для хранения сведений, которые необходимо сохранить после закрытия приложения и к которым необходимо получать доступ при перезагрузке приложения. Например, можно сохранять цветовые настройки, положение или размер окна. Для разных пользователей эти сведения могут сохраняться в различных местах реестра.

Класс Registry предоставляет доступ к следующим разделам:

CurrentUser – Сохраняет сведения о пользовательских параметрах.

LocalMachine – Сохраняет сведения о конфигурации для локального компьютера

ClassesRoot – Сохраняет сведения о типах (и классах) и их свойствах.

Users – Сохраняет сведения о стандартной пользовательской конфигурации.

PerformanceData – Сохраняет сведения о производительности программных компонентов.

CurrentConfig – Сохраняет сведения об оборудовании, не являющемся специфическим для пользователя.

DynData – Сохраняет динамические данные (Считается устаревшим).

RegistryKey — класс реализует методы для просмотра дочерних ключей, создания новых или чтения и модификации существующих, включая установку уровней безопасности для них.

Чтение из реестра осуществляется при помощи метода GetValue, узел должен быть предварительно открыт при помощи метода OpenSubKey.

Запись данных в реестр осуществляется при помощи метода SetValue, узел должен существовать и быть предварительно открытым при помощи метода OpenSubKey с указанием признака «открытие для записи».

Выводим информацию о структуре реестра:

static void Main()
		{
			// Registry - это класс, предоставляющий эксклюзивный доступ к ключам реестра для простых операций.
			// RegistryKey - класс реализует методы для просмотра дочерних ключей, создания новых или чтения и модификации существующих,
			//				 включая установку уровней безопасности для них.

			RegistryKey[] regKeyArray = new RegistryKey[] { Registry.ClassesRoot,
															Registry.CurrentUser,
															Registry.LocalMachine,
															Registry.Users,
															Registry.CurrentConfig,
															Registry.PerformanceData
															// Registry.DynData // Устарел.
														  };

			foreach (RegistryKey regKey in regKeyArray)
			{
				Console.WriteLine("{0} - всего элементов: {1}.", regKey.Name, regKey.SubKeyCount);
			}

			// Задержка на экране.
			Console.ReadKey();
		}

Навигация по реестру:

static void Main()
        {
            // Процесс получения ссылки на объект RegistryKey называется открытием ключа.
            RegistryKey myKey = Registry.LocalMachine;
            RegistryKey software = myKey.OpenSubKey("Software");
            RegistryKey microsoft = software.OpenSubKey("Microsoft");
           // software.Close();

            Console.WriteLine("{0} - всего элементов: {1}.", microsoft.Name, microsoft.SubKeyCount);
            microsoft.Close();

            // Попытка открыть несуществующий ключ. Переменной будет присвоено значение NULL.
            software = myKey.OpenSubKey("nookery");

            // В блоке try совершается попытка обратится к переменной, значение которой не присвоено.
            try
            {
                Console.WriteLine("Открыли узел: {0}.", software.Name);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                Console.WriteLine(e.GetType());
            }

            // Задержка на экране.
            Console.ReadKey();
        }

Редактирование реестра.

Добавляем запись.

static void Main()
        {
            // В этот раз открываем специально для записи.
            RegistryKey myKey = Registry.CurrentUser;

            // Второй аргумент (true) говорит о том, что будет совершаться запись.
            RegistryKey wKey = myKey.OpenSubKey("Software", true);	
            
            try
            {
                Console.WriteLine("Всего записей в {0}: {1}.", wKey.Name, wKey.SubKeyCount);

                // пытаемся создать новый ключ.
                RegistryKey newKey = wKey.CreateSubKey("nookery.ru");
                // Запись прошла успешно в HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node

                Console.WriteLine("Запись \'{0}\' успешно внесена в реестр!", newKey.Name);
                Console.WriteLine("Теперь записей стало: {0}.", wKey.SubKeyCount);
            }
            catch (Exception e)
            {
                // Если возникает проблема - выводим сообщение о ней на экран.
                Console.WriteLine(e.Message);
            }
            finally
            {
                // Закрыть ключ нужно обязательно.
                myKey.Close();
            }	

            // Задержка на экране.
            Console.ReadKey();
        }

Удаляем запись

 static void Main()
        {
            RegistryKey myKey = Registry.CurrentUser;

            // Для удаления тоже нужно иметь права редактирования.
            RegistryKey wKey = myKey.OpenSubKey("Software", true);

            // Вывод на экран всего содержимого ключа поименно.
            string[] keyNameArray = wKey.GetSubKeyNames();

            foreach (string name in keyNameArray)
            {
                Console.ForegroundColor = ConsoleColor.Gray;

                if (name.Contains("nookery"))
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                }

                Console.WriteLine(new string(' ', 5) + name);
            }

            // Теперь пытаемся удалить ключ.
            try
            {
                Console.WriteLine("Всего записей в {0}: {1}.", wKey.Name, wKey.SubKeyCount);
                wKey.DeleteSubKey("nookery");

                Console.WriteLine("Запись \'nookery\' успешно удалена из реестра!");
                Console.WriteLine("Теперь записей стало: {0}.", wKey.SubKeyCount);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            finally
            {
                wKey.Close();
            }

            // Задержка на экране.
            Console.ReadKey();
        }

Читаем ключи реестра:

static void Main()
		{
			// Совершаем навигацию по реестру и открываем ключ для чтения,
			// можно сразу указать весь путь, а не совершать навигацию поэтапно.
			RegistryKey myKey = Registry.CurrentUser;
			RegistryKey wKey = myKey.OpenSubKey(@"Software\nookery"); 

			// Читаем данные и конвертируем в нужный формат.
			string Str = wKey.GetValue("TheStringName") as string;
			int Int = Convert.ToInt32(wKey.GetValue("TheInt32Name"));
			int Ant = Convert.ToInt32(wKey.GetValue("AnotherName"));

			wKey.Close();

			// Покажем содержимое, чтобы убедиться в том, что чтение прошло успешно.
			Console.WriteLine("String: {0}\nInt32: {1}\nAnother: {2}", Str, Int, Ant);

			// Задержка.
			Console.ReadKey();
		}

Пример добавления программы в автозагрузку:

RegistryKey myKey =
Registry.LocalMachine.OpenSubKey(
@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true);
myKey.SetValue("MyProgram", Application.ExecutablePath);

Стоит также уделить больше внимания удалению, метод DeleteSubKey не имеет рекурсивного вызова, это означает что вам придется в начале удалить подраздел, а уже потом сам раздел.

   string registryLocation = @"Software\Microsoft\Windows\CurrentVersion\Uninstall";
            RegistryKey regKey = (Registry.LocalMachine).OpenSubKey(registryLocation, true);
            RegistryKey progKey = regKey.OpenSubKey(progName);
            // Если у нас такая ветка реестра есть
            if (progKey != null)
            {
                // Удаляем данные о программе
                regKey.DeleteSubKey(progName);
            }

Пример поиска по реестру параметра по разделам с помощью рекурсии, к сожалению доступ к некоторым веткам запрещен, да же под админом, пришлось использовать try cath

//Этот блок кода у меня находится в LoadForm
//RegistryKey[] key = {Registry.ClassesRoot,Registry.CurrentConfig,
//               Registry.LocalMachine, Registry.CurrentUser,Registry.Users};
///           comboBox1.DataSource = key;
/// <summary>
        /// запуск поиска параметра
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void BtnSearchValue_Click(object sender, EventArgs e)
        {

            RegistryKey key = (RegistryKey)comboBox1.SelectedItem;
            txtPath.Text = await Task.Run(() => Find(key));
        }

        /// <summary>
        /// передача сообщения в lable
        /// </summary>
        /// <param name="ctrl"></param>
        /// <param name="execute"></param>
        void MarshalToUIThread(Control ctrl, Action execute)
        {
            ctrl.BeginInvoke(execute);
        }

        /// <summary>
        /// Метод поиска по параметру среди всех разделов, рекурсивным вызовом
        /// </summary>
        /// <param name="oneKey"></param>
        /// <returns></returns>
        private string Find(RegistryKey oneKey)
        {
            foreach (var item in oneKey.GetSubKeyNames())
            {
                
                try
                {
                    RegistryKey twoKey = oneKey.OpenSubKey(item, false);
                    string[] nameArgs = twoKey.GetSubKeyNames();
                    var valNameOne = twoKey.GetValueNames();
                    MarshalToUIThread(lbInfo, () => { lbInfo.Text = twoKey.Name; });

                    for (int i = 0; i < valNameOne.Length; i++)
                    {
                        if (valNameOne[i] == txtArgs2.Text)
                        {
                            var rr = twoKey.GetSubKeyNames();
                        }
                    }

                    for (int i = 0; i < nameArgs.Length; i++)
                    {
                        try
                        {
                            RegistryKey three = twoKey.OpenSubKey(nameArgs[i], false);
                            var valNameTwo = three?.GetValueNames();
                            MarshalToUIThread(lbInfo, () => { lbInfo.Text = twoKey.Name; });
                            for (int q = 0; q < valNameTwo.Length; q++)
                            {
                                if (valNameTwo[q] == txtArgs2.Text)
                                {
                                   return three.Name;
                                }
                            }

                            Find(three);
                        }
                        catch { }
                    }
                }
                catch { }
            }
            return  "Не найдено";
        }

Начиная с выходом windows 8 ограничили права приложений с работой реестра, в целях безопасности и теперь для того что бы ваша приложения внесла какие либо изменения необходимо ее запускать  с правами администратора.

Можно пойти 3 путями:

  1. Приобрести сертификат, который будет выдан вам как разработчику и вы будете зарегистрированы.
  2. Продолжать запуск программ от имени администратора.
  3. Создать манифест, который будет сообщать пользователю при попытки запуска программы о том что ее надо запустить от имении администратора.

Как создать такой манифест читать <тут>

Еще очень важный момент если у вас 64бит система то путь сохранения будет отличатся от 32бит к примеру к разделу software, так как данные будут хранится в разделе Software\WOW6432Node. Что бы программа сохраняло по пути Software , можно использовать следующий код:

 

var hkcu = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64);
Обновлено: 09.11.2021 — 19:09

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.