|
Маленькие
хитрости с большой пользой |
Реестр
Реестр
Добавление элементов в контекстное меню "Создать"
1. Создать новый документ, поместить его в папку
Windows/ShellNew
2. В редакторе реестра найти расширение этого файла, добавить новый подключ,
добавить туда строку: FileName в качестве значения которой указать имя созданного
файла.
Путь к файлу который открывает не зарегистрированные файлы
1. Найти ключ HKEY_CLASSES_ROOT\Unknown\Shell
2. Добавить новый ключ Open
3. Под этим ключом еще ключ с именем command в котором изменить значение (По
умолчанию) на имя запускаемого файла, к имени нужно добавить %1.
(Windows заменит
этот символ на имя запускаемого файла)
В проводнике контекстное меню "Открыть в новом окне"
1. Найти ключ HKEY_CLASSES_ROOT\Directory\Shell
2. Создать подключ: opennew в котором изменить значение (По умолчанию) на: "Открыть
в новом окне"
3. Под этим ключом создать еще подключ command (По умолчанию) = explorer %1
Использование средней кнопки мыши Logitech в качестве двойного щелчка
Подключ HKEY_LOCAL_MACHINE\SoftWare\Logitech и там найти параметр DoubleClick
заменить 000 на 001
Новые звуковые события
Например создает звуки на запуск и закрытие WinWord
HKEY_CURRENT_USER\AppEvents\Shemes\Apps добавить подключ WinWord и к нему подключи
Open и Close.
Теперь в настройках звуков видны новые события
Путь в реестре для деинсталяции программ: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall
Наверх
Работа с реестром в Delphi 1
В Delphi 2 и выше появился объект TRegistry при помощи которого очень просто
работать с реестром. Но мы здесь рассмотрим функции
API, которые доступны и
в Delphi 1.
Реестр предназначен для хранения системных переменных и позволяет зарегистрировать
файлы программы, что обеспечивает их показ в проводнике с соответствующей иконкой,
вызов программы при щелчке на этом файле, добавление ряда команд в меню, вызываемое
при нажатии правой кнопки мыши над файлом. Кроме того, в реестр можно внести
некую свою информацию (переменные, константы, данные о инсталлированной программы
...). Программу можно добавить в список деинсталляции, что позволит удалить
ее из менеджера "Установка/Удаление программ" панели управления.
Для работы с реестром применяется ряд функций API :
RegCreateKey (Key: HKey; SubKey: PChar; var Result: HKey): Longint;
Создать подраздел в реестре. Key указывает на "корневой" раздел
реестра, в Delphi1 доступен только один - HKEY_CLASSES_ROOT, в в Delphi3 - все.
SubKey - имя раздела - строится по принципу пути к файлу в DOS (пример subkey1\subkey2\
...). Если такой раздел уже существует, то он открывается (в любом случае при
успешном вызове Result содержит Handle на раздел). Об успешности вызова судят
по возвращаемому значению, если ERROR_SUCCESS, то успешно, если иное - ошибка.
RegOpenKey(Key: HKey; SubKey: PChar; var Result: HKey): Longint;
Открыть подраздел Key\SubKey и возвращает Handle на него в переменной Result.
Если раздела с таким именем нет, то он не создается. Возврат - код ошибки или
ERROR_SUCCESS, если успешно.
RegCloseKey(Key: HKey): Longint;
Закрывает раздел, на который ссылается Key. Возврат - код ошибки или ERROR_SUCCESS,
если успешно.
RegDeleteKey(Key: HKey; SubKey: PChar): Longint;
Удалить подраздел Key\SubKey. Возврат - код ошибки или ERROR_SUCCESS, если
нет ошибок.
RegEnumKey(Key: HKey; index: Longint; Buffer: PChar;cb: Longint): Longint;
Получить имена всех подразделов раздела Key, где Key - Handle на открытый
или созданный раздел (см. RegCreateKey и RegOpenKey), Buffer - указатель на
буфер, cb - размер буфера, index - индекс, должен быть равен 0 при первом вызове
RegEnumKey. Типичное использование - в цикле While, где index увеличивается
до тех пор, пока очередной вызов RegEnumKey не завершится ошибкой (см. пример).
RegQueryValue(Key: HKey; SubKey: PChar; Value: PChar; var cb: Longint): Longint;
Возвращает текстовую строку, связанную с ключом Key\SubKey.Value - буфер для
строки; cb- размер, на входе - размер буфера, на выходе - длина возвращаемой
строки. Возврат - код ошибки.
RegSetValue(Key: HKey; SubKey: PChar; ValType: Longint; Value: PChar; cb:
Longint): Longint;
Задать новое значение ключу Key\SubKey, ValType - тип задаваемой переменной,
Value - буфер для переменной, cb - размер буфера. В Windows 3.1 допустимо только
Value=REG_SZ. Возврат - код ошибки или ERROR_SUCCESS, если нет ошибок.
Примеры :
{ Создаем список всех подразделов указанного раздела }
procedure TForm1.Button1Click(Sender: TObject);
var
MyKey : HKey; { Handle для работы с разделом }
Buffer : array[0..1000] of char; { Буфер }
Err, { Код ошибки }
index : longint; { Индекс подраздела }
begin
Err:=RegOpenKey(HKEY_CLASSES_ROOT,'DelphiUnit',MyKey); { Открыли раздел }
if Err<> ERROR_SUCCESS then
begin
MessageDlg('Нет такого раздела !!',mtError,[mbOk],0);
exit;
end;
index:=0;
{Определили имя первого подраздела }
Err:=RegEnumKey(MyKey,index,Buffer,Sizeof(Buffer));
while err=ERROR_SUCCESS do { Цикл, пока есть подразделы }
begin
memo1.lines.add(StrPas(Buffer)); { Добавим имя подраздела в список }
inc(index); { Увеличим номер подраздела }
Err:=RegEnumKey(MyKey,index,Buffer,Sizeof(Buffer)); { Запрос }
end;
RegCloseKey(MyKey); { Закрыли подраздел }
end;
Наверх
Объект INIFILES - работа с INI файлами.
Почему иногда лучше использовать INI-файлы, а не реестр?
1. INI-файлы можно просмотреть и отредактировать в обычном блокноте.
2. Если INI-файл хранить в папке с программой, то при переносе папки на другой
компьютер настройки сохраняются. (Я еще не написал ни одной программы, которая
бы не поместилась на одну дискету :)
3. Новичку в реестре можно запросто запутаться или (боже упаси), чего-нибудь
не то изменить.
Поэтому для хранения параметров настройки программы удобно использовать стандартные
INI файлы Windows. Работа с INI файлами ведется при помощи объекта TIniFiles
модуля IniFiles. Краткое описание методов объекта TIniFiles дано ниже.
Constructor Create('d:\test.INI');
Создать экземпляр объекта и связать его с файлом. Если такого файла нет,
то он создается, но только тогда, когда произведете в него запись информации.
WriteBool(const Section, Ident: string; Value: Boolean);
Присвоить элементу с именем Ident раздела Section значение типа boolean
WriteInteger(const Section, Ident: string; Value: Longint);
Присвоить элементу с именем Ident раздела Section значение типа Longint
WriteString(const Section, Ident, Value: string);
Присвоить элементу с именем Ident раздела Section значение типа String
ReadSection (const Section: string; Strings: TStrings);
Прочитать имена всех корректно описанных переменных раздела Section (некорректно
описанные опускаются)
ReadSectionValues(const Section: string; Strings: TStrings);
Прочитать имена и значения всех корректно описанных переменных раздела Section.
Формат :
имя_переменной = значение
EraseSection(const Section: string);
Удалить раздел Section со всем содержимым
ReadBool(const Section, Ident: string; Default: Boolean): Boolean;
Прочитать значение переменной типа Boolean раздела Section с именем Ident,
и если его нет, то вместо него подставить значение Default.
ReadInteger(const Section, Ident: string; Default: Longint): Longint;
Прочитать значение переменной типа Longint раздела Section с именем Ident,
и если его нет, то вместо него подставить значение Default.
ReadString(const Section, Ident, Default: string): string;
Прочитать значение переменной типа String раздела Section с именем Ident,
и если его нет, то вместо него подставить значение Default.
Free;
Закрыть и освободить ресурс. Необходимо вызвать при завершении работы с
INI файлом
Property Values[const Name: string]: string;
Доступ к существующему параметру по имени Name
Пример :
Procedure TForm1.FormClose(Sender: TObject);
var
IniFile:TIniFile;
begin
IniFile := TIniFile.Create('d:\test.INI'); { Создали экземпляр объекта }
IniFile.WriteBool('Options', 'Sound', True); { Секция Options: Sound:=true }
IniFile.WriteInteger('Options', 'Level', 3); { Секция Options: Level:=3 }
IniFile.WriteString('Options' , 'Secret password', Pass);
{ Секция Options: в Secret password записать значение переменной Pass }
IniFile.ReadSection('Options ', memo1.lines); { Читаем имена переменных}
IniFile.ReadSectionValues('Options ', memo2.lines); { Читаем имена и значения }
IniFile.Free; { Закрыли файл, уничтожили объект и освободили память }
end;
Наверх
Работа с реестром в Delphi 3-4
Итак, поговорим о работе с реестром, на сей
раз о работе с ним из Delphi 3-4. Как показал опыт и анализ работы с письмами,
этот раздел представляет собой трудность в изучении и многих интересует, как
работать с реестром (а в литературе, к сожалению, нет данных по работе с ним).
Возьмем за основу работу с реестром в Delphi 4.
В Delphi 4 для работы с реестром имеется класс TRegistry. В
отличии от своего "младшего брата" (TRegistry в Delphi 1)он может работать со
всеми ключами реестра, а не только с HKEY_CLASSES_ROOT.
Рассмотрим работу с TRegistry по шагам.
- Перед началом использования TRegistry необходимо объявить
подключение модуля Registry в Uses. Эту операцию Delphi не желает делать автоматически
- Необходимо объявить переменную типа TRegistry, для примера
назовем ее REG Необходимо проинициализировать: REG := TRegistry.Create;
- Работаем с REG
- Уничтожаем объект REG.Destroy;
Если опустить пункт 4, то рабочий минимум сводится к приведенному
ниже коду
var
REG : TRegistry;
begin
REG := TRegistry.Create;
REG.Destroy;
end;
Далее необходимо рассмотреть (вкратце) основные свойства и
методы TRegistry
Свойства
|
Свойства
|
Назначение
|
|
property RootKey: HKEY;
|
Самое полезное свойство. Допускает чтение и запись.
Определяет корневой ключ реестра. Допустимые значения:
HKEY_CLASSES_ROOT (по умолчанию)
HKEY_CURRENT_USER HKEY_LOCAL_MACHINE
HKEY_USERS HKEY_CURRENT_CONFIG
HKEY_DYN_DATA
Лично я не верю в эти "по умолчанию", потому начинаю работу с присвоения
значения RootKey
|
| property CurrentPath: String; |
Путь к текущему ключу |
| property LazyWrite: Boolean; |
"Ленивая запись". По умолчанию = true, что означает, что
на момент возврата из функции закрытия ключа не гарантируется, что изменения
в нем записаны в реестр. Если false, то на момент возврата из функции
закрытия ключа гарантируется, что все изменения уже записаны в реестр.
|
| property CurrentKey: HKEY; |
Открытый в настоящее время ключ реестра |
Методы
Procedure CloseKey;
Закрывает открытый в данный момент ключ реестра и записывает в реестра все
изменения (если таковые были), произведенные в данном ключе. Вызов CloseKey
несколько раз или при отсутствии открытого ключа не вызывает ошибки.
function CreateKey(const Key: String): Boolean;
Создает ключ Key (где Key - путь с разделителями "\", например Software\Test.
Имя корневого ключа в пути не указывается !! Он задается через property RootKey.
Возвращает True при успешном создании.
function DeleteKey(const Key: String): Boolean;
Удалить ключ Key (аналогично CreateKey, только с точностью до наоборот)
function DeleteValue(const Name: String): Boolean;
Удалить параметр с именем Name текущего ключа. Очевидно, что предварительно
необходимо открыть этот ключ.
function GetDataInfo(const ValueName: String; var Value:
TRegDataInfo): Boolean;
Получить информацию о параметре ValueName текущего ключа - его тип и размер.
При написании программ применяется редко, т.к. программист и сам знает, какого
типа его параметры. А вот при написании разного рода утилит для просмотра
и редактирования реестра он просто незаменим.
Типы:
TRegDataType = (rdUnknown, rdString, rdExpandString, rdInteger, rdBinary);
TRegDataInfo = record
RegData: TRegDataType; // Тип ключа
DataSize: Integer; // Размер данных
end;
Данная функция возвращает комплексную информацию о параметре,
для получения данных о размере или типе можно применять GetDataSize и GetDataType
function GetDataSize(const ValueName: String): Integer;
Получить размер параметра ValueName текущего ключа в байтах. Если - при ошибке.
Для строкового параметра размер учитывает в размере и один байт для #0, завершающего
строку .
function GetDataType(const ValueName: String): TRegDataType;
Получить тип текущего ключа.
function GetKeyInfo(var Value: TRegKeyInfo): Boolean;
Получить информацию о ключе. Возвращает заполненную структуру:
TRegKeyInfo = record
MaxSubKeyLen: Integer; // Количество подключей
NumValues: Integer; // Количество параметров
MaxValueLen: Integer; // Максимальная длина имени параметра
MaxDataLen: Integer; // Максимальная длина данных
FileTime: TFileTime; // Время последней записи ключа
end;
Как очевидно из структуры, она предназначена для построения
программ просмотра реестра. При успешном выполнении возвращает true.
procedure GetKeyNames(Strings: TStrings);
Заполняет указанный Strings списком под ключей текущего ключа. Применяется
для построения программ просмотра реестра или в том случае, когда количество
подключей неизвестно. Например, одна из моих программ создает в одном из ключей
несколько подключей с одинаковой структурой, но их количество заранее неизвестно
(настройки пользователей).
procedure GetValueNames(Strings: TStrings);
Заполняет указанный Strings списком параметров текущего ключа.
function HasSubKeys: Boolean;
Возвращает True, если текущий ключ имеет подключи и False в противном случае
function KeyExists(const Key: String): Boolean;
Возвращает True, если ключ Key существует. Полезная функция, рекомендуется
применять ее перед открытием ключей.
function LoadKey(const Key, FileName: String): Boolean;
Создает ключ Key и загружает в него данные из файла с именем FileName. Полезно
при написании инсталляторов. Возвращает True при успешном выполнении.
procedure MoveKey(const OldName, NewName: String; Delete:
Boolean);
Копировать или переименовать ключ. В любом случае копирует все из ключа OldName
в NewName (со всеми подключами). После копирования анализируется Delete, и
если он true, то ключ OldName уничтожается со всем содержимым. Лично у меня
не было потребности в применении данной функции - она не требуется программ
и предначначена для построения редакторов реестра.
function OpenKey(const Key: String; CanCreate: Boolean):
Boolean;
Очень важная функция - с нее начинается работа с ключом. Key - имя открываемого
ключа. Если ключ с указанным именем не найден и CanCreate=true, то производится
попытка создать ключ с указанным именем. Возвращает признак успешности открытия
ключа, его обязательно следует анализировать.
function OpenKeyReadOnly(const Key: String): Boolean;
Тоже, что и OpenKey, но открытие идет в режиме "только чтение"
Внимание !!!!!! Все функции типа Read** при вызове
генерируют исключение, если параметр не найден. Это исключение следует отлавливать
при помощи try except или проверять наличие параметра при помощи ValueExists
перед его чтением.
function ReadBinaryData(const Name: String; var Buffer;
BufSize: Integer): Integer;
Читает значение параметра с именем Name текущего (открытого) ключа в Buffer
размером BufSize.
function ReadBool(const Name: String): Boolean;
Считать значение параметра с именем Name типа Boolean
function ReadDate(const Name: String): TDateTime;
Считать значение параметра с именем Name типа дата
function ReadDateTime(const Name: String): TDateTime;
Считать значение параметра с именем Name типа дата-время
function ReadTime(const Name: String): TDateTime;
Считать значение параметра с именем Name типа время
function ReadFloat(const Name: String): Double;
Считать значение параметра с именем Name типа Double
function ReadInteger(const Name: String): Integer;
Считать значение параметра с именем Name типа Integer
function ReadString(const Name: String): String;
Считать значение параметра с именем Name типа String
function RegistryConnect(const UNCName: String): Boolean;
Подключить сетевой реестр машины UNCName (формат: \\сетевое имя машины). Перед
вызовом этой функции программа должна установить RootKey в значение HKEY_USERS
или HKEY_LOCAL_MACHINE. При успешном соединении и открытии удаленного реестра
его RootKey ставится в заданное перед вызовам значение свойства RootKey и
возвращается True.
procedure RenameValue(const OldName, NewName: String);
Переименовать параметр текущего ключа с именем OldName в NewName.
function ReplaceKey(const Key, FileName, BackUpFileName:
String): Boolean;
Заменить место хранения ключа. Обычно ключи хранятся в базовом файле реестра,
нот вызовом данной функции можно задать в качестве места хранения ключа отдельный
файл с именем FileName (его следует предварительно создать при помощи savekey).
При каждой перезагрузке компьютера ключ Key будет загружаться значениями,
считываемыми из файла этого файла FileName,т.е. по сути мы имеет дело с ульем
(hive) в терминологии Windows NT. Определение: Улей - часть реестра (его ячейка).
Улей является дискретным набором ключей, подключей и параметров, который находится
вверху иерархии реестра. Улей поддерживается одиночным файлом. BackUpFileName
- имя резервной копии, которая создается перед перезаписью данных ключа Key.
Если кого интересуют подробности, то следует почитать книгу по реестру Windows
NT, главы типа "Ульи и файлы" и "Целостность и восстановление улья в реестре".
При разработке практических приложений я не разу не применял этот вызов.
function RestoreKey(const Key, FileName: String): Boolean;
Открывает указанный ключ и перезаписывает его данные и подключи данными из
файла FileName.
function SaveKey(const Key, FileName: String): Boolean;
Сохраняет все параметры указанного ключа и всех его подключей в файле FileName.
Может применяться совместно с LoadKey и RestoreKey для создания и восстановления
ключей реестра.
function UnLoadKey(const Key: String): Boolean;
Удалить улей Key из реестра.
function ValueExists(const Name: string): Boolean;
Проверить, существует ли в текущем ключе параметр с именем Name. Весьма полезная
функция, т.к. чтение несуществующего параметра приводит к исключительной ситуации
procedure WriteBinaryData(const Name: String; var Buffer;
BufSize: Integer);
Записать в параметр с именем Name данные из буфера Buffer размером BufSize.
Если параметр существовал, то он будет перезаписан. Если параметр не существовал,
то он будет создан. Это справедливо и для всех последующих процедур записи
параметров
Остальные процедуры записи - WriteBool, WriteCurrency,WriteDate,WriteDateTime,
WriteExpandString, WriteFloat, WriteInteger, WriteString, WriteTime имеют
по два параметра - (имя ключа, значение ключа).
Ну вот, класс описали, теперь приведем парочку примеров.
Пример 1 - запись.
var
REG : TRegistry;
begin
REG := TRegistry.Create;
REG.RootKey:=HKEY_LOCAL_MACHINE;
REG.OpenKey('Software\Test',true);
REG.WriteBool('Test1',true);
REG.WriteInteger('Test2',12);
REG.CloseKey;
REG.Destroy;
end;
Данный пример создает (если его не было) или открывает ключ
реестра HKEY_LOCAL_MACHINE\Software\Test и записывает в него два параметра
типа Boolean и Integer.
Пример 2 - чтение.
var
REG : TRegistry;
B : Boolean;
I : Integer;
begin
REG := TRegistry.Create;
REG.RootKey:=HKEY_LOCAL_MACHINE;
if REG.OpenKey('Software\Test',false) then begin
if REG.ValueExists('Test1') then
B:=REG.ReadBool('Test1')
else ShowMessage('Параметр Test1 не найден');
if REG.ValueExists('Test2') then
I:=REG.ReadInteger('Test2')
else ShowMessage('Параметр Test2 не найден');
end else
ShowMessage('Ключ HKEY_LOCAL_MACHINE\Software\Test не найден');
REG.CloseKey;
REG.Destroy;
end;
Данный пример открывает ключ (контролируя, есть ли он) и пытается
читать параметры с проверкой, существуют ли они.
Наверх
|