В данной статье вы узнаете основные понятия необходимые для работы с реестром и научитесь легко и быстро его изменять через Unishell.
Что такое реестр Windows?
Реестр - это база данных, которая хранит настройки приложений( как пользовательских, так и системных) для всех пользователей компьютера.
Зачем мне реестр может понадобиться?
Реестр может понадобиться для добавления в автозагрузку, добавление ассоциаций файлов, контекстного меню, изменение Environment и PATH, взаимодействие с настройками других приложений, backup реестра, сохранение своих настроек для всех/текущего пользователя. Для просмотра реестра можно открыть редактор реестра: WIN + R и ввести regedit.
Основные разделы реестра (кусты)
В реестре есть основные два куста (корневые разделы реестра) HKLM и HKU, остальные являются ссылками на эти два куста. Первый содержит данные для всего компьютера, второй - информацию для каждого пользователя. Без прав администратора можно изменять только данные текущего пользователя в HKU (и то не все).
Но работать с этими кустами напрямую не всегда удобно, поэтому часто используют ссылки на них (псевдонимы).
HKLM(HKEY_LOCAL_MACHINE) - данные для всего компьютера
HKU(HKEY_USERS) - данные для всех пользователей
HKCU(HKEY_CURRENT_USER) - данные для текущего пользователя(ссылка на HKU)
HKCR(HKEY_CLASSES_ROOT) - данные ассоциаций файлов и папок( изменения сохраняются в HKCU, при получении являются объединением HKLM и HKCU, при совпадении берутся из HKCU)
HKCC(HKEY_CURRENT_CONFIG) - данные текущей аппаратной конфигурации( ссылка на HKLM)
Типы данных и устройство реестра
Реестр можно представить в виде файловой системы, у которой есть несколько дисков - кустов(HKU, ...), папок - ключей(subkey), файлов - полей с данными(field). Причем у ключа может быть тоже значение(поле), но в большинстве случаев оно не используется. Пользователь идентифицируется по SID.
Типы полей реестра(рекомендуемые для использования):
Имя типа в Unishell | Имя типа в реестре | Назначение |
STRING | REG_SZ | обычная строка |
STRINGS | REG_MULTI_SZ | список строк |
PATH | REG_EXPAND_SZ | строка, в которую при вызове Windows подставляются значения,например, "%USERPROFILE%", обычно нужна в путях которые вызывает сам Windows( ассоциация файлов) |
INTEGER | REG_DWORD | целое число(4 байта), используется как для хранения чисел, так и флагов( т.к. типа bool нет в реестре) |
LONG_INT | REG_QWORD | целое число(8 байт) |
BINARY | REG_BINARY | бинарные данные |
Также есть и другие типы данных, но скорей всего они вам не понадобятся, так как используются в основном системой.
Что же такое Unishell?
Это библиотека, предоставляющая унифицированный интерфейс, цель которого упростить работу на разных платформах. API стремится к обьектно-ориентированной модели и максимальному использованию свойств(property). Приоритет делается на читаемость кода.
Работа с реестром через Unishell
Установка библиотеки:
pip install unishellЕсть три типа для кого производятся изменения в Unishell:
from unishell.regedit import CurUser,User,Users
CurUser # Обьект для работы с текущим пользователем
User("sid") # Обьект для работы с конкретным пользователем
Users # Обьект для работы со всеми пользователямиВсе они могут заменять друг друга в большинстве случаев. Под капотом они автоматически определяют в какой куст реестра писать данные.
При работе с реестром желательно сделать его резервную копию через regedit.
Для начала подключимся к кусту текущего пользователя( в реальных задачах не рекомендуется использовать import *). Рекомендуется использовать 1 или 4 вариант, в целом они все идентичны. :
from unishell.regedit import *
import winreg
registry = Registry("HKCU")
registry2 = Registry(winreg.HKEY_CURRENT_USER)
user_sid = CurUser.id
registry3 = Registry(user_sid) # Получение куста(раздела реестра) по SID пользователя
registry4 = Registry(CurUser) # или Users/User("sid")Перемещение по ключам происходит через "/". ВАЖНО( реестр является регистронезависимым для доступа, формат сохраняется при создании ключа):
#Это одно и тоже
software = registry / "SOFTWARE"
software = registry / "software"
# просмотр содержимого ключа(в Unishell ключ is Container)
registry.containers() # ['AppEvents', ..., 'SOFTWARE',...]
registry.fields() # []Создадим настройки своего приложения для текущего пользователя( приложения обычно пишут свои настройки в HKCU / Software/ <MyApp>, что не требует прав админа):
myapp = registry / "SOFTWARE" / "MyApp"
myapp["version"] = "1.2.3" #STRING
myapp["dependies"] = ["winreg","unishell"] #STRINGS
myapp["num_load"] = 0 #INTEGER
myapp["int64"] = 2**32 + 5 #LONG_INT
myapp["all_users"] = False #INTEGER
myapp["dir_for_install"] = "%USERPROFILE%\\AppData\\MyApp" #PATH
myapp["bin"] = bytes([1,1,1]) #BINARYЕсли есть необходимость использовать определенный тип( работает быстрее):
from unishell.regedit.reg_types import STRING
field = Field(myapp,"dir_for_install")
field.set("%USERPROFILE%\\AppData\\MyApp",STRING) Дополнительные полезные методы Container и Field:
myapp.create() #создает ключ
myapp.exists() # True
myapp.rename("NewName")
myapp["all_users"] # 0
del myapp["all_users"]
myapp.delete() # рекурсивно удаляет ключ и его данные
field.get(default = None, return_type = False)
field.exists() # True
field.rename("NewName")
field.delete()Методы выгрузки / загрузки данных из реестра
Загрузить/ получить данные можно в двух форматах с типами или без. Рекомендуется использовать с типами для уменьшения ошибок. ВАЖНО: Unishell бинарные данные принимает/возвращает в типе bytes, который не является типом json и требует преобразования.Загрузка данных в реестр для нашего приложения из json:
# с типами
config = {
'version': ('1.2.3', 'STRING'),
'dependies': (['winreg', 'unishell'], 'STRINGS'),
'num_load': (0, 'INTEGER'),
'int64': (4294967301, 'LONG_INT'),
'all_users': (0, 'INTEGER'),
'dir_for_install': ('%USERPROFILE%\\AppData\\MyApp', 'PATH'),
'bin': (b'\x01\x01\x01', 'BINARY')}
myapp.from_json(config,use_types = True)Backup куста реестра(требует прав Администратора для загрузки):
from unishell import File
import json
import base64
class BytesEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, bytes):
return {
'__type__': 'bytes',
'value': base64.b64encode(obj).decode('utf-8')
}
return super().default(obj)
def bytes_decoder(dct):
if '__type__' in dct and dct['__type__'] == 'bytes':
return base64.b64decode(dct['value'].encode('utf-8'))
return dct
SOFTWARE_backup = json.dumps(software.json(use_types=True),cls=BytesEncoder)
File("SOFTWARE_backup.json")< SOFTWARE_backup
SOFTWARE_backup = File("HKCU_backup.json").content
SOFTWARE_json = json.loads(SOFTWARE_backup, object_hook=bytes_decoder)
software.from_json(SOFTWARE_json,use_types=True) #Требуются права админаПробовал выгрузить куст текущего пользователя с помощью regedit и Unishell, вследствие чего получил следующую таблицу(Windows 10):
Размер .reg | Размер json(use_types = True) | Размер json( use_types = False) |
100 Мб | 24 Мб | 23Мб |
Как ни странно получилось, что json весит значительно меньше чем reg, возможно структура reg не очень экономична. Вследствие этой таблицы рекомендую использовать json(use_types = True) для некорневых разделов, для кустов это не полностью работает( права администратора не все разрешают изменять).
Заключение
В ходе данной статьи были рассмотрены базовые принципы работы с реестром с помощью Unishell. Некоторые подробности (типы данных и др.) были опущены для того, чтобы не раздувать статью. Дополнения по устройству Реестра Windows и работы Unishell планируются в следующих статьях. Важно смотреть версию Unishell(API ее может меняться).
P. S: являюсь разработчиком Unishell, прошу прокомментировать ее API, основную часть документации планирую выкладывать на Хабре. Развиваю идею кроссплатформенной cmd. На данный момент в приоритете разработка под Windows. Позже будут аналоги под Unix с аналогичным интерфейсом. Дополнения по устройству Windows и работы Unishell планируются в следующих статьях.
