Многие клиентские приложения работают с системным Реестром: записывают в него какие-либо данные и считывают их оттуда. Например, приложение может хранить в Реестре свои конфигурационные параметры; так поступают большинство приложений, благо Реестр именно для этого и предназначен. Некоторые приложения могут считывать и модифицировать параметры других приложений, в том числе входящих в состав Windows, или же самой Windows; это всевозможные "твикалки" - программы тонкой настройки как самой операционной системы, так и других программ. Есть приложения, выполняющие чистку Реестра от ненужных и устаревших данных, - они также манипулируют содержимым Реестра.
Есть ли у нас возможность предоставить нашим HTML-приложениям доступ к Реестру? Разумеется, есть! И сейчас мы выясним, как это можно сделать.
Внимание! Перед чтением этой статьи настоятельно рекомендуется ознакомиться с предыдущими статьями цикла, посвящённого HTML-приложениям Internet Explorer.
1. Получение доступа к средствам работы с Реестром WSH
Для работы с Реестром используются внешние объекты, реализуемые программой Windows Scripting Host, или WSH. Эта программа уже знакомы нам по двум предыдущим статьям цикла, где описывались реализация файлового ввода-вывода и работа с объектами файловой системы - файлами, папками и дисками.
В предыдущей статье цикла мы несколько раз пользовались внешним объектом WScript.Shell, реализуемым WSH. Мы задействовали его экземпляр, чтобы получить системную папку и текущую папку приложения.
Так вот, для работы с Реестром также используется объект WScript.Shell. Поэтому сначала нам нужно будет создать его экземпляр уже известным нам способом:
var oWSS = new ActiveXObject("WScript.Shell");
2. Принципы организации Реестра. Параметры, разделы, пути и ключи
А теперь самое время рассмотреть принципы организации Реестра. Иначе мы просто не поймём, что говорится далее в этой статье.
Прежде всего, любые данные хранятся в Реестре в виде отдельных значений. Эти значения могут иметь либо строковый, либо целочисленный тип. Если же нам потребуется сохранить в Реестре значение другого типа, мы должны привести его либо к строке, либо к целому числу; так, число с плавающей точкой можно сохранить как строку, а логическую величину удобнее хранить в виде целого числа.
На заметку Вообще-то, Реестр поддерживает большее количество типов данных, но WSH позволяет нам работать только со строковым и целочисленным, а также с массивами строк и целых чисел.
Значения хранятся в Реестре в виде так называемых параметров - своего рода переменных. Каждый параметр может хранить только одно значение любого типа из поддерживаемых Реестром и WSH.
Отдельные параметры Реестра объединяются в группы - разделы. Раздел может содержать произвольное количество параметров или не содержать их вовсе (такое встречается очень часто).
Разделы Реестра могут содержать в себе другие разделы. Фактически Реестр представляет собой иерархическую структуру, в которой одни разделы вложены в другие. Здесь напрашивается аналогия со структурой папок файловой системы, где одни папки вложены в другие.
Но как нам получить доступ к нужному значению, хранящемуся в Реестре?
Каждый раздел Реестра имеет имя, уникальное в пределах того раздела, в который он вложен. А каждый параметр также имеет имя, уникальное в пределах раздела, в котором он находится.
Таким образом, чтобы получить доступ к какому-либо разделу или параметру, нам следует сформировать путь к нему, записав имена всех разделов, в которые он последовательно вложен, начиная с раздела самого верхнего - нулевого - уровня вложенности, и разделив их символами обратного слеша. (Снова аналогия с файловой системой, где мы используем пути для доступа к нужной нам папке или файлу.) Путь к разделу при этом должен заканчиваться символом обратного слеша, а путь к параметру - не должен.
HKEY_CURRENT_USER\Software\Microsoft\
Здесь мы указали путь к разделу Microsoft, вложенному в раздел Software, который, в свою очередь, вложен в раздел нулевого уровня вложенности HKEY_CURRENT_USER. Поскольку мы завершили этот путь символом обратного слеша, он укажет именно на раздел.
Кстати, пути к разделам Реестра часто называют ключами.
А здесь мы указали путь к параметру Composition, последовательно вложенному в разделы HKEY_CURRENT_USER, Software, Microsoft, Windows и DWM. Обратим внимание, что мы не указали символ обратного слеша в конце этого пути, дав системе понять, что это путь именно к параметру.
На самом верхнем - нулевом - уровне вложенности Реестра располагаются пять разделов, называемых корневыми. Один из таких корневых разделов уже упоминался выше - HKEY_CURRENT_USER. Он служит для хранения параметров уровня текущего пользователя. Именно в нём хранится большая часть параметров различных приложений.
Для хранения параметров, общих для всех пользователей, служит корневой раздел HKEY_LOCAL_MACHINE. В нём хранятся настройки, относящиеся к самой системе и самим программам и не относящиеся к текущему пользователю.
Помимо этого, существуют корневые разделы HKEY_CLASSES_ROOT, HKEY_USERS и HKEY_CURRENT_CONFIG. Но приложения, за исключением лишь тех, что глубоко "залезают" в систему, редко работают с ними.
Вместо полных имён корневых разделов мы можем использовать сокращённые. Они перечислены ниже.
HKEY_CURRENT_USER - HKCU.
HKEY_LOCAL_MACHINE - HKLM.
HKCU\Software\Microsoft\Windows\DWM\Composition
Ранее мы познакомились с параметрами Реестра и узнали, что каждый из них должен иметь уникальное в пределах раздела имя. Однако в каждом разделе существует особый параметр, называемый параметром по умолчанию, или параметром раздела. Он также может хранить одно значение любого типа, но не имеет имени. Как получить к нему доступ, мы узнаем потом.
3. Работа с Реестром
Теперь мы можем начать работать с содержимым Реестра - разделами, параметрами и их значениями.
3.1. Запись в Реестр
Для записи в Реестр нового значения используется метод RegWrite объекта WScript.Shell. Формат его вызова таков:
<экземпляр объекта WScript.Shell>.RegWrite(
<путь к разделу или параметру Реестра>,
<новое значение для записи>[,
<тип значения>]
);
ение для записи>[,
<тип значения>]
);[/code]
Первым параметром задаётся путь либо к разделу (то есть ключ), либо к параметру Реестра в виде строки. Если задан путь к разделу, будет выполнена запись нового значения в параметр по умолчанию этого раздела. Если же задан путь к параметру, новое значение будет записано в этот параметр.
Если заданный путь ещё не существует, WSH сам создаст недостающие разделы и параметры. Так что нам не придётся проверять, существуют ли они.
Второй параметр задаёт само новое значение, которое должно быть записано в параметр. Оно может быть задано в виде строки или целого числа.
Третий, необязательный, параметр позволяет задать тип, в котором новое значение будет сохранено в Реестре. Он задаётся в виде строки, содержащей обозначение типа. Все доступные типы и их обозначения перечислены ниже.
REG_SZ - обычная строка.
REG_EXPAND_SZ - расширяемая строка. Значение будет сохранено в виде строки.
REG_DWORD - 32-разрядное целое число.
REG_BINARY - двоичные данные. Реально значение будет сохранено в виде 32-разрядного целого числа.
Если третий параметр не указан, значение будет сохранено в виде обычной строки (тип REG_SZ).
Это выражение создаст в разделе Software, вложенном в корневой раздел HKEY_CURRENT_USER, раздел TheVista.ru, а в нём - раздел SampleApp. В параметре по умолчанию последнего раздела будет сохранена пустая строка.
При указании путей к разделам или параметрам Реестра следует иметь в виду следующее. Для разделения имён разделов и параметра в путях применяется символ обратного слеша (\). Этот же символ применяется для указания специальных символов (литералов) в строковых значениях JavaScript; например, литерал \" обозначает символ двойной кавычки, который нельзя просто так вставить в строку. Так вот, чтобы поместить в строку именно символ обратного слеша, следует использовать литерал \\ (что мы и сделали в предыдущем примере). Запомним это на будущее.
Это выражение сохранит в параметре по умолчанию созданного ранее раздела SampleApp строку "22". Здесь, поскольку мы не указали третий параметр метода RegWrite, заданное значение (число 22) будет сохранено в виде строки.
Создаём в разделе SampleApp параметр ItemsCount и сохраняем в нём число 4. Обратим внимание, что мы явно указали для сохраняемого значения целочисленный тип.
3.2. Чтение из Реестра
Для чтения из Реестра используется метод RegRead объекта WScript.Shell. Вот формат его вызова:
[code]<экземпляр объекта WScript.Shell>.RegRead(
<путь к разделу или параметру Реестра>
);[/code]
Единственным параметром задаётся путь либо к разделу, либо к параметру Реестра в виде строки. Если задан путь к разделу, будет выполнено чтение значения параметра по умолчанию этого раздела. Если же задан путь к параметру, будет прочитано значение этого параметра.
Внимание! Если указать путь к несуществующему разделу или параметру, возникнет ошибка выполнения Web-сценария.
Метод RegRead возвращает значение указанного раздела или параметра. Его тип зависит от типа значения, хранящегося в Реестре.
Значение типа REG_SZ (обычная строка) возвращается в виде строки.
Значение типа REG_EXPAND_SZ (расширяемая строка) возвращается в виде строки.
Значение типа REG_DWORD (32-разрядное целое число) возвращается в виде целого числа.
Значение типа REG_BINARY (двоичные данные) возвращается в виде экземпляра объекта VBArray, представляющего массив VBScript. Этот массив будет содержать отдельные целые числа, составляющие записанное в Реестре значение этого типа.
Значение типа REG_MULTI_SZ (массив строк) возвращается в виде экземпляра объекта VBArray, представляющего массив VBScript. Этот массив будет содержать отдельные строки, составляющие записанный в Реестре массив строк.
Работу с массивами VBScript мы рассмотрим потом.
Ранее говорилось, что при указании пути к несуществующему разделу или параметру Реестра вызов метода RegRead завершится с ошибкой. К сожалению, объект WScript.Shell не предоставляет никаких средств выяснить, существует ли в Реестре тот или иной раздел или параметр. Так что единственный выход из этого положения - поместить вызов метода RegRead в блок try-catch.
Здесь мы считываем из параметра ItemsCount Реестра хранящееся в нём значение и помещаем его в переменную iItemsCount. Если же такого параметра в Реестре ещё нет, мы помещаем в ту же переменную число 0, которое можно рассматривать как значение этого параметра по умолчанию.
3.3. Удаление параметров и разделов из Реестра
Иногда приходится удалять из Реестра не нужные более параметры или целые разделы. В этом нам поможет метод RegDelete объекта WScript.Shell. Вызывается он так:
[code]<экземпляр объекта WScript.Shell>.RegDelete(
<путь к разделу или параметру Реестра>
);[/code]
Единственным параметром задаётся путь либо к разделу, либо к параметру Реестра в виде строки. Если задан путь к разделу, будет удалён данный раздел. Если же задан путь к параметру, будет удалён этот параметр.
Внимание! Если указать путь к несуществующему разделу или параметру, возникнет ошибка выполнения Web-сценария.
Обратим внимание на две вещи.
Раздел удаляется вместе со всеми содержащимися в нём параметрами и их значениями.
Раздел, содержащий другие разделы, удалить нельзя - при попытке сделать возникнет ошибка. Чтобы всё-таки удалить такой раздел, понадобится сначала удалить все хранящиеся в нём разделы.
Удаляем сначала раздел HKCU\Software\TheVista.ru\SampleApp, а потом - раздел HKCU\Software\TheVista.ru. Так сказать, подчищаем за собой...
4. Работа с массивами VBScript в JavaScript
Как мы уже знаем из параграфа 3.2, в некоторых случаях метод RegRead объекта WScript.Shell возвращает массив VBScript - экземпляр объекта VBArray. К сожалению, работать с таким массивом в JavaScript крайне неудобно.
Поэтому первым же делом следует преобразовать его в обычный массив JavaScript (который, как мы знаем, представляется в виде экземпляра объекта Array).
Сделать это поможет метод toArray, поддерживаемый объектом VBArray. Он не принимает параметров и возвращает то, что нам нужно, - массив JavaScript.
[code]var vbaParams = oWSS.RegRead("HKCU\\Software\\TheVista.ru\\SampleApp\\Params");
var aParams = vbaParams.toArray();
var sParam1 = aParams[0];
var sParam2 = aParams[1];
. . .[/code]
Здесь мы считываем значение параметра Params раздела HKCU\Software\TheVista.ru\SampleApp, имеющее тип REG_MULTI_SZ (массив строк), в виде массива VBScript, преобразуем его в массив JavaScript и получаем доступ к его элементам - отдельным строкам хранящегося в Реестре значения.
5. Пример HTML-приложения, работающего с Реестром
Осталось только рассмотреть пример HTML-приложения, работающего с Реестром.
Давайте возьмём приложение простейшего текстового редактора, что мы создали в первой части статьи, посвящённой использованию диалоговых окон, и добавим в него возможность хранения сделанных пользователем настроек в Реестре. (Таких настроек наше приложение подерживает всего две: признак активности переноса строк и цвет текста.)
Ниже приведены фрагменты кода файла Textedit_modal.hta (самого HTML-приложения), показывающие, какие дополнения и исправления следует в него внести.
function writeOptions()
{
var oWSS = new ActiveXObject("WScript.Shell");
oWSS.RegWrite("HKCU\\Software\\TheVista.ru\\TextEdit\\Wrap", bWrap ? 1 : 0,
"REG_DWORD");
oWSS.RegWrite("HKCU\\Software\\TheVista.ru\\TextEdit\\Color", sColor);
}
</SCRIPT>
</HEAD>
<BODY ONLOAD="readOptions();" ONUNLOAD="writeOptions();">
. . .
</BODY>
</HTML>[/code]
Лучший момент для чтения настроек из Реестра - запуск приложения. Поэтому мы реализовали чтение настроек в функции readOptions, которую привязали к событию load Web-страницы в качестве обработчика. Благо событие load возникает как раз после окончания загрузки Web-страницы.
Аналогично, запись текущих настроек в Реестр лучше всего реализовать при закрытии приложения. Функцию writeOptions, которая это делает, мы сделали обработчиком события unload, которое возникает при уходе с Web-страницы. А уход с Web-страницы выполняется, в числе прочего, и при закрытии HTML-приложения.
Начнём с функции writeOptions как самой простой. Она записывает текущие настройки приложения в Реестр. Значение цвета текста записывается как строка, поскольку оно и представляет собой строку. А вот с признаком активности переноса строк дело обстоит сложнее - он является логической величиной. Выход из этого положения прост - мы сохраним его в виде целого числа; значение 1 будет представлять логическое true, а значение 0 - логическое false.
Функция readOptions немногим сложнее. Она считывает из Реестра сохранённые там значения настроек и сразу же применяет их к области редактирования txtText, где и редактируется текст. (За подробностями обращайтесь к первой части статьи о диалоговых окнах HTML.) Обратим внимание, что оба вызова метода RegRead мы заключили в блоки try-catch, чтобы исключить возникновение ошибки в случае, если настройки ещё ни разу не были записаны в Реестр.
Осталось только попробовать исправленное приложение в действии.
Сайт является источником уникальной информации о семействе операционных систем Windows и других продуктах Microsoft. Перепечатка материалов возможна только с разрешения редакции.
Работает на WMS 2.34 (Страница создана за 0.036 секунд (Общее время SQL: 0.013 секунд - SQL запросов: 51 - Среднее время SQL: 0.00026 секунд))