Приветствую всех, сегодня поговорим об одной интересной теме, работа с реестром.
Реестр 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 с указанием признака «открытие для записи».
Выводим информацию о структуре реестра:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
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(); } |
Навигация по реестру:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
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(); } |
Редактирование реестра.
Добавляем запись.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
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(); } |
Удаляем запись
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
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(); } |
Читаем ключи реестра:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
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(); } |
Пример добавления программы в автозагрузку:
1 2 3 4 |
RegistryKey myKey = Registry.LocalMachine.OpenSubKey( @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true); myKey.SetValue("MyProgram", Application.ExecutablePath); |
Стоит также уделить больше внимания удалению, метод DeleteSubKey не имеет рекурсивного вызова, это означает что вам придется в начале удалить подраздел, а уже потом сам раздел.
1 2 3 4 5 6 7 8 9 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
//Этот блок кода у меня находится в 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 путями:
- Приобрести сертификат, который будет выдан вам как разработчику и вы будете зарегистрированы.
- Продолжать запуск программ от имени администратора.
- Создать манифест, который будет сообщать пользователю при попытки запуска программы о том что ее надо запустить от имении администратора.
Как создать такой манифест читать <тут>
Еще очень важный момент если у вас 64бит система то путь сохранения будет отличатся от 32бит к примеру к разделу software, так как данные будут хранится в разделе Software\WOW6432Node. Что бы программа сохраняло по пути Software , можно использовать следующий код:
1 |
var hkcu = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64); |