Часть вторая
Мы с вами продолжим писать собственный твикер - утилиту для тонкой настройки системы. В этой части статьи вас ждут дальнейшие разбирательства с кодом твикера на языке C#.
Прежде чем приступать непосредственно к продолжению нашего с вами разговора о написании этой утилиты, кратко напомню, так сказать, "содержание первой серии". А в первой части статьи я, на самом-то деле, успел рассказать совсем немного, поскольку занимался разъяснением того, для чего нужна каждая переменная в коде нашей с вами программы, и размышлениями о том, какой именно спецификатор доступа нужен для каждой из них. Также мы с вами успели рассмотреть код, ответственный за определение того, является ли один конкретный "твик" включенным, или же всё обстоит совершенно наоборот.
Что ж, в этой части статьи о твикере, надеюсь, на всякую мелочь будем тратить уже меньше времени - во-первых, потому что уже не надо будет останавливаться на объяснении назначения глобальных переменных, а во-вторых, потому что вступление в этой части статьи будет существенно короче. Оно, собственно говоря, уже закончилось - давайте уже, пожалуй, приступим к разбору программного кода.
Внесение изменений в реестр
С реестром в C# мы уже, по большому счёту, научились работать в первой части статьи. А если конкретнее, то в том методе, в котором мы читали значения ключей реестра и сравнивали их с эталонными значениями "твикаемых" параметров (если помните, метод этот имел название CheckEnabled). Теперь давайте разберёмся с кодом, который будет вносить изменения в реестр в соответствие с тем, какие "твики" пользователь решил разрешить, а какие - запретить.
public void WriteChanges() { if (IsChanged == false){ return; } String Root = ""; String str; RegistryKey rk; RegistryKey rk1; int i = 0; while (RegistryPath[i] != '\\') { Root += RegistryPath[i]; i++; }; Root = Root.ToUpper(); rk = Registry.CurrentUser; // Здесь должен быть выбор раздела реестра str = RegistryPath; str = str.Remove(0, Root.Length + 1); rk1 = rk.OpenSubKey(str, true); String Val; if (IsEnabled){ Val = EnabledValue; } else { Val = DisabledValue; }; rk1.SetValue(KeyName, Val); return Result; }
Итак, давайте теперь разбираться с этим кодом. Первая осмысленная конструкция - это возврат из функции, если значение ключа не было изменено. Это ускоряет процесс внесения изменений в реестр при большом количестве "твиков" - однако при этом необходимо, чтобы реализация пользовательского интерфейса сама отлавливала, какие "твики" пользователь применяет, и устанавливала соответствующий флаг в поле IsChanged. Далее идёт кусок кода, определяющий, в какое именно место в реестре нужно писать изменения, связанные с "твиканьем" системы. Напомню, что у нас в свойствах каждого "твика" путь к нему в реестре хранится в следующем формате: "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\...". Ну, естественно, вместо HKEY_LOCAL_MACHINE может идти и любой другой корневой элемент реестра, как и вместо пути - любой другой путь к любому нужному для изменения каких-либо параметров ключу. Из-за того, что при работе с реестром в C# мы должны указывать корневой элемент в виде числовой константы, а не строки, необходимо выделять из всего пути эту часть и преобразовывать её в числовую константу. Часть кода, который за это дело отвечает, я пропустил (вместо него стоит комментарий "Здесь должен быть выбор раздела реестра"), потому что совершенно аналогичный код был приведен в предыдущей части статьи. Дальше мы открываем нужный ключ реестра, а потом занимаемся тем, что записываем в него нужное значение. Если "твик" выбран пользователем как разрешённый, в ключ записываем EnabledValue, в противном случае, само собой, пишем DisabledValue. Как видите, всё очень, очень просто.
Собственно, на этом методе разработка класса "твика" закончена. Дальше мы будем разрабатывать другой класс, который будет с "твиками" управляться. Я решил этот класс отдельно не выделять, а возложить обязанности по манипуляции с набором "твиков" на главный оконный класс приложения. Это, вообще говоря, не есть хорошо, потому что код интерфейса и бизнес-логику приложения всё же лучше разделять. Но, поскольку это просто пример, то для лучшего самостоятельного усвоения изложенного материала рекомендуется самостоятельно выделить класс для работы со списком "твиков".
Загрузка списка твиков: постановка
задачи
Этот раздел я, вообще-то, хотел отложить на потом, и на то имелась одна веская причина. Дело в том, что изначально взятый мною список "твиков" был скачан с какого-то сайта (не помню с какого - честно, а то сказал бы), где он был представлен в довольно интересном виде. Вот пример одного из этих "твиков" в его первозданном виде:
Disable "Screen Properties" If this option is enabled, Screen applet will be not avaliable from Control Panel. Requires reboot: yes Key: HKEY_CURRENT_USER\Software\Microsoft\ Windows\CurrentVersion\Policies\System\NoDispCPL Enabled: 1 Disabled: 0
В принципе, это уже довольно неплохо и практически пригодно для загрузки в программу. Тем не менее, буквально за пару минут можно сделать список, ещё более хорошо подходящий для загрузки нашим твикером. Вот как тот же самый "твик" будет выглядеть после небольшой переделки:
.Disable "Screen Properties" If this option is enabled, Screen applet will be not avaliable from Control Panel. Reboot HKEY_CURRENT_USER\Software\Microsoft\Windows\ CurrentVersion\Policies\System NoDispCPL Dword e=1 d=0 ,
Точка обозначает начало твика, запятая - это конец. Вместо Requires reboot: yes и Requires reboot: no лучше использовать Reboot и Noreboot, потому что тогда будет проще проводить парсинг файла со списком "твиков". То же относится и к разделению пути к ключу и самого ключа. Можно, конечно, было бы пойти ещё дальше и разделить также и путь с именем корневого раздела. Дам стандартную отмазку (э... рекомендацию) - лучше поэкспериментировать с этим самостоятельно, будет больше пользы.
Теперь, собственно, о том, что же меня здесь смущает. Дело в том, что лучше было бы записывать это всё не в таком странном формате, а в банальном, но более удобном XML. Кроме того, можно было бы продемонстрировать работу с XML, о которой Microsoft громко кричала ещё тогда, когда выпускала самый первый релиз платформы .NET. В общем, помучавшись немного сомнениями, решил я, что с XML'ем успеется. В крайнем случае, расскажу об этом в третьей части статьи - как об альтернативном способе записи "твиков".
Загрузка списка твиков: практика
Что ж, не буду дальше мучить вас неведением и приведу долгожданный программный код метода, загружающего "твики" в нашем твикере.
private void PrepareTweakingFeaturesList(string DataFile) { TweakerOption Opt_; String str; StreamReader fs = File.OpenText(DataFile); int u = 0; lst.Clear(); while ((str = fs.ReadLine()) != null) { if (str == "") { continue; } switch (str[0]) { case ';': break; case '.': str = str.Remove(0, 1); u = 0; Opt_ = new TweakerOption(); Opt_.OptionName = str; u++; break; case ',': lst.Add(Opt_); u = 0; break; default: switch (u) { case 1: Opt_.Description = str; u++; break; case 2: if (str.ToLower() == "reboot"){ Opt_.Reboot = true; } else { Opt_.Reboot = false; }; u++; break; case 3: Opt_.RegistryPath = str; u++; break; case 4: Opt_.KeyName = str; u++; break; case 5: Opt_.KeyType = str.ToLower(); u++; break; case 6: str = str.Remove(0, 2); Opt_.EnabledValue = str; u++; break; case 7: str = str.Remove(0, 2); Opt_.DisabledValue = str; u++; break; case 8: u = 0; break; default: break; } break; } } }
Ну что же, давайте разбираться с тем, что там написано. Во-первых, давайте разберёмся с переменными, используемыми в данном методе (не с глобальными, конечно, а с локальными). Opt_ - это текущий "твик", данные которого мы считываем из файла в цикле. Промежуточная переменная str используется в разных частях этого метода, поток ввода fs читает данные из нашего файла с описанием твиков, а u - это счётчик считанных строк, начиная от строки, которая начинается с символа ".".
Итак, что мы делаем? Считываем сначала строку и смотрим, что за она такая - если это ";", то ничего не делаем, если это "." - создаём новый экземпляр нашего "твикового" класса и записываем в его заголовок то, что следует за точкой. Дальше считываем по одной строке и, инкрементируя счётчик, определяем по нему, что за строку мы считали: то ли это пояснение к "твику", то ли путь в реестре, то ли значение ключа, когда "твик" включен... Здесь всё будет просто и понятно, если внимательно посмотреть на описание формата (вернее, на пример одного из "твиков") выше. "Твики" по мере считывания добавляются в глобальный список этих самых "твиков", который называется lst. Забегая наперёд, хочу сказать, что дальше мы этот список будем использовать, когда потребуется внести изменения в тот или иной "твик", т.е. включить или отключить его. Но это будет уже в следующей части статьи, которая, как я надеюсь, станет заключительной. На сегодня же, я так думаю, уже хватит - слишком много кода тоже не слишком полезно для газетной статьи.
Хочу теперь сказать пару слов в адрес любителей критики, которые найдутся и на нашем форуме, и среди читателей бумажной версии газеты. Код программы неидеален, но он и не создавался для того, чтобы быть эталонным. Он просто иллюстрирует две вещи: работу с языком программирования C# и платформой .NET Framework, на которой он выполняется, и одну идею, которая состоит в том, что написать собственный твикер - легче лёгкого. Для тех, кто только входит в удивительный мир программирования, эта статья должна быть полезной. А если вам она таковой не показалась - что ж, значит, ваш уровень уже выше.
Вадим СТАНКЕВИЧ,
dreamdrusch@tut.by
Комментарии