Твикер своими руками

Часть первая

Среди множества разнообразного софта в Сети твикером, наверное, является каждая пятая, если не каждая третья, утилита. Почему бы не прибавить к этому многообразию ещё один твикер, собственного производства? Тем более, программировать его вовсе не сложно...

Вот примерно такими рассуждениями я и руководствовался, когда задумывал написать эту статью. Конечно, многие читатели со мной не то что не согласятся - они наверняка обвинят меня в бесполезности такой статьи. Потому что твикеров и вправду пруд пруди, и вряд ли можно в одну статью уложить всё, что многие авторы твикеров накапливали в своих программных продуктах годами. Что ж, я и не буду спорить, что твикер, который выйдет из ваших рук, если вы решите повторить всё изложенное здесь, будет хуже, чем TweakXP - хотя, в общем-то, во многом всё в ваших собственных руках. Тем не менее, твикер - это отличный способ попрактиковаться в аккуратной работе с системным реестром и, при желании, выполнить ещё пару полезных для программирования упражнений. Так что твикер мы сейчас будем писать не для публики, а для себя, с целью совершенствования нашего внутреннего мира и постижения сокровенных тайн системного реестра, открытых немногим посвящённым.

Для вящей полезности этого дела в качестве языка программирования я выбрал C#. Думаю, те, кто до сих пор с ним ещё не работал, смогут оценить некоторые полезные свойства как самого языка, так и runtime-среды Microsoft .NET Framework, в которой выполняются программы, на этом языке написанные. Так что, в общем и целом, думаю, написание твикера будет не таким уж и бесполезным для многих читателей занятием.

Теперь давайте немного скажу о том, что нам понадобится для написания этого самого твикера. Собственно, кроме среды разработки, ничего особенного не понадобится. В качестве оной можно взять Microsoft Visual Studio, для которой существует бесплатная Express Edition. В общем-то, если вы привыкли программировать в Visual Studio, никуда с неё пересаживаться не нужно, но лично я использовал другую среду разработки - #Develop, найти которую на бескрайних просторах Всемирной паутины можно по адресу www.icsharpcode.net/OpenSource/SD. Не могу сказать, чтобы #Develop была сильно хуже или сильно лучше Visual Studio, но меня она вполне устраивает - так что, вполне вероятно, устроит и вас. По крайней мере, если у вас нет никакой среды для работы с C#, то скачать #Develop будет намного проще, чем Visual Studio, потому что "весит" она в десятки, если не в сотни раз меньше. Есть ещё C# Builder от CodeGear, и им тоже можно успешно пользоваться.

 

Поскольку я не привязываюсь к какой-то конкретной среде разработки, то и подробных инструкций "нажмите ту кнопку там, а эту здесь" не будет. Если есть какие-то вопросы касательно того, как, например, создать новую форму, то во всех средах разработки имеется справка, которая как раз и призвана подобные моменты разъяснять.

Ну, кажется, со вступлением, наконец-то, покончено, и можно приступать, что называется, к активным действиям. К каким таким активным, спросите вы? Писать твикер, конечно же. Для начала создайте новый проект и на всякий случай сохраните его в первозданном виде где-нибудь (например, под именем MySuperPuperMegaCoolAdvancedTweakerProfessional). Теперь добавьте в свой проект новый класс под названием TweakerOption (можно его называть и как-нибудь по-другому, например, просто Tweak, но главное не забыть, что в тексте статьи он будет называться всё-таки TweakerOption). Этот класс будет у нас содержать всё нужное для работы с каждым твиком. Сначала приведу список его полей, а затем уже расскажу, для чего каждое из них будет нужно.

public String OptionName;
public String Description;
public Boolean Reboot;
public String RegistryPath;
public String KeyName;
public String KeyType;
public String EnabledValue;
public String DisabledValue;
public Boolean IsEnabled;
public Boolean IsChanged;

Итак, поехали по порядку. Первое поле содержит в себе имя твика, которое будет отображаться на экране - например "Enable autorun for CD/DVD" ("Разрешить автозапуск для CD/DVD дисков"). Второй - краткое описание для этого параметра, которое нужно для того, чтобы разъяснить пользователю, что он получит в результате включения/отключения этого самого параметра. Третье поле, Reboot, будет true, если изменения параметра вступят в свою законную силу только после того, как пользователь перезагрузит компьютер. RegistryPath хранит в себе информацию о том, какой ключ реестра изменяется при изменении данного параметра, то есть он хранит в себе путь к этому ключу. Имя и тип самого ключа хранят, соответственно, такие поля, как KeyName и KeyType. Следующие два поля хранят в себе, соответственно, значения ключа реестра, соответствующие включённому и отключённому состоянию нашего с вами параметра. Обычно эти значения будут числовыми, но иногда могут встретиться и строковые параметры, так что наилучшим решением будет хранить их оба в виде строк - ведь перевести число в строку можно всегда, а обратное действие, увы и ах, часто бывает совершенно невозможно. Последние два параметра хранят в себе информацию о том, в каком состоянии сейчас находится данный параметр (например, включён ли для компакт-дисков автозапуск или нет) и были ли внесены какие-нибудь изменения.

Несколько слов, я так думаю, нужно сказать о спецификаторах доступа для этих полей. Я, как видите, поленился придумывать для каждого свой собственный спецификатор доступа и выставил им всем в качестве оного public. С точки зрения объектно-ориентированного программирования, это не очень-то хорошо, потому как любой класс может модифицировать любое из этих полей, записав в неё какое-нибудь не сильно подходящее значение. Грамотным подходом было бы сделать эти все поля private и обернуть каждое из них методом, возвращающим значение этого поля (так называемым "геттером", от английского get - получать). Инициализироваться поля будут всё равно специальным методом, так что посторонним классом из всех них придётся изменять разве что IsChanged и, в каких-нибудь исключительных случаях, IsEnabled. Но это всё сделать сравнительно несложно, поэтому я оставляю это упражнение, как сказали бы в школе, вам на самостоятельную проработку. Это изменение не займёт много времени, уверяю вас, зато каждый геттер-метод занял бы весьма существенную газетную площадь, которую мы с вами лучше используем в каких-нибудь более полезных целях.

Теперь давайте перейдём к методам нашего класса. Инициализацию значений твиков я решил оставить на следующий раз, поскольку это займёт довольно много места. Сейчас же давайте сначала посмотрим на конструктор нашего класса. Он получился весьма лаконичным:

public TweakerOption()
{
IsChanged = false;
}

То есть, в конструкторе мы только указываем, что никакие параметры пока не менялись. Да и откуда бы им поменяться, собственно, если пока ничего ни пользователь, ни сам твикер не делали?

Далее для того, чтобы определить, в каком состоянии находится параметр, описываемый классом, нужно сначала добавить в нашу программу namespace для работы с реестром. В C# namespace - аналог package из Java или unit'а из Delphi. Поэтому для того, чтобы мы могли работать с реестром Windows, в самое начало файла с исходным текстом нашей формы нужно дописать следующую строку (естественно, безо всяких кавычек): "using Microsoft.Win32;".

Теперь посмотрим, а после и разберём код метода, определяющего "включённость" твика.

public void CheckEnabled()
{
String Root = "";
String str;
RegistryKey rk;
RegistryKey rk1;
object s;
// Getting ROOT name
int i = 0;
while (RegistryPath[i] != '\\') {
Root += RegistryPath[i];
i++;
};
Root = Root.ToUpper();
rk = Registry.CurrentUser;
if (Root == "HKEY_CURRENT_USER"){
rk = Registry.CurrentUser;
};
if (Root == "HKEY_LOCAL_MACHINE"){
rk = Registry.LocalMachine;
};
if (Root == "HKEY_CLASSES_ROOT"){
rk = Registry.ClassesRoot;
};
if (Root == "HKEY_CURRENT_CONFIG"){
rk = Registry.CurrentConfig;
};
if (Root == "HKEY_DYN_DATA"){
rk = Registry.DynData;
};
if (Root == "HKEY_USERS"){
rk = Registry.Users;
};
if (Root == "HKEY_PERFORMANCE_DATA"){
rk = Registry.PerformanceData;
};
str = RegistryPath;
str = str.Remove(0, Root.Length + 1);
// Checking value (default = disabled)
rk1 = rk.OpenSubKey(str, false);
if (rk1 == null) {
IsEnabled = false;
return;
};
s = rk1.GetValue(KeyName, "");
IsEnabled = (s.ToString() == EnabledValue);
}

Кода, как видите, получилось сравнительно много, но он весь очень простой, в чём вы сейчас получите возможность самостоятельно убедиться. Для начала идут объявления переменных. Root - это корневой раздел реестра (один из следующих: HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_CLASSES_ROOT, HKEY_CURRENT_CONFIG, HKEY_DYN_DATA, HKEY_USERS, HKEY_PERFORMANCE_DATA. Реально нам, конечно, понадобятся только первые три, но, сами понимаете, мало ли что - пусть лучше наш с вами код будет более гибким. Переменная str - это вспомогательная переменная, которая активно участвует в различных промежуточных действиях. Переменная rk - это ключ реестра, указывающий на тот путь, в котором хранится, собственно, ключ нашего твикаемого параметра, который сам уже обозначается переменной rk1. Переменная s у нас используется в программе для того, чтобы хранить в ней значение ключа, имеющееся в настоящий момент.

Дальше идёт, собственно, производящий какие-то действия код. Какие именно он действия производит? Сначала мы выцарапываем из полного пути тот раздел реестра, в котором у нас хранится твикаемый параметр. Это, конечно, можно было бы реализовать и красивее, но это, опять-таки, задача для самостоятельного решения, чтобы вы чуть-чуть поизучали runtime-библиотеку C#. Дальше идёт длинный блок, в котором мы инициализируем rk для нужного нам раздела реестра. Дальше мы открываем нужный ключ, считываем его значение и сравниваем его с эталонным. Если текущее значение параметра совпало с тем, которое обозначает его "включённость", то всё в порядке, и параметр считаем включённым.

В общем-то, если вы скажете, что код, который я предложил вам выше, неоптимален, то я с вами соглашусь. Действительно, в нём есть что дорабатывать, и, я думаю, если вы это доработаете, то вам, как программисту, это пойдёт на пользу. Тем не менее, даже в своём современном виде этот код полностью рабочий, а потому его можно использовать для работы с системным реестром.

Но, конечно, это всё только начало написания твикера. Дальше будет интереснее, хотя, правда, и несколько сложнее.

(Продолжение следует)

Вадим СТАНКЕВИЧ

Версия для печатиВерсия для печати

Номер: 

20 за 2008 год

Рубрика: 

Software
Заметили ошибку? Выделите ее мышкой и нажмите Ctrl+Enter!