Используем реестр Windows на C# нестандартным способом

zarufakis

Client
Регистрация
22.03.2019
Сообщения
1 737
Благодарностей
1 130
Баллы
113
Введение

Мой путь использования внешних данных был таков:
1. Использую файлы с чтением и прямой записью – тут комментарии излишни (баги, ошибки, потерянные данные)
2. Использования списков Zennoposter – Можно работать с одним файлом из разных шаблонов в рамках одного Zennoposter
3. Использования файлов на прямую, без привязки к спискам Zennoposter (для записи использовать lock) - Значительно увеличивает производительность и не жрет память на многопотоке
4. Использование базы данных – масштабирваться есть куда, увеличивается производительность.
5. Использование самописного API + MySQL – Распределение клиентских возможностей, нет привязки к конкретному компьютеру.

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

Бинго и тут дело пошло.
Беглый гуглеж показал, что в одну запись можно засунуть до 1 мегабайта информации (примерно 1кк символов), в одной ветке до 512 мегабайт, а сам реестр можно забить до 4 гигабайт.
Учитывая то, что мы работаем с текстовой информацией и такие объемы ну точно не нужны, думаю, что для списков не слишком большого объема реестр можно использовать. Я проверял, в одну ветку спокойно поместилось 9000 строк.


Практика

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

Пихаем в юзинги
using Microsoft.Win32;

Пихаем в общий код, после всех закрывающихся скобок


C#:
namespace RegEdit
{
    public class RegistryHelper
    {
        private string _registryPath;

        public RegistryHelper(string registryPath)
        {
            _registryPath = registryPath;
        }

        // Метод для записи строкового значения в реестр
        public void WriteValue(string valueName, string value)
        {
            try
            {
                using (RegistryKey baseKey = Registry.CurrentUser.CreateSubKey(_registryPath))
                {
                    if (baseKey != null)
                    {
                        baseKey.SetValue(valueName, value, RegistryValueKind.String);

                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"Ошибка при записи в реестр: {ex.Message}");

            }
        }

        // Метод для чтения строкового значения из реестра
        public string ReadValue(string valueName)
        {
            try
            {
                using (RegistryKey baseKey = Registry.CurrentUser.OpenSubKey(_registryPath))
                {
                    if (baseKey != null)
                    {
                        object value = baseKey.GetValue(valueName);
                        if (value != null)
                        {
                            return value.ToString();
                        }
                    }
                    return null;
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"Ошибка при чтении из реестра: {ex.Message}");

            }
        }

        // Метод для удаления значения из реестра
        public void DeleteValue(string valueName)
        {
            try
            {
                using (RegistryKey baseKey = Registry.CurrentUser.OpenSubKey(_registryPath, true))
                {
                    if (baseKey != null)
                    {
                        baseKey.DeleteValue(valueName, false);
                        Console.WriteLine($"Значение {valueName} успешно удалено из реестра");
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"Ошибка при удалении из реестра: {ex.Message}");

            }
        }

        // Метод для удаления всех значений в ключе реестра
        public void DeleteAllValues()
        {
            try
            {
                using (RegistryKey baseKey = Registry.CurrentUser.OpenSubKey(_registryPath, true))
                {
                    if (baseKey != null)
                    {
                        // Получаем все имена значений
                        string[] valueNames = baseKey.GetValueNames();

                        // Удаляем каждое значение
                        foreach (string valueName in valueNames)
                        {
                            baseKey.DeleteValue(valueName, false);
                        }

                        Console.WriteLine("Все значения успешно удалены");
                    }
                    else
                    {
                        throw new Exception($"Путь {_registryPath} не найден в реестре");
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"Ошибка при удалении значений: {ex.Message}");
            }
        }
    }
}
Теперь перейдем к самим кубикам, в которых будем делать всю основную логику наших действий

Добавление записи

C#:
var registry = new RegEdit.RegistryHelper(@"SOFTWARE\MyApp");
registry.WriteValue("Key", "Value");
128756


Если данные нужно добавить из переменных

C#:
var registry = new RegEdit.RegistryHelper(@"SOFTWARE\MyApp");
string Key = project.Variables["Key"].Value;
string Value = project.Variables["Value"].Value;

registry.WriteValue(Key, Value);
Теперь давайте прочитаем данные

C#:
var registry = new RegEdit.RegistryHelper(@"SOFTWARE\MyApp");
string Value = registry.ReadValue("Key");
Ну а теперь попробуем удалить наш "Key"

C#:
var registry = new RegEdit.RegistryHelper(@"SOFTWARE\MyApp");
registry.DeleteValue("Key");
Как видите, все просто.

А что делать с массивом?
Тут нам помогут циклы
Допустим у нас есть такой массив в переменной и его нужно перенести в реестр

Код:
Директор;Василий Иванович
Помощник;Петька
Секретарша;Анка
Пишем код:

C#:
var registry = new RegEdit.RegistryHelper(@"SOFTWARE\MyApp");
string input = project.Variables["data"].Value; // Тут наш массив
string[] entries = input.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);

try
{
    // Записываем все entries
    foreach (string entry in entries)
    {
        string[] parts = entry.Split(';');
        if (parts.Length == 2)
        {
            string Key = parts[0].Trim();
            string Value = parts[1].Trim();
            registry.WriteValue(Key, Value);
        }
    }
}
catch (Exception ex)
{
    throw new Exception($"Ошибка при записи в реестр: {ex.Message}");
}
Теперь прочитаем, кто у нас директор

C#:
var registry = new RegEdit.RegistryHelper(@"SOFTWARE\MyApp");
return registry.ReadValue("Директор");
128758

Ух ты, как неожидано ))

А как быть с данными, которые нужно обновлять с периодичностью, ну например в 10 минут?
Просто добавь ключ "timestamp" с текущим "unixtime"

C#:
// Добавь выше строки "// Записываем все entries"
// Записываем текущее время
long unixTimestamp = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds();
registry.WriteValue("timestamp", unixTimestamp.ToString());
и при каждом выполнении шаблона проверяй, не привысил ли он порогового значения от текущего "timestamp-600"

C#:
var registry = new RegEdit.RegistryHelper(@"SOFTWARE\MyApp");

var timeStr = registry.ReadValue("timestamp");
int time_update = 0;

// Проверяем, есть ли значение времени в реестре
if (!string.IsNullOrEmpty(timeStr))
{
    time_update = Convert.ToInt32(timeStr);
}

long timestamp = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds();
// Вычисляем абсолютную разницу во времени
int timeDifference = Math.Abs((int)timestamp - time_update);
bool isTimeToUpdate = timeDifference <= 600;

if(isTimeToUpdate)
{
    throw new Exception($"Данные обновлять не пришло время: {timeDifference}");
}
Если 600 секунд (10 минут) не прошло с даты прошлого добавления, то кубик пойдет по красной, если прошло - по зеленой.

Ну а как же удалить все записи, если они больше не нужны?

C#:
var registry = new RegEdit.RegistryHelper(@"SOFTWARE\MyApp");
registry.DeleteAllValues();


Заключение

Понятно, что данный механизм требует хоть какого нибудь знания и опыта, но, если включить фантазию, то по моему нет границ того, что нельзя было запихать в реестр, ведь он может хранить данные не только в строковых значениях, но и в байтах. А если запихать туда картинку в Base64... Держите меня семеро!

А ты мой юный читатель, что первое пришло тебе на ум, что можно туда запихать и использовать в зенке?
 

Вложения

Последнее редактирование:

burhanov88

Client
Регистрация
08.04.2015
Сообщения
71
Благодарностей
23
Баллы
8
А потом реестр разрастется и ОС падает...
Интересно, но зачем? Чем не устраивает иерархия файлов и папок если БД не нравиться?
 

Alex91

Активный пользователь
Регистрация
15.08.2024
Сообщения
325
Благодарностей
82
Баллы
28
А потом реестр разрастется и ОС падает...
Интересно, но зачем? Чем не устраивает иерархия файлов и папок если БД не нравиться?
Тсс... Контору не палим....
Зато на следующий конкурс уже готовая тема, как дефрагментировать/очистить/сжать реестр, что бы система не упала :-)
 

zarufakis

Client
Регистрация
22.03.2019
Сообщения
1 737
Благодарностей
1 130
Баллы
113
А потом реестр разрастется и ОС падает...
Интересно, но зачем? Чем не устраивает иерархия файлов и папок если БД не нравиться?
Никто не говорит, что в реестр нужно пихать гигабайты, но система даже мне заметит статичный список на 100-200 строк.
 

Dmitriy Ka

Client
Регистрация
03.05.2016
Сообщения
773
Благодарностей
515
Баллы
93
Тсс... Контору не палим....
Зато на следующий конкурс уже готовая тема, как дефрагментировать/очистить/сжать реестр, что бы система не упала :-)
Ты такой смешной, говно статью с капчей ты защищаешь, а тут статью хорошо оформили, все разжевали и ты недоволен (facepalm)

Описан полный цикл CRUD, если ты будешь правильно подходить к логике работы шаблона ничего из "дефрагментировать/очистить/сжать реестр" не понадобится.
 

Alex91

Активный пользователь
Регистрация
15.08.2024
Сообщения
325
Благодарностей
82
Баллы
28
Ты такой смешной, говно статью с капчей ты защищаешь, а тут статью хорошо оформили, все разжевали и ты недоволен (facepalm)

Описан полный цикл CRUD, если ты будешь правильно подходить к логике работы шаблона ничего из "дефрагментировать/очистить/сжать реестр" не понадобится.
Просто ржу над такими как ты, ничего не защищаю и не продвигаю.

Ну а если по сути, то размещать списки в реестре... Это пи..ц как оригинальная мысль ;-)
Примерно из той же оперы как использовать механизмы мелкософцев для работы с буфером обмена...
Ну в принципе же тут на форуме на полных щах разрабатывали работу с буфером обмена, почему бы не быть статье на полных щах по работе с реестром... Я не против, пусть будет :-)
 

Alex91

Активный пользователь
Регистрация
15.08.2024
Сообщения
325
Благодарностей
82
Баллы
28
Ну нахрена ты вот пинганул меня ? :-)
Пришлось глянуть код, хотя тема в принципе не интересна....

Ну и первый же вопрос, а что будет если в многопотоке произойдёт одновременная работа с этим "списком" в реестре ?
 

zarufakis

Client
Регистрация
22.03.2019
Сообщения
1 737
Благодарностей
1 130
Баллы
113

Alex91

Активный пользователь
Регистрация
15.08.2024
Сообщения
325
Благодарностей
82
Баллы
28

bvbfor

Client
Регистрация
10.04.2016
Сообщения
384
Благодарностей
212
Баллы
43
А ты мой юный читатель, что первое пришло тебе на ум, что можно туда запихать и использовать в зенке?
Я бы не рискнул использовать шаблон, где юный читатель что то туда запихнул.

А так можно использовать например как флаги. Написать прогу на c# c формой, которая устанавливает различные значения, а шаблоны считывают эти значения и в зависимости от них - разная логика работы.
 

samsonnn

Client
Регистрация
02.06.2015
Сообщения
1 802
Благодарностей
1 473
Баллы
113
Я бы не рискнул использовать шаблон, где юный читатель что то туда запихнул.
Неужели вы думаете что прочитав эту статью, все побегут ее применять? Далеко не все будут этим пользоваться. Можете спать спокойно!
 
  • Спасибо
Реакции: djaga

zarufakis

Client
Регистрация
22.03.2019
Сообщения
1 737
Благодарностей
1 130
Баллы
113
Скажу так, что на форуме это первая статья (других не нашел) объясняющий по шагам как работать с реестром винды из зенки. Надо это, полезно или совершенно бесполезная херня - каждый решает сам, но данный метод есть и я об этом рассказал.
 
  • Спасибо
Реакции: Lest и samsonnn

bvbfor

Client
Регистрация
10.04.2016
Сообщения
384
Благодарностей
212
Баллы
43
Неужели вы думаете что прочитав эту статью, все побегут ее применять? Далеко не все будут этим пользоваться. Можете спать спокойно!
Да что вы напали на статью, можно применять самому, если знаешь, что делаешь.

По сути можно сделать панель управления работающими шаблонами.
Здесь есть статья по управлению шаблонами через телеграм, можно сделать панель управления на c# через реестр, это и проще и по скорости намного выигрышнее чем у ботов. И ботов делать не нужно.
 

samsonnn

Client
Регистрация
02.06.2015
Сообщения
1 802
Благодарностей
1 473
Баллы
113
Скажу так, что на форуме это первая статья (других не нашел) объясняющий по шагам как работать с реестром винды из зенки. Надо это, полезно или совершенно бесполезная херня - каждый решает сам, но данный метод есть и я об этом рассказал.
Да, но так же надо рассказать про то, что это каждый будет использовать на свой страх и риск. Если какой то криворукий что то нахимичит с реестром, чтоб потом ТС не был виноват, но и зенолаб тоже. А то все думают, что все выложенно на зено лаб, это мега безопасно, но это не так!
 
  • Спасибо
Реакции: djaga

seodamage

Client
Регистрация
08.09.2014
Сообщения
227
Благодарностей
69
Баллы
28
наверное как то можно применить чтобы раз в какое то время делался гет запрос куда то к себе на сервер и оттуда парсилось значение, а затем заносилось в реестр. и если что то не так, то сделать невозможным запуск шабов с этим кодом. что то типо системы защиты лицензии на шабы. сам пока ещё не успел посмотреть в полном обьёме, к сожалению)
 
  • Спасибо
Реакции: zarufakis

zarufakis

Client
Регистрация
22.03.2019
Сообщения
1 737
Благодарностей
1 130
Баллы
113
наверное как то можно применить чтобы раз в какое то время делался гет запрос куда то к себе на сервер и оттуда парсилось значение, а затем заносилось в реестр. и если что то не так, то сделать невозможным запуск шабов с этим кодом. что то типо системы защиты лицензии на шабы. сам пока ещё не успел посмотреть в полном обьёме, к сожалению)
Ты прям очень рядом. Сейчас разрабатываю реализацию лицензирования, по заветам Бендера ))
 
  • Спасибо
Реакции: Dmitriy Ka и seodamage

Dmitriy Ka

Client
Регистрация
03.05.2016
Сообщения
773
Благодарностей
515
Баллы
93
наверное как то можно применить чтобы раз в какое то время делался гет запрос куда то к себе на сервер и оттуда парсилось значение, а затем заносилось в реестр. и если что то не так, то сделать невозможным запуск шабов с этим кодом. что то типо системы защиты лицензии на шабы. сам пока ещё не успел посмотреть в полном обьёме, к сожалению)
А это интересно)
 

Кто просматривает тему: (Всего: 3, Пользователи: 0, Гости: 3)